PageRenderTime 50ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/jar.php

http://github.com/joshtronic/pickles
PHP | 2804 lines | 1242 code | 304 blank | 1258 comment | 227 complexity | e158d778c2f12e09fc370bfdb9b6e80c MD5 | raw file
Possible License(s): MIT
  1. <?php
  2. /**
  3. * Common API Class File for PICKLES
  4. *
  5. * PHP version 5
  6. *
  7. * Licensed under The MIT License
  8. * Redistribution of these files must retain the above copyright notice.
  9. *
  10. * @author Josh Sherman <josh@gravityblvd.com>
  11. * @copyright Copyright 2007-2011, Josh Sherman
  12. * @license http://www.opensource.org/licenses/mit-license.html
  13. * @package PICKLES
  14. * @link http://p.ickl.es
  15. */
  16. /**
  17. * Common API Interface
  18. *
  19. * Parent class that our API interface classes should be extending. Contains
  20. * execution of parental functions but may contain more down the road.
  21. */
  22. abstract class API_Common extends Object
  23. {
  24. /**
  25. * Constructor
  26. */
  27. public function __construct()
  28. {
  29. parent::__construct();
  30. }
  31. /**
  32. * Destructor
  33. */
  34. public function __destruct()
  35. {
  36. parent::__destruct();
  37. }
  38. }
  39. /**
  40. * Google Profanity Class File for PICKLES
  41. *
  42. * PHP version 5
  43. *
  44. * Licensed under The MIT License
  45. * Redistribution of these files must retain the above copyright notice.
  46. *
  47. * @author Josh Sherman <josh@gravityblvd.com>
  48. * @copyright Copyright 2007-2011, Josh Sherman
  49. * @license http://www.opensource.org/licenses/mit-license.html
  50. * @package PICKLES
  51. * @link http://p.ickl.es
  52. */
  53. /**
  54. * Google Profanity API Interface
  55. */
  56. class API_Google_Profanity extends API_Common
  57. {
  58. /**
  59. * Check
  60. *
  61. * Checks if a word is considered profanity.
  62. *
  63. * @usage API_Google_Profanity::check('fuck'); // returns true
  64. * @param string $word word to check
  65. * @return boolean whether or not the word is profanity
  66. */
  67. public static function check($word)
  68. {
  69. $response = json_decode(file_get_contents('http://www.wdyl.com/profanity?q=' . $word), true);
  70. if ($response == null || !isset($response['response']) || !in_array($response['response'], array('true', 'false')))
  71. {
  72. throw new Exception('Invalid response from API.');
  73. }
  74. else
  75. {
  76. return $response['response'] == 'true';
  77. }
  78. }
  79. }
  80. /**
  81. * Tinychat Class File for PICKLES
  82. *
  83. * PHP version 5
  84. *
  85. * Licensed under The MIT License
  86. * Redistribution of these files must retain the above copyright notice.
  87. *
  88. * @author Josh Sherman <josh@gravityblvd.com>
  89. * @copyright Copyright 2007-2011, Josh Sherman
  90. * @license http://www.opensource.org/licenses/mit-license.html
  91. * @package PICKLES
  92. * @link http://p.ickl.es
  93. */
  94. /**
  95. * Tinychat API Interface
  96. *
  97. * @link http://tinychat.com/developer/docs
  98. */
  99. class API_Tinychat extends API_Common
  100. {
  101. /**
  102. * Public Key
  103. *
  104. * @access private
  105. * @var string
  106. */
  107. private $public_key = null;
  108. /**
  109. * Secret Key
  110. *
  111. * @access private
  112. * @var string
  113. */
  114. private $secret_key = null;
  115. /**
  116. * Constructor
  117. *
  118. * Assigns our public and secret keys from the configuration.
  119. */
  120. public function __construct()
  121. {
  122. parent::__construct();
  123. if (isset($this->config->api['tinychat'], $this->config->api['tinychat']['public_key'], $this->config->api['tinychat']['secret_key']))
  124. {
  125. $this->public_key = $this->config->api['tinychat']['public_key'];
  126. $this->secret_key = $this->config->api['tinychat']['secret_key'];
  127. }
  128. else
  129. {
  130. throw new Exception('Unable to load TinyChat configuration.');
  131. }
  132. }
  133. /**
  134. * Execute
  135. *
  136. * Constructs a valid API call, executes it and returns the results.
  137. *
  138. * @param string $codephrase name of the API call being called
  139. * @param string $authentication post-codephrase portion of the auth string
  140. * @param array $parameters key / value pairs for additional data
  141. * @return array results of the API call
  142. */
  143. private function execute($codephrase, $authentication, $parameters = null)
  144. {
  145. // Assembles and hashes the authentication token
  146. $authentication = md5($this->secret_key . ':' . $authentication);
  147. // Assembles any additional parameters
  148. $additional = '';
  149. if ($parameters && is_array($parameters))
  150. {
  151. foreach ($parameters as $key => $value)
  152. {
  153. $additional .= '&' . $key . '=' . $value;
  154. }
  155. }
  156. // Executes the API call
  157. $results = file_get_contents('http://tinychat.apigee.com/' . $codephrase . '?result=json&key=' . $this->public_key . '&auth=' . $authentication . $additional);
  158. return json_decode($results, true);
  159. }
  160. /**
  161. * List Rooms
  162. *
  163. * Pulls all rooms for the API application.
  164. *
  165. * @return array API results
  166. */
  167. public function listRooms()
  168. {
  169. return $this->execute('roomlist', 'roomlist');
  170. }
  171. /**
  172. * Room Info
  173. *
  174. * Pulls the information for a room.
  175. *
  176. * @param string $room name of the room
  177. * @param boolean $with_ip whether or not to include users IP addresses
  178. * @return array API results
  179. */
  180. public function roomInfo($room, $with_ip = false)
  181. {
  182. return $this->execute('roominfo', $room . ':roominfo', array('room' => $room, 'with_ip' => ($with_ip ? 1 : 0)));
  183. }
  184. /**
  185. * Set Room Password
  186. *
  187. * Sets the password for the room, only users with the correct password
  188. * will be able to enter.
  189. *
  190. * @param string $room name of the room
  191. * @param string $password password to use, blank for no password
  192. * @return array API results
  193. */
  194. public function setRoomPassword($room, $password = '')
  195. {
  196. return $this->execute('setroompassword', $room . ':setroompassword', array('room' => $room, 'password' => $password));
  197. }
  198. /**
  199. * Set Broadcast Password
  200. *
  201. * Sets the password to allow broadcasting in the room. Only users with the
  202. * correct password will be able to broadcast.
  203. *
  204. * @param string $room name of the room
  205. * @param string $password password to use, blank for no password
  206. * @return array API results
  207. */
  208. public function setBroadcastPassword($room, $password = '')
  209. {
  210. return $this->execute('setbroadcastpassword', $room . ':setbroadcastpassword', array('room' => $room, 'password' => $password));
  211. }
  212. /**
  213. * Generate HTML
  214. *
  215. * Creates the HTML to place a chat on a site.
  216. *
  217. * @todo List params...
  218. * @return array API results
  219. */
  220. public function generateHTML($room, $join = false, $nick = false, $change = false, $login = false, $oper = false, $owner = false, $bcast = false, $api = false, $colorbk = false, $tcdisplay = false, $autoop = false, $urlsuper = false, $langdefault = false)
  221. {
  222. return '
  223. <script type="text/javascript">
  224. var tinychat = {'
  225. . 'room: "' . $room . '",'
  226. . ($join ? 'join: "auto",' : '')
  227. . ($nick ? 'nick: "' . $nick . '",' : '')
  228. . ($change ? 'change: "none",' : '')
  229. . ($login ? 'login: "' . $login . '",' : '')
  230. . ($oper ? 'oper: "none",' : '')
  231. . ($owner ? 'owner: "none",' : '')
  232. . ($bcast ? 'bcast: "restrict",' : '')
  233. . ($api ? 'api: "' . $api . '",' : '')
  234. . ($colorbk ? 'colorbk: "' . $colorbk . '",' : '')
  235. . ($tcdisplay ? 'tcdisplay: "vidonly",' : '')
  236. /* @todo Implement $autoop, it's an array and needs validated */
  237. . ($urlsuper ? 'urlsuper: "' . $urlsuper . '",' : '')
  238. . ($langdefault ? 'langdefault: "' . $langdefault . '",' : '')
  239. . 'key: "' . $this->public_key . '"'
  240. . '};
  241. </script>
  242. <script src="http://tinychat.com/js/embed.js"></script>
  243. <div id="client"></div>
  244. ';
  245. }
  246. }
  247. /**
  248. * Caching System for PICKLES
  249. *
  250. * PHP version 5
  251. *
  252. * Licensed under The MIT License
  253. * Redistribution of these files must retain the above copyright notice.
  254. *
  255. * @author Josh Sherman <josh@gravityblvd.com>
  256. * @copyright Copyright 2007-2011, Josh Sherman
  257. * @license http://www.opensource.org/licenses/mit-license.html
  258. * @package PICKLES
  259. * @link http://p.ickl.es
  260. */
  261. /**
  262. * Cache Class
  263. *
  264. * Wrapper class for Memcache() to allow for better error handling when the
  265. * Memcached server is unavailable. Designed around the syntax for Memcached()
  266. * to allow for an easier transistion to the aforementioned in the future. I
  267. * don't entirely remember specifics, but the reason for not using Memcached()
  268. * was due to an unexplainable bug in the version in the repository for Ubuntu
  269. * 10.04 LTS. Memcached() does support more of the memcached protocol and will
  270. * eventually be what PICKLES uses.
  271. *
  272. * Requires php5-memcache
  273. *
  274. * @link http://us.php.net/manual/en/book.memcache.php
  275. * @link http://packages.ubuntu.com/lucid/php5-memcache
  276. * @link http://www.memcached.org/
  277. */
  278. class Cache extends Object
  279. {
  280. /**
  281. * Hostname for the Memcached Server
  282. *
  283. * @access private
  284. * @var string
  285. */
  286. private $hostname = null;
  287. /**
  288. * Port to use to connect
  289. *
  290. * @access private
  291. * @var integer
  292. */
  293. private $port = null;
  294. /**
  295. * Connection resource to Memcached
  296. *
  297. * @access private
  298. * @var object
  299. */
  300. private $connection = null;
  301. /**
  302. * Constructor
  303. *
  304. * Sets up our connection variables.
  305. *
  306. * @param string $hostname optional hostname to connect to
  307. * @param string $database optional port to use
  308. */
  309. public function __construct($hostname = null, $port = null)
  310. {
  311. parent::__construct();
  312. if ($this->config->pickles['cache'])
  313. {
  314. if (isset($this->config->datasources[$this->config->pickles['cache']]))
  315. {
  316. $datasource = $this->config->datasources[$this->config->pickles['cache']];
  317. if (isset($datasource['hostname'], $datasource['port']))
  318. {
  319. $this->hostname = $datasource['hostname'];
  320. $this->port = $datasource['port'];
  321. }
  322. }
  323. }
  324. }
  325. /**
  326. * Destructor
  327. *
  328. * Closes the connection when the object dies.
  329. */
  330. public function __destruct()
  331. {
  332. if ($this->connection)
  333. {
  334. $this->connection->close();
  335. }
  336. }
  337. /**
  338. * Get Instance
  339. *
  340. * Let's the parent class do all the work.
  341. *
  342. * @static
  343. * @param string $class name of the class to instantiate
  344. * @return object self::$instance instance of the Cache class
  345. */
  346. public static function getInstance($class = 'Cache')
  347. {
  348. return parent::getInstance($class);
  349. }
  350. /**
  351. * Opens Connection
  352. *
  353. * Establishes a connection to the memcached server.
  354. */
  355. public function open()
  356. {
  357. if ($this->connection === null)
  358. {
  359. $this->connection = new Memcache();
  360. $this->connection->connect($this->hostname, $this->port);
  361. }
  362. return true;
  363. }
  364. /**
  365. * Get Key
  366. *
  367. * Gets the value of the key and returns it.
  368. *
  369. * @param string $key key to retrieve
  370. * @return mixed value of the requested key, false if not set
  371. */
  372. public function get($key)
  373. {
  374. if ($this->open())
  375. {
  376. return $this->connection->get($key);
  377. }
  378. return false;
  379. }
  380. /**
  381. * Set Key
  382. *
  383. * Sets key to the specified value. I've found that compression can lead to
  384. * issues with integers and can slow down the storage and retrieval of data
  385. * (defeats the purpose of caching if you ask me) and isn't supported. I've
  386. * also been burned by data inadvertantly being cached for infinity, hence
  387. * the 5 minute default.
  388. *
  389. * @param string $key key to set
  390. * @param mixed $value value to set
  391. * @param integer $expiration optional expiration, defaults to 5 minutes
  392. * @return boolean status of writing the data to the key
  393. */
  394. public function set($key, $value, $expire = 300)
  395. {
  396. if ($this->open())
  397. {
  398. return $this->connection->set($key, $value, 0, $expire);
  399. }
  400. return false;
  401. }
  402. /**
  403. * Delete Key
  404. *
  405. * Deletes the specified key.
  406. *
  407. * @param string $key key to delete
  408. * @return boolean status of deleting the key
  409. */
  410. public function delete($key)
  411. {
  412. if ($this->open())
  413. {
  414. return $this->connection->delete($key);
  415. }
  416. return false;
  417. }
  418. /**
  419. * Increment Key
  420. *
  421. * Increments the value of an existing key.
  422. *
  423. * @param string $key key to increment
  424. * @return boolean status of incrementing the key
  425. * @todo Wondering if I should check the key and set to 1 if it's new
  426. */
  427. public function increment($key)
  428. {
  429. if ($this->open())
  430. {
  431. return $this->connection->increment($key);
  432. }
  433. return false;
  434. }
  435. }
  436. /**
  437. * Configuration Class File for PICKLES
  438. *
  439. * PHP version 5
  440. *
  441. * Licensed under The MIT License
  442. * Redistribution of these files must retain the above copyright notice.
  443. *
  444. * @author Josh Sherman <josh@gravityblvd.com>
  445. * @copyright Copyright 2007-2011, Josh Sherman
  446. * @license http://www.opensource.org/licenses/mit-license.html
  447. * @package PICKLES
  448. * @link http://p.ickl.es
  449. */
  450. /**
  451. * Config Class
  452. *
  453. * Handles loading the site's configuration file (if available). At the moment
  454. * this class is a very skewed Singleton. The plan is to eventually extend this
  455. * out to support multiple configuration files, and the ability to load in
  456. * custom config files on the fly as well. The core of PICKLES uses the class
  457. * as a Singleton so we're not loading the configuration multiple times per
  458. * page load.
  459. *
  460. * @usage <code>$config = new Config($filename);</code>
  461. */
  462. class Config extends Object
  463. {
  464. /**
  465. * Config data
  466. *
  467. * @access private
  468. * @var array
  469. */
  470. private $data = array();
  471. /**
  472. * Constructor
  473. *
  474. * Calls the parent constructor and loads the passed file.
  475. *
  476. * @param string $filename optional Filename of the config
  477. */
  478. public function __construct($filename = null)
  479. {
  480. parent::__construct();
  481. // Try to fine the configuration
  482. if ($filename == null)
  483. {
  484. $filename = 'config.php';
  485. $loaded = false;
  486. $cwd = getcwd();
  487. while ($loaded == false)
  488. {
  489. chdir(dirname($filename));
  490. if (getcwd() == '/')
  491. {
  492. throw new Exception('Unable to load configuration.');
  493. }
  494. chdir($cwd);
  495. $filename = '../' . $filename;
  496. $loaded = $this->load($filename);
  497. }
  498. }
  499. else
  500. {
  501. $this->load($filename);
  502. }
  503. }
  504. /**
  505. * Loads a configuration file
  506. *
  507. * @param string $filename filename of the config file
  508. * @return boolean success of the load process
  509. */
  510. public function load($filename)
  511. {
  512. $environments = false;
  513. $environment = false;
  514. // Sanity checks the config file
  515. if (file_exists($filename) && is_file($filename) && is_readable($filename))
  516. {
  517. require_once $filename;
  518. // Determines the environment
  519. if (isset($config['environment']))
  520. {
  521. $environment = $config['environment'];
  522. }
  523. else
  524. {
  525. if (isset($config['environments']) && is_array($config['environments']))
  526. {
  527. $environments = $config['environments'];
  528. // If we're on the CLI, check an environment was even passed in
  529. if (IS_CLI == true && $_SERVER['argc'] < 2)
  530. {
  531. throw new Exception('You must pass an environment (e.g. php script.php <environment>)');
  532. }
  533. // Loops through the environments and tries to match on IP or name
  534. foreach ($config['environments'] as $name => $hosts)
  535. {
  536. if (!is_array($hosts))
  537. {
  538. $hosts = array($hosts);
  539. }
  540. // Tries to determine the environment name
  541. foreach ($hosts as $host)
  542. {
  543. if (IS_CLI == true)
  544. {
  545. // Checks the first argument on the command line
  546. if ($_SERVER['argv'][1] == $name)
  547. {
  548. $environment = $name;
  549. break;
  550. }
  551. }
  552. else
  553. {
  554. if ((preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $host)
  555. && $_SERVER['SERVER_ADDR'] == $host)
  556. || $_SERVER['HTTP_HOST'] == $host)
  557. {
  558. // Sets the environment and makes a run for it
  559. $environment = $name;
  560. break;
  561. }
  562. }
  563. }
  564. }
  565. }
  566. }
  567. // Flattens the array based on the environment
  568. $this->data = $this->flatten($environment, $config);
  569. // Restore environments value
  570. if ($environments != false)
  571. {
  572. $this->data['environments'] = $environments;
  573. }
  574. // Sets the environment if it's not set already
  575. if (!isset($this->data['environment']))
  576. {
  577. $this->data['environment'] = $environment;
  578. }
  579. // Defaults profiler to true if it doesn't match an option exactly
  580. if (isset($this->data['pickles']['profiler']))
  581. {
  582. if ($this->data['pickles']['profiler'] !== true)
  583. {
  584. // If we have an array convert to a string
  585. if (is_array($this->data['pickles']['profiler']))
  586. {
  587. $this->data['pickles']['profiler'] = implode(',', $this->data['pickles']['profiler']);
  588. }
  589. // Checks that one of our known values exists, if not, force true
  590. if (preg_match('/(objects|timers|queries|explains)/', $this->data['pickles']['profiler'] == false))
  591. {
  592. $this->data['pickles']['profiler'] = true;
  593. }
  594. }
  595. }
  596. else
  597. {
  598. $this->data['pickles']['profiler'] = false;
  599. }
  600. // Defaults expected PICKLES options to false
  601. foreach (array('cache', 'logging') as $variable)
  602. {
  603. if (!isset($this->data['pickles'][$variable]))
  604. {
  605. $this->data['pickles'][$variable] = false;
  606. }
  607. }
  608. // Creates constants for the security levels
  609. if (isset($this->data['security']['levels']) && is_array($this->data['security']['levels']))
  610. {
  611. foreach ($this->data['security']['levels'] as $value => $name)
  612. {
  613. $constant = 'SECURITY_LEVEL_' . strtoupper($name);
  614. // Checks if constant is already defined, and throws an error
  615. if (defined($constant))
  616. {
  617. throw new Exception('The constant ' . $constant . ' is already defined');
  618. }
  619. else
  620. {
  621. define($constant, $value);
  622. }
  623. }
  624. }
  625. return true;
  626. }
  627. return false;
  628. }
  629. /**
  630. * Flatten
  631. *
  632. * Flattens the configuration array around the specified environment.
  633. *
  634. * @param string $environment selected environment
  635. * @param array $array configuration error to flatten
  636. * @return array flattened configuration array
  637. */
  638. private function flatten($environment, $array)
  639. {
  640. if (is_array($array))
  641. {
  642. foreach ($array as $key => $value)
  643. {
  644. if (is_array($value))
  645. {
  646. if (isset($value[$environment]))
  647. {
  648. $value = $value[$environment];
  649. }
  650. else
  651. {
  652. $value = $this->flatten($environment, $value);
  653. }
  654. }
  655. $array[$key] = $value;
  656. }
  657. }
  658. return $array;
  659. }
  660. /**
  661. * Get instance of the object
  662. *
  663. * Let's the parent class do all the work
  664. *
  665. * @static
  666. * @param string $class name of the class to instantiate
  667. * @return object self::$instance instance of the Config class
  668. */
  669. public static function getInstance($class = 'Config')
  670. {
  671. return parent::getInstance($class);
  672. }
  673. /**
  674. * Magic Setter Method
  675. *
  676. * Prohibits the direct modification of module variables.
  677. *
  678. * @param string $name name of the variable to be set
  679. * @param mixed $value value of the variable to be set
  680. */
  681. public function __set($name, $value)
  682. {
  683. throw new Exception('Cannot set config variables directly', E_USER_ERROR);
  684. }
  685. /**
  686. * Magic Getter Method
  687. *
  688. * Attempts to load the config variable. If it's not set, will override
  689. * the variable with boolean false.
  690. *
  691. * @param string $name name of the variable requested
  692. * @return mixed value of the variable or boolean false
  693. */
  694. public function __get($name)
  695. {
  696. if (!isset($this->data[$name]))
  697. {
  698. $this->data[$name] = false;
  699. }
  700. return $this->data[$name];
  701. }
  702. }
  703. /**
  704. * Single Entry Controller
  705. *
  706. * PHP version 5
  707. *
  708. * Licensed under The MIT License
  709. * Redistribution of these files must retain the above copyright notice.
  710. *
  711. * @author Josh Sherman <josh@gravityblvd.com>
  712. * @copyright Copyright 2007-2011, Josh Sherman
  713. * @license http://www.opensource.org/licenses/mit-license.html
  714. * @package PICKLES
  715. * @link http://p.ickl.es
  716. */
  717. /**
  718. * Controller Class
  719. *
  720. * The heavy lifter of PICKLES, makes the calls to get the session and
  721. * configuration loaded. Loads modules, serves up user authentication when the
  722. * module asks for it, and loads the viewer that the module requested. Default
  723. * values are present to make things easier on the user.
  724. *
  725. * @usage <code>new Controller($config);</code>
  726. */
  727. class Controller extends Object
  728. {
  729. /**
  730. * Pass Thru
  731. *
  732. * Whether or not the page being loaded is simple a pass thru for an
  733. * internal PICKLES file. The point of this variable is to suppress the
  734. * profiler report in the destructor.
  735. *
  736. * @access private
  737. * @var boolean
  738. */
  739. private $passthru = false;
  740. /**
  741. * Constructor
  742. *
  743. * To make life a bit easier when using PICKLES, the Controller logic is
  744. * executed automatically via use of a constructor.
  745. */
  746. public function __construct()
  747. {
  748. parent::__construct();
  749. if (isset($_REQUEST['request']))
  750. {
  751. // Catches requests that aren't lowercase
  752. $lowercase_reqest = strtolower($_REQUEST['request']);
  753. if ($_REQUEST['request'] != $lowercase_reqest)
  754. {
  755. header('Location: ' . substr_replace($_SERVER['REQUEST_URI'], $lowercase_reqest, 1, strlen($lowercase_reqest)));
  756. exit;
  757. }
  758. // Catches requests to the __shared directory
  759. if (preg_match('/^__shared/', $_REQUEST['request']))
  760. {
  761. header('Location: /');
  762. exit;
  763. }
  764. }
  765. // Generate a generic "site down" message if the site is set to be disabled
  766. if (isset($this->config->pickles['disabled']) && $this->config->pickles['disabled'] == true)
  767. {
  768. Error::fatal($_SERVER['SERVER_NAME'] . ' is currently<br />down for maintenance');
  769. }
  770. // Checks the passed request for validity
  771. if (isset($_REQUEST['request']) && trim($_REQUEST['request']) != '')
  772. {
  773. $request = $_REQUEST['request'];
  774. }
  775. // Loads the default module information if we don't have a valid request
  776. else
  777. {
  778. $request = isset($this->config->pickles['module']) ? $this->config->pickles['module'] : 'home';
  779. }
  780. // Loads the module's information
  781. list($module_class, $module_filename, $template_basename, $css_class, $js_basename) = $this->prepareVariables($request);
  782. unset($request);
  783. $module_exists = (isset($module_filename) && $module_filename != null && file_exists($module_filename));
  784. // Instantiates an instance of the module
  785. if ($module_exists)
  786. {
  787. require_once $module_filename;
  788. // Checks that our class exists
  789. if (class_exists($module_class))
  790. {
  791. $module = new $module_class;
  792. }
  793. else
  794. {
  795. if ($this->config->pickles['logging'] === true)
  796. {
  797. Log::warning('Class named ' . $module_class . ' was not found in ' . $module_filename);
  798. }
  799. }
  800. }
  801. // If a new module object wasn't created, create a generic one
  802. if (!isset($module))
  803. {
  804. $module = new Module();
  805. }
  806. // Determines if the module is private and should be, well, private
  807. if ($module->private == true)
  808. {
  809. header('Location: /');
  810. exit;
  811. }
  812. // Determines if we need to serve over HTTP or HTTPS
  813. if ($module->secure == false && isset($_SERVER['HTTPS']))
  814. {
  815. header('Location: http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
  816. exit;
  817. }
  818. elseif ($module->secure == true && !isset($_SERVER['HTTPS']))
  819. {
  820. header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
  821. exit;
  822. }
  823. // Establishes the session
  824. if (ini_get('session.auto_start') == 0)
  825. {
  826. if ($module->session)
  827. {
  828. if (session_id() == '')
  829. {
  830. session_start();
  831. }
  832. }
  833. }
  834. // Validates security level
  835. if ($module->security !== false)
  836. {
  837. $is_authenticated = false;
  838. if (is_array($module->security))
  839. {
  840. $module_security = $module->security;
  841. $security_check_class = 'isLevel';
  842. // Checks the type and validates it
  843. if (isset($module_security['type']))
  844. {
  845. $security_check_type = strtoupper($module_security['type']);
  846. if (in_array($security_check_type, array('IS', 'HAS', 'BETWEEN')))
  847. {
  848. $security_check_class = $security_check_type;
  849. }
  850. unset($security_check_type, $module_security['type']);
  851. }
  852. $module_security_levels = array();
  853. // If there's a level(s) key use it
  854. foreach (array('level', 'levels') as $security_level_key)
  855. {
  856. if (isset($module_security[$security_level_key]))
  857. {
  858. if (is_array($module_security[$security_level_key]))
  859. {
  860. array_merge($module_security_levels, $module_security[$security_level_key]);
  861. }
  862. else
  863. {
  864. $module_security_levels[] = $module_security[$security_level_key];
  865. }
  866. unset($module_security[$security_level_key]);
  867. }
  868. }
  869. // Assume everything left in the array is a level and add it to the array
  870. array_merge($module_security_levels, $module_security);
  871. $security_level_count = count($module_security_levels);
  872. switch ($security_check_class)
  873. {
  874. case 'BETWEEN':
  875. if ($security_level_count >= 2)
  876. {
  877. $is_authenticated = Security::betweenLevel($module_security_levels[0], array_pop($module_security_levels));
  878. }
  879. break;
  880. case 'HAS':
  881. if ($security_level_count > 0)
  882. {
  883. $is_authenticated = Security::hasLevel($module_security_levels);
  884. }
  885. break;
  886. case 'IS':
  887. if ($security_level_count > 0)
  888. {
  889. $is_authenticated = Security::isLevel($module_security_levels);
  890. }
  891. break;
  892. }
  893. }
  894. else
  895. {
  896. $is_authenticated = Security::isLevel($module->security);
  897. }
  898. if ($is_authenticated == false)
  899. {
  900. if ($_SERVER['REQUEST_METHOD'] == 'POST')
  901. {
  902. exit('{ "status": "error", "message": "You are not properly authenticated" }');
  903. }
  904. else
  905. {
  906. // Sets variable for the destination
  907. $_SESSION['__pickles']['login']['destination'] = isset($_REQUEST['request']) ? $_REQUEST['request'] : '/';
  908. // Redirect to login page, potentially configured in the config, else /login
  909. header('Location: /' . (isset($this->config->security['login']) ? $this->config->security['login'] : 'login'));
  910. exit;
  911. }
  912. }
  913. }
  914. // Validates the rendering engine
  915. $engines = is_array($module->engine) ? array_values($module->engine) : array($module->engine);
  916. $engines = array_combine($engines, $engines);
  917. $engine = current($engines);
  918. // Possibly overrides the engine with the passed return type
  919. if (isset($return_type))
  920. {
  921. $return_type = strtoupper($return_type);
  922. // Validates the return type against the module
  923. if (in_array($return_type, array('JSON', 'RSS', 'XML')) && in_array($return_type, $engines))
  924. {
  925. $engine = $return_type;
  926. }
  927. unset($return_type);
  928. }
  929. // Starts up the display engine
  930. $display_class = 'Display_' . $engine;
  931. $display = new $display_class();
  932. // Assigns the template / template variables
  933. $display->setTemplateVariables($module->template, $template_basename, $css_class, $js_basename);
  934. // Checks the templates
  935. $template_exists = $display->templateExists();
  936. // If there is no valid module or template, then redirect
  937. if (!$module_exists && !$template_exists)
  938. {
  939. if (!isset($_REQUEST['request']))
  940. {
  941. Error::fatal('Way to go, you\'ve successfully created an infinite redirect loop. Good thing I was here or you would have been served with a pretty ugly browser error.<br /><br />So here\'s the deal, no templates were able to be loaded. Make sure your parent and child templates actually exist and if you\'re using non-default values, make sure they\'re defined correctly in your config.');
  942. }
  943. else
  944. {
  945. $redirect_url = '/';
  946. if (isset($this->config->pickles['404']) && $_REQUEST['request'] != $this->config->pickles['404'])
  947. {
  948. $redirect_url .= $this->config->pickles['404'];
  949. }
  950. header('Location: ' . $redirect_url, 404);
  951. exit;
  952. }
  953. }
  954. // Gets the profiler status
  955. $profiler = $this->config->pickles['profiler'];
  956. // Attempts to execute the default method
  957. if (method_exists($module, '__default'))
  958. {
  959. if (isset($requested_id))
  960. {
  961. $module->setRequest(array('id' => $requested_id));
  962. }
  963. // Sets meta data from the module
  964. $display->setMetaData(array(
  965. 'title' => $module->title,
  966. 'description' => $module->description,
  967. 'keywords' => $module->keywords
  968. ));
  969. // Starts a timer before the module is executed
  970. if ($profiler === true || stripos($profiler, 'timers') !== false)
  971. {
  972. Profiler::timer('module __default');
  973. }
  974. $valid_request = false;
  975. $valid_security_hash = false;
  976. $error_message = 'An unexpected error has occurred';
  977. // Determines if the request method is valid for this request
  978. if ($module->method != false)
  979. {
  980. $methods = (is_array($module->method) ? $module->method : array($module->method));
  981. $request_method = $_SERVER['REQUEST_METHOD'];
  982. foreach ($methods as $method)
  983. {
  984. if ($request_method == strtoupper($method))
  985. {
  986. $valid_request = true;
  987. break;
  988. }
  989. }
  990. if ($valid_request == false)
  991. {
  992. $error_message = 'There was a problem with your request method';
  993. }
  994. unset($methods, $request_method, $method);
  995. }
  996. else
  997. {
  998. $valid_request = true;
  999. }
  1000. // Validates the hash if applicable
  1001. if ($module->hash != false)
  1002. {
  1003. if (isset($_REQUEST['security_hash']))
  1004. {
  1005. $hash_value = ($module->hash === true ? get_class($module) : $module->hash);
  1006. if (Security::generateHash($hash_value) == $_REQUEST['security_hash'])
  1007. {
  1008. $valid_security_hash = true;
  1009. }
  1010. else
  1011. {
  1012. $error_message = 'Invalid security hash';
  1013. }
  1014. unset($hash_value);
  1015. }
  1016. else
  1017. {
  1018. $error_message = 'Missing security hash';
  1019. }
  1020. }
  1021. else
  1022. {
  1023. $valid_security_hash = true;
  1024. }
  1025. /**
  1026. * Note to Self: When building in caching will need to let the
  1027. * module know to use the cache, either passing in a variable
  1028. * or setting it on the object
  1029. */
  1030. $display->setModuleReturn($valid_request && $valid_security_hash ? $module->__default() : array('status' => 'error', 'message' => $error_message));
  1031. unset($error_message);
  1032. // Stops the module timer
  1033. if ($profiler === true || stripos($profiler, 'timers') !== false)
  1034. {
  1035. Profiler::timer('module __default');
  1036. }
  1037. }
  1038. // Starts a timer for the display rendering
  1039. if ($profiler === true || stripos($profiler, 'timers') !== false)
  1040. {
  1041. Profiler::timer('display render');
  1042. }
  1043. // Renders the content
  1044. $display->render();
  1045. // Steps the display timer
  1046. if ($profiler === true || stripos($profiler, 'timers') !== false)
  1047. {
  1048. Profiler::timer('display render');
  1049. }
  1050. }
  1051. /**
  1052. * Destructor
  1053. *
  1054. * Dumps out the Profiler's report if applicable.
  1055. */
  1056. public function __destruct()
  1057. {
  1058. parent::__destruct();
  1059. // Display the Profiler's report is the stars are aligned
  1060. if ($this->config->pickles['profiler'] != false && $this->passthru == false)
  1061. {
  1062. Profiler::report();
  1063. }
  1064. }
  1065. /**
  1066. * Prepare Variables
  1067. *
  1068. * Processes the request variable and creates all the variables that the
  1069. * Controller needs to load the page.
  1070. *
  1071. * @param string $basename the requested page
  1072. * @return array the resulting variables
  1073. */
  1074. public function prepareVariables($basename)
  1075. {
  1076. // Sets up all of our variables
  1077. $module_class = strtr($basename, '/', '_');
  1078. $module_filename = SITE_MODULE_PATH . $basename . '.php';
  1079. $template_basename = $basename;
  1080. $css_class = $module_class;
  1081. $js_basename = $basename;
  1082. // Scrubs class names with hyphens
  1083. if (strpos($module_class, '-') !== false)
  1084. {
  1085. $module_class = preg_replace('/(-(.{1}))/e', 'strtoupper("$2")', $module_class);
  1086. }
  1087. return array($module_class, $module_filename, $template_basename, $css_class, $js_basename);
  1088. }
  1089. }
  1090. /**
  1091. * Converter
  1092. *
  1093. * PHP version 5
  1094. *
  1095. * Licensed under The MIT License
  1096. * Redistribution of these files must retain the above copyright notice.
  1097. *
  1098. * @author Josh Sherman <josh@gravityblvd.com>
  1099. * @copyright Copyright 2007-2011, Josh Sherman
  1100. * @license http://www.opensource.org/licenses/mit-license.html
  1101. * @package PICKLES
  1102. * @link http://p.ickl.es
  1103. */
  1104. /**
  1105. * Convert Class
  1106. *
  1107. * Collection of statically called methods to help aid in converting formats.
  1108. */
  1109. class Convert
  1110. {
  1111. /**
  1112. * To JSON
  1113. *
  1114. * Encodes passed variable as JSON.
  1115. *
  1116. * Requires PHP 5 >= 5.2.0 or PECL json >= 1.2.0
  1117. * Note: PECL json 1.2.1 is included /vendors
  1118. *
  1119. * @link http://json.org/
  1120. * @link http://us.php.net/json_encode
  1121. * @link http://pecl.php.net/package/json
  1122. *
  1123. * @static
  1124. * @param mixed $variable variable to convert
  1125. * @return JSON encoded string
  1126. */
  1127. public static function toJSON($variable)
  1128. {
  1129. if (JSON_AVAILABLE)
  1130. {
  1131. return json_encode($variable);
  1132. }
  1133. else
  1134. {
  1135. return '{ "status": "error", "message": "json_encode() not found" }';
  1136. }
  1137. }
  1138. /**
  1139. * Array to XML
  1140. *
  1141. * Converts an array into XML tags (recursive). This method expects the
  1142. * passed array to be formatted very specifically to accomodate the fact
  1143. * that an array's format isn't quite the same as well-formed XML.
  1144. *
  1145. * Input Array =
  1146. * array('children' => array(
  1147. * 'child' => array(
  1148. * array('name' => 'Wendy Darling'),
  1149. * array('name' => 'John Darling'),
  1150. * array('name' => 'Michael Darling')
  1151. * )
  1152. * ))
  1153. *
  1154. * Output XML =
  1155. * <children>
  1156. * <child><name>Wendy Darling</name></child>
  1157. * <child><name>John Darling</name></child>
  1158. * <child><name>Michael Darling</name></child>
  1159. * </children>
  1160. *
  1161. * @static
  1162. * @param array $array array to convert into XML
  1163. * @return string generated XML
  1164. */
  1165. public static function arrayToXML($array, $format = false, $level = 0)
  1166. {
  1167. $xml = '';
  1168. if (is_array($array))
  1169. {
  1170. foreach ($array as $node => $value)
  1171. {
  1172. // Checks if the value is an array
  1173. if (is_array($value))
  1174. {
  1175. foreach ($value as $node2 => $value2)
  1176. {
  1177. if (is_array($value2))
  1178. {
  1179. // Nest the value if the node is an integer
  1180. $new_value = (is_int($node2) ? $value2 : array($node2 => $value2));
  1181. $xml .= ($format ? str_repeat("\t", $level) : '');
  1182. $xml .= '<' . $node . '>' . ($format ? "\n" : '');
  1183. $xml .= self::arrayToXML($new_value, $format, $level + 1);
  1184. $xml .= ($format ? str_repeat("\t", $level) : '');
  1185. $xml .= '</' . $node . '>' . ($format ? "\n" : '');
  1186. }
  1187. else
  1188. {
  1189. if (is_int($node2))
  1190. {
  1191. $node2 = $node;
  1192. }
  1193. // Checks for special characters
  1194. if (htmlspecialchars($value2) != $value2)
  1195. {
  1196. $xml .= ($format ? str_repeat("\t", $level) : '');
  1197. $xml .= '<' . $node2 . '><![CDATA[' . $value2 . ']]></' . $node2 . '>' . ($format ? "\n" : '');
  1198. }
  1199. else
  1200. {
  1201. $xml .= ($format ? str_repeat("\t", $level) : '');
  1202. $xml .= '<' . $node2 . '>' . $value2 . '</' . $node2 . '>' . ($format ? "\n" : '');
  1203. }
  1204. }
  1205. }
  1206. }
  1207. else
  1208. {
  1209. // Checks for special characters
  1210. if (htmlspecialchars($value) != $value)
  1211. {
  1212. $xml .= ($format ? str_repeat("\t", $level) : '');
  1213. $xml .= '<' . $node . '><![CDATA[' . $value . ']]></' . $node . '>' . ($format ? "\n" : '');
  1214. }
  1215. else
  1216. {
  1217. $xml .= ($format ? str_repeat("\t", $level) : '');
  1218. $xml .= '<' . $node . '>' . $value . '</' . $node . '>' . ($format ? "\n" : '');
  1219. }
  1220. }
  1221. }
  1222. }
  1223. return $xml;
  1224. }
  1225. }
  1226. /**
  1227. * Common Database Class File for PICKLES
  1228. *
  1229. * PHP version 5
  1230. *
  1231. * Licensed under The MIT License
  1232. * Redistribution of these files must retain the above copyright notice.
  1233. *
  1234. * @author Josh Sherman <josh@gravityblvd.com>
  1235. * @copyright Copyright 2007-2011, Josh Sherman
  1236. * @license http://www.opensource.org/licenses/mit-license.html
  1237. * @package PICKLES
  1238. * @link http://p.ickl.es
  1239. */
  1240. /**
  1241. * Common Database Abstraction Layer
  1242. *
  1243. * Parent class that our database driver classes should be extending. Contains
  1244. * basic functionality for instantiation and interfacing.
  1245. */
  1246. abstract class Database_Common extends Object
  1247. {
  1248. /**
  1249. * Driver
  1250. *
  1251. * @access protected
  1252. * @var string
  1253. */
  1254. protected $driver = null;
  1255. /**
  1256. * Hostname for the server
  1257. *
  1258. * @access protected
  1259. * @var string
  1260. */
  1261. protected $hostname = 'localhost';
  1262. /**
  1263. * Port number for the server
  1264. *
  1265. * @access protected
  1266. * @var integer
  1267. */
  1268. protected $port = null;
  1269. /**
  1270. * UNIX socket for the server
  1271. *
  1272. * @access protected
  1273. * @var integer
  1274. */
  1275. protected $socket = null;
  1276. /**
  1277. * Username for the server
  1278. *
  1279. * @access protected
  1280. * @var string
  1281. */
  1282. protected $username = null;
  1283. /**
  1284. * Password for the server
  1285. *
  1286. * @access protected
  1287. * @var string
  1288. */
  1289. protected $password = null;
  1290. /**
  1291. * Database name for the server
  1292. *
  1293. * @access protected
  1294. * @var string
  1295. */
  1296. protected $database = null;
  1297. /**
  1298. * Whether or not to use caching
  1299. *
  1300. * @access protected
  1301. * @var boolean
  1302. */
  1303. protected $cache = false;
  1304. /**
  1305. * Connection resource
  1306. *
  1307. * @access protected
  1308. * @var object
  1309. */
  1310. protected $connection = null;
  1311. /**
  1312. * Results object for the executed statement
  1313. *
  1314. * @access protected
  1315. * @var object
  1316. */
  1317. protected $results = null;
  1318. /**
  1319. * Constructor
  1320. */
  1321. public function __construct()
  1322. {
  1323. parent::__construct();
  1324. // Checks the driver is set and available
  1325. if ($this->driver == null)
  1326. {
  1327. throw new Exception('Driver name is not set');
  1328. }
  1329. else
  1330. {
  1331. if (extension_loaded($this->driver) == false)
  1332. {
  1333. throw new Exception('Driver "' . $this->driver . '" is not loaded');
  1334. }
  1335. }
  1336. }
  1337. /**
  1338. * Set Hostname
  1339. *
  1340. * @param string $hostname hostname for the database
  1341. */
  1342. public function setHostname($hostname)
  1343. {
  1344. return $this->hostname = $hostname;
  1345. }
  1346. /**
  1347. * Set Port
  1348. *
  1349. * @param integer $port port for the database
  1350. */
  1351. public function setPort($port)
  1352. {
  1353. return $this->port = $port;
  1354. }
  1355. /**
  1356. * Set Socket
  1357. *
  1358. * @param string $socket name of the UNIX socket
  1359. */
  1360. public function setSocket($socket)
  1361. {
  1362. return $this->socket = $socket;
  1363. }
  1364. /**
  1365. * Set Username
  1366. *
  1367. * @param string $username username for the database
  1368. */
  1369. public function setUsername($username)
  1370. {
  1371. return $this->username = $username;
  1372. }
  1373. /**
  1374. * Set Password
  1375. *
  1376. * @param string $password password for the database
  1377. */
  1378. public function setPassword($password)
  1379. {
  1380. return $this->password = $password;
  1381. }
  1382. /**
  1383. * Set Database
  1384. *
  1385. * @param string $database database for the database
  1386. */
  1387. public function setDatabase($database)
  1388. {
  1389. return $this->database = $database;
  1390. }
  1391. /**
  1392. * Set Cache
  1393. *
  1394. * @param boolean whether or not to use cache
  1395. */
  1396. public function setCache($cache)
  1397. {
  1398. return $this->cache = $cache;
  1399. }
  1400. /**
  1401. * Get Driver
  1402. *
  1403. * Returns the name of the driver in use. Used by the Model class to
  1404. * determine which path to take when interfacing with the Database object.
  1405. *
  1406. * @return string name of the driver in use
  1407. */
  1408. public function getDriver()
  1409. {
  1410. return $this->driver;
  1411. }
  1412. /**
  1413. * Get Cache
  1414. *
  1415. * Returns the status of caching for this datasource.
  1416. *
  1417. * @return string whether or not to use the cache
  1418. */
  1419. public function getCache()
  1420. {
  1421. return $this->cache;
  1422. }
  1423. /**
  1424. * Opens database connection
  1425. *
  1426. * Establishes a connection to the MySQL database based on the
  1427. * configuration options that are available in the Config object.
  1428. *
  1429. * @abstract
  1430. * @return boolean true on success, throws an exception overwise
  1431. */
  1432. abstract public function open();
  1433. /**
  1434. * Closes database connection
  1435. *
  1436. * Sets the connection to null regardless of state.
  1437. *
  1438. * @return boolean always true
  1439. */
  1440. abstract public function close();
  1441. }
  1442. /**
  1443. * PDO Class File for PICKLES
  1444. *
  1445. * PHP version 5
  1446. *
  1447. * Licensed under The MIT License
  1448. * Redistribution of these files must retain the above copyright notice.
  1449. *
  1450. * @author Josh Sherman <josh@gravityblvd.com>
  1451. * @copyright Copyright 2007-2011, Josh Sherman
  1452. * @license http://www.opensource.org/licenses/mit-license.html
  1453. * @package PICKLES
  1454. * @link http://p.ickl.es
  1455. */
  1456. /**
  1457. * PDO Abstraction Layer
  1458. *
  1459. * Parent class for any of our database classes that use PDO.
  1460. */
  1461. class Database_PDO_Common extends Database_Common
  1462. {
  1463. /**
  1464. * DSN format
  1465. *
  1466. * @access protected
  1467. * @var string
  1468. */
  1469. protected $dsn;
  1470. /**
  1471. * PDO Attributes
  1472. *
  1473. * @access protected
  1474. * @var string
  1475. */
  1476. protected $attributes = array(
  1477. PDO::ATTR_PERSISTENT => true,
  1478. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  1479. PDO::NULL_EMPTY_STRING => true
  1480. );
  1481. /**
  1482. * Constructor
  1483. */
  1484. public function __construct()
  1485. {
  1486. parent::__construct();
  1487. // Checks that the prefix is set
  1488. if ($this->dsn == null)
  1489. {
  1490. throw new Exception('Data source name is not defined');
  1491. }
  1492. }
  1493. /**
  1494. * Opens database connection
  1495. *
  1496. * Establishes a connection to the database based on the set configuration
  1497. * options.
  1498. *
  1499. * @return boolean true on success, throws an exception overwise
  1500. */
  1501. public function open()
  1502. {
  1503. if ($this->connection === null)
  1504. {
  1505. if (isset($this->username, $this->password, $this->database))
  1506. {
  1507. // Creates a new PDO database object (persistent)
  1508. try
  1509. {
  1510. // Swaps out any variables with values in the DSN
  1511. $this->dsn = str_replace(
  1512. array('[[hostname]]', '[[port]]', '[[socket]]', '[[username]]', '[[password]]', '[[database]]'),
  1513. array($this->hostname, $this->port, $this->socket, $this->username, $this->password, $this->database),
  1514. $this->dsn
  1515. );
  1516. // Strips any empty parameters in the DSN
  1517. $this->dsn = str_replace(array('host=;', 'port=;', 'unix_socket=;'), '', $this->dsn);
  1518. // Attempts to establish a connection
  1519. $this->connection = new PDO($this->dsn, $this->username, $this->password, $this->attributes);
  1520. }
  1521. catch (PDOException $e)
  1522. {
  1523. throw new Exception($e);
  1524. }
  1525. }
  1526. else
  1527. {
  1528. throw new Exception('There was an error loading the database configuration');
  1529. }
  1530. }
  1531. return true;
  1532. }
  1533. /**
  1534. * Closes database connection
  1535. *
  1536. * Sets the connection to null regardless of state.
  1537. *
  1538. * @return boolean always true
  1539. */
  1540. public function close()
  1541. {
  1542. $this->connection = null;
  1543. return true;
  1544. }
  1545. /**
  1546. * Executes an SQL Statement
  1547. *
  1548. * Executes a standard or prepared query based on passed parameters. All
  1549. * queries are logged to a file as well as timed and logged in the
  1550. * execution time is over 1 second.
  1551. *
  1552. * @param string $sql statement to execute
  1553. * @param array $input_parameters optional key/values to be bound
  1554. * @return integer ID of the last inserted row or sequence number
  1555. */
  1556. public function execute($sql, $input_parameters = null)
  1557. {
  1558. $this->open();
  1559. if ($this->config->pickles['logging'] === true)
  1560. {
  1561. $loggable_query = $sql;
  1562. if ($input_parameters != null)
  1563. {
  1564. $loggable_query .= ' -- ' . (JSON_AVAILABLE ? json_encode($input_parameters) : serialize($input_parameters));
  1565. }
  1566. Log::query($loggable_query);
  1567. }
  1568. $sql = trim($sql);
  1569. // Checks if the query is blank
  1570. if ($sql != '')
  1571. {
  1572. try
  1573. {
  1574. // Establishes if we're working on an EXPLAIN
  1575. if (Profiler::enabled('explains') == true)
  1576. {
  1577. $explaining = preg_match('/^EXPLAIN /i', $sql);
  1578. $selecting = preg_match('/^SELECT /i', $sql);
  1579. }
  1580. else
  1581. {
  1582. $explaining = null;
  1583. $selecting = null;
  1584. }
  1585. // Executes a standard query
  1586. if ($input_parameters === null)
  1587. {
  1588. // Explains the query
  1589. if ($selecting == true && $explaining == false)
  1590. {
  1591. $explain = $this->fetch('EXPLAIN ' . $sql);
  1592. }
  1593. $start_time = microtime(true);
  1594. $this->results = $this->connection->query($sql);
  1595. }
  1596. // Executes a prepared statement
  1597. else
  1598. {
  1599. // Explains the query
  1600. if ($selecting == true && $explaining == false)
  1601. {
  1602. $explain = $this->fetch('EXPLAIN ' . $sql, $input_parameters);
  1603. }
  1604. $start_time = microtime(true);
  1605. $this->results = $this->connection->prepare($sql);
  1606. $this->results->execute($input_parameters);
  1607. }
  1608. $end_time = microtime(true);
  1609. $duration = $end_time - $start_time;
  1610. if ($this->config->pickles['logging'] === true && $duration >= 1)
  1611. {
  1612. Log::slowQuery($duration . ' seconds: ' . $loggable_query);
  1613. }
  1614. // Logs the information to the profiler
  1615. if ($explaining == false && Profiler::enabled('explains', 'queries'))
  1616. {
  1617. Profiler::logQuery($sql, $input_parameters, (isset($explain) ? $explain : false), $duration);
  1618. }
  1619. }
  1620. catch (PDOException $e)
  1621. {
  1622. throw new Exception($e);
  1623. }
  1624. }
  1625. else
  1626. {
  1627. throw new Exception('No query to execute');
  1628. }
  1629. return $this->connection->lastInsertId();
  1630. }
  1631. /**
  1632. * Fetch records from the database
  1633. *
  1634. * @param string $sql statement to be executed
  1635. * @param array $input_parameters optional key/values to be bound
  1636. * @param string $return_type optional type of return set
  1637. * @return mixed based on return type
  1638. */
  1639. public function fetch($sql = null, $input_parameters = null)
  1640. {
  1641. $this->open();
  1642. if ($sql !== null)
  1643. {
  1644. $this->execute($sql, $input_parameters);
  1645. }
  1646. // Pulls the results based on the type
  1647. $results = $this->results->fetchAll(PDO::FETCH_ASSOC);
  1648. return $results;
  1649. }
  1650. }
  1651. /**
  1652. * MySQL Class File for PICKLES
  1653. *
  1654. * PHP version 5
  1655. *
  1656. * Licensed under The MIT License
  1657. * Redistribution of these files must retain the above copyright notice.
  1658. *
  1659. * @author Josh Sherman <josh@gravityblvd.com>
  1660. * @copyright Copyright 2007-2011, Josh Sherman
  1661. * @license http://www.opensource.org/licenses/mit-license.html
  1662. * @package PICKLES
  1663. * @link http://p.ickl.es
  1664. */
  1665. /**
  1666. * MySQL Database Abstraction Layer
  1667. */
  1668. class Database_PDO_MySQL extends Database_PDO_Common
  1669. {
  1670. /**
  1671. * Driver
  1672. *
  1673. * @access protected
  1674. * @var string
  1675. */
  1676. protected $driver = 'pdo_mysql';
  1677. /**
  1678. * DSN format
  1679. *
  1680. * @access protected
  1681. * @var string
  1682. */
  1683. protected $dsn = 'mysql:host=[[hostname]];port=[[port]];unix_socket=[[socket]];dbname=[[database]]';
  1684. /**
  1685. * Default port
  1686. *
  1687. * @access proceted
  1688. * @var integer
  1689. */
  1690. protected $port = 3306;
  1691. }
  1692. /**
  1693. * PostgreSQL Class File for PICKLES
  1694. *
  1695. * PHP version 5
  1696. *
  1697. * Licensed under The MIT License
  1698. * Redistribution of these files must retain the above copyright notice.
  1699. *
  1700. * @author Josh Sherman <josh@gravityblvd.com>
  1701. * @copyright Copyright 2007-2011, Josh Sherman
  1702. * @license http://www.opensource.org/licenses/mit-license.html
  1703. * @package PICKLES
  1704. * @link http://p.ickl.es
  1705. */
  1706. /**
  1707. * PostgreSQL Database Abstraction Layer
  1708. */
  1709. class Database_PDO_PostgreSQL extends Database_PDO_Common
  1710. {
  1711. /**
  1712. * Driver
  1713. *
  1714. * @access protected
  1715. * @var string
  1716. */
  1717. protected $driver = 'pdo_pgsql';
  1718. /**
  1719. * DSN format
  1720. *
  1721. * @access protected
  1722. * @var string
  1723. */
  1724. protected $dsn = 'pgsql:host=[[hostname]];port=[[port]];dbname=[[database]];user=[[username]];password=[[password]]';
  1725. /**
  1726. * Default port
  1727. *
  1728. * @access proceted
  1729. * @var integer
  1730. */
  1731. protected $port = 5432;
  1732. }
  1733. /**
  1734. * SQLite Class File for PICKLES
  1735. *
  1736. * PHP version 5
  1737. *
  1738. * Licensed under The MIT License
  1739. * Redistribution of these files must retain the above copyright notice.
  1740. *
  1741. * @author Josh Sherman <josh@gravityblvd.com>
  1742. * @copyright Copyright 2007-2011, Josh Sherman
  1743. * @license http://www.opensource.org/licenses/mit-license.html
  1744. * @package PICKLES
  1745. * @link http://p.ickl.es
  1746. */
  1747. /**
  1748. * SQLite Database Abstraction Layer
  1749. */
  1750. class Database_PDO_SQLite extends Database_PDO_Common
  1751. {
  1752. /**
  1753. * Driver
  1754. *
  1755. * @access protected
  1756. * @var string
  1757. */
  1758. protected $driver = 'pdo_sqlite';
  1759. /**
  1760. * DSN format
  1761. *
  1762. * @access protected
  1763. * @var string
  1764. */
  1765. protected $dsn = 'sqlite:[[hostname]]';
  1766. }
  1767. /**
  1768. * Database Class File for PICKLES
  1769. *
  1770. * PHP version 5
  1771. *
  1772. * Licensed under The MIT License
  1773. * Redistribution of these files must retain the above copyright notice.
  1774. *
  1775. * @author Josh Sherman <josh@gravityblvd.com>
  1776. * @copyright Copyright 2007-2011, Josh Sherman
  1777. * @license http://www.opensource.org/licenses/mit-license.html
  1778. * @package PICKLES
  1779. * @link http://p.ickl.es
  1780. */
  1781. /**
  1782. * Database Factory
  1783. *
  1784. * Generic class to simplify connecting to a database. All database objects
  1785. * should be created by this class to future proof against any internal changes
  1786. * to PICKLES.
  1787. */
  1788. class Database extends Object
  1789. {
  1790. /**
  1791. * Constructor
  1792. *
  1793. * Attempts to get an instance of the passed database type or attempts to
  1794. * use a default specified in the config.
  1795. *
  1796. * @param string $name optional name of the connection to use
  1797. */
  1798. public function __construct(String $name = null)
  1799. {
  1800. parent::__construct();
  1801. return Database::getInstance($name);
  1802. }
  1803. /**
  1804. * Get instance
  1805. *
  1806. * Looks up the datasource using the passed name and gets an instance of
  1807. * it. Allows for easy sharing of certain classes within the system to
  1808. * avoid the extra overhead of creating new objects each time. Also avoids
  1809. * the hassle of passing around variables (yeah I know, very global-ish)
  1810. *
  1811. * @static
  1812. * @param string $name name of the datasource
  1813. * @return object instance of the class
  1814. */
  1815. public static function getInstance($name = null)
  1816. {
  1817. $config = Config::getInstance();
  1818. // Checks if we have a default
  1819. if ($name == null)
  1820. {
  1821. // Checks the config for a default
  1822. if (isset($config->pickles['datasource']))
  1823. {
  1824. $name = $config->pickles['datasource'];
  1825. }
  1826. // Tries to use the first defined datasource
  1827. elseif (is_array($config->datasources))
  1828. {
  1829. $datasources = $config->datasources;
  1830. $name = key($datasources);
  1831. }
  1832. }
  1833. // If we have a name try to set up a connection
  1834. if ($name != null)
  1835. {
  1836. if (isset($config->datasources[$name]))
  1837. {
  1838. $datasource = $config->datasources[$name];
  1839. $datasource['driver'] = strtolower($datasource['driver']);
  1840. if (!isset(self::$instances['Database'][$name]))
  1841. {
  1842. // Checks the driver is legit and scrubs the name
  1843. switch ($datasource['driver'])
  1844. {
  1845. case 'pdo_mysql': $class = 'PDO_MySQL'; break;
  1846. case 'pdo_pgsql': $class = 'PDO_PostgreSQL'; break;
  1847. case 'pdo_sqlite': $class = 'PDO_SQLite'; break;
  1848. default:
  1849. throw new Exception('Datasource driver "' . $datasource['driver'] . '" is invalid');
  1850. break;
  1851. }
  1852. // Instantiates our database class
  1853. $class = 'Database_' . $class;
  1854. $instance = new $class();
  1855. // Sets our database parameters
  1856. if (isset($datasource['hostname']))
  1857. {
  1858. $instance->setHostname($datasource['hostname']);
  1859. }
  1860. if (isset($datasource['port']))
  1861. {
  1862. $instance->setPort($datasource['port']);
  1863. }
  1864. if (isset($datasource['socket']))
  1865. {
  1866. $instance->setSocket($datasource['socket']);
  1867. }
  1868. if (isset($datasource['username']))
  1869. {
  1870. $instance->setUsername($datasource['username']);
  1871. }
  1872. if (isset($datasource['password']))
  1873. {
  1874. $instance->setPassword($datasource['password']);
  1875. }
  1876. if (isset($datasource['database']))
  1877. {
  1878. $instance->setDatabase($datasource['database']);
  1879. }
  1880. if (isset($datasource['cache']))
  1881. {
  1882. $instance->setCache($datasource['cache']);
  1883. }
  1884. }
  1885. // Caches the instance for possible reuse later
  1886. if (isset($instance))
  1887. {
  1888. self::$instances['Database'][$name] = $instance;
  1889. }
  1890. // Returns the instance
  1891. return self::$instances['Database'][$name];
  1892. }
  1893. }
  1894. return false;
  1895. }
  1896. }
  1897. /**
  1898. * Date Utility Collection
  1899. *
  1900. * PHP version 5
  1901. *
  1902. * Licensed under The MIT License
  1903. * Redistribution of these files must retain the above copyright notice.
  1904. *
  1905. * @author Josh Sherman <josh@gravityblvd.com>
  1906. * @copyright Copyright 2007-2011, Josh Sherman
  1907. * @license http://www.opensource.org/licenses/mit-license.html
  1908. * @package PICKLES
  1909. * @link http://p.ickl.es
  1910. */
  1911. /**
  1912. * Date Class
  1913. *
  1914. * Just a simple collection of static functions to accomplish some of the more
  1915. * redundant date related manipulation.
  1916. */
  1917. class Date
  1918. {
  1919. // {{{ Age
  1920. /**
  1921. * Age
  1922. *
  1923. * Calculates age based on the passed date.
  1924. *
  1925. * @static
  1926. * @param string $date birth / inception date
  1927. * @return integer $age number of years old
  1928. */
  1929. public static function age($date)
  1930. {
  1931. if (!preg_match('/\d{4}-\d{2}-\d{2}/', $date))
  1932. {
  1933. $date = date('Y-m-d', strtotime($date));
  1934. }
  1935. list($year, $month, $day) = explode('-', $date, 3);
  1936. $age = date('Y') - $year;
  1937. if (date('md') < $month . $day)
  1938. {
  1939. $age--;
  1940. }
  1941. return $age;
  1942. }
  1943. // }}}
  1944. }
  1945. /**
  1946. * Common Display Class File for PICKLES
  1947. *
  1948. * PHP version 5
  1949. *
  1950. * Licensed under The MIT License
  1951. * Redistribution of these files must retain the above copyright notice.
  1952. *
  1953. * @author Josh Sherman <josh@gravityblvd.com>
  1954. * @copyright Copyright 2007-2011, Josh Sherman
  1955. * @license http://www.opensource.org/licenses/mit-license.html
  1956. * @package PICKLES
  1957. * @link http://p.ickl.es
  1958. */
  1959. /**
  1960. * Common Display Class
  1961. *
  1962. * This is the parent class class that each display class should be
  1963. * extending and executing parent::render()
  1964. */
  1965. abstract class Display_Common extends Object
  1966. {
  1967. /**
  1968. * Template Extension
  1969. *
  1970. * @access protected
  1971. * @var string $extension file extension for the template files
  1972. */
  1973. protected $extension = null;
  1974. /**
  1975. * Parent Template
  1976. *
  1977. * @access protected
  1978. * @var string
  1979. */
  1980. protected $parent_template = null;
  1981. /**
  1982. * Child (sub) Template
  1983. *
  1984. * @access protected
  1985. * @var string
  1986. */
  1987. protected $child_template = null;
  1988. /**
  1989. * CSS Class Name
  1990. *
  1991. * @access protected
  1992. * @var string
  1993. */
  1994. protected $css_class = '';
  1995. /**
  1996. * Javascript [Path and] Basename
  1997. *
  1998. * @access protected
  1999. * @var array
  2000. */
  2001. protected $js_basename = '';
  2002. /**
  2003. * Meta Data
  2004. *
  2005. * @access protected
  2006. * @var array
  2007. */
  2008. protected $meta_data = null;
  2009. /**
  2010. * Module Return Data
  2011. *
  2012. * @access protected
  2013. * @var array
  2014. */
  2015. protected $module_return = null;
  2016. /**
  2017. * Constructor
  2018. *
  2019. * Gets those headers working
  2020. */
  2021. public function __construct()
  2022. {
  2023. parent::__construct();
  2024. // Obliterates any passed in PHPSESSID (thanks Google)
  2025. if (stripos($_SERVER['REQUEST_URI'], '?PHPSESSID=') !== false)
  2026. {
  2027. list($request_uri, $phpsessid) = explode('?PHPSESSID=', $_SERVER['REQUEST_URI'], 2);
  2028. header('HTTP/1.1 301 Moved Permanently');
  2029. header('Location: ' . $request_uri);
  2030. exit;
  2031. }
  2032. else
  2033. {
  2034. // XHTML compliancy stuff
  2035. ini_set('arg_separator.output', '&amp;');
  2036. ini_set('url_rewriter.tags', 'a=href,area=href,frame=src,input=src,fieldset=');
  2037. header('Content-type: text/html; charset=UTF-8');
  2038. }
  2039. }
  2040. /**
  2041. * Set Template
  2042. *
  2043. * Sets the template file based on passed template type. Adds path and
  2044. * extension if applicable.
  2045. *
  2046. * @param string $template template file's basename
  2047. * @param string $type template file's type (either parent or child)
  2048. */
  2049. private function setTemplate($template, $type)
  2050. {
  2051. if ($template != null)
  2052. {
  2053. $template_name = $type . '_template';
  2054. $template_path = SITE_TEMPLATE_PATH . ($type == 'parent' ? '__shared/' : '');
  2055. $template_file = $template_path . $template . ($this->extension != false ? '.' . $this->extension : '');
  2056. if (file_exists($template_file))
  2057. {
  2058. $this->$template_name = $template_file;
  2059. }
  2060. }
  2061. }
  2062. /**
  2063. * Set Template Variables
  2064. *
  2065. * Sets the variables used by the templates
  2066. *
  2067. * @param string $parent_template parent template
  2068. * @param string $child_template child (sub) template
  2069. * @param string $css_class name of the CSS class for the module
  2070. * @param string $js_basename basename for the javascript file for the module
  2071. */
  2072. public function setTemplateVariables($parent_template, $child_template, $css_class, $js_basename)
  2073. {
  2074. $this->setTemplate($parent_template, 'parent');
  2075. $this->setTemplate($child_template, 'child');
  2076. $this->css_class = $css_class;
  2077. $this->js_basename = $js_basename;
  2078. }
  2079. /**
  2080. * Set Meta Data
  2081. *
  2082. * Sets the meta data from the module so the display class can use it
  2083. *
  2084. * @param array $meta_data key/value array of data
  2085. */
  2086. public function setMetaData($meta_data)
  2087. {
  2088. $this->meta_data = $meta_data;
  2089. }
  2090. /**
  2091. * Set Module Return
  2092. *
  2093. * Sets the return data from the module so the display class can display it
  2094. *
  2095. * @param array $module_return key / value pairs for the data
  2096. */
  2097. public function setModuleReturn($module_return)
  2098. {
  2099. $this->module_return = $module_return;
  2100. }
  2101. /**
  2102. * Template Exists
  2103. *
  2104. * Checks the templates for validity, not required by every display type so
  2105. * the return defaults to true.
  2106. *
  2107. * @return boolean whether or not the template exists
  2108. */
  2109. public function templateExists()
  2110. {
  2111. return true;
  2112. }
  2113. /**
  2114. * Rendering Method
  2115. *
  2116. * @abstract
  2117. */
  2118. abstract public function render();
  2119. }
  2120. /**
  2121. * JSON Display Class File for PICKLES
  2122. *
  2123. * PHP version 5
  2124. *
  2125. * Licensed under The MIT License
  2126. * Redistribution of these files must retain the above copyright notice.
  2127. *
  2128. * @author Josh Sherman <josh@gravityblvd.com>
  2129. * @copyright Copyright 2007-2011, Josh Sherman
  2130. * @license http://www.opensource.org/licenses/mit-license.html
  2131. * @package PICKLES
  2132. * @link http://p.ickl.es
  2133. */
  2134. /**
  2135. * JSON Display
  2136. *
  2137. * Displays data in JavaScript Object Notation.
  2138. */
  2139. class Display_JSON extends Display_Common
  2140. {
  2141. /**
  2142. * Renders the data in JSON format
  2143. */
  2144. public function render()
  2145. {
  2146. echo Convert::toJSON($this->module_return);
  2147. }
  2148. }
  2149. /**
  2150. * PHP Display Class File for PICKLES
  2151. *
  2152. * PHP version 5
  2153. *
  2154. * Licensed under The MIT License
  2155. * Redistribution of these files must retain the above copyright notice.
  2156. *
  2157. * @author Josh Sherman <josh@gravityblvd.com>
  2158. * @copyright Copyright 2007-2011, Josh Sherman
  2159. * @license http://www.opensource.org/licenses/mit-license.html
  2160. * @package PICKLES
  2161. * @link http://p.ickl.es
  2162. */
  2163. /**
  2164. * PHP Display
  2165. *
  2166. * Displays the associated PHP templates for the Model.
  2167. */
  2168. class Display_PHP extends Display_Common
  2169. {
  2170. /**
  2171. * Template Extension
  2172. *
  2173. * I know there's some controversy amoungst my peers concerning the
  2174. * usage of the .phtml extension for these PHP template files. If you
  2175. * would prefer .php or .tpl extensions, feel free to void your
  2176. * warranty and change it here.
  2177. *
  2178. * @access protected
  2179. * @var string $extension file extension for the template files
  2180. */
  2181. protected $extension = 'phtml';
  2182. /**
  2183. * Template Exists
  2184. *
  2185. * @return integer the number of templates defined
  2186. */
  2187. public function templateExists()
  2188. {
  2189. if ($this->parent_template != null)
  2190. {
  2191. return file_exists($this->parent_template) && file_exists($this->child_template);
  2192. }
  2193. else
  2194. {
  2195. return file_exists($this->child_template);
  2196. }
  2197. }
  2198. /**
  2199. * Renders the PHP templated pages
  2200. */
  2201. public function render()
  2202. {
  2203. if ($this->templateExists())
  2204. {
  2205. // Starts up the buffer
  2206. ob_start();
  2207. // Puts the class variables in local scope of the template
  2208. $__config = $this->config;
  2209. $__meta = $this->meta_data;
  2210. $__module = $this->module_return;
  2211. $__css_class = $this->css_class;
  2212. $__js_file = $this->js_basename;
  2213. // Creates (possibly overwritten) objects
  2214. $form_class = (class_exists('CustomForm') ? 'CustomForm' : 'Form');
  2215. $dynamic_class = (class_exists('CustomDynamic') ? 'CustomDynamic' : 'Dynamic');
  2216. $__form = new $form_class();
  2217. $__dynamic = new $dynamic_class();
  2218. // Loads the template
  2219. if ($this->parent_template != null)
  2220. {
  2221. if ($this->child_template == null)
  2222. {
  2223. $__template = $this->parent_template;
  2224. }
  2225. else
  2226. {
  2227. $__template = $this->child_template;
  2228. }
  2229. require_once $this->parent_template;
  2230. }
  2231. elseif ($this->child_template != null)
  2232. {
  2233. $__template = $this->child_template;
  2234. require_once $__template;
  2235. }
  2236. // Grabs the buffer contents and clears it out
  2237. $buffer = ob_get_clean();
  2238. // Kills any whitespace and HTML comments
  2239. $buffer = preg_replace(array('/^[\s]+/m', '/<!--.*-->/U'), '', $buffer);
  2240. // Note, this doesn't exit in case you want to run code after the display of the page
  2241. echo $buffer;
  2242. }
  2243. else
  2244. {
  2245. echo Convert::toJSON($this->module_return);
  2246. }
  2247. }
  2248. }
  2249. /**
  2250. * RSS Display Class File for PICKLES
  2251. *
  2252. * PHP version 5
  2253. *
  2254. * Licensed under The MIT License
  2255. * Redistribution of these files must retain the above copyright notice.
  2256. *
  2257. * @author Josh Sherman <josh@gravityblvd.com>
  2258. * @copyright Copyright 2007-2011, Josh Sherman
  2259. * @license http://www.opensource.org/licenses/mit-license.html
  2260. * @package PICKLES
  2261. * @link http://p.ickl.es
  2262. */
  2263. /**
  2264. * RSS Display
  2265. *
  2266. * Displays data as an RSS formatted XML string.
  2267. */
  2268. class Display_RSS extends Display_Common
  2269. {
  2270. // {{{ Feed Defaults
  2271. /**
  2272. * RSS Version
  2273. *
  2274. * @access private
  2275. * @var string
  2276. */
  2277. private $version = '2.0';
  2278. /**
  2279. * Date Format
  2280. *
  2281. * @access private
  2282. * @var string
  2283. */
  2284. private $date_format = 'r';
  2285. // }}}
  2286. // {{{ Channel Defaults
  2287. /**
  2288. * Title
  2289. *
  2290. * @access private
  2291. * @var string
  2292. */
  2293. private $title = '';
  2294. /**
  2295. * Link
  2296. *
  2297. * @access private
  2298. * @var string
  2299. */
  2300. private $link = '';
  2301. /**
  2302. * Description
  2303. *
  2304. * @access private
  2305. * @var string
  2306. */
  2307. private $description = '';
  2308. /**
  2309. * Language
  2310. *
  2311. * @access private
  2312. * @var string
  2313. */
  2314. private $language = 'en-us';
  2315. /**
  2316. * Generator
  2317. *
  2318. * @access private
  2319. * @var string
  2320. */
  2321. private $generator = 'http://p.ickl.es';
  2322. // }}}
  2323. /**
  2324. * Renders the data in RSS format
  2325. */
  2326. public function render()
  2327. {
  2328. // Throws off the syntax highlighter otherwise
  2329. echo '<' . '?xml version="1.0" ?' . '><rss version="' . $this->version . '"><channel>';
  2330. // Loops through the passable channel variables
  2331. $channel = array();
  2332. foreach (array('title', 'link', 'description', 'language') as $variable)
  2333. {
  2334. if (isset($this->module_return[$variable]))
  2335. {
  2336. $this->$variable = $this->module_return[$variable];
  2337. }
  2338. $channel[$variable] = $this->$variable;
  2339. }
  2340. $channel['generator'] = $this->generator;
  2341. // Loops through the items
  2342. $items = '';
  2343. $build_date = '';
  2344. if (isset($this->module_return['items']) && is_array($this->module_return['items']))
  2345. {
  2346. foreach ($this->module_return['items'] as $item)
  2347. {
  2348. // Note: time is the equivalent to pubDate, I just don't like camel case variables
  2349. $publish_date = date($this->date_format, is_numeric($item['time']) ? $item['time'] : strtotime($item['time']));
  2350. if ($build_date == '')
  2351. {
  2352. $build_date = $publish_date;
  2353. }
  2354. if (isset($item['link']))
  2355. {
  2356. $item['guid'] = $item['link'];
  2357. }
  2358. $item['pubDate'] = $publish_date;
  2359. unset($item['time']);
  2360. $items .= Convert::arrayToXML($item);
  2361. }
  2362. }
  2363. $channel['pubDate'] = $build_date;
  2364. $channel['lastBuildDate'] = $build_date;
  2365. echo Convert::arrayToXML($channel) . $items . '</channel></rss>';
  2366. }
  2367. }
  2368. /**
  2369. * XML Display Class File for PICKLES
  2370. *
  2371. * PHP version 5
  2372. *
  2373. * Licensed under The MIT License
  2374. * Redistribution of these files must retain the above copyright notice.
  2375. *
  2376. * @author Josh Sherman <josh@gravityblvd.com>
  2377. * @copyright Copyright 2007-2011, Josh Sherman
  2378. * @license http://www.opensource.org/licenses/mit-license.html
  2379. * @package PICKLES
  2380. * @link http://p.ickl.es
  2381. */
  2382. /**
  2383. * XML Display
  2384. *
  2385. * Displays data in XML format.
  2386. */
  2387. class Display_XML extends Display_Common
  2388. {
  2389. /**
  2390. * Renders the data in XML format
  2391. */
  2392. public function render()
  2393. {
  2394. echo Convert::arrayToXML($this->module_return);
  2395. }
  2396. }
  2397. /**
  2398. * Dynamic Content Class File for PICKLES
  2399. *
  2400. * PHP version 5
  2401. *
  2402. * Licensed under The MIT License
  2403. * Redistribution of these files must retain the above copyright notice.
  2404. *
  2405. * @author Josh Sherman <josh@gravityblvd.com>
  2406. * @copyright Copyright 2007-2011, Josh Sherman
  2407. * @license http://www.opensource.org/licenses/mit-license.html
  2408. * @package PICKLES
  2409. * @link http://p.ickl.es
  2410. */
  2411. /**
  2412. * Dynamic Class
  2413. *
  2414. * Handles generating links to static content that are a timestamp injected as
  2415. * to avoid hard caching. Also minifies content where applicable.
  2416. *
  2417. * Note: you will want to add a mod_rewrite line to your .htaccess to support
  2418. * the routing to the filenames with the timestamp injected:
  2419. *
  2420. * RewriteRule ^(.+)\.([\d]+)\.(css|js|gif|png|jpg|jpeg)$ /$1.$3 [NC,QSA]
  2421. */
  2422. class Dynamic extends Object
  2423. {
  2424. /**
  2425. * Generate Reference
  2426. *
  2427. * Appends a dynamic piece of information to the passed reference in the
  2428. * form of a UNIX timestamp added to the query string.
  2429. *
  2430. * @param string $reference URI reference of the file
  2431. * @param string $failover URI reference to use if the reference can't be found
  2432. * @return string URI reference reference with dynamic content
  2433. */
  2434. public function reference($reference, $failover = false)
  2435. {
  2436. // Checks if the URI reference is absolute, and not relative
  2437. if (substr($reference, 0, 1) == '/')
  2438. {
  2439. $query_string = '';
  2440. // Checks for ? and extracts query string
  2441. if (strstr($reference, '?'))
  2442. {
  2443. list($reference, $query_string) = explode('?', $reference);
  2444. }
  2445. // Adds the dot so the file functions can find the file
  2446. $file = '.' . $reference;
  2447. if (file_exists($file))
  2448. {
  2449. // Replaces the extension with time().extension
  2450. $parts = explode('.', $reference);
  2451. if (count($parts) == 1)
  2452. {
  2453. throw new Exception('Filename must have an extension (e.g. /path/to/file.png)');
  2454. }
  2455. else
  2456. {
  2457. end($parts);
  2458. $parts[key($parts)] = filemtime($file) . '.' . current($parts);
  2459. $reference = implode('.', $parts);
  2460. }
  2461. // Adds the query string back
  2462. if ($query_string != '')
  2463. {
  2464. $reference .= '?' . $query_string;
  2465. }
  2466. }
  2467. else
  2468. {
  2469. if ($failover != false)
  2470. {
  2471. $reference = $failover;
  2472. }
  2473. else
  2474. {
  2475. throw new Exception('Supplied reference does not exist (' . $reference . ')');
  2476. }
  2477. }
  2478. }
  2479. else
  2480. {
  2481. throw new Exception('Reference value must be absolute (e.g. /path/to/file.png)');
  2482. }
  2483. return $reference;
  2484. }
  2485. /**
  2486. * Generate Stylesheet Reference
  2487. *
  2488. * Attempts to minify the stylesheet and then returns the reference URI
  2489. * for the file, minified or not.
  2490. *
  2491. * @param string $reference URI reference of the Stylesheet
  2492. * @return string URI reference reference with dynamic content
  2493. */
  2494. public function css($original_reference)
  2495. {
  2496. // Injects .min into the filename
  2497. $parts = explode('.', $original_reference);
  2498. if (count($parts) == 1)
  2499. {
  2500. throw new Exception('Filename must have an extension (e.g. /path/to/file.css)');