PageRenderTime 274ms CodeModel.GetById 232ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 1ms

/jar.php

http://github.com/joshtronic/pickles
PHP | 2804 lines | 1242 code | 304 blank | 1258 comment | 227 complexity | e158d778c2f12e09fc370bfdb9b6e80c MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file