Kohana v3.3.0

This commit is contained in:
Deon George
2013-04-22 14:09:50 +10:00
commit f96694b18f
1280 changed files with 145034 additions and 0 deletions

3
system/classes/Arr.php Normal file
View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Arr extends Kohana_Arr {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Config extends Kohana_Config {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Config_File extends Kohana_Config_File {}

View File

@@ -0,0 +1,4 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Config_Group extends Kohana_Config_Group {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
abstract class Controller extends Kohana_Controller {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
abstract class Controller_Template extends Kohana_Controller_Template {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Cookie extends Kohana_Cookie {}

3
system/classes/Date.php Normal file
View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Date extends Kohana_Date {}

3
system/classes/Debug.php Normal file
View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Debug extends Kohana_Debug {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Encrypt extends Kohana_Encrypt {}

3
system/classes/Feed.php Normal file
View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Feed extends Kohana_Feed {}

3
system/classes/File.php Normal file
View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class File extends Kohana_File {}

3
system/classes/Form.php Normal file
View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Form extends Kohana_Form {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Fragment extends Kohana_Fragment {}

3
system/classes/HTML.php Normal file
View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTML extends Kohana_HTML {}

3
system/classes/HTTP.php Normal file
View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
abstract class HTTP extends Kohana_HTTP {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception extends Kohana_HTTP_Exception {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_300 extends Kohana_HTTP_Exception_300 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_301 extends Kohana_HTTP_Exception_301 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_302 extends Kohana_HTTP_Exception_302 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_303 extends Kohana_HTTP_Exception_303 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_304 extends Kohana_HTTP_Exception_304 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_305 extends Kohana_HTTP_Exception_305 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_307 extends Kohana_HTTP_Exception_307 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_400 extends Kohana_HTTP_Exception_400 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_401 extends Kohana_HTTP_Exception_401 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_402 extends Kohana_HTTP_Exception_402 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_403 extends Kohana_HTTP_Exception_403 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_404 extends Kohana_HTTP_Exception_404 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_405 extends Kohana_HTTP_Exception_405 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_406 extends Kohana_HTTP_Exception_406 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_407 extends Kohana_HTTP_Exception_407 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_408 extends Kohana_HTTP_Exception_408 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_409 extends Kohana_HTTP_Exception_409 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_410 extends Kohana_HTTP_Exception_410 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_411 extends Kohana_HTTP_Exception_411 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_412 extends Kohana_HTTP_Exception_412 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_413 extends Kohana_HTTP_Exception_413 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_414 extends Kohana_HTTP_Exception_414 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_415 extends Kohana_HTTP_Exception_415 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_416 extends Kohana_HTTP_Exception_416 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_417 extends Kohana_HTTP_Exception_417 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_500 extends Kohana_HTTP_Exception_500 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_501 extends Kohana_HTTP_Exception_501 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_502 extends Kohana_HTTP_Exception_502 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_503 extends Kohana_HTTP_Exception_503 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_504 extends Kohana_HTTP_Exception_504 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Exception_505 extends Kohana_HTTP_Exception_505 {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
abstract class HTTP_Exception_Expected extends Kohana_HTTP_Exception_Expected {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
abstract class HTTP_Exception_Redirect extends Kohana_HTTP_Exception_Redirect {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_Header extends Kohana_HTTP_Header {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
interface HTTP_Message extends Kohana_HTTP_Message {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
interface HTTP_Request extends Kohana_HTTP_Request {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
interface HTTP_Response extends Kohana_HTTP_Response {}

3
system/classes/I18n.php Normal file
View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class I18n extends Kohana_I18n {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Inflector extends Kohana_Inflector {}

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana extends Kohana_Core {}

View File

@@ -0,0 +1,620 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Array helper.
*
* @package Kohana
* @category Helpers
* @author Kohana Team
* @copyright (c) 2007-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_Arr {
/**
* @var string default delimiter for path()
*/
public static $delimiter = '.';
/**
* Tests if an array is associative or not.
*
* // Returns TRUE
* Arr::is_assoc(array('username' => 'john.doe'));
*
* // Returns FALSE
* Arr::is_assoc('foo', 'bar');
*
* @param array $array array to check
* @return boolean
*/
public static function is_assoc(array $array)
{
// Keys of the array
$keys = array_keys($array);
// If the array keys of the keys match the keys, then the array must
// not be associative (e.g. the keys array looked like {0:0, 1:1...}).
return array_keys($keys) !== $keys;
}
/**
* Test if a value is an array with an additional check for array-like objects.
*
* // Returns TRUE
* Arr::is_array(array());
* Arr::is_array(new ArrayObject);
*
* // Returns FALSE
* Arr::is_array(FALSE);
* Arr::is_array('not an array!');
* Arr::is_array(Database::instance());
*
* @param mixed $value value to check
* @return boolean
*/
public static function is_array($value)
{
if (is_array($value))
{
// Definitely an array
return TRUE;
}
else
{
// Possibly a Traversable object, functionally the same as an array
return (is_object($value) AND $value instanceof Traversable);
}
}
/**
* Gets a value from an array using a dot separated path.
*
* // Get the value of $array['foo']['bar']
* $value = Arr::path($array, 'foo.bar');
*
* Using a wildcard "*" will search intermediate arrays and return an array.
*
* // Get the values of "color" in theme
* $colors = Arr::path($array, 'theme.*.color');
*
* // Using an array of keys
* $colors = Arr::path($array, array('theme', '*', 'color'));
*
* @param array $array array to search
* @param mixed $path key path string (delimiter separated) or array of keys
* @param mixed $default default value if the path is not set
* @param string $delimiter key path delimiter
* @return mixed
*/
public static function path($array, $path, $default = NULL, $delimiter = NULL)
{
if ( ! Arr::is_array($array))
{
// This is not an array!
return $default;
}
if (is_array($path))
{
// The path has already been separated into keys
$keys = $path;
}
else
{
if (array_key_exists($path, $array))
{
// No need to do extra processing
return $array[$path];
}
if ($delimiter === NULL)
{
// Use the default delimiter
$delimiter = Arr::$delimiter;
}
// Remove starting delimiters and spaces
$path = ltrim($path, "{$delimiter} ");
// Remove ending delimiters, spaces, and wildcards
$path = rtrim($path, "{$delimiter} *");
// Split the keys by delimiter
$keys = explode($delimiter, $path);
}
do
{
$key = array_shift($keys);
if (ctype_digit($key))
{
// Make the key an integer
$key = (int) $key;
}
if (isset($array[$key]))
{
if ($keys)
{
if (Arr::is_array($array[$key]))
{
// Dig down into the next part of the path
$array = $array[$key];
}
else
{
// Unable to dig deeper
break;
}
}
else
{
// Found the path requested
return $array[$key];
}
}
elseif ($key === '*')
{
// Handle wildcards
$values = array();
foreach ($array as $arr)
{
if ($value = Arr::path($arr, implode('.', $keys)))
{
$values[] = $value;
}
}
if ($values)
{
// Found the values requested
return $values;
}
else
{
// Unable to dig deeper
break;
}
}
else
{
// Unable to dig deeper
break;
}
}
while ($keys);
// Unable to find the value requested
return $default;
}
/**
* Set a value on an array by path.
*
* @see Arr::path()
* @param array $array Array to update
* @param string $path Path
* @param mixed $value Value to set
* @param string $delimiter Path delimiter
*/
public static function set_path( & $array, $path, $value, $delimiter = NULL)
{
if ( ! $delimiter)
{
// Use the default delimiter
$delimiter = Arr::$delimiter;
}
// Split the keys by delimiter
$keys = explode($delimiter, $path);
// Set current $array to inner-most array path
while (count($keys) > 1)
{
$key = array_shift($keys);
if (ctype_digit($key))
{
// Make the key an integer
$key = (int) $key;
}
if ( ! isset($array[$key]))
{
$array[$key] = array();
}
$array = & $array[$key];
}
// Set key on inner-most array
$array[array_shift($keys)] = $value;
}
/**
* Fill an array with a range of numbers.
*
* // Fill an array with values 5, 10, 15, 20
* $values = Arr::range(5, 20);
*
* @param integer $step stepping
* @param integer $max ending number
* @return array
*/
public static function range($step = 10, $max = 100)
{
if ($step < 1)
return array();
$array = array();
for ($i = $step; $i <= $max; $i += $step)
{
$array[$i] = $i;
}
return $array;
}
/**
* Retrieve a single key from an array. If the key does not exist in the
* array, the default value will be returned instead.
*
* // Get the value "username" from $_POST, if it exists
* $username = Arr::get($_POST, 'username');
*
* // Get the value "sorting" from $_GET, if it exists
* $sorting = Arr::get($_GET, 'sorting');
*
* @param array $array array to extract from
* @param string $key key name
* @param mixed $default default value
* @return mixed
*/
public static function get($array, $key, $default = NULL)
{
return isset($array[$key]) ? $array[$key] : $default;
}
/**
* Retrieves multiple paths from an array. If the path does not exist in the
* array, the default value will be added instead.
*
* // Get the values "username", "password" from $_POST
* $auth = Arr::extract($_POST, array('username', 'password'));
*
* // Get the value "level1.level2a" from $data
* $data = array('level1' => array('level2a' => 'value 1', 'level2b' => 'value 2'));
* Arr::extract($data, array('level1.level2a', 'password'));
*
* @param array $array array to extract paths from
* @param array $paths list of path
* @param mixed $default default value
* @return array
*/
public static function extract($array, array $paths, $default = NULL)
{
$found = array();
foreach ($paths as $path)
{
Arr::set_path($found, $path, Arr::path($array, $path, $default));
}
return $found;
}
/**
* Retrieves muliple single-key values from a list of arrays.
*
* // Get all of the "id" values from a result
* $ids = Arr::pluck($result, 'id');
*
* [!!] A list of arrays is an array that contains arrays, eg: array(array $a, array $b, array $c, ...)
*
* @param array $array list of arrays to check
* @param string $key key to pluck
* @return array
*/
public static function pluck($array, $key)
{
$values = array();
foreach ($array as $row)
{
if (isset($row[$key]))
{
// Found a value in this row
$values[] = $row[$key];
}
}
return $values;
}
/**
* Adds a value to the beginning of an associative array.
*
* // Add an empty value to the start of a select list
* Arr::unshift($array, 'none', 'Select a value');
*
* @param array $array array to modify
* @param string $key array key name
* @param mixed $val array value
* @return array
*/
public static function unshift( array & $array, $key, $val)
{
$array = array_reverse($array, TRUE);
$array[$key] = $val;
$array = array_reverse($array, TRUE);
return $array;
}
/**
* Recursive version of [array_map](http://php.net/array_map), applies one or more
* callbacks to all elements in an array, including sub-arrays.
*
* // Apply "strip_tags" to every element in the array
* $array = Arr::map('strip_tags', $array);
*
* // Apply $this->filter to every element in the array
* $array = Arr::map(array(array($this,'filter')), $array);
*
* // Apply strip_tags and $this->filter to every element
* $array = Arr::map(array('strip_tags',array($this,'filter')), $array);
*
* [!!] Because you can pass an array of callbacks, if you wish to use an array-form callback
* you must nest it in an additional array as above. Calling Arr::map(array($this,'filter'), $array)
* will cause an error.
* [!!] Unlike `array_map`, this method requires a callback and will only map
* a single array.
*
* @param mixed $callbacks array of callbacks to apply to every element in the array
* @param array $array array to map
* @param array $keys array of keys to apply to
* @return array
*/
public static function map($callbacks, $array, $keys = NULL)
{
foreach ($array as $key => $val)
{
if (is_array($val))
{
$array[$key] = Arr::map($callbacks, $array[$key]);
}
elseif ( ! is_array($keys) OR in_array($key, $keys))
{
if (is_array($callbacks))
{
foreach ($callbacks as $cb)
{
$array[$key] = call_user_func($cb, $array[$key]);
}
}
else
{
$array[$key] = call_user_func($callbacks, $array[$key]);
}
}
}
return $array;
}
/**
* Recursively merge two or more arrays. Values in an associative array
* overwrite previous values with the same key. Values in an indexed array
* are appended, but only when they do not already exist in the result.
*
* Note that this does not work the same as [array_merge_recursive](http://php.net/array_merge_recursive)!
*
* $john = array('name' => 'john', 'children' => array('fred', 'paul', 'sally', 'jane'));
* $mary = array('name' => 'mary', 'children' => array('jane'));
*
* // John and Mary are married, merge them together
* $john = Arr::merge($john, $mary);
*
* // The output of $john will now be:
* array('name' => 'mary', 'children' => array('fred', 'paul', 'sally', 'jane'))
*
* @param array $array1 initial array
* @param array $array2,... array to merge
* @return array
*/
public static function merge($array1, $array2)
{
if (Arr::is_assoc($array2))
{
foreach ($array2 as $key => $value)
{
if (is_array($value)
AND isset($array1[$key])
AND is_array($array1[$key])
)
{
$array1[$key] = Arr::merge($array1[$key], $value);
}
else
{
$array1[$key] = $value;
}
}
}
else
{
foreach ($array2 as $value)
{
if ( ! in_array($value, $array1, TRUE))
{
$array1[] = $value;
}
}
}
if (func_num_args() > 2)
{
foreach (array_slice(func_get_args(), 2) as $array2)
{
if (Arr::is_assoc($array2))
{
foreach ($array2 as $key => $value)
{
if (is_array($value)
AND isset($array1[$key])
AND is_array($array1[$key])
)
{
$array1[$key] = Arr::merge($array1[$key], $value);
}
else
{
$array1[$key] = $value;
}
}
}
else
{
foreach ($array2 as $value)
{
if ( ! in_array($value, $array1, TRUE))
{
$array1[] = $value;
}
}
}
}
}
return $array1;
}
/**
* Overwrites an array with values from input arrays.
* Keys that do not exist in the first array will not be added!
*
* $a1 = array('name' => 'john', 'mood' => 'happy', 'food' => 'bacon');
* $a2 = array('name' => 'jack', 'food' => 'tacos', 'drink' => 'beer');
*
* // Overwrite the values of $a1 with $a2
* $array = Arr::overwrite($a1, $a2);
*
* // The output of $array will now be:
* array('name' => 'jack', 'mood' => 'happy', 'food' => 'tacos')
*
* @param array $array1 master array
* @param array $array2 input arrays that will overwrite existing values
* @return array
*/
public static function overwrite($array1, $array2)
{
foreach (array_intersect_key($array2, $array1) as $key => $value)
{
$array1[$key] = $value;
}
if (func_num_args() > 2)
{
foreach (array_slice(func_get_args(), 2) as $array2)
{
foreach (array_intersect_key($array2, $array1) as $key => $value)
{
$array1[$key] = $value;
}
}
}
return $array1;
}
/**
* Creates a callable function and parameter list from a string representation.
* Note that this function does not validate the callback string.
*
* // Get the callback function and parameters
* list($func, $params) = Arr::callback('Foo::bar(apple,orange)');
*
* // Get the result of the callback
* $result = call_user_func_array($func, $params);
*
* @param string $str callback string
* @return array function, params
*/
public static function callback($str)
{
// Overloaded as parts are found
$command = $params = NULL;
// command[param,param]
if (preg_match('/^([^\(]*+)\((.*)\)$/', $str, $match))
{
// command
$command = $match[1];
if ($match[2] !== '')
{
// param,param
$params = preg_split('/(?<!\\\\),/', $match[2]);
$params = str_replace('\,', ',', $params);
}
}
else
{
// command
$command = $str;
}
if (strpos($command, '::') !== FALSE)
{
// Create a static method callable command
$command = explode('::', $command, 2);
}
return array($command, $params);
}
/**
* Convert a multi-dimensional array into a single-dimensional array.
*
* $array = array('set' => array('one' => 'something'), 'two' => 'other');
*
* // Flatten the array
* $array = Arr::flatten($array);
*
* // The array will now be
* array('one' => 'something', 'two' => 'other');
*
* [!!] The keys of array values will be discarded.
*
* @param array $array array to flatten
* @return array
* @since 3.0.6
*/
public static function flatten($array)
{
$is_assoc = Arr::is_assoc($array);
$flat = array();
foreach ($array as $key => $value)
{
if (is_array($value))
{
$flat = array_merge($flat, Arr::flatten($value));
}
else
{
if ($is_assoc)
{
$flat[$key] = $value;
}
else
{
$flat[] = $value;
}
}
}
return $flat;
}
} // End arr

View File

@@ -0,0 +1,192 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Wrapper for configuration arrays. Multiple configuration readers can be
* attached to allow loading configuration from files, database, etc.
*
* Configuration directives cascade across config sources in the same way that
* files cascade across the filesystem.
*
* Directives from sources high in the sources list will override ones from those
* below them.
*
* @package Kohana
* @category Configuration
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_Config {
// Configuration readers
protected $_sources = array();
// Array of config groups
protected $_groups = array();
/**
* Attach a configuration reader. By default, the reader will be added as
* the first used reader. However, if the reader should be used only when
* all other readers fail, use `FALSE` for the second parameter.
*
* $config->attach($reader); // Try first
* $config->attach($reader, FALSE); // Try last
*
* @param Kohana_Config_Source $source instance
* @param boolean $first add the reader as the first used object
* @return $this
*/
public function attach(Kohana_Config_Source $source, $first = TRUE)
{
if ($first === TRUE)
{
// Place the log reader at the top of the stack
array_unshift($this->_sources, $source);
}
else
{
// Place the reader at the bottom of the stack
$this->_sources[] = $source;
}
// Clear any cached _groups
$this->_groups = array();
return $this;
}
/**
* Detach a configuration reader.
*
* $config->detach($reader);
*
* @param Kohana_Config_Source $source instance
* @return $this
*/
public function detach(Kohana_Config_Source $source)
{
if (($key = array_search($source, $this->_sources)) !== FALSE)
{
// Remove the writer
unset($this->_sources[$key]);
}
return $this;
}
/**
* Load a configuration group. Searches all the config sources, merging all the
* directives found into a single config group. Any changes made to the config
* in this group will be mirrored across all writable sources.
*
* $array = $config->load($name);
*
* See [Kohana_Config_Group] for more info
*
* @param string $group configuration group name
* @return Kohana_Config_Group
* @throws Kohana_Exception
*/
public function load($group)
{
if ( ! count($this->_sources))
{
throw new Kohana_Exception('No configuration sources attached');
}
if (empty($group))
{
throw new Kohana_Exception("Need to specify a config group");
}
if ( ! is_string($group))
{
throw new Kohana_Exception("Config group must be a string");
}
if (strpos($group, '.') !== FALSE)
{
// Split the config group and path
list($group, $path) = explode('.', $group, 2);
}
if (isset($this->_groups[$group]))
{
if (isset($path))
{
return Arr::path($this->_groups[$group], $path, NULL, '.');
}
return $this->_groups[$group];
}
$config = array();
// We search from the "lowest" source and work our way up
$sources = array_reverse($this->_sources);
foreach ($sources as $source)
{
if ($source instanceof Kohana_Config_Reader)
{
if ($source_config = $source->load($group))
{
$config = Arr::merge($config, $source_config);
}
}
}
$this->_groups[$group] = new Config_Group($this, $group, $config);
if (isset($path))
{
return Arr::path($config, $path, NULL, '.');
}
return $this->_groups[$group];
}
/**
* Copy one configuration group to all of the other writers.
*
* $config->copy($name);
*
* @param string $group configuration group name
* @return $this
*/
public function copy($group)
{
// Load the configuration group
$config = $this->load($group);
foreach ($config->as_array() as $key => $value)
{
$this->_write_config($group, $key, $value);
}
return $this;
}
/**
* Callback used by the config group to store changes made to configuration
*
* @param string $group Group name
* @param string $key Variable name
* @param mixed $value The new value
* @return Kohana_Config Chainable instance
*/
public function _write_config($group, $key, $value)
{
foreach ($this->_sources as $source)
{
if ( ! ($source instanceof Kohana_Config_Writer))
{
continue;
}
// Copy each value in the config
$source->write($group, $key, $value);
}
return $this;
}
} // End Kohana_Config

View File

@@ -0,0 +1,15 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* File-based configuration reader. Multiple configuration directories can be
* used by attaching multiple instances of this class to [Config].
*
* @package Kohana
* @category Configuration
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_Config_File extends Kohana_Config_File_Reader
{
// @see Kohana_Config_File_Reader
}

View File

@@ -0,0 +1,56 @@
<?php
/**
* File-based configuration reader. Multiple configuration directories can be
* used by attaching multiple instances of this class to [Kohana_Config].
*
* @package Kohana
* @category Configuration
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_Config_File_Reader implements Kohana_Config_Reader {
/**
* The directory where config files are located
* @var string
*/
protected $_directory = '';
/**
* Creates a new file reader using the given directory as a config source
*
* @param string $directory Configuration directory to search
*/
public function __construct($directory = 'config')
{
// Set the configuration directory name
$this->_directory = trim($directory, '/');
}
/**
* Load and merge all of the configuration files in this group.
*
* $config->load($name);
*
* @param string $group configuration group name
* @return $this current object
* @uses Kohana::load
*/
public function load($group)
{
$config = array();
if ($files = Kohana::find_file($this->_directory, $group, NULL, TRUE))
{
foreach ($files as $file)
{
// Merge each file to the configuration array
$config = Arr::merge($config, Kohana::load($file));
}
}
return $config;
}
} // End Kohana_Config

View File

@@ -0,0 +1,130 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* The group wrapper acts as an interface to all the config directives
* gathered from across the system.
*
* This is the object returned from Kohana_Config::load
*
* Any modifications to configuration items should be done through an instance of this object
*
* @package Kohana
* @category Configuration
* @author Kohana Team
* @copyright (c) 2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Config_Group extends ArrayObject {
/**
* Reference the config object that created this group
* Used when updating config
* @var Kohana_Config
*/
protected $_parent_instance = NULL;
/**
* The group this config is for
* Used when updating config items
* @var string
*/
protected $_group_name = '';
/**
* Constructs the group object. Kohana_Config passes the config group
* and its config items to the object here.
*
* @param Kohana_Config $instance "Owning" instance of Kohana_Config
* @param string $group The group name
* @param array $config Group's config
*/
public function __construct(Kohana_Config $instance, $group, array $config = array())
{
$this->_parent_instance = $instance;
$this->_group_name = $group;
parent::__construct($config, ArrayObject::ARRAY_AS_PROPS);
}
/**
* Return the current group in serialized form.
*
* echo $config;
*
* @return string
*/
public function __toString()
{
return serialize($this->getArrayCopy());
}
/**
* Alias for getArrayCopy()
*
* @return array Array copy of the group's config
*/
public function as_array()
{
return $this->getArrayCopy();
}
/**
* Returns the config group's name
*
* @return string The group name
*/
public function group_name()
{
return $this->_group_name;
}
/**
* Get a variable from the configuration or return the default value.
*
* $value = $config->get($key);
*
* @param string $key array key
* @param mixed $default default value
* @return mixed
*/
public function get($key, $default = NULL)
{
return $this->offsetExists($key) ? $this->offsetGet($key) : $default;
}
/**
* Sets a value in the configuration array.
*
* $config->set($key, $new_value);
*
* @param string $key array key
* @param mixed $value array value
* @return $this
*/
public function set($key, $value)
{
$this->offsetSet($key, $value);
return $this;
}
/**
* Overrides ArrayObject::offsetSet()
* This method is called when config is changed via
*
* $config->var = 'asd';
*
* // OR
*
* $config['var'] = 'asd';
*
* @param string $key The key of the config item we're changing
* @param mixed $value The new array value
*/
public function offsetSet($key, $value)
{
$this->_parent_instance->_write_config($this->_group_name, $key, $value);
return parent::offsetSet($key, $value);
}
}

View File

@@ -0,0 +1,25 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Interface for config readers
*
* @package Kohana
* @category Configuration
* @author Kohana Team
* @copyright (c) 2008-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
interface Kohana_Config_Reader extends Kohana_Config_Source
{
/**
* Tries to load the specificed configuration group
*
* Returns FALSE if group does not exist or an array if it does
*
* @param string $group Configuration group
* @return boolean|array
*/
public function load($group);
}

View File

@@ -0,0 +1,14 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Base Config source Interface
*
* Used to identify either config readers or writers when calling [Kohana_Config::attach()]
*
* @package Kohana
* @category Configuration
* @author Kohana Team
* @copyright (c) 2012 Kohana Team
* @license http://kohanaphp.com/license
*/
interface Kohana_Config_Source {}

View File

@@ -0,0 +1,27 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Interface for config writers
*
* Specifies the methods that a config writer must implement
*
* @package Kohana
* @author Kohana Team
* @copyright (c) 2008-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
interface Kohana_Config_Writer extends Kohana_Config_Source
{
/**
* Writes the passed config for $group
*
* Returns chainable instance on success or throws
* Kohana_Config_Exception on failure
*
* @param string $group The config group
* @param string $key The config key to write to
* @param array $config The configuration to write
* @return boolean
*/
public function write($group, $key, $config);
}

View File

@@ -0,0 +1,145 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Abstract controller class. Controllers should only be created using a [Request].
*
* Controllers methods will be automatically called in the following order by
* the request:
*
* $controller = new Controller_Foo($request);
* $controller->before();
* $controller->action_bar();
* $controller->after();
*
* The controller action should add the output it creates to
* `$this->response->body($output)`, typically in the form of a [View], during the
* "action" part of execution.
*
* @package Kohana
* @category Controller
* @author Kohana Team
* @copyright (c) 2008-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
abstract class Kohana_Controller {
/**
* @var Request Request that created the controller
*/
public $request;
/**
* @var Response The response that will be returned from controller
*/
public $response;
/**
* Creates a new controller instance. Each controller must be constructed
* with the request object that created it.
*
* @param Request $request Request that created the controller
* @param Response $response The request's response
* @return void
*/
public function __construct(Request $request, Response $response)
{
// Assign the request to the controller
$this->request = $request;
// Assign a response to the controller
$this->response = $response;
}
/**
* Executes the given action and calls the [Controller::before] and [Controller::after] methods.
*
* Can also be used to catch exceptions from actions in a single place.
*
* 1. Before the controller action is called, the [Controller::before] method
* will be called.
* 2. Next the controller action will be called.
* 3. After the controller action is called, the [Controller::after] method
* will be called.
*
* @throws HTTP_Exception_404
* @return Response
*/
public function execute()
{
// Execute the "before action" method
$this->before();
// Determine the action to use
$action = 'action_'.$this->request->action();
// If the action doesn't exist, it's a 404
if ( ! method_exists($this, $action))
{
throw HTTP_Exception::factory(404,
'The requested URL :uri was not found on this server.',
array(':uri' => $this->request->uri())
)->request($this->request);
}
// Execute the action itself
$this->{$action}();
// Execute the "after action" method
$this->after();
// Return the response
return $this->response;
}
/**
* Automatically executed before the controller action. Can be used to set
* class properties, do authorization checks, and execute other custom code.
*
* @return void
*/
public function before()
{
// Nothing by default
}
/**
* Automatically executed after the controller action. Can be used to apply
* transformation to the response, add extra output, and execute
* other custom code.
*
* @return void
*/
public function after()
{
// Nothing by default
}
/**
* Issues a HTTP redirect.
*
* Proxies to the [HTTP::redirect] method.
*
* @param string $uri URI to redirect to
* @param int $code HTTP Status code to use for the redirect
* @throws HTTP_Exception
*/
public static function redirect($uri = '', $code = 302)
{
return HTTP::redirect($uri, $code);
}
/**
* Checks the browser cache to see the response needs to be returned,
* execution will halt and a 304 Not Modified will be sent if the
* browser cache is up to date.
*
* $this->check_cache(sha1($content));
*
* @param string $etag Resource Etag
* @return Response
*/
protected function check_cache($etag = NULL)
{
return HTTP::check_cache($this->request, $this->response, $etag);
}
} // End Controller

View File

@@ -0,0 +1,50 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Abstract controller class for automatic templating.
*
* @package Kohana
* @category Controller
* @author Kohana Team
* @copyright (c) 2008-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
abstract class Kohana_Controller_Template extends Controller {
/**
* @var View page template
*/
public $template = 'template';
/**
* @var boolean auto render template
**/
public $auto_render = TRUE;
/**
* Loads the template [View] object.
*/
public function before()
{
parent::before();
if ($this->auto_render === TRUE)
{
// Load the template
$this->template = View::factory($this->template);
}
}
/**
* Assigns the template [View] as the request response.
*/
public function after()
{
if ($this->auto_render === TRUE)
{
$this->response->body($this->template->render());
}
parent::after();
}
} // End Controller_Template

View File

@@ -0,0 +1,161 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Cookie helper.
*
* @package Kohana
* @category Helpers
* @author Kohana Team
* @copyright (c) 2008-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_Cookie {
/**
* @var string Magic salt to add to the cookie
*/
public static $salt = NULL;
/**
* @var integer Number of seconds before the cookie expires
*/
public static $expiration = 0;
/**
* @var string Restrict the path that the cookie is available to
*/
public static $path = '/';
/**
* @var string Restrict the domain that the cookie is available to
*/
public static $domain = NULL;
/**
* @var boolean Only transmit cookies over secure connections
*/
public static $secure = FALSE;
/**
* @var boolean Only transmit cookies over HTTP, disabling Javascript access
*/
public static $httponly = FALSE;
/**
* Gets the value of a signed cookie. Cookies without signatures will not
* be returned. If the cookie signature is present, but invalid, the cookie
* will be deleted.
*
* // Get the "theme" cookie, or use "blue" if the cookie does not exist
* $theme = Cookie::get('theme', 'blue');
*
* @param string $key cookie name
* @param mixed $default default value to return
* @return string
*/
public static function get($key, $default = NULL)
{
if ( ! isset($_COOKIE[$key]))
{
// The cookie does not exist
return $default;
}
// Get the cookie value
$cookie = $_COOKIE[$key];
// Find the position of the split between salt and contents
$split = strlen(Cookie::salt($key, NULL));
if (isset($cookie[$split]) AND $cookie[$split] === '~')
{
// Separate the salt and the value
list ($hash, $value) = explode('~', $cookie, 2);
if (Cookie::salt($key, $value) === $hash)
{
// Cookie signature is valid
return $value;
}
// The cookie signature is invalid, delete it
Cookie::delete($key);
}
return $default;
}
/**
* Sets a signed cookie. Note that all cookie values must be strings and no
* automatic serialization will be performed!
*
* // Set the "theme" cookie
* Cookie::set('theme', 'red');
*
* @param string $name name of cookie
* @param string $value value of cookie
* @param integer $expiration lifetime in seconds
* @return boolean
* @uses Cookie::salt
*/
public static function set($name, $value, $expiration = NULL)
{
if ($expiration === NULL)
{
// Use the default expiration
$expiration = Cookie::$expiration;
}
if ($expiration !== 0)
{
// The expiration is expected to be a UNIX timestamp
$expiration += time();
}
// Add the salt to the cookie value
$value = Cookie::salt($name, $value).'~'.$value;
return setcookie($name, $value, $expiration, Cookie::$path, Cookie::$domain, Cookie::$secure, Cookie::$httponly);
}
/**
* Deletes a cookie by making the value NULL and expiring it.
*
* Cookie::delete('theme');
*
* @param string $name cookie name
* @return boolean
* @uses Cookie::set
*/
public static function delete($name)
{
// Remove the cookie
unset($_COOKIE[$name]);
// Nullify the cookie and make it expire
return setcookie($name, NULL, -86400, Cookie::$path, Cookie::$domain, Cookie::$secure, Cookie::$httponly);
}
/**
* Generates a salt string for a cookie based on the name and value.
*
* $salt = Cookie::salt('theme', 'red');
*
* @param string $name name of cookie
* @param string $value value of cookie
* @return string
*/
public static function salt($name, $value)
{
// Require a valid salt
if ( ! Cookie::$salt)
{
throw new Kohana_Exception('A valid cookie salt is required. Please set Cookie::$salt.');
}
// Determine the user agent
$agent = isset($_SERVER['HTTP_USER_AGENT']) ? strtolower($_SERVER['HTTP_USER_AGENT']) : 'unknown';
return sha1($agent.$name.$value.Cookie::$salt);
}
} // End cookie

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,603 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Date helper.
*
* @package Kohana
* @category Helpers
* @author Kohana Team
* @copyright (c) 2007-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_Date {
// Second amounts for various time increments
const YEAR = 31556926;
const MONTH = 2629744;
const WEEK = 604800;
const DAY = 86400;
const HOUR = 3600;
const MINUTE = 60;
// Available formats for Date::months()
const MONTHS_LONG = '%B';
const MONTHS_SHORT = '%b';
/**
* Default timestamp format for formatted_time
* @var string
*/
public static $timestamp_format = 'Y-m-d H:i:s';
/**
* Timezone for formatted_time
* @link http://uk2.php.net/manual/en/timezones.php
* @var string
*/
public static $timezone;
/**
* Returns the offset (in seconds) between two time zones. Use this to
* display dates to users in different time zones.
*
* $seconds = Date::offset('America/Chicago', 'GMT');
*
* [!!] A list of time zones that PHP supports can be found at
* <http://php.net/timezones>.
*
* @param string $remote timezone that to find the offset of
* @param string $local timezone used as the baseline
* @param mixed $now UNIX timestamp or date string
* @return integer
*/
public static function offset($remote, $local = NULL, $now = NULL)
{
if ($local === NULL)
{
// Use the default timezone
$local = date_default_timezone_get();
}
if (is_int($now))
{
// Convert the timestamp into a string
$now = date(DateTime::RFC2822, $now);
}
// Create timezone objects
$zone_remote = new DateTimeZone($remote);
$zone_local = new DateTimeZone($local);
// Create date objects from timezones
$time_remote = new DateTime($now, $zone_remote);
$time_local = new DateTime($now, $zone_local);
// Find the offset
$offset = $zone_remote->getOffset($time_remote) - $zone_local->getOffset($time_local);
return $offset;
}
/**
* Number of seconds in a minute, incrementing by a step. Typically used as
* a shortcut for generating a list that can used in a form.
*
* $seconds = Date::seconds(); // 01, 02, 03, ..., 58, 59, 60
*
* @param integer $step amount to increment each step by, 1 to 30
* @param integer $start start value
* @param integer $end end value
* @return array A mirrored (foo => foo) array from 1-60.
*/
public static function seconds($step = 1, $start = 0, $end = 60)
{
// Always integer
$step = (int) $step;
$seconds = array();
for ($i = $start; $i < $end; $i += $step)
{
$seconds[$i] = sprintf('%02d', $i);
}
return $seconds;
}
/**
* Number of minutes in an hour, incrementing by a step. Typically used as
* a shortcut for generating a list that can be used in a form.
*
* $minutes = Date::minutes(); // 05, 10, 15, ..., 50, 55, 60
*
* @uses Date::seconds
* @param integer $step amount to increment each step by, 1 to 30
* @return array A mirrored (foo => foo) array from 1-60.
*/
public static function minutes($step = 5)
{
// Because there are the same number of minutes as seconds in this set,
// we choose to re-use seconds(), rather than creating an entirely new
// function. Shhhh, it's cheating! ;) There are several more of these
// in the following methods.
return Date::seconds($step);
}
/**
* Number of hours in a day. Typically used as a shortcut for generating a
* list that can be used in a form.
*
* $hours = Date::hours(); // 01, 02, 03, ..., 10, 11, 12
*
* @param integer $step amount to increment each step by
* @param boolean $long use 24-hour time
* @param integer $start the hour to start at
* @return array A mirrored (foo => foo) array from start-12 or start-23.
*/
public static function hours($step = 1, $long = FALSE, $start = NULL)
{
// Default values
$step = (int) $step;
$long = (bool) $long;
$hours = array();
// Set the default start if none was specified.
if ($start === NULL)
{
$start = ($long === FALSE) ? 1 : 0;
}
$hours = array();
// 24-hour time has 24 hours, instead of 12
$size = ($long === TRUE) ? 23 : 12;
for ($i = $start; $i <= $size; $i += $step)
{
$hours[$i] = (string) $i;
}
return $hours;
}
/**
* Returns AM or PM, based on a given hour (in 24 hour format).
*
* $type = Date::ampm(12); // PM
* $type = Date::ampm(1); // AM
*
* @param integer $hour number of the hour
* @return string
*/
public static function ampm($hour)
{
// Always integer
$hour = (int) $hour;
return ($hour > 11) ? 'PM' : 'AM';
}
/**
* Adjusts a non-24-hour number into a 24-hour number.
*
* $hour = Date::adjust(3, 'pm'); // 15
*
* @param integer $hour hour to adjust
* @param string $ampm AM or PM
* @return string
*/
public static function adjust($hour, $ampm)
{
$hour = (int) $hour;
$ampm = strtolower($ampm);
switch ($ampm)
{
case 'am':
if ($hour == 12)
{
$hour = 0;
}
break;
case 'pm':
if ($hour < 12)
{
$hour += 12;
}
break;
}
return sprintf('%02d', $hour);
}
/**
* Number of days in a given month and year. Typically used as a shortcut
* for generating a list that can be used in a form.
*
* Date::days(4, 2010); // 1, 2, 3, ..., 28, 29, 30
*
* @param integer $month number of month
* @param integer $year number of year to check month, defaults to the current year
* @return array A mirrored (foo => foo) array of the days.
*/
public static function days($month, $year = FALSE)
{
static $months;
if ($year === FALSE)
{
// Use the current year by default
$year = date('Y');
}
// Always integers
$month = (int) $month;
$year = (int) $year;
// We use caching for months, because time functions are used
if (empty($months[$year][$month]))
{
$months[$year][$month] = array();
// Use date to find the number of days in the given month
$total = date('t', mktime(1, 0, 0, $month, 1, $year)) + 1;
for ($i = 1; $i < $total; $i++)
{
$months[$year][$month][$i] = (string) $i;
}
}
return $months[$year][$month];
}
/**
* Number of months in a year. Typically used as a shortcut for generating
* a list that can be used in a form.
*
* By default a mirrored array of $month_number => $month_number is returned
*
* Date::months();
* // aray(1 => 1, 2 => 2, 3 => 3, ..., 12 => 12)
*
* But you can customise this by passing in either Date::MONTHS_LONG
*
* Date::months(Date::MONTHS_LONG);
* // array(1 => 'January', 2 => 'February', ..., 12 => 'December')
*
* Or Date::MONTHS_SHORT
*
* Date::months(Date::MONTHS_SHORT);
* // array(1 => 'Jan', 2 => 'Feb', ..., 12 => 'Dec')
*
* @uses Date::hours
* @param string $format The format to use for months
* @return array An array of months based on the specified format
*/
public static function months($format = NULL)
{
$months = array();
if ($format === Date::MONTHS_LONG OR $format === Date::MONTHS_SHORT)
{
for ($i = 1; $i <= 12; ++$i)
{
$months[$i] = strftime($format, mktime(0, 0, 0, $i, 1));
}
}
else
{
$months = Date::hours();
}
return $months;
}
/**
* Returns an array of years between a starting and ending year. By default,
* the the current year - 5 and current year + 5 will be used. Typically used
* as a shortcut for generating a list that can be used in a form.
*
* $years = Date::years(2000, 2010); // 2000, 2001, ..., 2009, 2010
*
* @param integer $start starting year (default is current year - 5)
* @param integer $end ending year (default is current year + 5)
* @return array
*/
public static function years($start = FALSE, $end = FALSE)
{
// Default values
$start = ($start === FALSE) ? (date('Y') - 5) : (int) $start;
$end = ($end === FALSE) ? (date('Y') + 5) : (int) $end;
$years = array();
for ($i = $start; $i <= $end; $i++)
{
$years[$i] = (string) $i;
}
return $years;
}
/**
* Returns time difference between two timestamps, in human readable format.
* If the second timestamp is not given, the current time will be used.
* Also consider using [Date::fuzzy_span] when displaying a span.
*
* $span = Date::span(60, 182, 'minutes,seconds'); // array('minutes' => 2, 'seconds' => 2)
* $span = Date::span(60, 182, 'minutes'); // 2
*
* @param integer $remote timestamp to find the span of
* @param integer $local timestamp to use as the baseline
* @param string $output formatting string
* @return string when only a single output is requested
* @return array associative list of all outputs requested
*/
public static function span($remote, $local = NULL, $output = 'years,months,weeks,days,hours,minutes,seconds')
{
// Normalize output
$output = trim(strtolower( (string) $output));
if ( ! $output)
{
// Invalid output
return FALSE;
}
// Array with the output formats
$output = preg_split('/[^a-z]+/', $output);
// Convert the list of outputs to an associative array
$output = array_combine($output, array_fill(0, count($output), 0));
// Make the output values into keys
extract(array_flip($output), EXTR_SKIP);
if ($local === NULL)
{
// Calculate the span from the current time
$local = time();
}
// Calculate timespan (seconds)
$timespan = abs($remote - $local);
if (isset($output['years']))
{
$timespan -= Date::YEAR * ($output['years'] = (int) floor($timespan / Date::YEAR));
}
if (isset($output['months']))
{
$timespan -= Date::MONTH * ($output['months'] = (int) floor($timespan / Date::MONTH));
}
if (isset($output['weeks']))
{
$timespan -= Date::WEEK * ($output['weeks'] = (int) floor($timespan / Date::WEEK));
}
if (isset($output['days']))
{
$timespan -= Date::DAY * ($output['days'] = (int) floor($timespan / Date::DAY));
}
if (isset($output['hours']))
{
$timespan -= Date::HOUR * ($output['hours'] = (int) floor($timespan / Date::HOUR));
}
if (isset($output['minutes']))
{
$timespan -= Date::MINUTE * ($output['minutes'] = (int) floor($timespan / Date::MINUTE));
}
// Seconds ago, 1
if (isset($output['seconds']))
{
$output['seconds'] = $timespan;
}
if (count($output) === 1)
{
// Only a single output was requested, return it
return array_pop($output);
}
// Return array
return $output;
}
/**
* Returns the difference between a time and now in a "fuzzy" way.
* Displaying a fuzzy time instead of a date is usually faster to read and understand.
*
* $span = Date::fuzzy_span(time() - 10); // "moments ago"
* $span = Date::fuzzy_span(time() + 20); // "in moments"
*
* A second parameter is available to manually set the "local" timestamp,
* however this parameter shouldn't be needed in normal usage and is only
* included for unit tests
*
* @param integer $timestamp "remote" timestamp
* @param integer $local_timestamp "local" timestamp, defaults to time()
* @return string
*/
public static function fuzzy_span($timestamp, $local_timestamp = NULL)
{
$local_timestamp = ($local_timestamp === NULL) ? time() : (int) $local_timestamp;
// Determine the difference in seconds
$offset = abs($local_timestamp - $timestamp);
if ($offset <= Date::MINUTE)
{
$span = 'moments';
}
elseif ($offset < (Date::MINUTE * 20))
{
$span = 'a few minutes';
}
elseif ($offset < Date::HOUR)
{
$span = 'less than an hour';
}
elseif ($offset < (Date::HOUR * 4))
{
$span = 'a couple of hours';
}
elseif ($offset < Date::DAY)
{
$span = 'less than a day';
}
elseif ($offset < (Date::DAY * 2))
{
$span = 'about a day';
}
elseif ($offset < (Date::DAY * 4))
{
$span = 'a couple of days';
}
elseif ($offset < Date::WEEK)
{
$span = 'less than a week';
}
elseif ($offset < (Date::WEEK * 2))
{
$span = 'about a week';
}
elseif ($offset < Date::MONTH)
{
$span = 'less than a month';
}
elseif ($offset < (Date::MONTH * 2))
{
$span = 'about a month';
}
elseif ($offset < (Date::MONTH * 4))
{
$span = 'a couple of months';
}
elseif ($offset < Date::YEAR)
{
$span = 'less than a year';
}
elseif ($offset < (Date::YEAR * 2))
{
$span = 'about a year';
}
elseif ($offset < (Date::YEAR * 4))
{
$span = 'a couple of years';
}
elseif ($offset < (Date::YEAR * 8))
{
$span = 'a few years';
}
elseif ($offset < (Date::YEAR * 12))
{
$span = 'about a decade';
}
elseif ($offset < (Date::YEAR * 24))
{
$span = 'a couple of decades';
}
elseif ($offset < (Date::YEAR * 64))
{
$span = 'several decades';
}
else
{
$span = 'a long time';
}
if ($timestamp <= $local_timestamp)
{
// This is in the past
return $span.' ago';
}
else
{
// This in the future
return 'in '.$span;
}
}
/**
* Converts a UNIX timestamp to DOS format. There are very few cases where
* this is needed, but some binary formats use it (eg: zip files.)
* Converting the other direction is done using {@link Date::dos2unix}.
*
* $dos = Date::unix2dos($unix);
*
* @param integer $timestamp UNIX timestamp
* @return integer
*/
public static function unix2dos($timestamp = FALSE)
{
$timestamp = ($timestamp === FALSE) ? getdate() : getdate($timestamp);
if ($timestamp['year'] < 1980)
{
return (1 << 21 | 1 << 16);
}
$timestamp['year'] -= 1980;
// What voodoo is this? I have no idea... Geert can explain it though,
// and that's good enough for me.
return ($timestamp['year'] << 25 | $timestamp['mon'] << 21 |
$timestamp['mday'] << 16 | $timestamp['hours'] << 11 |
$timestamp['minutes'] << 5 | $timestamp['seconds'] >> 1);
}
/**
* Converts a DOS timestamp to UNIX format.There are very few cases where
* this is needed, but some binary formats use it (eg: zip files.)
* Converting the other direction is done using {@link Date::unix2dos}.
*
* $unix = Date::dos2unix($dos);
*
* @param integer $timestamp DOS timestamp
* @return integer
*/
public static function dos2unix($timestamp = FALSE)
{
$sec = 2 * ($timestamp & 0x1f);
$min = ($timestamp >> 5) & 0x3f;
$hrs = ($timestamp >> 11) & 0x1f;
$day = ($timestamp >> 16) & 0x1f;
$mon = ($timestamp >> 21) & 0x0f;
$year = ($timestamp >> 25) & 0x7f;
return mktime($hrs, $min, $sec, $mon, $day, $year + 1980);
}
/**
* Returns a date/time string with the specified timestamp format
*
* $time = Date::formatted_time('5 minutes ago');
*
* @link http://www.php.net/manual/datetime.construct
* @param string $datetime_str datetime string
* @param string $timestamp_format timestamp format
* @param string $timezone timezone identifier
* @return string
*/
public static function formatted_time($datetime_str = 'now', $timestamp_format = NULL, $timezone = NULL)
{
$timestamp_format = ($timestamp_format == NULL) ? Date::$timestamp_format : $timestamp_format;
$timezone = ($timezone === NULL) ? Date::$timezone : $timezone;
$tz = new DateTimeZone($timezone ? $timezone : date_default_timezone_get());
$time = new DateTime($datetime_str, $tz);
if ($time->getTimeZone()->getName() !== $tz->getName())
{
$time->setTimeZone($tz);
}
return $time->format($timestamp_format);
}
} // End date

View File

@@ -0,0 +1,465 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Contains debugging and dumping tools.
*
* @package Kohana
* @category Base
* @author Kohana Team
* @copyright (c) 2008-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
class Kohana_Debug {
/**
* Returns an HTML string of debugging information about any number of
* variables, each wrapped in a "pre" tag:
*
* // Displays the type and value of each variable
* echo Debug::vars($foo, $bar, $baz);
*
* @param mixed $var,... variable to debug
* @return string
*/
public static function vars()
{
if (func_num_args() === 0)
return;
// Get all passed variables
$variables = func_get_args();
$output = array();
foreach ($variables as $var)
{
$output[] = Debug::_dump($var, 1024);
}
return '<pre class="debug">'.implode("\n", $output).'</pre>';
}
/**
* Returns an HTML string of information about a single variable.
*
* Borrows heavily on concepts from the Debug class of [Nette](http://nettephp.com/).
*
* @param mixed $value variable to dump
* @param integer $length maximum length of strings
* @param integer $level_recursion recursion limit
* @return string
*/
public static function dump($value, $length = 128, $level_recursion = 10)
{
return Debug::_dump($value, $length, $level_recursion);
}
/**
* Helper for Debug::dump(), handles recursion in arrays and objects.
*
* @param mixed $var variable to dump
* @param integer $length maximum length of strings
* @param integer $limit recursion limit
* @param integer $level current recursion level (internal usage only!)
* @return string
*/
protected static function _dump( & $var, $length = 128, $limit = 10, $level = 0)
{
if ($var === NULL)
{
return '<small>NULL</small>';
}
elseif (is_bool($var))
{
return '<small>bool</small> '.($var ? 'TRUE' : 'FALSE');
}
elseif (is_float($var))
{
return '<small>float</small> '.$var;
}
elseif (is_resource($var))
{
if (($type = get_resource_type($var)) === 'stream' AND $meta = stream_get_meta_data($var))
{
$meta = stream_get_meta_data($var);
if (isset($meta['uri']))
{
$file = $meta['uri'];
if (function_exists('stream_is_local'))
{
// Only exists on PHP >= 5.2.4
if (stream_is_local($file))
{
$file = Debug::path($file);
}
}
return '<small>resource</small><span>('.$type.')</span> '.htmlspecialchars($file, ENT_NOQUOTES, Kohana::$charset);
}
}
else
{
return '<small>resource</small><span>('.$type.')</span>';
}
}
elseif (is_string($var))
{
// Clean invalid multibyte characters. iconv is only invoked
// if there are non ASCII characters in the string, so this
// isn't too much of a hit.
$var = UTF8::clean($var, Kohana::$charset);
if (UTF8::strlen($var) > $length)
{
// Encode the truncated string
$str = htmlspecialchars(UTF8::substr($var, 0, $length), ENT_NOQUOTES, Kohana::$charset).'&nbsp;&hellip;';
}
else
{
// Encode the string
$str = htmlspecialchars($var, ENT_NOQUOTES, Kohana::$charset);
}
return '<small>string</small><span>('.strlen($var).')</span> "'.$str.'"';
}
elseif (is_array($var))
{
$output = array();
// Indentation for this variable
$space = str_repeat($s = ' ', $level);
static $marker;
if ($marker === NULL)
{
// Make a unique marker
$marker = uniqid("\x00");
}
if (empty($var))
{
// Do nothing
}
elseif (isset($var[$marker]))
{
$output[] = "(\n$space$s*RECURSION*\n$space)";
}
elseif ($level < $limit)
{
$output[] = "<span>(";
$var[$marker] = TRUE;
foreach ($var as $key => & $val)
{
if ($key === $marker) continue;
if ( ! is_int($key))
{
$key = '"'.htmlspecialchars($key, ENT_NOQUOTES, Kohana::$charset).'"';
}
$output[] = "$space$s$key => ".Debug::_dump($val, $length, $limit, $level + 1);
}
unset($var[$marker]);
$output[] = "$space)</span>";
}
else
{
// Depth too great
$output[] = "(\n$space$s...\n$space)";
}
return '<small>array</small><span>('.count($var).')</span> '.implode("\n", $output);
}
elseif (is_object($var))
{
// Copy the object as an array
$array = (array) $var;
$output = array();
// Indentation for this variable
$space = str_repeat($s = ' ', $level);
$hash = spl_object_hash($var);
// Objects that are being dumped
static $objects = array();
if (empty($var))
{
// Do nothing
}
elseif (isset($objects[$hash]))
{
$output[] = "{\n$space$s*RECURSION*\n$space}";
}
elseif ($level < $limit)
{
$output[] = "<code>{";
$objects[$hash] = TRUE;
foreach ($array as $key => & $val)
{
if ($key[0] === "\x00")
{
// Determine if the access is protected or protected
$access = '<small>'.(($key[1] === '*') ? 'protected' : 'private').'</small>';
// Remove the access level from the variable name
$key = substr($key, strrpos($key, "\x00") + 1);
}
else
{
$access = '<small>public</small>';
}
$output[] = "$space$s$access $key => ".Debug::_dump($val, $length, $limit, $level + 1);
}
unset($objects[$hash]);
$output[] = "$space}</code>";
}
else
{
// Depth too great
$output[] = "{\n$space$s...\n$space}";
}
return '<small>object</small> <span>'.get_class($var).'('.count($array).')</span> '.implode("\n", $output);
}
else
{
return '<small>'.gettype($var).'</small> '.htmlspecialchars(print_r($var, TRUE), ENT_NOQUOTES, Kohana::$charset);
}
}
/**
* Removes application, system, modpath, or docroot from a filename,
* replacing them with the plain text equivalents. Useful for debugging
* when you want to display a shorter path.
*
* // Displays SYSPATH/classes/kohana.php
* echo Debug::path(Kohana::find_file('classes', 'kohana'));
*
* @param string $file path to debug
* @return string
*/
public static function path($file)
{
if (strpos($file, APPPATH) === 0)
{
$file = 'APPPATH'.DIRECTORY_SEPARATOR.substr($file, strlen(APPPATH));
}
elseif (strpos($file, SYSPATH) === 0)
{
$file = 'SYSPATH'.DIRECTORY_SEPARATOR.substr($file, strlen(SYSPATH));
}
elseif (strpos($file, MODPATH) === 0)
{
$file = 'MODPATH'.DIRECTORY_SEPARATOR.substr($file, strlen(MODPATH));
}
elseif (strpos($file, DOCROOT) === 0)
{
$file = 'DOCROOT'.DIRECTORY_SEPARATOR.substr($file, strlen(DOCROOT));
}
return $file;
}
/**
* Returns an HTML string, highlighting a specific line of a file, with some
* number of lines padded above and below.
*
* // Highlights the current line of the current file
* echo Debug::source(__FILE__, __LINE__);
*
* @param string $file file to open
* @param integer $line_number line number to highlight
* @param integer $padding number of padding lines
* @return string source of file
* @return FALSE file is unreadable
*/
public static function source($file, $line_number, $padding = 5)
{
if ( ! $file OR ! is_readable($file))
{
// Continuing will cause errors
return FALSE;
}
// Open the file and set the line position
$file = fopen($file, 'r');
$line = 0;
// Set the reading range
$range = array('start' => $line_number - $padding, 'end' => $line_number + $padding);
// Set the zero-padding amount for line numbers
$format = '% '.strlen($range['end']).'d';
$source = '';
while (($row = fgets($file)) !== FALSE)
{
// Increment the line number
if (++$line > $range['end'])
break;
if ($line >= $range['start'])
{
// Make the row safe for output
$row = htmlspecialchars($row, ENT_NOQUOTES, Kohana::$charset);
// Trim whitespace and sanitize the row
$row = '<span class="number">'.sprintf($format, $line).'</span> '.$row;
if ($line === $line_number)
{
// Apply highlighting to this row
$row = '<span class="line highlight">'.$row.'</span>';
}
else
{
$row = '<span class="line">'.$row.'</span>';
}
// Add to the captured source
$source .= $row;
}
}
// Close the file
fclose($file);
return '<pre class="source"><code>'.$source.'</code></pre>';
}
/**
* Returns an array of HTML strings that represent each step in the backtrace.
*
* // Displays the entire current backtrace
* echo implode('<br/>', Debug::trace());
*
* @param array $trace
* @return string
*/
public static function trace(array $trace = NULL)
{
if ($trace === NULL)
{
// Start a new trace
$trace = debug_backtrace();
}
// Non-standard function calls
$statements = array('include', 'include_once', 'require', 'require_once');
$output = array();
foreach ($trace as $step)
{
if ( ! isset($step['function']))
{
// Invalid trace step
continue;
}
if (isset($step['file']) AND isset($step['line']))
{
// Include the source of this step
$source = Debug::source($step['file'], $step['line']);
}
if (isset($step['file']))
{
$file = $step['file'];
if (isset($step['line']))
{
$line = $step['line'];
}
}
// function()
$function = $step['function'];
if (in_array($step['function'], $statements))
{
if (empty($step['args']))
{
// No arguments
$args = array();
}
else
{
// Sanitize the file path
$args = array($step['args'][0]);
}
}
elseif (isset($step['args']))
{
if ( ! function_exists($step['function']) OR strpos($step['function'], '{closure}') !== FALSE)
{
// Introspection on closures or language constructs in a stack trace is impossible
$params = NULL;
}
else
{
if (isset($step['class']))
{
if (method_exists($step['class'], $step['function']))
{
$reflection = new ReflectionMethod($step['class'], $step['function']);
}
else
{
$reflection = new ReflectionMethod($step['class'], '__call');
}
}
else
{
$reflection = new ReflectionFunction($step['function']);
}
// Get the function parameters
$params = $reflection->getParameters();
}
$args = array();
foreach ($step['args'] as $i => $arg)
{
if (isset($params[$i]))
{
// Assign the argument by the parameter name
$args[$params[$i]->name] = $arg;
}
else
{
// Assign the argument by number
$args[$i] = $arg;
}
}
}
if (isset($step['class']))
{
// Class->method() or Class::method()
$function = $step['class'].$step['type'].$step['function'];
}
$output[] = array(
'function' => $function,
'args' => isset($args) ? $args : NULL,
'file' => isset($file) ? $file : NULL,
'line' => isset($line) ? $line : NULL,
'source' => isset($source) ? $source : NULL,
);
unset($function, $args, $file, $line, $source);
}
return $output;
}
}

View File

@@ -0,0 +1,213 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* The Encrypt library provides two-way encryption of text and binary strings
* using the [Mcrypt](http://php.net/mcrypt) extension, which consists of three
* parts: the key, the cipher, and the mode.
*
* The Key
* : A secret passphrase that is used for encoding and decoding
*
* The Cipher
* : A [cipher](http://php.net/mcrypt.ciphers) determines how the encryption
* is mathematically calculated. By default, the "rijndael-128" cipher
* is used. This is commonly known as "AES-128" and is an industry standard.
*
* The Mode
* : The [mode](http://php.net/mcrypt.constants) determines how the encrypted
* data is written in binary form. By default, the "nofb" mode is used,
* which produces short output with high entropy.
*
* @package Kohana
* @category Security
* @author Kohana Team
* @copyright (c) 2007-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_Encrypt {
/**
* @var string default instance name
*/
public static $default = 'default';
/**
* @var array Encrypt class instances
*/
public static $instances = array();
/**
* @var string OS-dependent RAND type to use
*/
protected static $_rand;
/**
* Returns a singleton instance of Encrypt. An encryption key must be
* provided in your "encrypt" configuration file.
*
* $encrypt = Encrypt::instance();
*
* @param string $name configuration group name
* @return Encrypt
*/
public static function instance($name = NULL)
{
if ($name === NULL)
{
// Use the default instance name
$name = Encrypt::$default;
}
if ( ! isset(Encrypt::$instances[$name]))
{
// Load the configuration data
$config = Kohana::$config->load('encrypt')->$name;
if ( ! isset($config['key']))
{
// No default encryption key is provided!
throw new Kohana_Exception('No encryption key is defined in the encryption configuration group: :group',
array(':group' => $name));
}
if ( ! isset($config['mode']))
{
// Add the default mode
$config['mode'] = MCRYPT_MODE_NOFB;
}
if ( ! isset($config['cipher']))
{
// Add the default cipher
$config['cipher'] = MCRYPT_RIJNDAEL_128;
}
// Create a new instance
Encrypt::$instances[$name] = new Encrypt($config['key'], $config['mode'], $config['cipher']);
}
return Encrypt::$instances[$name];
}
/**
* Creates a new mcrypt wrapper.
*
* @param string $key encryption key
* @param string $mode mcrypt mode
* @param string $cipher mcrypt cipher
*/
public function __construct($key, $mode, $cipher)
{
// Find the max length of the key, based on cipher and mode
$size = mcrypt_get_key_size($cipher, $mode);
if (isset($key[$size]))
{
// Shorten the key to the maximum size
$key = substr($key, 0, $size);
}
// Store the key, mode, and cipher
$this->_key = $key;
$this->_mode = $mode;
$this->_cipher = $cipher;
// Store the IV size
$this->_iv_size = mcrypt_get_iv_size($this->_cipher, $this->_mode);
}
/**
* Encrypts a string and returns an encrypted string that can be decoded.
*
* $data = $encrypt->encode($data);
*
* The encrypted binary data is encoded using [base64](http://php.net/base64_encode)
* to convert it to a string. This string can be stored in a database,
* displayed, and passed using most other means without corruption.
*
* @param string $data data to be encrypted
* @return string
*/
public function encode($data)
{
// Set the rand type if it has not already been set
if (Encrypt::$_rand === NULL)
{
if (Kohana::$is_windows)
{
// Windows only supports the system random number generator
Encrypt::$_rand = MCRYPT_RAND;
}
else
{
if (defined('MCRYPT_DEV_URANDOM'))
{
// Use /dev/urandom
Encrypt::$_rand = MCRYPT_DEV_URANDOM;
}
elseif (defined('MCRYPT_DEV_RANDOM'))
{
// Use /dev/random
Encrypt::$_rand = MCRYPT_DEV_RANDOM;
}
else
{
// Use the system random number generator
Encrypt::$_rand = MCRYPT_RAND;
}
}
}
if (Encrypt::$_rand === MCRYPT_RAND)
{
// The system random number generator must always be seeded each
// time it is used, or it will not produce true random results
mt_srand();
}
// Create a random initialization vector of the proper size for the current cipher
$iv = mcrypt_create_iv($this->_iv_size, Encrypt::$_rand);
// Encrypt the data using the configured options and generated iv
$data = mcrypt_encrypt($this->_cipher, $this->_key, $data, $this->_mode, $iv);
// Use base64 encoding to convert to a string
return base64_encode($iv.$data);
}
/**
* Decrypts an encoded string back to its original value.
*
* $data = $encrypt->decode($data);
*
* @param string $data encoded string to be decrypted
* @return FALSE if decryption fails
* @return string
*/
public function decode($data)
{
// Convert the data back to binary
$data = base64_decode($data, TRUE);
if ( ! $data)
{
// Invalid base64 data
return FALSE;
}
// Extract the initialization vector from the data
$iv = substr($data, 0, $this->_iv_size);
if ($this->_iv_size !== strlen($iv))
{
// The iv is not the expected size
return FALSE;
}
// Remove the iv from the data
$data = substr($data, $this->_iv_size);
// Return the decrypted data, trimming the \0 padding bytes from the end of the data
return rtrim(mcrypt_decrypt($this->_cipher, $this->_key, $data, $this->_mode, $iv), "\0");
}
} // End Encrypt

View File

@@ -0,0 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_Exception extends Kohana_Kohana_Exception {}

View File

@@ -0,0 +1,185 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* RSS and Atom feed helper.
*
* @package Kohana
* @category Helpers
* @author Kohana Team
* @copyright (c) 2007-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_Feed {
/**
* Parses a remote feed into an array.
*
* @param string $feed remote feed URL
* @param integer $limit item limit to fetch
* @return array
*/
public static function parse($feed, $limit = 0)
{
// Check if SimpleXML is installed
if ( ! function_exists('simplexml_load_file'))
throw new Kohana_Exception('SimpleXML must be installed!');
// Make limit an integer
$limit = (int) $limit;
// Disable error reporting while opening the feed
$error_level = error_reporting(0);
// Allow loading by filename or raw XML string
if (Valid::url($feed))
{
// Use native Request client to get remote contents
$response = Request::factory($feed)->execute();
$feed = $response->body();
}
elseif (is_file($feed))
{
// Get file contents
$feed = file_get_contents($feed);
}
// Load the feed
$feed = simplexml_load_string($feed, 'SimpleXMLElement', LIBXML_NOCDATA);
// Restore error reporting
error_reporting($error_level);
// Feed could not be loaded
if ($feed === FALSE)
return array();
$namespaces = $feed->getNamespaces(TRUE);
// Detect the feed type. RSS 1.0/2.0 and Atom 1.0 are supported.
$feed = isset($feed->channel) ? $feed->xpath('//item') : $feed->entry;
$i = 0;
$items = array();
foreach ($feed as $item)
{
if ($limit > 0 AND $i++ === $limit)
break;
$item_fields = (array) $item;
// get namespaced tags
foreach ($namespaces as $ns)
{
$item_fields += (array) $item->children($ns);
}
$items[] = $item_fields;
}
return $items;
}
/**
* Creates a feed from the given parameters.
*
* @param array $info feed information
* @param array $items items to add to the feed
* @param string $encoding define which encoding to use
* @return string
*/
public static function create($info, $items, $encoding = 'UTF-8')
{
$info += array('title' => 'Generated Feed', 'link' => '', 'generator' => 'KohanaPHP');
$feed = '<?xml version="1.0" encoding="'.$encoding.'"?><rss version="2.0"><channel></channel></rss>';
$feed = simplexml_load_string($feed);
foreach ($info as $name => $value)
{
if ($name === 'image')
{
// Create an image element
$image = $feed->channel->addChild('image');
if ( ! isset($value['link'], $value['url'], $value['title']))
{
throw new Kohana_Exception('Feed images require a link, url, and title');
}
if (strpos($value['link'], '://') === FALSE)
{
// Convert URIs to URLs
$value['link'] = URL::site($value['link'], 'http');
}
if (strpos($value['url'], '://') === FALSE)
{
// Convert URIs to URLs
$value['url'] = URL::site($value['url'], 'http');
}
// Create the image elements
$image->addChild('link', $value['link']);
$image->addChild('url', $value['url']);
$image->addChild('title', $value['title']);
}
else
{
if (($name === 'pubDate' OR $name === 'lastBuildDate') AND (is_int($value) OR ctype_digit($value)))
{
// Convert timestamps to RFC 822 formatted dates
$value = date('r', $value);
}
elseif (($name === 'link' OR $name === 'docs') AND strpos($value, '://') === FALSE)
{
// Convert URIs to URLs
$value = URL::site($value, 'http');
}
// Add the info to the channel
$feed->channel->addChild($name, $value);
}
}
foreach ($items as $item)
{
// Add the item to the channel
$row = $feed->channel->addChild('item');
foreach ($item as $name => $value)
{
if ($name === 'pubDate' AND (is_int($value) OR ctype_digit($value)))
{
// Convert timestamps to RFC 822 formatted dates
$value = date('r', $value);
}
elseif (($name === 'link' OR $name === 'guid') AND strpos($value, '://') === FALSE)
{
// Convert URIs to URLs
$value = URL::site($value, 'http');
}
// Add the info to the row
$row->addChild($name, $value);
}
}
if (function_exists('dom_import_simplexml'))
{
// Convert the feed object to a DOM object
$feed = dom_import_simplexml($feed)->ownerDocument;
// DOM generates more readable XML
$feed->formatOutput = TRUE;
// Export the document as XML
$feed = $feed->saveXML();
}
else
{
// Export the document as XML
$feed = $feed->asXML();
}
return $feed;
}
} // End Feed

View File

@@ -0,0 +1,241 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* File helper class.
*
* @package Kohana
* @category Helpers
* @author Kohana Team
* @copyright (c) 2007-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_File {
/**
* Attempt to get the mime type from a file. This method is horribly
* unreliable, due to PHP being horribly unreliable when it comes to
* determining the mime type of a file.
*
* $mime = File::mime($file);
*
* @param string $filename file name or path
* @return string mime type on success
* @return FALSE on failure
*/
public static function mime($filename)
{
// Get the complete path to the file
$filename = realpath($filename);
// Get the extension from the filename
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (preg_match('/^(?:jpe?g|png|[gt]if|bmp|swf)$/', $extension))
{
// Use getimagesize() to find the mime type on images
$file = getimagesize($filename);
if (isset($file['mime']))
return $file['mime'];
}
if (class_exists('finfo', FALSE))
{
if ($info = new finfo(defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME))
{
return $info->file($filename);
}
}
if (ini_get('mime_magic.magicfile') AND function_exists('mime_content_type'))
{
// The mime_content_type function is only useful with a magic file
return mime_content_type($filename);
}
if ( ! empty($extension))
{
return File::mime_by_ext($extension);
}
// Unable to find the mime-type
return FALSE;
}
/**
* Return the mime type of an extension.
*
* $mime = File::mime_by_ext('png'); // "image/png"
*
* @param string $extension php, pdf, txt, etc
* @return string mime type on success
* @return FALSE on failure
*/
public static function mime_by_ext($extension)
{
// Load all of the mime types
$mimes = Kohana::$config->load('mimes');
return isset($mimes[$extension]) ? $mimes[$extension][0] : FALSE;
}
/**
* Lookup MIME types for a file
*
* @see Kohana_File::mime_by_ext()
* @param string $extension Extension to lookup
* @return array Array of MIMEs associated with the specified extension
*/
public static function mimes_by_ext($extension)
{
// Load all of the mime types
$mimes = Kohana::$config->load('mimes');
return isset($mimes[$extension]) ? ( (array) $mimes[$extension]) : array();
}
/**
* Lookup file extensions by MIME type
*
* @param string $type File MIME type
* @return array File extensions matching MIME type
*/
public static function exts_by_mime($type)
{
static $types = array();
// Fill the static array
if (empty($types))
{
foreach (Kohana::$config->load('mimes') as $ext => $mimes)
{
foreach ($mimes as $mime)
{
if ($mime == 'application/octet-stream')
{
// octet-stream is a generic binary
continue;
}
if ( ! isset($types[$mime]))
{
$types[$mime] = array( (string) $ext);
}
elseif ( ! in_array($ext, $types[$mime]))
{
$types[$mime][] = (string) $ext;
}
}
}
}
return isset($types[$type]) ? $types[$type] : FALSE;
}
/**
* Lookup a single file extension by MIME type.
*
* @param string $type MIME type to lookup
* @return mixed First file extension matching or false
*/
public static function ext_by_mime($type)
{
return current(File::exts_by_mime($type));
}
/**
* Split a file into pieces matching a specific size. Used when you need to
* split large files into smaller pieces for easy transmission.
*
* $count = File::split($file);
*
* @param string $filename file to be split
* @param integer $piece_size size, in MB, for each piece to be
* @return integer The number of pieces that were created
*/
public static function split($filename, $piece_size = 10)
{
// Open the input file
$file = fopen($filename, 'rb');
// Change the piece size to bytes
$piece_size = floor($piece_size * 1024 * 1024);
// Write files in 8k blocks
$block_size = 1024 * 8;
// Total number of peices
$peices = 0;
while ( ! feof($file))
{
// Create another piece
$peices += 1;
// Create a new file piece
$piece = str_pad($peices, 3, '0', STR_PAD_LEFT);
$piece = fopen($filename.'.'.$piece, 'wb+');
// Number of bytes read
$read = 0;
do
{
// Transfer the data in blocks
fwrite($piece, fread($file, $block_size));
// Another block has been read
$read += $block_size;
}
while ($read < $piece_size);
// Close the piece
fclose($piece);
}
// Close the file
fclose($file);
return $peices;
}
/**
* Join a split file into a whole file. Does the reverse of [File::split].
*
* $count = File::join($file);
*
* @param string $filename split filename, without .000 extension
* @return integer The number of pieces that were joined.
*/
public static function join($filename)
{
// Open the file
$file = fopen($filename, 'wb+');
// Read files in 8k blocks
$block_size = 1024 * 8;
// Total number of peices
$pieces = 0;
while (is_file($piece = $filename.'.'.str_pad($pieces + 1, 3, '0', STR_PAD_LEFT)))
{
// Read another piece
$pieces += 1;
// Open the piece for reading
$piece = fopen($piece, 'rb');
while ( ! feof($piece))
{
// Transfer the data in blocks
fwrite($file, fread($piece, $block_size));
}
// Close the peice
fclose($piece);
}
return $pieces;
}
} // End file

View File

@@ -0,0 +1,434 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Form helper class. Unless otherwise noted, all generated HTML will be made
* safe using the [HTML::chars] method. This prevents against simple XSS
* attacks that could otherwise be trigged by inserting HTML characters into
* form fields.
*
* @package Kohana
* @category Helpers
* @author Kohana Team
* @copyright (c) 2007-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_Form {
/**
* Generates an opening HTML form tag.
*
* // Form will submit back to the current page using POST
* echo Form::open();
*
* // Form will submit to 'search' using GET
* echo Form::open('search', array('method' => 'get'));
*
* // When "file" inputs are present, you must include the "enctype"
* echo Form::open(NULL, array('enctype' => 'multipart/form-data'));
*
* @param mixed $action form action, defaults to the current request URI, or [Request] class to use
* @param array $attributes html attributes
* @return string
* @uses Request::instance
* @uses URL::site
* @uses HTML::attributes
*/
public static function open($action = NULL, array $attributes = NULL)
{
if ($action instanceof Request)
{
// Use the current URI
$action = $action->uri();
}
if ( ! $action)
{
// Allow empty form actions (submits back to the current url).
$action = '';
}
elseif (strpos($action, '://') === FALSE)
{
// Make the URI absolute
$action = URL::site($action);
}
// Add the form action to the attributes
$attributes['action'] = $action;
// Only accept the default character set
$attributes['accept-charset'] = Kohana::$charset;
if ( ! isset($attributes['method']))
{
// Use POST method
$attributes['method'] = 'post';
}
return '<form'.HTML::attributes($attributes).'>';
}
/**
* Creates the closing form tag.
*
* echo Form::close();
*
* @return string
*/
public static function close()
{
return '</form>';
}
/**
* Creates a form input. If no type is specified, a "text" type input will
* be returned.
*
* echo Form::input('username', $username);
*
* @param string $name input name
* @param string $value input value
* @param array $attributes html attributes
* @return string
* @uses HTML::attributes
*/
public static function input($name, $value = NULL, array $attributes = NULL)
{
// Set the input name
$attributes['name'] = $name;
// Set the input value
$attributes['value'] = $value;
if ( ! isset($attributes['type']))
{
// Default type is text
$attributes['type'] = 'text';
}
return '<input'.HTML::attributes($attributes).' />';
}
/**
* Creates a hidden form input.
*
* echo Form::hidden('csrf', $token);
*
* @param string $name input name
* @param string $value input value
* @param array $attributes html attributes
* @return string
* @uses Form::input
*/
public static function hidden($name, $value = NULL, array $attributes = NULL)
{
$attributes['type'] = 'hidden';
return Form::input($name, $value, $attributes);
}
/**
* Creates a password form input.
*
* echo Form::password('password');
*
* @param string $name input name
* @param string $value input value
* @param array $attributes html attributes
* @return string
* @uses Form::input
*/
public static function password($name, $value = NULL, array $attributes = NULL)
{
$attributes['type'] = 'password';
return Form::input($name, $value, $attributes);
}
/**
* Creates a file upload form input. No input value can be specified.
*
* echo Form::file('image');
*
* @param string $name input name
* @param array $attributes html attributes
* @return string
* @uses Form::input
*/
public static function file($name, array $attributes = NULL)
{
$attributes['type'] = 'file';
return Form::input($name, NULL, $attributes);
}
/**
* Creates a checkbox form input.
*
* echo Form::checkbox('remember_me', 1, (bool) $remember);
*
* @param string $name input name
* @param string $value input value
* @param boolean $checked checked status
* @param array $attributes html attributes
* @return string
* @uses Form::input
*/
public static function checkbox($name, $value = NULL, $checked = FALSE, array $attributes = NULL)
{
$attributes['type'] = 'checkbox';
if ($checked === TRUE)
{
// Make the checkbox active
$attributes[] = 'checked';
}
return Form::input($name, $value, $attributes);
}
/**
* Creates a radio form input.
*
* echo Form::radio('like_cats', 1, $cats);
* echo Form::radio('like_cats', 0, ! $cats);
*
* @param string $name input name
* @param string $value input value
* @param boolean $checked checked status
* @param array $attributes html attributes
* @return string
* @uses Form::input
*/
public static function radio($name, $value = NULL, $checked = FALSE, array $attributes = NULL)
{
$attributes['type'] = 'radio';
if ($checked === TRUE)
{
// Make the radio active
$attributes[] = 'checked';
}
return Form::input($name, $value, $attributes);
}
/**
* Creates a textarea form input.
*
* echo Form::textarea('about', $about);
*
* @param string $name textarea name
* @param string $body textarea body
* @param array $attributes html attributes
* @param boolean $double_encode encode existing HTML characters
* @return string
* @uses HTML::attributes
* @uses HTML::chars
*/
public static function textarea($name, $body = '', array $attributes = NULL, $double_encode = TRUE)
{
// Set the input name
$attributes['name'] = $name;
// Add default rows and cols attributes (required)
$attributes += array('rows' => 10, 'cols' => 50);
return '<textarea'.HTML::attributes($attributes).'>'.HTML::chars($body, $double_encode).'</textarea>';
}
/**
* Creates a select form input.
*
* echo Form::select('country', $countries, $country);
*
* [!!] Support for multiple selected options was added in v3.0.7.
*
* @param string $name input name
* @param array $options available options
* @param mixed $selected selected option string, or an array of selected options
* @param array $attributes html attributes
* @return string
* @uses HTML::attributes
*/
public static function select($name, array $options = NULL, $selected = NULL, array $attributes = NULL)
{
// Set the input name
$attributes['name'] = $name;
if (is_array($selected))
{
// This is a multi-select, god save us!
$attributes[] = 'multiple';
}
if ( ! is_array($selected))
{
if ($selected === NULL)
{
// Use an empty array
$selected = array();
}
else
{
// Convert the selected options to an array
$selected = array( (string) $selected);
}
}
if (empty($options))
{
// There are no options
$options = '';
}
else
{
foreach ($options as $value => $name)
{
if (is_array($name))
{
// Create a new optgroup
$group = array('label' => $value);
// Create a new list of options
$_options = array();
foreach ($name as $_value => $_name)
{
// Force value to be string
$_value = (string) $_value;
// Create a new attribute set for this option
$option = array('value' => $_value);
if (in_array($_value, $selected))
{
// This option is selected
$option[] = 'selected';
}
// Change the option to the HTML string
$_options[] = '<option'.HTML::attributes($option).'>'.HTML::chars($_name, FALSE).'</option>';
}
// Compile the options into a string
$_options = "\n".implode("\n", $_options)."\n";
$options[$value] = '<optgroup'.HTML::attributes($group).'>'.$_options.'</optgroup>';
}
else
{
// Force value to be string
$value = (string) $value;
// Create a new attribute set for this option
$option = array('value' => $value);
if (in_array($value, $selected))
{
// This option is selected
$option[] = 'selected';
}
// Change the option to the HTML string
$options[$value] = '<option'.HTML::attributes($option).'>'.HTML::chars($name, FALSE).'</option>';
}
}
// Compile the options into a single string
$options = "\n".implode("\n", $options)."\n";
}
return '<select'.HTML::attributes($attributes).'>'.$options.'</select>';
}
/**
* Creates a submit form input.
*
* echo Form::submit(NULL, 'Login');
*
* @param string $name input name
* @param string $value input value
* @param array $attributes html attributes
* @return string
* @uses Form::input
*/
public static function submit($name, $value, array $attributes = NULL)
{
$attributes['type'] = 'submit';
return Form::input($name, $value, $attributes);
}
/**
* Creates a image form input.
*
* echo Form::image(NULL, NULL, array('src' => 'media/img/login.png'));
*
* @param string $name input name
* @param string $value input value
* @param array $attributes html attributes
* @param boolean $index add index file to URL?
* @return string
* @uses Form::input
*/
public static function image($name, $value, array $attributes = NULL, $index = FALSE)
{
if ( ! empty($attributes['src']))
{
if (strpos($attributes['src'], '://') === FALSE)
{
// Add the base URL
$attributes['src'] = URL::base($index).$attributes['src'];
}
}
$attributes['type'] = 'image';
return Form::input($name, $value, $attributes);
}
/**
* Creates a button form input. Note that the body of a button is NOT escaped,
* to allow images and other HTML to be used.
*
* echo Form::button('save', 'Save Profile', array('type' => 'submit'));
*
* @param string $name input name
* @param string $body input value
* @param array $attributes html attributes
* @return string
* @uses HTML::attributes
*/
public static function button($name, $body, array $attributes = NULL)
{
// Set the input name
$attributes['name'] = $name;
return '<button'.HTML::attributes($attributes).'>'.$body.'</button>';
}
/**
* Creates a form label. Label text is not automatically translated.
*
* echo Form::label('username', 'Username');
*
* @param string $input target input
* @param string $text label text
* @param array $attributes html attributes
* @return string
* @uses HTML::attributes
*/
public static function label($input, $text = NULL, array $attributes = NULL)
{
if ($text === NULL)
{
// Use the input name as the text
$text = ucwords(preg_replace('/[\W_]+/', ' ', $input));
}
// Set the label target
$attributes['for'] = $input;
return '<label'.HTML::attributes($attributes).'>'.$text.'</label>';
}
} // End form

View File

@@ -0,0 +1,147 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* View fragment caching. This is primarily used to cache small parts of a view
* that rarely change. For instance, you may want to cache the footer of your
* template because it has very little dynamic content. Or you could cache a
* user profile page and delete the fragment when the user updates.
*
* For obvious reasons, fragment caching should not be applied to any
* content that contains forms.
*
* [!!] Multiple language (I18n) support was added in v3.0.4.
*
* @package Kohana
* @category Helpers
* @author Kohana Team
* @copyright (c) 2009-2012 Kohana Team
* @license http://kohanaframework.org/license
* @uses Kohana::cache
*/
class Kohana_Fragment {
/**
* @var integer default number of seconds to cache for
*/
public static $lifetime = 30;
/**
* @var boolean use multilingual fragment support?
*/
public static $i18n = FALSE;
/**
* @var array list of buffer => cache key
*/
protected static $_caches = array();
/**
* Generate the cache key name for a fragment.
*
* $key = Fragment::_cache_key('footer', TRUE);
*
* @param string $name fragment name
* @param boolean $i18n multilingual fragment support
* @return string
* @uses I18n::lang
* @since 3.0.4
*/
protected static function _cache_key($name, $i18n = NULL)
{
if ($i18n === NULL)
{
// Use the default setting
$i18n = Fragment::$i18n;
}
// Language prefix for cache key
$i18n = ($i18n === TRUE) ? I18n::lang() : '';
// Note: $i18n and $name need to be delimited to prevent naming collisions
return 'Fragment::cache('.$i18n.'+'.$name.')';
}
/**
* Load a fragment from cache and display it. Multiple fragments can
* be nested with different life times.
*
* if ( ! Fragment::load('footer')) {
* // Anything that is echo'ed here will be saved
* Fragment::save();
* }
*
* @param string $name fragment name
* @param integer $lifetime fragment cache lifetime
* @param boolean $i18n multilingual fragment support
* @return boolean
*/
public static function load($name, $lifetime = NULL, $i18n = NULL)
{
// Set the cache lifetime
$lifetime = ($lifetime === NULL) ? Fragment::$lifetime : (int) $lifetime;
// Get the cache key name
$cache_key = Fragment::_cache_key($name, $i18n);
if ($fragment = Kohana::cache($cache_key, NULL, $lifetime))
{
// Display the cached fragment now
echo $fragment;
return TRUE;
}
else
{
// Start the output buffer
ob_start();
// Store the cache key by the buffer level
Fragment::$_caches[ob_get_level()] = $cache_key;
return FALSE;
}
}
/**
* Saves the currently open fragment in the cache.
*
* Fragment::save();
*
* @return void
*/
public static function save()
{
// Get the buffer level
$level = ob_get_level();
if (isset(Fragment::$_caches[$level]))
{
// Get the cache key based on the level
$cache_key = Fragment::$_caches[$level];
// Delete the cache key, we don't need it anymore
unset(Fragment::$_caches[$level]);
// Get the output buffer and display it at the same time
$fragment = ob_get_flush();
// Cache the fragment
Kohana::cache($cache_key, $fragment);
}
}
/**
* Delete a cached fragment.
*
* Fragment::delete($key);
*
* @param string $name fragment name
* @param boolean $i18n multilingual fragment support
* @return void
*/
public static function delete($name, $i18n = NULL)
{
// Invalid the cache
Kohana::cache(Fragment::_cache_key($name, $i18n), NULL, -3600);
}
} // End Fragment

View File

@@ -0,0 +1,345 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* HTML helper class. Provides generic methods for generating various HTML
* tags and making output HTML safe.
*
* @package Kohana
* @category Helpers
* @author Kohana Team
* @copyright (c) 2007-2012 Kohana Team
* @license http://kohanaframework.org/license
*/
class Kohana_HTML {
/**
* @var array preferred order of attributes
*/
public static $attribute_order = array
(
'action',
'method',
'type',
'id',
'name',
'value',
'href',
'src',
'width',
'height',
'cols',
'rows',
'size',
'maxlength',
'rel',
'media',
'accept-charset',
'accept',
'tabindex',
'accesskey',
'alt',
'title',
'class',
'style',
'selected',
'checked',
'readonly',
'disabled',
);
/**
* @var boolean use strict XHTML mode?
*/
public static $strict = TRUE;
/**
* @var boolean automatically target external URLs to a new window?
*/
public static $windowed_urls = FALSE;
/**
* Convert special characters to HTML entities. All untrusted content
* should be passed through this method to prevent XSS injections.
*
* echo HTML::chars($username);
*
* @param string $value string to convert
* @param boolean $double_encode encode existing entities
* @return string
*/
public static function chars($value, $double_encode = TRUE)
{
return htmlspecialchars( (string) $value, ENT_QUOTES, Kohana::$charset, $double_encode);
}
/**
* Convert all applicable characters to HTML entities. All characters
* that cannot be represented in HTML with the current character set
* will be converted to entities.
*
* echo HTML::entities($username);
*
* @param string $value string to convert
* @param boolean $double_encode encode existing entities
* @return string
*/
public static function entities($value, $double_encode = TRUE)
{
return htmlentities( (string) $value, ENT_QUOTES, Kohana::$charset, $double_encode);
}
/**
* Create HTML link anchors. Note that the title is not escaped, to allow
* HTML elements within links (images, etc).
*
* echo HTML::anchor('/user/profile', 'My Profile');
*
* @param string $uri URL or URI string
* @param string $title link text
* @param array $attributes HTML anchor attributes
* @param mixed $protocol protocol to pass to URL::base()
* @param boolean $index include the index page
* @return string
* @uses URL::base
* @uses URL::site
* @uses HTML::attributes
*/
public static function anchor($uri, $title = NULL, array $attributes = NULL, $protocol = NULL, $index = TRUE)
{
if ($title === NULL)
{
// Use the URI as the title
$title = $uri;
}
if ($uri === '')
{
// Only use the base URL
$uri = URL::base($protocol, $index);
}
else
{
if (strpos($uri, '://') !== FALSE)
{
if (HTML::$windowed_urls === TRUE AND empty($attributes['target']))
{
// Make the link open in a new window
$attributes['target'] = '_blank';
}
}
elseif ($uri[0] !== '#')
{
// Make the URI absolute for non-id anchors
$uri = URL::site($uri, $protocol, $index);
}
}
// Add the sanitized link to the attributes
$attributes['href'] = $uri;
return '<a'.HTML::attributes($attributes).'>'.$title.'</a>';
}
/**
* Creates an HTML anchor to a file. Note that the title is not escaped,
* to allow HTML elements within links (images, etc).
*
* echo HTML::file_anchor('media/doc/user_guide.pdf', 'User Guide');
*
* @param string $file name of file to link to
* @param string $title link text
* @param array $attributes HTML anchor attributes
* @param mixed $protocol protocol to pass to URL::base()
* @param boolean $index include the index page
* @return string
* @uses URL::base
* @uses HTML::attributes
*/
public static function file_anchor($file, $title = NULL, array $attributes = NULL, $protocol = NULL, $index = FALSE)
{
if ($title === NULL)
{
// Use the file name as the title
$title = basename($file);
}
// Add the file link to the attributes
$attributes['href'] = URL::site($file, $protocol, $index);
return '<a'.HTML::attributes($attributes).'>'.$title.'</a>';
}
/**
* Creates an email (mailto:) anchor. Note that the title is not escaped,
* to allow HTML elements within links (images, etc).
*
* echo HTML::mailto($address);
*
* @param string $email email address to send to
* @param string $title link text
* @param array $attributes HTML anchor attributes
* @return string
* @uses HTML::attributes
*/
public static function mailto($email, $title = NULL, array $attributes = NULL)
{
if ($title === NULL)
{
// Use the email address as the title
$title = $email;
}
return '<a href="&#109;&#097;&#105;&#108;&#116;&#111;&#058;'.$email.'"'.HTML::attributes($attributes).'>'.$title.'</a>';
}
/**
* Creates a style sheet link element.
*
* echo HTML::style('media/css/screen.css');
*
* @param string $file file name
* @param array $attributes default attributes
* @param mixed $protocol protocol to pass to URL::base()
* @param boolean $index include the index page
* @return string
* @uses URL::base
* @uses HTML::attributes
*/
public static function style($file, array $attributes = NULL, $protocol = NULL, $index = FALSE)
{
if (strpos($file, '://') === FALSE)
{
// Add the base URL
$file = URL::site($file, $protocol, $index);
}
// Set the stylesheet link
$attributes['href'] = $file;
// Set the stylesheet rel
$attributes['rel'] = empty($attributes['rel']) ? 'stylesheet' : $attributes['rel'];
// Set the stylesheet type
$attributes['type'] = 'text/css';
return '<link'.HTML::attributes($attributes).' />';
}
/**
* Creates a script link.
*
* echo HTML::script('media/js/jquery.min.js');
*
* @param string $file file name
* @param array $attributes default attributes
* @param mixed $protocol protocol to pass to URL::base()
* @param boolean $index include the index page
* @return string
* @uses URL::base
* @uses HTML::attributes
*/
public static function script($file, array $attributes = NULL, $protocol = NULL, $index = FALSE)
{
if (strpos($file, '://') === FALSE)
{
// Add the base URL
$file = URL::site($file, $protocol, $index);
}
// Set the script link
$attributes['src'] = $file;
// Set the script type
$attributes['type'] = 'text/javascript';
return '<script'.HTML::attributes($attributes).'></script>';
}
/**
* Creates a image link.
*
* echo HTML::image('media/img/logo.png', array('alt' => 'My Company'));
*
* @param string $file file name
* @param array $attributes default attributes
* @param mixed $protocol protocol to pass to URL::base()
* @param boolean $index include the index page
* @return string
* @uses URL::base
* @uses HTML::attributes
*/
public static function image($file, array $attributes = NULL, $protocol = NULL, $index = FALSE)
{
if (strpos($file, '://') === FALSE)
{
// Add the base URL
$file = URL::site($file, $protocol, $index);
}
// Add the image link
$attributes['src'] = $file;
return '<img'.HTML::attributes($attributes).' />';
}
/**
* Compiles an array of HTML attributes into an attribute string.
* Attributes will be sorted using HTML::$attribute_order for consistency.
*
* echo '<div'.HTML::attributes($attrs).'>'.$content.'</div>';
*
* @param array $attributes attribute list
* @return string
*/
public static function attributes(array $attributes = NULL)
{
if (empty($attributes))
return '';
$sorted = array();
foreach (HTML::$attribute_order as $key)
{
if (isset($attributes[$key]))
{
// Add the attribute to the sorted list
$sorted[$key] = $attributes[$key];
}
}
// Combine the sorted attributes
$attributes = $sorted + $attributes;
$compiled = '';
foreach ($attributes as $key => $value)
{
if ($value === NULL)
{
// Skip attributes that have NULL values
continue;
}
if (is_int($key))
{
// Assume non-associative keys are mirrored attributes
$key = $value;
if ( ! HTML::$strict)
{
// Just use a key
$value = FALSE;
}
}
// Add the attribute key
$compiled .= ' '.$key;
if ($value OR HTML::$strict)
{
// Add the attribute value
$compiled .= '="'.HTML::chars($value).'"';
}
}
return $compiled;
}
} // End html

View File

@@ -0,0 +1,217 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
* Contains the most low-level helpers methods in Kohana:
*
* - Environment initialization
* - Locating files within the cascading filesystem
* - Auto-loading and transparent extension of classes
* - Variable and path debugging
*
* @package Kohana
* @category HTTP
* @author Kohana Team
* @since 3.1.0
* @copyright (c) 2008-2012 Kohana Team
* @license http://kohanaphp.com/license
*/
abstract class Kohana_HTTP {
/**
* @var The default protocol to use if it cannot be detected
*/
public static $protocol = 'HTTP/1.1';
/**
* Issues a HTTP redirect.
*
* @param string $uri URI to redirect to
* @param int $code HTTP Status code to use for the redirect
* @throws HTTP_Exception
*/
public static function redirect($uri = '', $code = 302)
{
$e = HTTP_Exception::factory($code);
if ( ! $e instanceof HTTP_Exception_Redirect)
throw new Kohana_Exception('Invalid redirect code \':code\'', array(
':code' => $code
));
throw $e->location($uri);
}
/**
* Checks the browser cache to see the response needs to be returned,
* execution will halt and a 304 Not Modified will be sent if the
* browser cache is up to date.
*
* @param Request $request Request
* @param Response $response Response
* @param string $etag Resource ETag
* @throws HTTP_Exception_304
* @return Response
*/
public static function check_cache(Request $request, Response $response, $etag = NULL)
{
// Generate an etag if necessary
if ($etag == NULL)
{
$etag = $response->generate_etag();
}
// Set the ETag header
$response->headers('etag', $etag);
// Add the Cache-Control header if it is not already set
// This allows etags to be used with max-age, etc
if ($response->headers('cache-control'))
{
$response->headers('cache-control', $response->headers('cache-control').', must-revalidate');
}
else
{
$response->headers('cache-control', 'must-revalidate');
}
// Check if we have a matching etag
if ($request->headers('if-none-match') AND (string) $request->headers('if-none-match') === $etag)
{
// No need to send data again
throw HTTP_Exception::factory(304)->headers('etag', $etag);
}
return $response;
}
/**
* Parses a HTTP header string into an associative array
*
* @param string $header_string Header string to parse
* @return HTTP_Header
*/
public static function parse_header_string($header_string)
{
// If the PECL HTTP extension is loaded
if (extension_loaded('http'))
{
// Use the fast method to parse header string
return new HTTP_Header(http_parse_headers($header_string));
}
// Otherwise we use the slower PHP parsing
$headers = array();
// Match all HTTP headers
if (preg_match_all('/(\w[^\s:]*):[ ]*([^\r\n]*(?:\r\n[ \t][^\r\n]*)*)/', $header_string, $matches))
{
// Parse each matched header
foreach ($matches[0] as $key => $value)
{
// If the header has not already been set
if ( ! isset($headers[$matches[1][$key]]))
{
// Apply the header directly
$headers[$matches[1][$key]] = $matches[2][$key];
}
// Otherwise there is an existing entry
else
{
// If the entry is an array
if (is_array($headers[$matches[1][$key]]))
{
// Apply the new entry to the array
$headers[$matches[1][$key]][] = $matches[2][$key];
}
// Otherwise create a new array with the entries
else
{
$headers[$matches[1][$key]] = array(
$headers[$matches[1][$key]],
$matches[2][$key],
);
}
}
}
}
// Return the headers
return new HTTP_Header($headers);
}
/**
* Parses the the HTTP request headers and returns an array containing
* key value pairs. This method is slow, but provides an accurate
* representation of the HTTP request.
*
* // Get http headers into the request
* $request->headers = HTTP::request_headers();
*
* @return HTTP_Header
*/
public static function request_headers()
{
// If running on apache server
if (function_exists('apache_request_headers'))
{
// Return the much faster method
return new HTTP_Header(apache_request_headers());
}
// If the PECL HTTP tools are installed
elseif (extension_loaded('http'))
{
// Return the much faster method
return new HTTP_Header(http_get_request_headers());
}
// Setup the output
$headers = array();
// Parse the content type
if ( ! empty($_SERVER['CONTENT_TYPE']))
{
$headers['content-type'] = $_SERVER['CONTENT_TYPE'];
}
// Parse the content length
if ( ! empty($_SERVER['CONTENT_LENGTH']))
{
$headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
}
foreach ($_SERVER as $key => $value)
{
// If there is no HTTP header here, skip
if (strpos($key, 'HTTP_') !== 0)
{
continue;
}
// This is a dirty hack to ensure HTTP_X_FOO_BAR becomes x-foo-bar
$headers[str_replace(array('HTTP_', '_'), array('', '-'), $key)] = $value;
}
return new HTTP_Header($headers);
}
/**
* Processes an array of key value pairs and encodes
* the values to meet RFC 3986
*
* @param array $params Params
* @return string
*/
public static function www_form_urlencode(array $params = array())
{
if ( ! $params)
return;
$encoded = array();
foreach ($params as $key => $value)
{
$encoded[] = $key.'='.rawurlencode($value);
}
return implode('&', $encoded);
}
} // End Kohana_HTTP

View File

@@ -0,0 +1,72 @@
<?php defined('SYSPATH') OR die('No direct script access.');
abstract class Kohana_HTTP_Exception extends Kohana_Exception {
/**
* Creates an HTTP_Exception of the specified type.
*
* @param integer $code the http status code
* @param string $message status message, custom content to display with error
* @param array $variables translation variables
* @return HTTP_Exception
*/
public static function factory($code, $message = NULL, array $variables = NULL, Exception $previous = NULL)
{
$class = 'HTTP_Exception_'.$code;
return new $class($message, $variables, $previous);
}
/**
* @var int http status code
*/
protected $_code = 0;
/**
* @var Request Request instance that triggered this exception.
*/
protected $_request;
/**
* Creates a new translated exception.
*
* throw new Kohana_Exception('Something went terrible wrong, :user',
* array(':user' => $user));
*
* @param string $message status message, custom content to display with error
* @param array $variables translation variables
* @return void
*/
public function __construct($message = NULL, array $variables = NULL, Exception $previous = NULL)
{
parent::__construct($message, $variables, $this->_code, $previous);
}
/**
* Store the Request that triggered this exception.
*
* @param Request $request Request object that triggered this exception.
* @return Response
*/
public function request(Request $request = NULL)
{
if ($request === NULL)
return $this->_request;
$this->_request = $request;
return $this;
}
/**
* Generate a Response for the current Exception
*
* @uses Kohana_Exception::response()
* @return Response
*/
public function get_response()
{
return Kohana_Exception::response($this);
}
} // End Kohana_HTTP_Exception

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_300 extends HTTP_Exception_Redirect {
/**
* @var integer HTTP 300 Multiple Choices
*/
protected $_code = 300;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_301 extends HTTP_Exception_Redirect {
/**
* @var integer HTTP 301 Moved Permanently
*/
protected $_code = 301;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_302 extends HTTP_Exception_Redirect {
/**
* @var integer HTTP 302 Found
*/
protected $_code = 302;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_303 extends HTTP_Exception_Redirect {
/**
* @var integer HTTP 303 See Other
*/
protected $_code = 303;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_304 extends HTTP_Exception_Expected {
/**
* @var integer HTTP 304 Not Modified
*/
protected $_code = 304;
}

View File

@@ -0,0 +1,41 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_305 extends HTTP_Exception_Expected {
/**
* @var integer HTTP 305 Use Proxy
*/
protected $_code = 305;
/**
* Specifies the proxy to replay this request via
*
* @param string $location URI of the proxy
*/
public function location($uri = NULL)
{
if ($uri === NULL)
return $this->headers('Location');
$this->headers('Location', $uri);
return $this;
}
/**
* Validate this exception contains everything needed to continue.
*
* @throws Kohana_Exception
* @return bool
*/
public function check()
{
if ($location = $this->headers('location') === NULL)
throw new Kohana_Exception('A \'location\' must be specified for a redirect');
if (strpos($location, '://') === FALSE)
throw new Kohana_Exception('An absolute URI to the proxy server must be specified');
return TRUE;
}
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_307 extends HTTP_Exception_Redirect {
/**
* @var integer HTTP 307 Temporary Redirect
*/
protected $_code = 307;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_400 extends HTTP_Exception {
/**
* @var integer HTTP 400 Bad Request
*/
protected $_code = 400;
}

View File

@@ -0,0 +1,38 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_401 extends HTTP_Exception_Expected {
/**
* @var integer HTTP 401 Unauthorized
*/
protected $_code = 401;
/**
* Specifies the WWW-Authenticate challenge.
*
* @param string $challenge WWW-Authenticate challenge (eg `Basic realm="Control Panel"`)
*/
public function authenticate($challenge = NULL)
{
if ($challenge === NULL)
return $this->headers('www-authenticate');
$this->headers('www-authenticate', $challenge);
return $this;
}
/**
* Validate this exception contains everything needed to continue.
*
* @throws Kohana_Exception
* @return bool
*/
public function check()
{
if ($this->headers('www-authenticate') === NULL)
throw new Kohana_Exception('A \'www-authenticate\' header must be specified for a HTTP 401 Unauthorized');
return TRUE;
}
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_402 extends HTTP_Exception {
/**
* @var integer HTTP 402 Payment Required
*/
protected $_code = 402;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_403 extends HTTP_Exception {
/**
* @var integer HTTP 403 Forbidden
*/
protected $_code = 403;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_404 extends HTTP_Exception {
/**
* @var integer HTTP 404 Not Found
*/
protected $_code = 404;
}

View File

@@ -0,0 +1,41 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_405 extends HTTP_Exception_Expected {
/**
* @var integer HTTP 405 Method Not Allowed
*/
protected $_code = 405;
/**
* Specifies the list of allowed HTTP methods
*
* @param array $methods List of allowed methods
*/
public function allowed($methods)
{
if (is_array($methods))
{
$methods = implode(',', $methods);
}
$this->headers('allow', $methods);
return $this;
}
/**
* Validate this exception contains everything needed to continue.
*
* @throws Kohana_Exception
* @return bool
*/
public function check()
{
if ($location = $this->headers('allow') === NULL)
throw new Kohana_Exception('A list of allowed methods must be specified');
return TRUE;
}
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_406 extends HTTP_Exception {
/**
* @var integer HTTP 406 Not Acceptable
*/
protected $_code = 406;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_407 extends HTTP_Exception {
/**
* @var integer HTTP 407 Proxy Authentication Required
*/
protected $_code = 407;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_408 extends HTTP_Exception {
/**
* @var integer HTTP 408 Request Timeout
*/
protected $_code = 408;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_409 extends HTTP_Exception {
/**
* @var integer HTTP 409 Conflict
*/
protected $_code = 409;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_410 extends HTTP_Exception {
/**
* @var integer HTTP 410 Gone
*/
protected $_code = 410;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_411 extends HTTP_Exception {
/**
* @var integer HTTP 411 Length Required
*/
protected $_code = 411;
}

View File

@@ -0,0 +1,10 @@
<?php defined('SYSPATH') OR die('No direct script access.');
class Kohana_HTTP_Exception_412 extends HTTP_Exception {
/**
* @var integer HTTP 412 Precondition Failed
*/
protected $_code = 412;
}

Some files were not shown because too many files have changed in this diff Show More