1<?php
2/**
3 * PhpThumb Library Definition File
4 *
5 * This file contains the definitions for the PhpThumb class.
6 *
7 * PHP Version 5 with GD 2.0+
8 * PhpThumb : PHP Thumb Library <http://phpthumb.gxdlabs.com>
9 * Copyright (c) 2009, Ian Selby/Gen X Design
10 *
11 * Author(s): Ian Selby <ian@gen-x-design.com>
12 *
13 * Licensed under the MIT License
14 * Redistributions of files must retain the above copyright notice.
15 *
16 * @author Ian Selby <ian@gen-x-design.com>
17 * @copyright Copyright (c) 2009 Gen X Design
18 * @link http://phpthumb.gxdlabs.com
19 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
20 * @version 3.0
21 * @package PhpThumb
22 * @filesource
23 */
24
25
26
27/**
28 * PhpThumb Object
29 *
30 * This singleton object is essentially a function library that helps with core validation
31 * and loading of the core classes and plugins.  There isn't really any need to access it directly,
32 * unless you're developing a plugin and need to take advantage of any of the functionality contained
33 * within.
34 *
35 * If you're not familiar with singleton patterns, here's how you get an instance of this class (since you
36 * can't create one via the new keyword):
37 * <code>$pt = PhpThumb::getInstance();</code>
38 *
39 * It's that simple!  Outside of that, there's no need to modify anything within this class, unless you're doing
40 * some crazy customization... then knock yourself out! :)
41 *
42 * @package PhpThumb
43 * @subpackage Core
44 */
45class PhpThumb
46{
47	/**
48	 * Instance of self
49	 *
50	 * @var object PhpThumb
51	 */
52	protected static $_instance;
53	/**
54	 * The plugin registry
55	 *
56	 * This is where all plugins to be loaded are stored.  Data about the plugin is
57	 * provided, and currently consists of:
58	 *  - loaded: true/false
59	 *  - implementation: gd/imagick/both
60	 *
61	 * @var array
62	 */
63	protected $_registry;
64	/**
65	 * What implementations are available
66	 *
67	 * This stores what implementations are available based on the loaded
68	 * extensions in PHP, NOT whether or not the class files are present.
69	 *
70	 * @var array
71	 */
72	protected $_implementations;
73
74	/**
75	 * Returns an instance of self
76	 *
77	 * This is the usual singleton function that returns / instantiates the object
78	 *
79	 * @return PhpThumb
80	 */
81	public static function getInstance ()
82	{
83		if(!(self::$_instance instanceof self))
84		{
85			self::$_instance = new self();
86		}
87
88		return self::$_instance;
89	}
90
91	/**
92	 * Class constructor
93	 *
94	 * Initializes all the variables, and does some preliminary validation / checking of stuff
95	 *
96	 */
97	private function __construct ()
98	{
99		$this->_registry		= array();
100		$this->_implementations	= array('gd' => false, 'imagick' => false);
101
102		$this->getImplementations();
103	}
104
105	/**
106	 * Finds out what implementations are available
107	 *
108	 * This function loops over $this->_implementations and validates that the required extensions are loaded.
109	 *
110	 * I had planned on attempting to load them dynamically via dl(), but that would provide more overhead than I
111	 * was comfortable with (and would probably fail 99% of the time anyway)
112	 *
113	 */
114	private function getImplementations ()
115	{
116		foreach($this->_implementations as $extension => $loaded)
117		{
118			if($loaded)
119			{
120				continue;
121			}
122
123			if(extension_loaded($extension))
124			{
125				$this->_implementations[$extension] = true;
126			}
127		}
128	}
129
130	/**
131	 * Returns whether or not $implementation is valid (available)
132	 *
133	 * If 'all' is passed, true is only returned if ALL implementations are available.
134	 *
135	 * You can also pass 'n/a', which always returns true
136	 *
137	 * @return bool
138	 * @param string $implementation
139	 */
140	public function isValidImplementation ($implementation)
141	{
142		if ($implementation == 'n/a')
143		{
144			return true;
145		}
146
147		if ($implementation == 'all')
148		{
149			foreach ($this->_implementations as $imp => $value)
150			{
151				if ($value == false)
152				{
153					return false;
154				}
155			}
156
157			return true;
158		}
159
160		if (array_key_exists($implementation, $this->_implementations))
161		{
162			return $this->_implementations[$implementation];
163		}
164
165		return false;
166	}
167
168	/**
169	 * Registers a plugin in the registry
170	 *
171	 * Adds a plugin to the registry if it isn't already loaded, and if the provided
172	 * implementation is valid.  Note that you can pass the following special keywords
173	 * for implementation:
174	 *  - all - Requires that all implementations be available
175	 *  - n/a - Doesn't require any implementation
176	 *
177	 * When a plugin is added to the registry, it's added as a key on $this->_registry with the value
178	 * being an array containing the following keys:
179	 *  - loaded - whether or not the plugin has been "loaded" into the core class
180	 *  - implementation - what implementation this plugin is valid for
181	 *
182	 * @return bool
183	 * @param string $pluginName
184	 * @param string $implementation
185	 */
186	public function registerPlugin ($pluginName, $implementation)
187	{
188		if (!array_key_exists($pluginName, $this->_registry) && $this->isValidImplementation($implementation))
189		{
190			$this->_registry[$pluginName] = array('loaded' => false, 'implementation' => $implementation);
191			return true;
192		}
193
194		return false;
195	}
196
197	/**
198	 * Loads all the plugins in $pluginPath
199	 *
200	 * All this function does is include all files inside the $pluginPath directory.  The plugins themselves
201	 * will not be added to the registry unless you've properly added the code to do so inside your plugin file.
202	 *
203	 * @param string $pluginPath
204	 */
205	public function loadPlugins ($pluginPath)
206	{
207		// strip the trailing slash if present
208		if (substr($pluginPath, strlen($pluginPath) - 1, 1) == '/')
209		{
210			$pluginPath = substr($pluginPath, 0, strlen($pluginPath) - 1);
211		}
212
213		if ($handle = opendir($pluginPath))
214		{
215			while (false !== ($file = readdir($handle)))
216			{
217				if ($file == '.' || $file == '..' || $file == '.svn')
218				{
219					continue;
220				}
221
222				include_once($pluginPath . '/' . $file);
223			}
224		}
225	}
226
227	/**
228	 * Returns the plugin registry for the supplied implementation
229	 *
230	 * @return array
231	 * @param string $implementation
232	 */
233	public function getPluginRegistry ($implementation)
234	{
235		$returnArray = array();
236
237		foreach ($this->_registry as $plugin => $meta)
238		{
239			if ($meta['implementation'] == 'n/a' || $meta['implementation'] == $implementation)
240			{
241				$returnArray[$plugin] = $meta;
242			}
243		}
244
245		return $returnArray;
246	}
247}
248