Clean sources, remove useless FuelPHP Core, Packages and vendor files

pull/9/head
Chewbaka69 5 years ago
parent 0f93ac18ca
commit dc2bcaa364

3
.gitignore vendored

@ -2,7 +2,9 @@
# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
# /composer.lock
/fuel/core
/fuel/vendor
/fuel/packages
# the fuelphp document
/docs/
@ -24,3 +26,4 @@
/fuel/app/config/lock.php
/.idea
composer.lock

@ -1,15 +0,0 @@
*~
*.bak
Thumbs.db
desktop.ini
.DS_Store
.buildpath
.project
.settings
fuel/app/logs/*/*/*
fuel/app/cache/*/*
nbproject/
.idea
*.tmproj
*.sublime-project
*.sublime-workspace

@ -1,3 +0,0 @@
Please read the project contibuting guidelines before creating an issue of sending in a pull request:
https://github.com/fuel/fuel/wiki/Contributing

@ -1,572 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
// load PHP 5.6+ specific code
if (PHP_VERSION_ID >= 50600)
{
include "base56.php";
}
/**
* Loads in a core class and optionally an app class override if it exists.
*
* @param string $path
* @param string $folder
* @return void
*/
if ( ! function_exists('import'))
{
function import($path, $folder = 'classes')
{
$path = str_replace('/', DIRECTORY_SEPARATOR, $path);
// load it ffrom the core if it exists
if (is_file(COREPATH.$folder.DIRECTORY_SEPARATOR.$path.'.php'))
{
require_once COREPATH.$folder.DIRECTORY_SEPARATOR.$path.'.php';
}
// if the app has an override (or a non-core file), load that too
if (is_file(APPPATH.$folder.DIRECTORY_SEPARATOR.$path.'.php'))
{
require_once APPPATH.$folder.DIRECTORY_SEPARATOR.$path.'.php';
}
}
}
/**
* Shortcut for writing to the Log
*
* @param int|string the error level
* @param string the error message
* @param string information about the method
* @return bool
*/
if ( ! function_exists('logger'))
{
function logger($level, $msg, $method = null)
{
static $labels = array(
100 => 'DEBUG',
200 => 'INFO',
250 => 'NOTICE',
300 => 'WARNING',
400 => 'ERROR',
500 => 'CRITICAL',
550 => 'ALERT',
600 => 'EMERGENCY',
700 => 'ALL',
);
// make sure $level has the correct value
if ((is_int($level) and ! isset($labels[$level])) or (is_string($level) and ! array_search(strtoupper($level), $labels)))
{
throw new \FuelException('Invalid level "'.$level.'" passed to logger()');
}
if(is_string($level)) $level = array_search(strtoupper($level), $labels);
// get the levels defined to be logged
$loglabels = \Config::get('log_threshold');
// bail out if we don't need logging at all
if ($loglabels == \Fuel::L_NONE)
{
return false;
}
// if profiling is active log the message to the profile
if (\Config::get('profiling'))
{
\Console::log($method.' - '.$msg);
}
// if it's not an array, assume it's an "up to" level
if ( ! is_array($loglabels))
{
$a = array();
foreach ($labels as $l => $label)
{
$l >= $loglabels and $a[] = $l;
}
$loglabels = $a;
}
// do we need to log the message with this level?
if ( ! in_array($level, $loglabels))
{
return false;
}
return \Log::instance()->log($level, (empty($method) ? '' : $method.' - ').$msg);
}
}
/**
* Takes an array of attributes and turns it into a string for an html tag
*
* @param array $attr
* @return string
*/
if ( ! function_exists('array_to_attr'))
{
function array_to_attr($attr)
{
$attr_str = '';
foreach ((array) $attr as $property => $value)
{
// Ignore null/false
if ($value === null or $value === false)
{
continue;
}
// If the key is numeric then it must be something like selected="selected"
if (is_numeric($property))
{
$property = $value;
}
$attr_str .= $property.'="'.str_replace('"', '&quot;', $value).'" ';
}
// We strip off the last space for return
return trim($attr_str);
}
}
/**
* Create a XHTML tag
*
* @param string The tag name
* @param array|string The tag attributes
* @param string|bool The content to place in the tag, or false for no closing tag
* @return string
*/
if ( ! function_exists('html_tag'))
{
function html_tag($tag, $attr = array(), $content = false)
{
// list of void elements (tags that can not have content)
static $void_elements = array(
// html4
"area","base","br","col","hr","img","input","link","meta","param",
// html5
"command","embed","keygen","source","track","wbr",
// html5.1
"menuitem",
);
// construct the HTML
$html = '<'.$tag;
$html .= ( ! empty($attr)) ? ' '.(is_array($attr) ? array_to_attr($attr) : $attr) : '';
// a void element?
if (in_array(strtolower($tag), $void_elements))
{
// these can not have content
$html .= ' />';
}
else
{
// add the content and close the tag
$html .= '>'.$content.'</'.$tag.'>';
}
return $html;
}
}
/**
* A case-insensitive version of in_array.
*
* @param mixed $needle
* @param array $haystack
* @return bool
*/
if ( ! function_exists('in_arrayi'))
{
function in_arrayi($needle, $haystack)
{
return in_array(strtolower($needle), array_map('strtolower', $haystack));
}
}
/**
* Gets all the public vars for an object. Use this if you need to get all the
* public vars of $this inside an object.
*
* @return array
*/
if ( ! function_exists('get_object_public_vars'))
{
function get_object_public_vars($obj)
{
return get_object_vars($obj);
}
}
/**
* Renders a view and returns the output.
*
* @param string The view name/path
* @param array The data for the view
* @param bool Auto filter override
* @return string
*/
if ( ! function_exists('render'))
{
function render($view, $data = null, $auto_filter = null)
{
return \View::forge($view, $data, $auto_filter)->render();
}
}
/**
* A wrapper function for Lang::get()
*
* @param mixed The string to translate
* @param array The parameters
* @return string
*/
if ( ! function_exists('__'))
{
function __($string, $params = array(), $default = null, $language = null)
{
return \Lang::get($string, $params, $default, $language);
}
}
/**
* Encodes the given string. This is just a wrapper function for Security::htmlentities()
*
* @param mixed The string to encode
* @return string
*/
if ( ! function_exists('e'))
{
function e($string)
{
return \Security::htmlentities($string);
}
}
/**
* Takes a classname and returns the actual classname for an alias or just the classname
* if it's a normal class.
*
* @param string classname to check
* @return string real classname
*/
if ( ! function_exists('get_real_class'))
{
function get_real_class($class)
{
static $classes = array();
if ( ! array_key_exists($class, $classes))
{
$reflect = new ReflectionClass($class);
$classes[$class] = $reflect->getName();
}
return $classes[$class];
}
}
/**
* Takes an associative array in the layout of parse_url, and constructs a URL from it
*
* see http://www.php.net/manual/en/function.http-build-url.php#96335
*
* @param mixed (Part(s) of) an URL in form of a string or associative array like parse_url() returns
* @param mixed Same as the first argument
* @param int A bitmask of binary or'ed HTTP_URL constants (Optional)HTTP_URL_REPLACE is the default
* @param array If set, it will be filled with the parts of the composed url like parse_url() would return
*
* @return string constructed URL
*/
if (!function_exists('http_build_url'))
{
define('HTTP_URL_REPLACE', 1); // Replace every part of the first URL when there's one of the second URL
define('HTTP_URL_JOIN_PATH', 2); // Join relative paths
define('HTTP_URL_JOIN_QUERY', 4); // Join query strings
define('HTTP_URL_STRIP_USER', 8); // Strip any user authentication information
define('HTTP_URL_STRIP_PASS', 16); // Strip any password authentication information
define('HTTP_URL_STRIP_AUTH', 32); // Strip any authentication information
define('HTTP_URL_STRIP_PORT', 64); // Strip explicit port numbers
define('HTTP_URL_STRIP_PATH', 128); // Strip complete path
define('HTTP_URL_STRIP_QUERY', 256); // Strip query string
define('HTTP_URL_STRIP_FRAGMENT', 512); // Strip any fragments (#identifier)
define('HTTP_URL_STRIP_ALL', 1024); // Strip anything but scheme and host
function http_build_url($url, $parts = array(), $flags = HTTP_URL_REPLACE, &$new_url = false)
{
$keys = array('user','pass','port','path','query','fragment');
// HTTP_URL_STRIP_ALL becomes all the HTTP_URL_STRIP_Xs
if ($flags & HTTP_URL_STRIP_ALL)
{
$flags |= HTTP_URL_STRIP_USER;
$flags |= HTTP_URL_STRIP_PASS;
$flags |= HTTP_URL_STRIP_PORT;
$flags |= HTTP_URL_STRIP_PATH;
$flags |= HTTP_URL_STRIP_QUERY;
$flags |= HTTP_URL_STRIP_FRAGMENT;
}
// HTTP_URL_STRIP_AUTH becomes HTTP_URL_STRIP_USER and HTTP_URL_STRIP_PASS
elseif ($flags & HTTP_URL_STRIP_AUTH)
{
$flags |= HTTP_URL_STRIP_USER;
$flags |= HTTP_URL_STRIP_PASS;
}
// parse the original URL
$parse_url = is_array($url) ? $url : parse_url($url);
// make sure we always have a scheme, host and path
empty($parse_url['scheme']) and $parse_url['scheme'] = 'http';
empty($parse_url['host']) and $parse_url['host'] = \Input::server('http_host');
isset($parse_url['path']) or $parse_url['path'] = '';
// make the path absolute if needed
if ( ! empty($parse_url['path']) and substr($parse_url['path'], 0, 1) != '/')
{
$parse_url['path'] = '/'.$parse_url['path'];
}
// scheme and host are always replaced
isset($parts['scheme']) and $parse_url['scheme'] = $parts['scheme'];
isset($parts['host']) and $parse_url['host'] = $parts['host'];
// replace the original URL with it's new parts (if applicable)
if ($flags & HTTP_URL_REPLACE)
{
foreach ($keys as $key)
{
if (isset($parts[$key]))
$parse_url[$key] = $parts[$key];
}
}
else
{
// join the original URL path with the new path
if (isset($parts['path']) && ($flags & HTTP_URL_JOIN_PATH))
{
if (isset($parse_url['path']))
$parse_url['path'] = rtrim(str_replace(basename($parse_url['path']), '', $parse_url['path']), '/') . '/' . ltrim($parts['path'], '/');
else
$parse_url['path'] = $parts['path'];
}
// join the original query string with the new query string
if (isset($parts['query']) && ($flags & HTTP_URL_JOIN_QUERY))
{
if (isset($parse_url['query']))
$parse_url['query'] .= '&' . $parts['query'];
else
$parse_url['query'] = $parts['query'];
}
}
// strips all the applicable sections of the URL
// note: scheme and host are never stripped
foreach ($keys as $key)
{
if ($flags & (int) constant('HTTP_URL_STRIP_' . strtoupper($key)))
unset($parse_url[$key]);
}
$new_url = $parse_url;
return
((isset($parse_url['scheme'])) ? $parse_url['scheme'] . '://' : '')
.((isset($parse_url['user'])) ? $parse_url['user'] . ((isset($parse_url['pass'])) ? ':' . $parse_url['pass'] : '') .'@' : '')
.((isset($parse_url['host'])) ? $parse_url['host'] : '')
.((isset($parse_url['port'])) ? ':' . $parse_url['port'] : '')
.((isset($parse_url['path'])) ? $parse_url['path'] : '')
.((isset($parse_url['query'])) ? '?' . $parse_url['query'] : '')
.((isset($parse_url['fragment'])) ? '#' . $parse_url['fragment'] : '')
;
}
}
/**
* Find the common "root" path of two given paths or FQFN's
*
* @param array array with the paths to compare
*
* @return string the determined common path section
*/
if ( ! function_exists('get_common_path'))
{
function get_common_path($paths)
{
$lastOffset = 1;
$common = '/';
while (($index = strpos($paths[0], '/', $lastOffset)) !== false)
{
$dirLen = $index - $lastOffset + 1; // include /
$dir = substr($paths[0], $lastOffset, $dirLen);
foreach ($paths as $path)
{
if (substr($path, $lastOffset, $dirLen) != $dir)
{
return $common;
}
}
$common .= $dir;
$lastOffset = $index + 1;
}
return $common;
}
}
/**
* Faster equivalent of call_user_func_array
*/
if ( ! function_exists('call_fuel_func_array'))
{
function call_fuel_func_array($callback, array $args)
{
// deal with "class::method" syntax
if (is_string($callback) and strpos($callback, '::') !== false)
{
$callback = explode('::', $callback);
}
// if an array is passed, extract the object and method to call
if (is_array($callback) and isset($callback[1]) and is_object($callback[0]))
{
// make sure our arguments array is indexed
if ($count = count($args))
{
$args = array_values($args);
}
list($instance, $method) = $callback;
// calling the method directly is faster then call_user_func_array() !
switch ($count)
{
case 0:
return $instance->$method();
case 1:
return $instance->$method($args[0]);
case 2:
return $instance->$method($args[0], $args[1]);
case 3:
return $instance->$method($args[0], $args[1], $args[2]);
case 4:
return $instance->$method($args[0], $args[1], $args[2], $args[3]);
}
}
elseif (is_array($callback) and isset($callback[1]) and is_string($callback[0]))
{
list($class, $method) = $callback;
$class = '\\'.ltrim($class, '\\');
// calling the method directly is faster then call_user_func_array() !
switch (count($args))
{
case 0:
return $class::$method();
case 1:
return $class::$method($args[0]);
case 2:
return $class::$method($args[0], $args[1]);
case 3:
return $class::$method($args[0], $args[1], $args[2]);
case 4:
return $class::$method($args[0], $args[1], $args[2], $args[3]);
}
}
// if it's a string, it's a native function or a static method call
elseif (is_string($callback) or $callback instanceOf \Closure)
{
is_string($callback) and $callback = ltrim($callback, '\\');
// calling the method directly is faster then call_user_func_array() !
switch (count($args))
{
case 0:
return $callback();
case 1:
return $callback($args[0]);
case 2:
return $callback($args[0], $args[1]);
case 3:
return $callback($args[0], $args[1], $args[2]);
case 4:
return $callback($args[0], $args[1], $args[2], $args[3]);
}
}
// fallback, handle the old way
return call_user_func_array($callback, $args);
}
}
/**
* hash_pbkdf2() implementation for PHP < 5.5.0
*/
if ( ! function_exists('hash_pbkdf2'))
{
/* PBKDF2 Implementation (described in RFC 2898)
*
* @param string a hash algorithm to use
* @param string p password
* @param string s salt
* @param int c iteration count (use 1000 or higher)
* @param int kl derived key length
* @param bool r when set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits.
*
* @return string derived key
*/
function hash_pbkdf2($a, $p, $s, $c, $kl = 0, $r = false)
{
$hl = strlen(hash($a, null, true)); # Hash length
$kb = ceil($kl / $hl); # Key blocks to compute
$dk = ''; # Derived key
# Create key
for ( $block = 1; $block <= $kb; $block ++ )
{
# Initial hash for this block
$ib = $b = hash_hmac($a, $s . pack('N', $block), $p, true);
# Perform block iterations
for ( $i = 1; $i < $c; $i ++ )
{
# XOR each iterate
$ib ^= ($b = hash_hmac($a, $b, $p, true));
}
$dk .= $ib; # Append iterated block
}
# Return derived key of correct length
return substr($r ? $dk : bin2hex($dk), 0, $kl);
}
}

@ -1,57 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
/**
* Faster equivalent of call_user_func_array using variadics
*/
if ( ! function_exists('call_fuel_func_array'))
{
function call_fuel_func_array($callback, array $args)
{
// deal with "class::method" syntax
if (is_string($callback) and strpos($callback, '::') !== false)
{
$callback = explode('::', $callback);
}
// dynamic call on an object?
if (is_array($callback) and isset($callback[1]) and is_object($callback[0]))
{
// make sure our arguments array is indexed
if ($count = count($args))
{
$args = array_values($args);
}
list($instance, $method) = $callback;
return $instance->{$method}(...$args);
}
// static call?
elseif (is_array($callback) and isset($callback[1]) and is_string($callback[0]))
{
list($class, $method) = $callback;
$class = '\\'.ltrim($class, '\\');
return $class::{$method}(...$args);
}
// if it's a string, it's a native function or a static method call
elseif (is_string($callback) or $callback instanceOf \Closure)
{
is_string($callback) and $callback = ltrim($callback, '\\');
}
return $callback(...$args);
}
}

@ -1,347 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
define('DS', DIRECTORY_SEPARATOR);
define('CRLF', chr(13).chr(10));
/**
* Do we have access to mbstring?
* We need this in order to work with UTF-8 strings
*/
define('MBSTRING', function_exists('mb_get_info'));
// load the base functions
require COREPATH.'base.php';
// define the core classes to the autoloader
setup_autoloader();
// setup the composer autoloader
get_composer();
/**
* Register all the error/shutdown handlers
*/
register_shutdown_function(function ()
{
// reset the autoloader
\Autoloader::_reset();
// if we have sessions loaded, and native session emulation active
if (\Config::get('session.native_emulation', false))
{
// close the name session
session_id() and session_write_close();
}
// make sure we're having an output filter so we can display errors
// occuring before the main config file is loaded
\Config::get('security.output_filter', null) or \Config::set('security.output_filter', 'Security::htmlentities');
try
{
// fire any app shutdown events
\Event::instance()->trigger('shutdown', '', 'none', true);
// fire any framework shutdown events
\Event::instance()->trigger('fuel-shutdown', '', 'none', true);
}
catch (\Exception $e)
{
if (\Fuel::$is_cli)
{
\Cli::error("Error: ".$e->getMessage()." in ".$e->getFile()." on ".$e->getLine());
\Cli::beep();
exit(1);
}
else
{
logger(\Fuel::L_ERROR, 'shutdown - ' . $e->getMessage()." in ".$e->getFile()." on ".$e->getLine());
}
}
return \Errorhandler::shutdown_handler();
});
set_exception_handler(function ($e)
{
// reset the autoloader
\Autoloader::_reset();
// deal with PHP bugs #42098/#54054
if ( ! class_exists('Errorhandler'))
{
include COREPATH.'classes/errorhandler.php';
class_alias('\Fuel\Core\Errorhandler', 'Errorhandler');
class_alias('\Fuel\Core\PhpErrorException', 'PhpErrorException');
}
return \Errorhandler::exception_handler($e);
});
set_error_handler(function ($severity, $message, $filepath, $line)
{
// reset the autoloader
\Autoloader::_reset();
// deal with PHP bugs #42098/#54054
if ( ! class_exists('Errorhandler'))
{
include COREPATH.'classes/errorhandler.php';
class_alias('\Fuel\Core\Errorhandler', 'Errorhandler');
class_alias('\Fuel\Core\PhpErrorException', 'PhpErrorException');
}
return \Errorhandler::error_handler($severity, $message, $filepath, $line);
});
function setup_autoloader()
{
\Autoloader::add_namespace('Fuel\\Core', COREPATH.'classes/');
\Autoloader::add_classes(array(
'Fuel\\Core\\Agent' => COREPATH.'classes/agent.php',
'Fuel\\Core\\Arr' => COREPATH.'classes/arr.php',
'Fuel\\Core\\Asset' => COREPATH.'classes/asset.php',
'Fuel\\Core\\Asset_Instance' => COREPATH.'classes/asset/instance.php',
'Fuel\\Core\\Cache' => COREPATH.'classes/cache.php',
'Fuel\\Core\\CacheNotFoundException' => COREPATH.'classes/cache/notfound.php',
'Fuel\\Core\\CacheExpiredException' => COREPATH.'classes/cache.php',
'Fuel\\Core\\Cache_Handler_Driver' => COREPATH.'classes/cache/handler/driver.php',
'Fuel\\Core\\Cache_Handler_Json' => COREPATH.'classes/cache/handler/json.php',
'Fuel\\Core\\Cache_Handler_Serialized' => COREPATH.'classes/cache/handler/serialized.php',
'Fuel\\Core\\Cache_Handler_String' => COREPATH.'classes/cache/handler/string.php',
'Fuel\\Core\\Cache_Storage_Driver' => COREPATH.'classes/cache/storage/driver.php',
'Fuel\\Core\\Cache_Storage_Apc' => COREPATH.'classes/cache/storage/apc.php',
'Fuel\\Core\\Cache_Storage_File' => COREPATH.'classes/cache/storage/file.php',
'Fuel\\Core\\Cache_Storage_Memcached' => COREPATH.'classes/cache/storage/memcached.php',
'Fuel\\Core\\Cache_Storage_Redis' => COREPATH.'classes/cache/storage/redis.php',
'Fuel\\Core\\Cache_Storage_Xcache' => COREPATH.'classes/cache/storage/xcache.php',
'Fuel\\Core\\Config' => COREPATH.'classes/config.php',
'Fuel\\Core\\ConfigException' => COREPATH.'classes/config.php',
'Fuel\\Core\\Config_Db' => COREPATH.'classes/config/db.php',
'Fuel\\Core\\Config_File' => COREPATH.'classes/config/file.php',
'Fuel\\Core\\Config_Ini' => COREPATH.'classes/config/ini.php',
'Fuel\\Core\\Config_Json' => COREPATH.'classes/config/json.php',
'Fuel\\Core\\Config_Interface' => COREPATH.'classes/config/interface.php',
'Fuel\\Core\\Config_Php' => COREPATH.'classes/config/php.php',
'Fuel\\Core\\Config_Yml' => COREPATH.'classes/config/yml.php',
'Fuel\\Core\\Config_Memcached' => COREPATH.'classes/config/memcached.php',
'Fuel\\Core\\Controller' => COREPATH.'classes/controller.php',
'Fuel\\Core\\Controller_Rest' => COREPATH.'classes/controller/rest.php',
'Fuel\\Core\\Controller_Template' => COREPATH.'classes/controller/template.php',
'Fuel\\Core\\Controller_Hybrid' => COREPATH.'classes/controller/hybrid.php',
'Fuel\\Core\\Cookie' => COREPATH.'classes/cookie.php',
'Fuel\\Core\\DB' => COREPATH.'classes/db.php',
'Fuel\\Core\\DBUtil' => COREPATH.'classes/dbutil.php',
'Fuel\\Core\\Database_Connection' => COREPATH.'classes/database/connection.php',
'Fuel\\Core\\Database_Result' => COREPATH.'classes/database/result.php',
'Fuel\\Core\\Database_Result_Cached' => COREPATH.'classes/database/result/cached.php',
'Fuel\\Core\\Database_Exception' => COREPATH.'classes/database/exception.php',
'Fuel\\Core\\Database_Expression' => COREPATH.'classes/database/expression.php',
// Generic Schema builder
'Fuel\\Core\\Database_Schema' => COREPATH.'classes/database/schema.php',
// Specific Schema builders
// Generic Query builder
'Fuel\\Core\\Database_Query' => COREPATH.'classes/database/query.php',
'Fuel\\Core\\Database_Query_Builder' => COREPATH.'classes/database/query/builder.php',
'Fuel\\Core\\Database_Query_Builder_Insert' => COREPATH.'classes/database/query/builder/insert.php',
'Fuel\\Core\\Database_Query_Builder_Delete' => COREPATH.'classes/database/query/builder/delete.php',
'Fuel\\Core\\Database_Query_Builder_Update' => COREPATH.'classes/database/query/builder/update.php',
'Fuel\\Core\\Database_Query_Builder_Select' => COREPATH.'classes/database/query/builder/select.php',
'Fuel\\Core\\Database_Query_Builder_Where' => COREPATH.'classes/database/query/builder/where.php',
'Fuel\\Core\\Database_Query_Builder_Join' => COREPATH.'classes/database/query/builder/join.php',
// Specific Query builders
'Fuel\\Core\\Database_SQLite_Builder_Delete' => COREPATH.'classes/database/sqlite/builder/delete.php',
'Fuel\\Core\\Database_SQLite_Builder_Update' => COREPATH.'classes/database/sqlite/builder/update.php',
// Generic PDO driver
'Fuel\\Core\\Database_Pdo_Connection' => COREPATH.'classes/database/pdo/connection.php',
// Specific PDO drivers
'Fuel\\Core\\Database_MySQL_Connection' => COREPATH.'classes/database/mysql/connection.php',
'Fuel\\Core\\Database_SQLite_Connection' => COREPATH.'classes/database/sqlite/connection.php',
'Fuel\\Core\\Database_Sqlsrv_Connection' => COREPATH.'classes/database/sqlsrv/connection.php',
'Fuel\\Core\\Database_Dblib_Connection' => COREPATH.'classes/database/dblib/connection.php',
// Legacy drivers
'Fuel\\Core\\Database_MySQLi_Connection' => COREPATH.'classes/database/mysqli/connection.php',
'Fuel\\Core\\Database_MySQLi_Result' => COREPATH.'classes/database/mysqli/result.php',
'Fuel\\Core\\Fuel' => COREPATH.'classes/fuel.php',
'Fuel\\Core\\FuelException' => COREPATH.'classes/fuel.php',
'Fuel\\Core\\Finder' => COREPATH.'classes/finder.php',
'Fuel\\Core\\Date' => COREPATH.'classes/date.php',
'Fuel\\Core\\Debug' => COREPATH.'classes/debug.php',
'Fuel\\Core\\Cli' => COREPATH.'classes/cli.php',
'Fuel\\Core\\Crypt' => COREPATH.'classes/crypt.php',
'Fuel\\Core\\Event' => COREPATH.'classes/event.php',
'Fuel\\Core\\Event_Instance' => COREPATH.'classes/event/instance.php',
'Fuel\\Core\\Errorhandler' => COREPATH.'classes/errorhandler.php',
'Fuel\\Core\\PhpErrorException' => COREPATH.'classes/errorhandler.php',
'Fuel\\Core\\Format' => COREPATH.'classes/format.php',
'Fuel\\Core\\Fieldset' => COREPATH.'classes/fieldset.php',
'Fuel\\Core\\Fieldset_Field' => COREPATH.'classes/fieldset/field.php',
'Fuel\\Core\\File' => COREPATH.'classes/file.php',
'Fuel\\Core\\FileAccessException' => COREPATH.'classes/file.php',
'Fuel\\Core\\OutsideAreaException' => COREPATH.'classes/file.php',
'Fuel\\Core\\InvalidPathException' => COREPATH.'classes/file.php',
'Fuel\\Core\\File_Area' => COREPATH.'classes/file/area.php',
'Fuel\\Core\\File_Handler_File' => COREPATH.'classes/file/handler/file.php',
'Fuel\\Core\\File_Handler_Directory' => COREPATH.'classes/file/handler/directory.php',
'Fuel\\Core\\Form' => COREPATH.'classes/form.php',
'Fuel\\Core\\Form_Instance' => COREPATH.'classes/form/instance.php',
'Fuel\\Core\\Ftp' => COREPATH.'classes/ftp.php',
'Fuel\\Core\\FtpConnectionException' => COREPATH.'classes/ftp.php',
'Fuel\\Core\\FtpFileAccessException' => COREPATH.'classes/ftp.php',
'Fuel\\Core\\HttpException' => COREPATH.'classes/httpexception.php',
'Fuel\\Core\\HttpBadRequestException' => COREPATH.'classes/httpexceptions.php',
'Fuel\\Core\\HttpNoAccessException' => COREPATH.'classes/httpexceptions.php',
'Fuel\\Core\\HttpNotFoundException' => COREPATH.'classes/httpexceptions.php',
'Fuel\\Core\\HttpServerErrorException' => COREPATH.'classes/httpexceptions.php',
'Fuel\\Core\\Html' => COREPATH.'classes/html.php',
'Fuel\\Core\\Image' => COREPATH.'classes/image.php',
'Fuel\\Core\\Image_Driver' => COREPATH.'classes/image/driver.php',
'Fuel\\Core\\Image_Gd' => COREPATH.'classes/image/gd.php',
'Fuel\\Core\\Image_Imagemagick' => COREPATH.'classes/image/imagemagick.php',
'Fuel\\Core\\Image_Imagick' => COREPATH.'classes/image/imagick.php',
'Fuel\\Core\\Inflector' => COREPATH.'classes/inflector.php',
'Fuel\\Core\\Input' => COREPATH.'classes/input.php',
'Fuel\\Core\\Lang' => COREPATH.'classes/lang.php',
'Fuel\\Core\\LangException' => COREPATH.'classes/lang.php',
'Fuel\\Core\\Lang_Db' => COREPATH.'classes/lang/db.php',
'Fuel\\Core\\Lang_File' => COREPATH.'classes/lang/file.php',
'Fuel\\Core\\Lang_Ini' => COREPATH.'classes/lang/ini.php',
'Fuel\\Core\\Lang_Json' => COREPATH.'classes/lang/json.php',
'Fuel\\Core\\Lang_Interface' => COREPATH.'classes/lang/interface.php',
'Fuel\\Core\\Lang_Php' => COREPATH.'classes/lang/php.php',
'Fuel\\Core\\Lang_Yml' => COREPATH.'classes/lang/yml.php',
'Fuel\\Core\\Log' => COREPATH.'classes/log.php',
'Fuel\\Core\\Markdown' => COREPATH.'classes/markdown.php',
'Fuel\\Core\\Migrate' => COREPATH.'classes/migrate.php',
'Fuel\\Core\\Model' => COREPATH.'classes/model.php',
'Fuel\\Core\\Model_Crud' => COREPATH.'classes/model/crud.php',
'Fuel\\Core\\Module' => COREPATH.'classes/module.php',
'Fuel\\Core\\ModuleNotFoundException' => COREPATH.'classes/module.php',
'Fuel\\Core\\Mongo_Db' => COREPATH.'classes/mongo/db.php',
'Fuel\\Core\\Mongo_DbException' => COREPATH.'classes/mongo/db.php',
'Fuel\\Core\\Output' => COREPATH.'classes/output.php',
'Fuel\\Core\\Package' => COREPATH.'classes/package.php',
'Fuel\\Core\\PackageNotFoundException' => COREPATH.'classes/package.php',
'Fuel\\Core\\Pagination' => COREPATH.'classes/pagination.php',
'Fuel\\Core\\Presenter' => COREPATH.'classes/presenter.php',
'Fuel\\Core\\Profiler' => COREPATH.'classes/profiler.php',
'Fuel\\Core\\Request' => COREPATH.'classes/request.php',
'Fuel\\Core\\Request_Driver' => COREPATH.'classes/request/driver.php',
'Fuel\\Core\\RequestException' => COREPATH.'classes/request/driver.php',
'Fuel\\Core\\RequestStatusException' => COREPATH.'classes/request/driver.php',
'Fuel\\Core\\Request_Curl' => COREPATH.'classes/request/curl.php',
'Fuel\\Core\\Request_Soap' => COREPATH.'classes/request/soap.php',
'Fuel\\Core\\Redis_Db' => COREPATH.'classes/redis/db.php',
'Fuel\\Core\\RedisException' => COREPATH.'classes/redis/db.php',
'Fuel\\Core\\Response' => COREPATH.'classes/response.php',
'Fuel\\Core\\Route' => COREPATH.'classes/route.php',
'Fuel\\Core\\Router' => COREPATH.'classes/router.php',
'Fuel\\Core\\Sanitization' => COREPATH.'classes/sanitization.php',
'Fuel\\Core\\Security' => COREPATH.'classes/security.php',
'Fuel\\Core\\SecurityException' => COREPATH.'classes/security.php',
'Fuel\\Core\\Session' => COREPATH.'classes/session.php',
'Fuel\\Core\\Session_Driver' => COREPATH.'classes/session/driver.php',
'Fuel\\Core\\Session_Db' => COREPATH.'classes/session/db.php',
'Fuel\\Core\\Session_Cookie' => COREPATH.'classes/session/cookie.php',
'Fuel\\Core\\Session_File' => COREPATH.'classes/session/file.php',
'Fuel\\Core\\Session_Memcached' => COREPATH.'classes/session/memcached.php',
'Fuel\\Core\\Session_Redis' => COREPATH.'classes/session/redis.php',
'Fuel\\Core\\Session_Exception' => COREPATH.'classes/session/exception.php',
'Fuel\\Core\\Num' => COREPATH.'classes/num.php',
'Fuel\\Core\\Str' => COREPATH.'classes/str.php',
'Fuel\\Core\\TestCase' => COREPATH.'classes/testcase.php',
'Fuel\\Core\\Theme' => COREPATH.'classes/theme.php',
'Fuel\\Core\\ThemeException' => COREPATH.'classes/theme.php',
'Fuel\\Core\\Uri' => COREPATH.'classes/uri.php',
'Fuel\\Core\\Unzip' => COREPATH.'classes/unzip.php',
'Fuel\\Core\\Upload' => COREPATH.'classes/upload.php',
'Fuel\\Core\\Validation' => COREPATH.'classes/validation.php',
'Fuel\\Core\\Validation_Error' => COREPATH.'classes/validation/error.php',
'Fuel\\Core\\View' => COREPATH.'classes/view.php',
'Fuel\\Core\\Viewmodel' => COREPATH.'classes/viewmodel.php',
));
};
function get_composer()
{
// storage for the composer autoloader
static $composer;
// load composer
if ( ! $composer)
{
// load the Composer autoloader if present
defined('VENDORPATH') or define('VENDORPATH', realpath(COREPATH.'..'.DS.'vendor').DS);
if ( ! is_file(VENDORPATH.'autoload.php'))
{
die('Composer is not installed. Please run "php composer.phar update" in the root to install Composer');
}
$composer = require(VENDORPATH.'autoload.php');
}
return $composer;
}

@ -1,83 +0,0 @@
<?php
/**
* Set error reporting and display errors settings. You will want to change these when in production.
*/
error_reporting(E_ALL);
ini_set('display_errors', 1);
$app_path = rtrim($_SERVER['app_path'], '/').'/';
$package_path = rtrim($_SERVER['package_path'], '/').'/';
$vendor_path = rtrim($_SERVER['vendor_path'], '/').'/';
$core_path = rtrim($_SERVER['core_path'], '/').'/';
/**
* Website docroot
*/
define('DOCROOT', realpath(__DIR__.DIRECTORY_SEPARATOR.$_SERVER['doc_root']).DIRECTORY_SEPARATOR);
( ! is_dir($app_path) and is_dir(DOCROOT.$app_path)) and $app_path = DOCROOT.$app_path;
( ! is_dir($core_path) and is_dir(DOCROOT.$core_path)) and $core_path = DOCROOT.$core_path;
( ! is_dir($vendor_path) and is_dir(DOCROOT.$vendor_path)) and $vendor_path = DOCROOT.$vendor_path;
( ! is_dir($package_path) and is_dir(DOCROOT.$package_path)) and $package_path = DOCROOT.$package_path;
define('APPPATH', realpath($app_path).DIRECTORY_SEPARATOR);
define('PKGPATH', realpath($package_path).DIRECTORY_SEPARATOR);
define('VENDORPATH', realpath($vendor_path).DIRECTORY_SEPARATOR);
define('COREPATH', realpath($core_path).DIRECTORY_SEPARATOR);
unset($app_path, $core_path, $package_path, $_SERVER['app_path'], $_SERVER['core_path'], $_SERVER['package_path']);
// Get the start time and memory for use later
defined('FUEL_START_TIME') or define('FUEL_START_TIME', microtime(true));
defined('FUEL_START_MEM') or define('FUEL_START_MEM', memory_get_usage());
// Load the Composer autoloader if present
defined('VENDORPATH') or define('VENDORPATH', realpath(COREPATH.'..'.DS.'vendor').DS);
if ( ! is_file(VENDORPATH.'autoload.php'))
{
die('Composer is not installed. Please run "php composer.phar update" in the project root to install Composer');
}
require VENDORPATH.'autoload.php';
if (class_exists('AspectMock\Kernel'))
{
// Configure AspectMock
$kernel = \AspectMock\Kernel::getInstance();
$kernel->init(array(
'debug' => true,
'appDir' => __DIR__.'/../',
'includePaths' => array(
APPPATH, COREPATH, PKGPATH,
),
'excludePaths' => array(
APPPATH.'tests', COREPATH.'tests',
),
'cacheDir' => APPPATH.'tmp/AspectMock',
));
// Load in the Fuel autoloader
$kernel->loadFile(COREPATH.'classes'.DIRECTORY_SEPARATOR.'autoloader.php');
}
else
{
// Load in the Fuel autoloader
require COREPATH.'classes'.DIRECTORY_SEPARATOR.'autoloader.php';
}
class_alias('Fuel\\Core\\Autoloader', 'Autoloader');
// Boot the app
require_once APPPATH.'bootstrap.php';
// Set test mode
\Fuel::$is_test = true;
// Ad hoc fix for AspectMock error
if (class_exists('AspectMock\Kernel'))
{
class_exists('Errorhandler');
}
// Import the TestCase class
import('testcase');

@ -1,657 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Identifies the platform, browser, robot, or mobile device from the user agent string
*
* This class uses PHP's get_browser() to get details from the browsers user agent
* string. If not available, it can use a coded alternative using the php_browscap.ini
* file from http://browsers.garykeith.com.
*
* @package Fuel
* @subpackage Core
* @category Core
* @author Harro Verton
*/
class Agent
{
/**
* @var array information about the current browser
*/
protected static $properties = array(
'browser' => 'unknown',
'version' => 0,
'majorver' => 0,
'minorver' => 0,
'platform' => 'unknown',
'alpha' => false,
'beta' => false,
'win16' => false,
'win32' => false,
'win64' => false,
'frames' => false,
'iframes' => false,
'tables' => false,
'cookies' => false,
'backgroundsounds' => false,
'javascript' => false,
'vbscript' => false,
'javaapplets' => false,
'activexcontrols' => false,
'isbanned' => false,
'ismobiledevice' => false,
'issyndicationreader' => false,
'crawler' => false,
'cssversion' => 0,
'aolversion' => 0,
);
/**
* @var array property to cache key mapping
*/
protected static $keys = array(
'browser' => 'A',
'version' => 'B',
'majorver' => 'C',
'minorver' => 'D',
'platform' => 'E',
'alpha' => 'F',
'beta' => 'G',
'win16' => 'H',
'win32' => 'I',
'win64' => 'J',
'frames' => 'K',
'iframes' => 'L',
'tables' => 'M',
'cookies' => 'N',
'backgroundsounds' => 'O',
'javascript' => 'P',
'vbscript' => 'Q',
'javaapplets' => 'R',
'activexcontrols' => 'S',
'isbanned' => 'T',
'ismobiledevice' => 'U',
'issyndicationreader' => 'V',
'crawler' => 'W',
'cssversion' => 'X',
'aolversion' => 'Y',
);
/**
* @var array global config defaults
*/
protected static $defaults = array(
'browscap' => array(
'enabled' => true,
'url' => 'http://browscap.org/stream?q=Lite_PHP_BrowsCapINI',
'method' => 'wrapper',
'proxy' => array(
'host' => null,
'port' => null,
'auth' => 'none',
'username' => null,
'password' => null,
),
'file' => '',
),
'cache' => array(
'driver' => '',
'expiry' => 604800,
'identifier' => 'fuel.agent',
),
);
/**
* @var array global config items
*/
protected static $config = array(
);
/**
* @var string detected user agent string
*/
protected static $user_agent = '';
// --------------------------------------------------------------------
// public static methods
// --------------------------------------------------------------------
/**
* map the user agent string to browser specifications
*
* @return void
*/
public static function _init()
{
// fetch and store the user agent
static::$user_agent = \Input::server('http_user_agent', '');
// fetch and process the configuration
\Config::load('agent', true);
static::$config = array_merge(static::$defaults, \Config::get('agent', array()));
// validate the browscap configuration
if ( ! is_array(static::$config['browscap']))
{
static::$config['browscap'] = static::$defaults['browscap'];
}
else
{
if ( ! array_key_exists('enabled', static::$config['browscap']) or ! is_bool(static::$config['browscap']['enabled']))
{
static::$config['browscap']['enabled'] = true;
}
if ( ! array_key_exists('url', static::$config['browscap']) or ! is_string(static::$config['browscap']['url']))
{
static::$config['browscap']['url'] = static::$defaults['browscap']['url'];
}
if ( ! array_key_exists('file', static::$config['browscap']) or ! is_string(static::$config['browscap']['file']))
{
static::$config['browscap']['file'] = static::$defaults['browscap']['file'];
}
if ( ! array_key_exists('method', static::$config['browscap']) or ! is_string(static::$config['browscap']['method']))
{
static::$config['browscap']['method'] = static::$defaults['browscap']['method'];
}
static::$config['browscap']['method'] = strtolower(static::$config['browscap']['method']);
}
// validate the cache configuration
if ( ! is_array(static::$config['cache']))
{
static::$config['cache'] = static::$defaults['cache'];
}
else
{
if ( ! array_key_exists('driver', static::$config['cache']) or ! is_string(static::$config['cache']['driver']))
{
static::$config['cache']['driver'] = static::$defaults['cache']['driver'];
}
if ( ! array_key_exists('expiry', static::$config['cache']) or ! is_numeric(static::$config['cache']['expiry']) or static::$config['cache']['expiry'] < 7200)
{
static::$config['cache']['expiry'] = static::$defaults['cache']['expiry'];
}
if ( ! array_key_exists('identifier', static::$config['cache']) or ! is_string(static::$config['cache']['identifier']))
{
static::$config['cache']['identifier'] = static::$defaults['cache']['identifier'];
}
}
// do we have a user agent?
if (static::$user_agent)
{
// try the build in get_browser() method
if (static::$config['browscap']['method'] == 'local' or ini_get('browscap') == '' or false === $browser = get_browser(static::$user_agent, true))
{
// if it fails, emulate get_browser()
$browser = static::get_from_browscap();
}
if ($browser)
{
// save it for future reference
static::$properties = array_change_key_case($browser);
}
}
}
// --------------------------------------------------------------------
/**
* get the normalized browser name
*
* @return string
*/
public static function browser()
{
return static::$properties['browser'];
}
// --------------------------------------------------------------------
/**
* Get the browser platform
*
* @return string
*/
public static function platform()
{
return static::$properties['platform'];
}
// --------------------------------------------------------------------
/**
* Get the Browser Version
*
* @return string
*/
public static function version()
{
return static::$properties['version'];
}
// --------------------------------------------------------------------
/**
* Get any browser property
*
* @param string $property
* @return string|null
*/
public static function property($property = null)
{
$property = strtolower($property);
return array_key_exists($property, static::$properties) ? static::$properties[$property] : null;
}
// --------------------------------------------------------------------
/**
* Get all browser properties
*
* @return array
*/
public static function properties()
{
return static::$properties;
}
// --------------------------------------------------------------------
/**
* check if the current browser is a robot or crawler
*
* @return bool
*/
public static function is_robot()
{
return static::$properties['crawler'];
}
// --------------------------------------------------------------------
/**
* check if the current browser is mobile device
*
* @return bool
*/
public static function is_mobiledevice()
{
return static::$properties['ismobiledevice'];
}
// --------------------------------------------------------------------
/**
* check if the current browser accepts a specific language
*
* @param string $language optional ISO language code, defaults to 'en'
* @return bool
*/
public static function accepts_language($language = 'en')
{
return (in_array(strtolower($language), static::languages(), true)) ? true : false;
}
// --------------------------------------------------------------------
/**
* check if the current browser accepts a specific character set
*
* @param string $charset optional character set, defaults to 'utf-8'
* @return bool
*/
public static function accepts_charset($charset = 'utf-8')
{
return (in_array(strtolower($charset), static::charsets(), true)) ? true : false;
}
// --------------------------------------------------------------------
/**
* get the list of browser accepted languages
*
* @return array
*/
public static function languages()
{
return explode(',', preg_replace('/(;q=[0-9\.]+)/i', '', strtolower(trim(\Input::server('http_accept_language')))));
}
// --------------------------------------------------------------------
/**
* get the list of browser accepted charactersets
*
* @return array
*/
public static function charsets()
{
return explode(',', preg_replace('/(;q=.+)/i', '', strtolower(trim(\Input::server('http_accept_charset')))));
}
// --------------------------------------------------------------------
// internal static methods
// --------------------------------------------------------------------
/**
* use the parsed php_browscap.ini file to find a user agent match
*
* @return mixed array if a match is found, of false if not cached yet
*/
protected static function get_from_browscap()
{
$cache = \Cache::forge(static::$config['cache']['identifier'].'.browscap', static::$config['cache']['driver']);
// load the cached browscap data
try
{
$browscap = $cache->get();
}
// browscap not cached
catch (\Exception $e)
{
$browscap = static::$config['browscap']['enabled'] ? static::parse_browscap() : array();
}
$search = array('\*', '\?');
$replace = array('.*', '.');
$result = false;
// find a match for the user agent string
foreach($browscap as $browser => $properties)
{
$pattern = '@^'.str_replace($search, $replace, preg_quote($browser, '@')).'$@i';
if (preg_match($pattern, static::$user_agent))
{
// store the browser name
$properties['browser'] = $browser;
// fetch possible parent info
if (array_key_exists('Parent', $properties))
{
if ($properties['Parent'] > 0)
{
$parent = array_slice($browscap, $properties['Parent'], 1);
unset($properties['Parent']);
$properties = array_merge(current($parent), $properties);
// store the browser name
$properties['browser'] = key($parent);
}
}
// normalize keys
$properties = \Arr::replace_key($properties, array_flip(static::$keys));
// merge it with the defaults to add missing values
$result = array_merge(static::$properties, $properties);
break;
}
}
return $result;
}
// --------------------------------------------------------------------
/**
* download and parse the browscap file
*
* @return array array with parsed download info, or empty if the download is disabled of failed
* @throws \Exception
* @throws \FuelException
*/
protected static function parse_browscap()
{
$cache = \Cache::forge(static::$config['cache']['identifier'].'.browscap_file', static::$config['cache']['driver']);
// get the browscap.ini file
switch (static::$config['browscap']['method'])
{
case 'local':
if ( ! is_file(static::$config['browscap']['file']) or filesize(static::$config['browscap']['file']) == 0)
{
throw new \Exception('Agent class: could not open the local browscap.ini file: '.static::$config['browscap']['file']);
}
$data = @file_get_contents(static::$config['browscap']['file']);
break;
// socket connections are not implemented yet!
case 'sockets':
$data = false;
break;
case 'curl':
// initialize the proxy request
$curl = curl_init();
curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_MAXREDIRS, 5);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_USERAGENT, 'Fuel PHP framework - Agent class (http://fuelphp.com)');
curl_setopt($curl, CURLOPT_URL, static::$config['browscap']['url']);
// add a proxy configuration if needed
if ( ! empty(static::$config['browscap']['proxy']['host']) and ! empty(static::$config['browscap']['proxy']['port']))
{
curl_setopt($curl, CURLOPT_PROXY, static::$config['browscap']['proxy']['host']);
curl_setopt($curl, CURLOPT_PROXYPORT, static::$config['browscap']['proxy']['port']);
}
// authentication set?
switch (static::$config['browscap']['proxy']['auth'])
{
case 'basic':
curl_setopt($curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
break;
case 'ntlm':
curl_setopt($curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
break;
default:
// no action
}
// do we need to pass credentials?
switch (static::$config['browscap']['proxy']['auth'])
{
case 'basic':
case 'ntlm':
if (empty(static::$config['browscap']['proxy']['username']) or empty(static::$config['browscap']['proxy']['password']))
{
logger(\Fuel::L_ERROR, 'Failed to set a proxy for Agent, cURL auth configured but no username or password configured');
}
else
{
curl_setopt($curl, CURLOPT_PROXYUSERPWD, static::$config['browscap']['proxy']['username'].':'.static::$config['browscap']['proxy']['password']);
}
break;
default:
// no action
}
// execute the request
$data = curl_exec($curl);
// check the response
$result = curl_getinfo($curl);
if ($result['http_code'] !== 200)
{
logger(\Fuel::L_ERROR, 'Failed to download browscap.ini file. cURL response code was '.$result['http_code'], 'Agent::parse_browscap');
logger(\Fuel::L_ERROR, $data);
$data = false;
}
break;
case 'wrapper':
// set our custom user agent
ini_set('user_agent', 'Fuel PHP framework - Agent class (http://fuelphp.com)');
// create a stream context if needed
$context = null;
if ( ! empty(static::$config['browscap']['proxy']['host']) and ! empty(static::$config['browscap']['proxy']['port']))
{
$context = array (
'http' => array (
'proxy' => 'tcp://'.static::$config['browscap']['proxy']['host'].':'.static::$config['browscap']['proxy']['port'],
'request_fulluri' => true,
),
);
}
// add credentials if needed
if ( ! empty(static::$config['browscap']['proxy']['auth']) and static::$config['browscap']['proxy']['auth'] == 'basic')
{
if ( ! empty(static::$config['browscap']['proxy']['username']) and ! empty(static::$config['browscap']['proxy']['password']))
{
$context['http']['header'] = 'Proxy-Authorization: Basic '.base64_encode(static::$config['browscap']['proxy']['username'].':'.static::$config['browscap']['proxy']['password']);
}
else
{
logger(\Fuel::L_ERROR, 'Failed to set a proxy for Agent, "basic" auth configured but no username or password configured');
$context = null;
}
}
// attempt to download the file
try
{
if ($context)
{
$context = stream_context_create($context);
}
$data = file_get_contents(static::$config['browscap']['url'], false, $context);
}
catch (\ErrorException $e)
{
logger(\Fuel::L_ERROR, 'Failed to download browscap.ini file.', 'Agent::parse_browscap');
logger(\Fuel::L_ERROR, $e->getMessage());
$data = false;
}
break;
default:
break;
}
if ($data === false)
{
// if no data could be download, try retrieving a cached version
try
{
$data = $cache->get(false);
// if the cached version is used, only cache the parsed result for a day
static::$config['cache']['expiry'] = 86400;
}
catch (\Exception $e)
{
logger(\Fuel::L_ERROR, 'Failed to get the cache of browscap.ini file.', 'Agent::parse_browscap');
}
}
else
{
// store the downloaded data in the cache as a backup for future use
$cache->set($data, null);
}
// parse the downloaded data
$browsers = @parse_ini_string($data, true, INI_SCANNER_RAW) or $browsers = array();
// remove the version and timestamp entry
array_shift($browsers);
$result = array();
// reverse sort on key string length
uksort($browsers, function($a, $b) { return strlen($a) < strlen($b) ? 1 : -1; } );
$index = array();
$count = 0;
// reduce the array keys
foreach($browsers as $browser => $properties)
{
$index[$browser] = $count++;
// fix any type issues
foreach ($properties as $var => $value)
{
if (is_numeric($value))
{
$properties[$var] = $value + 0;
}
elseif ($value == 'true')
{
$properties[$var] = true;
}
elseif ($value == 'false')
{
$properties[$var] = false;
}
}
$result[$browser] = \Arr::replace_key($properties, static::$keys);
}
// reduce parent links to
foreach($result as $browser => &$properties)
{
if (array_key_exists('Parent', $properties))
{
if ($properties['Parent'] == 'DefaultProperties')
{
unset($properties['Parent']);
}
else
{
if (array_key_exists($properties['Parent'], $index))
{
$properties['Parent'] = $index[$properties['Parent']];
}
else
{
unset($properties['Parent']);
}
}
}
}
// save the result to the cache
if ( ! empty($result))
{
$cache = \Cache::forge(static::$config['cache']['identifier'].'.browscap', static::$config['cache']['driver']);
$cache->set($result, static::$config['cache']['expiry']);
}
return $result;
}
}

File diff suppressed because it is too large Load Diff

@ -1,254 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* The Asset class allows you to easily work with your apps assets.
* It allows you to specify multiple paths to be searched for the
* assets.
*
* You can configure the paths by copying the core/config/asset.php
* config file into your app/config folder and changing the settings.
*
* @package Fuel
* @subpackage Core
*/
class Asset
{
/**
* default instance
*
* @var array
*/
protected static $_instance = null;
/**
* All the Asset instances
*
* @var array
*/
protected static $_instances = array();
/**
* Default configuration values
*
* @var array
*/
protected static $default_config = array(
'paths' => array('assets/'),
'img_dir' => 'img/',
'js_dir' => 'js/',
'css_dir' => 'css/',
'folders' => array(
'css' => array(),
'js' => array(),
'img' => array(),
),
'url' => '/',
'add_mtime' => true,
'indent_level' => 1,
'indent_with' => "\t",
'auto_render' => true,
'fail_silently' => false,
);
/**
* This is called automatically by the Autoloader. It loads in the config
*
* @return void
*/
public static function _init()
{
\Config::load('asset', true, false, true);
}
/**
* Return a specific instance, or the default instance (is created if necessary)
*
* @param string $instance instance name
* @return Asset_Instance
*/
public static function instance($instance = null)
{
if ($instance !== null)
{
if ( ! array_key_exists($instance, static::$_instances))
{
return false;
}
return static::$_instances[$instance];
}
if (static::$_instance === null)
{
static::$_instance = static::forge();
}
return static::$_instance;
}
/**
* Gets a new instance of the Asset class.
*
* @param string $name instance name
* @param array $config default config overrides
* @return Asset_Instance
*/
public static function forge($name = 'default', array $config = array())
{
if ($exists = static::instance($name))
{
\Errorhandler::notice('Asset with this name exists already, cannot be overwritten.');
return $exists;
}
static::$_instances[$name] = new \Asset_Instance(array_merge(static::$default_config, \Config::get('asset'), $config));
if ($name == 'default')
{
static::$_instance = static::$_instances[$name];
}
return static::$_instances[$name];
}
/**
* Adds the given path to the front of the asset paths array. It adds paths
* in a way so that asset paths are used First in Last Out.
*
* @param string $path the path to add
* @param string $type optional path type (js, css or img)
* @return void
*/
public static function add_path($path, $type = null)
{
static::instance()->add_path($path, $type);
}
/**
* Removes the given path from the asset paths array
*
* @param string $path the path to remove
* @return void
*/
public static function remove_path($path, $type = null)
{
static::instance()->remove_path($path, $type);
}
/**
* Renders the given group. Each tag will be separated by a line break.
* You can optionally tell it to render the files raw. This means that
* all CSS and JS files in the group will be read and the contents included
* in the returning value.
*
* @param mixed $group the group to render
* @param bool $raw whether to return the raw file or not
* @return string the group's output
*/
public static function render($group = null, $raw = false)
{
return static::instance()->render($group, $raw);
}
// --------------------------------------------------------------------
/**
* CSS
*
* Either adds the stylesheet to the group, or returns the CSS tag.
*
* @param mixed $stylesheets The file name, or an array files.
* @param array $attr An array of extra attributes
* @param string $group The asset group name
* @param bool $raw whether to return the raw file or not when group is not set
* @return string
*/
public static function css($stylesheets = array(), $attr = array(), $group = NULL, $raw = false)
{
return static::instance()->assettype('css', $stylesheets, $attr, $group, $raw);
}
// --------------------------------------------------------------------
/**
* JS
*
* Either adds the javascript to the group, or returns the script tag.
*
* @param mixed $scripts The file name, or an array files.
* @param array $attr An array of extra attributes
* @param string $group The asset group name
* @param bool $raw whether to return the raw file or not when group is not set
* @return string
*/
public static function js($scripts = array(), $attr = array(), $group = NULL, $raw = false)
{
return static::instance()->assettype('js', $scripts, $attr, $group, $raw);
}
// --------------------------------------------------------------------
/**
* Img
*
* Either adds the image to the group, or returns the image tag.
*
* @access public
* @param mixed $images The file name, or an array files.
* @param array $attr An array of extra attributes
* @param string $group The asset group name
* @return string
*/
public static function img($images = array(), $attr = array(), $group = NULL)
{
return static::instance()->assettype('img', $images, $attr, $group);
}
// --------------------------------------------------------------------
/**
* Get File
*
* Locates a file in all the asset paths, and return it relative to the docroot
*
* @access public
* @param string $file The filename to locate
* @param string $type The type of asset file
* @param string $folder The sub-folder to look in (optional)
* @return mixed Either the path to the file or false if not found
*/
public static function get_file($file, $type, $folder = '')
{
return static::instance()->get_file($file, $type, $folder);
}
// --------------------------------------------------------------------
/**
* Find File
*
* Locates a file in all the asset paths.
*
* @access public
* @param string $file The filename to locate
* @param string $type The type of asset file to search
* @param string $folder The sub-folder to look in (optional)
* @return mixed Either the path to the file or false if not found
*/
public static function find_file($file, $type, $folder = '')
{
return static::instance()->find_file($file, $type, $folder);
}
}

@ -1,632 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* The Asset class allows you to easily work with your apps assets.
* It allows you to specify multiple paths to be searched for the
* assets.
*
* You can configure the paths by copying the core/config/asset.php
* config file into your app/config folder and changing the settings.
*
* @package Fuel
* @subpackage Core
*/
class Asset_Instance
{
/**
* @var array the asset paths to be searched
*/
protected $_asset_paths = array(
'css' => array(),
'js' => array(),
'img' => array(),
);
/**
* @var array the sub-folders to be searched
*/
protected $_path_folders = array(
'css' => 'css/',
'js' => 'js/',
'img' => 'img/',
);
/**
* @var array custom type renderers
*/
protected $_renderers = array(
);
/**
* @var string the URL to be prepended to all assets
*/
protected $_asset_url = '/';
/**
* @var bool whether to append the file mtime to the url
*/
protected $_add_mtime = true;
/**
* @var array holds the groups of assets
*/
protected $_groups = array();
/**
* @var string prefix for generated output to provide proper indentation
*/
protected $_indent = '';
/**
* @var bool if true, directly renders the output of no group name is given
*/
protected $_auto_render = true;
/**
* @var bool if true the 'not found' exception will not be thrown and the asset is ignored.
*/
protected $_fail_silently = false;
/**
* @var bool if true, will always true to resolve assets. if false, it will only try to resolve if the asset url is relative.
*/
protected $_always_resolve = false;
/**
* Parse the config and initialize the object instance
*
* @param array $config
*/
public function __construct(Array $config)
{
// look for global search path folders
foreach ($config as $key => $value)
{
if (\Str::ends_with($key, '_dir'))
{
$key = substr($key, 0, -4);
$this->_path_folders[$key] = $this->_unify_path($value);
}
}
// global search paths
foreach ($config['paths'] as $path)
{
$this->add_path($path);
}
// per-type search paths
foreach ($config['folders'] as $type => $folders)
{
is_array($folders) or $folders = array($folders);
foreach ($folders as $path)
{
$this->add_path($path, $type);
}
}
$this->_add_mtime = (bool) $config['add_mtime'];
$this->_asset_url = $config['url'];
$this->_indent = str_repeat($config['indent_with'], $config['indent_level']);
$this->_auto_render = (bool) $config['auto_render'];
$this->_fail_silently = (bool) $config['fail_silently'];
$this->_always_resolve = (bool) $config['always_resolve'];
}
/**
* Provide backward compatibility for old type methods
*
* @param $method
* @param $args
* @return mixed
* @throws \ErrorException
*/
public function __call($method, $args)
{
// check if we can render this type
if ( ! isset($this->_path_folders[$method]))
{
throw new \ErrorException('Call to undefined method Fuel\Core\Asset_Instance::'.$method.'()');
}
// add the type to the arguments
array_unshift($args, $method);
// call assettype to store the info
return call_user_func_array(array($this, 'assettype'), $args);
}
/**
* Adds a new asset type to the list so we can load files of this type
*
* @param string $type new path type
* @param string $path optional default path
* @param Closure $renderer function to custom render this type
*
* @return object current instance
*/
public function add_type($type, $path = null, $renderer = null)
{
isset($this->_asset_paths[$type]) or $this->_asset_paths[$type] = array();
isset($this->_path_folders[$type]) or $this->_path_folders[$type] = $type.'/';
if ( ! is_null($path))
{
$path = $this->_unify_path($path);
$this->_asset_paths[$type][] = $path;
}
if ( ! is_null($renderer))
{
if ( ! $renderer instanceOf \Closure)
{
throw new \OutOfBoundsException('Asset type renderer must be passed as a Closure!');
}
$this->_renderers[$type] = $renderer;
}
return $this;
}
/**
* Adds the given path to the front of the asset paths array. It adds paths
* in a way so that asset paths are used First in Last Out.
*
* @param string $path the path to add
* @param string $type optional path type (js, css or img)
* @return object current instance
*/
public function add_path($path, $type = null)
{
is_null($type) and $type = $this->_path_folders;
empty($path) and $path = DOCROOT;
if( is_array($type))
{
foreach ($type as $key => $folder)
{
is_numeric($key) and $key = $folder;
$folder = $this->_unify_path($path).ltrim($this->_unify_path($folder), DS);
in_array($folder, $this->_asset_paths[$key]) or array_unshift($this->_asset_paths[$key], $folder);
}
}
else
{
// create the asset type if it doesn't exist
if ( ! isset($this->_asset_paths[$type]))
{
$this->_asset_paths[$type] = array();
$this->_path_folders[$type] = $type.'/';
}
$path = $this->_unify_path($path);
in_array($path, $this->_asset_paths[$type]) or array_unshift($this->_asset_paths[$type], $path);
}
return $this;
}
/**
* Removes the given path from the asset paths array
*
* @param string $path the path to remove
* @param string $type optional path type (js, css or img)
* @return object current instance
*/
public function remove_path($path, $type = null)
{
is_null($type) and $type = $this->_path_folders;
if( is_array($type))
{
foreach ($type as $key => $folder)
{
is_numeric($key) and $key = $folder;
$folder = $this->_unify_path($path).ltrim($this->_unify_path($folder), DS);
if (($found = array_search($folder, $this->_asset_paths[$key])) !== false)
{
unset($this->_asset_paths[$key][$found]);
}
}
}
else
{
$path = $this->_unify_path($path);
if (($key = array_search($path, $this->_asset_paths[$type])) !== false)
{
unset($this->_asset_paths[$type][$key]);
}
}
return $this;
}
// --------------------------------------------------------------------
/**
* Asset type store.
*
* Either adds the asset to the group, or directly return the tag.
*
* @param string $type The asset type
* @param mixed $files The file name, or an array files.
* @param array $attr An array of extra attributes
* @param string $group The asset group name
* @param boolean $raw whether to return the raw file or not when group is not set (optional)
* @return string|object Rendered asset or current instance when adding to group
*/
public function assettype($type, $files = array(), $attr = array(), $group = null, $raw = false)
{
static $temp_group = 50000000;
if ($group === null)
{
$render = $this->_auto_render;
$group = $render ? (string) (++$temp_group) : '_default_';
}
else
{
$render = false;
}
$this->_parse_assets($type, $files, $attr, $group, $raw);
if ($render)
{
return $this->render($group, $raw);
}
return $this;
}
// --------------------------------------------------------------------
/**
* Find File
*
* Locates a file in all the asset paths.
*
* @param string $file The filename to locate
* @param string $type The type of asset file to search
* @param string $folder The sub-folder to look in (optional)
* @return mixed Either the path to the file or false if not found
*/
public function find_file($file, $type, $folder = '')
{
foreach ($this->_asset_paths[$type] as $path)
{
empty($folder) or $folder = $this->_unify_path($folder);
if (is_file($newfile = $path.$folder.$this->_unify_path($file, null, false)))
{
// return the file found, make sure it uses forward slashes on Windows
return str_replace(DS, '/', $newfile);
}
}
return false;
}
// --------------------------------------------------------------------
/**
* Get File
*
* Locates a file in all the asset paths, and return it relative to the docroot
*
* @param string $file The filename to locate
* @param string $type The type of asset file
* @param string $folder The sub-folder to look in (optional)
* @return mixed Either the path to the file or false if not found
*/
public function get_file($file, $type, $folder = '')
{
if ($file = $this->find_file($file, $type, $folder))
{
strpos($file, DOCROOT) === 0 and $file = substr($file, strlen(DOCROOT));
return $this->_asset_url.$file;
}
return false;
}
/**
* Renders the given group. Each tag will be separated by a line break.
* You can optionally tell it to render the files raw. This means that
* all CSS and JS files in the group will be read and the contents included
* in the returning value.
*
* @param mixed $group the group to render
* @param bool $raw whether to return the raw file or not
* @return string the group's output
* @throws \FuelException
*/
public function render($group = null, $raw = false)
{
// determine the group to render
is_null($group) and $group = '_default_';
if (is_string($group))
{
isset($this->_groups[$group]) and $group = $this->_groups[$group];
}
is_array($group) or $group = array();
// storage for the result
$result = array();
// pre-define known types so the order is correct
foreach($this->_path_folders as $type => $unused)
{
$result[$type] = '';
}
// loop over the group entries
foreach ($group as $key => $item)
{
// determine file name and inline status
$type = $item['type'];
$filename = $item['file'];
$attr = $item['attr'];
$inline = $item['raw'];
// make sure we have storage space for this result
if ( ! isset($result[$type]))
{
$result[$type] = '';
}
// only do a file search if the asset is not a URI
if ($this->_always_resolve or ! preg_match('|^(\w+:)?//|', $filename))
{
// and only if the asset is local to the applications base_url
if ($this->_always_resolve or ! preg_match('|^(\w+:)?//|', $this->_asset_url) or strpos($this->_asset_url, \Config::get('base_url')) === 0)
{
if ( ! ($file = $this->find_file($filename, $type)))
{
if ($raw or $inline)
{
$file = $filename;
}
else
{
if ($this->_fail_silently)
{
continue;
}
throw new \FuelException('Could not find asset: '.$filename);
}
}
else
{
if ($raw or $inline)
{
$file = file_get_contents($file);
$inline = true;
}
else
{
$file = $this->_asset_url.$file.($this->_add_mtime ? '?'.filemtime($file) : '');
$file = str_replace(str_replace(DS, '/', DOCROOT), '', $file);
}
}
}
else
{
// a remote file and multiple paths? use the first one!
$path = reset($this->_asset_paths[$type]);
$file = $this->_asset_url.$path.$filename;
if ($raw or $inline)
{
$file = file_get_contents($file);
$inline = true;
}
else
{
$file = str_replace(str_replace(DS, '/', DOCROOT), '', $file);
}
}
}
else
{
$file = $filename;
}
// deal with stray backslashes on Windows
$file = str_replace('\\', '/', $file);
// call the renderer for this type
if (isset($this->_renderers[$type]))
{
$method = $this->_renderers[$type];
$result[$type] .= $method($file, $attr, $inline);
}
else
{
$method = 'render_'.$type;
if (method_exists($this, $method))
{
$result[$type] .= $this->$method($file, $attr, $inline);
}
else
{
throw new \OutOfBoundsException('Asset does not know how to render files of type "'.$type.'"!');
}
}
}
// return them in the correct order, as a string
return implode("", $result);
}
// --------------------------------------------------------------------
/**
* CSS tag renderer
*
* @param $file
* @param $attr
* @param $inline
* @return string
*/
protected function render_css($file, $attr, $inline)
{
// storage for the result
$result = '';
// make sure we have a type
isset($attr['type']) or $attr['type'] = 'text/css';
// render inline. or not
if ($inline)
{
$result = html_tag('style', $attr, PHP_EOL.$file.PHP_EOL).PHP_EOL;
}
else
{
if ( ! isset($attr['rel']) or empty($attr['rel']))
{
$attr['rel'] = 'stylesheet';
}
$attr['href'] = $file;
$result = $this->_indent.html_tag('link', $attr).PHP_EOL;
}
// return the result
return $result;
}
// --------------------------------------------------------------------
/**
* JS tag renderer
*
* @param $file
* @param $attr
* @param $inline
* @return string
*/
protected function render_js($file, $attr, $inline)
{
// storage for the result
$result = '';
// render inline. or not
$attr['type'] = 'text/javascript';
if ($inline)
{
$result = html_tag('script', $attr, PHP_EOL.$file.PHP_EOL).PHP_EOL;
}
else
{
$attr['src'] = $file;
$result = $this->_indent.html_tag('script', $attr, '').PHP_EOL;
}
// return the result
return $result;
}
// --------------------------------------------------------------------
/**
* IMG tag renderer
*
* @param $file
* @param $attr
* @param $inline
* @return string
*/
protected function render_img($file, $attr, $inline)
{
// storage for the result
$result = '';
// render the image
$attr['src'] = $file;
$attr['alt'] = isset($attr['alt']) ? $attr['alt'] : '';
$result = html_tag('img', $attr );
// return the result
return $result;
}
// --------------------------------------------------------------------
/**
* Parse Assets
*
* Pareses the assets and adds them to the group
*
* @param string $type The asset type
* @param mixed $assets The file name, or an array files.
* @param array $attr An array of extra attributes
* @param string $group The asset group name
* @param bool $raw
* @return string
*/
protected function _parse_assets($type, $assets, $attr, $group, $raw = false)
{
if ( ! is_array($assets))
{
$assets = array($assets);
}
foreach ($assets as $key => $asset)
{
// Prevent duplicate files in a group.
if (\Arr::get($this->_groups, "$group.$key.file") == $asset)
{
continue;
}
$this->_groups[$group][] = array(
'type' => $type,
'file' => $asset,
'raw' => $raw,
'attr' => (array) $attr,
);
}
}
// --------------------------------------------------------------------
/**
* Unify the path
*
* make sure the directory separator in the path is correct for the
* platform used, is terminated with a directory separator, and all
* relative path references are removed
*
* @param string $path The path
* @param mixed $ds Optional directory separator
* @param boolean $trailing Optional whether to add trailing directory separator
* @return string
*/
protected function _unify_path($path, $ds = null, $trailing = true)
{
$ds === null and $ds = DS;
return rtrim(str_replace(array('\\', '/'), $ds, $path), $ds).($trailing ? $ds : '');
}
}

@ -1,404 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* The Autoloader is responsible for all class loading. It allows you to define
* different load paths based on namespaces. It also lets you set explicit paths
* for classes to be loaded from.
*
* @package Fuel
* @subpackage Core
*/
class Autoloader
{
/**
* @var array $classes holds all the classes and paths
*/
protected static $classes = array();
/**
* @var array holds all the namespace paths
*/
protected static $namespaces = array();
/**
* Holds all the PSR-0 compliant namespaces. These namespaces should
* be loaded according to the PSR-0 standard.
*
* @var array
*/
protected static $psr_namespaces = array();
/**
* @var array list off namespaces of which classes will be aliased to global namespace
*/
protected static $core_namespaces = array(
'Fuel\\Core',
);
/**
* @var array the default path to look in if the class is not in a package
*/
protected static $default_path = null;
/**
* @var bool whether to initialize a loaded class
*/
protected static $auto_initialize = null;
/**
* Adds a namespace search path. Any class in the given namespace will be
* looked for in the given path.
*
* @param string $namespace the namespace
* @param string $path the path
* @param bool $psr whether this is a PSR-0 compliant class
* @return void
*/
public static function add_namespace($namespace, $path, $psr = false)
{
static::$namespaces[$namespace] = $path;
if ($psr)
{
static::$psr_namespaces[$namespace] = $path;
}
}
/**
* Adds an array of namespace paths. See {add_namespace}.
*
* @param array $namespaces the namespaces
* @param bool $prepend whether to prepend the namespace to the search path
* @return void
*/
public static function add_namespaces(array $namespaces, $prepend = false)
{
if ( ! $prepend)
{
static::$namespaces = array_merge(static::$namespaces, $namespaces);
}
else
{
static::$namespaces = $namespaces + static::$namespaces;
}
}
/**
* Returns the namespace's path or false when it doesn't exist.
*
* @param string $namespace the namespace to get the path for
* @return array|bool the namespace path or false
*/
public static function namespace_path($namespace)
{
if ( ! array_key_exists($namespace, static::$namespaces))
{
return false;
}
return static::$namespaces[$namespace];
}
/**
* Adds a classes load path. Any class added here will not be searched for
* but explicitly loaded from the path.
*
* @param string $class the class name
* @param string $path the path to the class file
* @return void
*/
public static function add_class($class, $path)
{
static::$classes[strtolower($class)] = $path;
}
/**
* Adds multiple class paths to the load path. See {@see Autoloader::add_class}.
*
* @param array $classes the class names and paths
* @return void
*/
public static function add_classes($classes)
{
foreach ($classes as $class => $path)
{
static::$classes[strtolower($class)] = $path;
}
}
/**
* Aliases the given class into the given Namespace. By default it will
* add it to the global namespace.
*
* <code>
* Autoloader::alias_to_namespace('Foo\\Bar');
* Autoloader::alias_to_namespace('Foo\\Bar', '\\Baz');
* </code>
*
* @param string $class the class name
* @param string $namespace the namespace to alias to
*/
public static function alias_to_namespace($class, $namespace = '')
{
empty($namespace) or $namespace = rtrim($namespace, '\\').'\\';
$parts = explode('\\', $class);
$root_class = $namespace.array_pop($parts);
class_alias($class, $root_class);
}
/**
* Register's the autoloader to the SPL autoload stack.
*
* @return void
*/
public static function register()
{
spl_autoload_register('Autoloader::load', true, true);
}
/**
* Returns the class with namespace prefix when available
*
* @param string $class
* @return bool|string
*/
protected static function find_core_class($class)
{
foreach (static::$core_namespaces as $ns)
{
if (array_key_exists(strtolower($ns_class = $ns.'\\'.$class), static::$classes))
{
return $ns_class;
}
}
return false;
}
/**
* Add a namespace for which classes may be used without the namespace prefix and
* will be auto-aliased to the global namespace.
* Prefixing the classes will overwrite core classes and previously added namespaces.
*
* @param string $namespace
* @param bool $prefix
* @return void
*/
public static function add_core_namespace($namespace, $prefix = true)
{
if ($prefix)
{
array_unshift(static::$core_namespaces, $namespace);
}
else
{
static::$core_namespaces[] = $namespace;
}
}
/**
* Loads a class.
*
* @param string $class Class to load
* @return bool If it loaded the class
*/
public static function load($class)
{
// deal with funny is_callable('static::classname') side-effect
if (strpos($class, 'static::') === 0)
{
// is called from within the class, so it's already loaded
return true;
}
$loaded = false;
$class = ltrim($class, '\\');
$pos = strripos($class, '\\');
if (empty(static::$auto_initialize))
{
static::$auto_initialize = $class;
}
if (isset(static::$classes[strtolower($class)]))
{
static::init_class($class, str_replace('/', DS, static::$classes[strtolower($class)]));
$loaded = true;
}
elseif ($full_class = static::find_core_class($class))
{
if ( ! class_exists($full_class, false) and ! interface_exists($full_class, false))
{
include static::prep_path(static::$classes[strtolower($full_class)]);
}
if ( ! class_exists($class, false))
{
class_alias($full_class, $class);
}
static::init_class($class);
$loaded = true;
}
else
{
$full_ns = substr($class, 0, $pos);
if ($full_ns)
{
foreach (static::$namespaces as $ns => $path)
{
$ns = ltrim($ns, '\\');
if (stripos($full_ns, $ns) === 0)
{
$path .= static::class_to_path(
substr($class, strlen($ns) + 1),
array_key_exists($ns, static::$psr_namespaces)
);
if (is_file($path))
{
static::init_class($class, $path);
$loaded = true;
break;
}
}
}
}
if ( ! $loaded)
{
$path = APPPATH.'classes'.DS.static::class_to_path($class);
if (is_file($path))
{
static::init_class($class, $path);
$loaded = true;
}
}
}
// Prevent failed load from keeping other classes from initializing
if (static::$auto_initialize == $class)
{
static::$auto_initialize = null;
}
return $loaded;
}
/**
* Reset the auto initialize state after an autoloader exception.
* This method is called by the exception handler, and is considered an
* internal method!
*
* @access protected
*/
public static function _reset()
{
static::$auto_initialize = null;
}
/**
* Takes a class name and turns it into a path. It follows the PSR-0
* standard, except for makes the entire path lower case, unless you
* tell it otherwise.
*
* Note: This does not check if the file exists...just gets the path
*
* @param string $class Class name
* @param bool $psr Whether this is a PSR-0 compliant class
* @return string Path for the class
*/
protected static function class_to_path($class, $psr = false)
{
$file = '';
if ($last_ns_pos = strripos($class, '\\'))
{
$namespace = substr($class, 0, $last_ns_pos);
$class = substr($class, $last_ns_pos + 1);
$file = str_replace('\\', DS, $namespace).DS;
}
$file .= str_replace('_', DS, $class).'.php';
if ( ! $psr)
{
$file = strtolower($file);
}
return $file;
}
/**
* Prepares a given path by making sure the directory separators are correct.
*
* @param string $path Path to prepare
* @return string Prepped path
*/
protected static function prep_path($path)
{
return str_replace(array('/', '\\'), DS, $path);
}
/**
* Checks to see if the given class has a static _init() method. If so then
* it calls it.
*
* @param string $class the class name
* @param string $file the file containing the class to include
* @throws \Exception
* @throws \FuelException
*/
protected static function init_class($class, $file = null)
{
// include the file if needed
if ($file)
{
include $file;
}
// if the loaded file contains a class...
if (class_exists($class, false))
{
// call the classes static init if needed
if (static::$auto_initialize === $class)
{
static::$auto_initialize = null;
if (method_exists($class, '_init') and is_callable($class.'::_init'))
{
call_user_func($class.'::_init');
}
}
}
// or an interface...
elseif (interface_exists($class, false))
{
// nothing to do here
}
// or a trait if you're not on 5.3 anymore...
elseif (function_exists('trait_exists') and trait_exists($class, false))
{
// nothing to do here
}
// else something went wrong somewhere, barf and exit now
elseif ($file)
{
throw new \Exception('File "'.\Fuel::clean_path($file).'" does not contain class "'.$class.'"');
}
else
{
throw new \FuelException('Class "'.$class.'" is not defined');
}
}
}

@ -1,136 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
// Exception thrown when the Cache was found but expired (auto deleted)
class CacheExpiredException extends \CacheNotFoundException {}
class Cache
{
/**
* Loads any default caching settings when available
*/
public static function _init()
{
\Config::load('cache', true);
}
/**
* Creates a new cache instance.
*
* @param mixed $identifier The identifier of the cache, can be anything but empty
* @param array $config Either an array of settings or the storage driver to be used
* @return Cache_Storage_Driver The new cache object
*/
public static function forge($identifier, $config = array())
{
// load the default config
$defaults = \Config::get('cache', array());
// $config can be either an array of config settings or the name of the storage driver
if ( ! empty($config) and ! is_array($config) and ! is_null($config))
{
$config = array('driver' => $config);
}
// Overwrite default values with given config
$config = array_merge($defaults, (array) $config);
if (empty($config['driver']))
{
throw new \FuelException('No cache driver given or no default cache driver set.');
}
$class = '\\Cache_Storage_'.ucfirst($config['driver']);
// Convert the name to a string when necessary
$identifier = call_user_func($class.'::stringify_identifier', $identifier);
// Return instance of the requested cache object
return new $class($identifier, $config);
}
/**
* Front for writing the cache, ensures interchangeability of storage drivers. Actual writing
* is being done by the _set() method which needs to be extended.
*
* @param mixed $identifier The identifier of the cache, can be anything but empty
* @param mixed $contents The content to be cached
* @param bool $expiration The time in seconds until the cache will expire, =< 0 or null means no expiration
* @param array $dependencies Contains the identifiers of caches this one will depend on (not supported by all drivers!)
* @return Cache_Storage_Driver The new Cache object
*/
public static function set($identifier, $contents = null, $expiration = false, $dependencies = array())
{
$contents = \Fuel::value($contents);
$cache = static::forge($identifier);
return $cache->set($contents, $expiration, $dependencies);
}
/**
* Does get() & set() in one call that takes a callback and it's arguments to generate the contents
*
* @param mixed $identifier The identifier of the cache, can be anything but empty
* @param string|array $callback Valid PHP callback
* @param array $args Arguments for the above function/method
* @param int $expiration Cache expiration in seconds
* @param array $dependencies Contains the identifiers of caches this one will depend on (not supported by all drivers!)
* @return mixed
*/
public static function call($identifier, $callback, $args = array(), $expiration = null, $dependencies = array())
{
$cache = static::forge($identifier);
return $cache->call($callback, $args, $expiration, $dependencies);
}
/**
* Front for reading the cache, ensures interchangeability of storage drivers. Actual reading
* is being done by the _get() method which needs to be extended.
*
* @param mixed $identifier The identifier of the cache, can be anything but empty
* @param bool $use_expiration
* @return mixed
*/
public static function get($identifier, $use_expiration = true)
{
$cache = static::forge($identifier);
return $cache->get($use_expiration);
}
/**
* Frontend for deleting item from the cache, interchangeable storage methods. Actual operation
* handled by delete() call on storage driver class
*
* @param mixed $identifier The identifier of the cache, can be anything but empty
*/
public static function delete($identifier)
{
$cache = static::forge($identifier);
return $cache->delete();
}
/**
* Flushes the whole cache for a specific storage driver or just a part of it when $section is set
* (might not work with all storage drivers), defaults to the default storage driver
*
* @param null|string
* @param null|string
* @return bool
*/
public static function delete_all($section = null, $driver = null)
{
$cache = static::forge('__NOT_USED__', $driver);
return $cache->delete_all($section);
}
}

@ -1,31 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
interface Cache_Handler_Driver {
/**
* Should make the contents readable
*
* @param mixed
* @return mixed
*/
public function readable($contents);
/**
* Should make the contents writable
*
* @param mixed
* @return mixed
*/
public function writable($contents);
}

@ -1,39 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Cache_Handler_Json implements \Cache_Handler_Driver
{
public function readable($contents)
{
$array = false;
if (substr($contents, 0, 1) == 'a')
{
$contents = substr($contents, 1);
$array = true;
}
return json_decode($contents, $array);
}
public function writable($contents)
{
$array = '';
if (is_array($contents))
{
$array = 'a';
}
return $array.json_encode($contents);
}
}

@ -1,27 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Cache_Handler_Serialized implements \Cache_Handler_Driver
{
public function readable($contents)
{
return unserialize($contents);
}
public function writable($contents)
{
return serialize($contents);
}
}

@ -1,26 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Cache_Handler_String implements \Cache_Handler_Driver
{
public function readable($contents)
{
return (string) $contents;
}
public function writable($contents)
{
return (string) $contents;
}
}

@ -1,16 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
// Exception thrown when the Cache wasn't found
class CacheNotFoundException extends \OutOfBoundsException {}

@ -1,382 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Cache_Storage_Apc extends \Cache_Storage_Driver
{
/**
* @const string Tag used for opening & closing cache properties
*/
const PROPS_TAG = 'Fuel_Cache_Properties';
/**
* @var array driver specific configuration
*/
protected $config = array();
// ---------------------------------------------------------------------
public function __construct($identifier, $config)
{
parent::__construct($identifier, $config);
$this->config = isset($config['apc']) ? $config['apc'] : array();
// make sure we have an id
$this->config['cache_id'] = $this->_validate_config('cache_id', isset($this->config['cache_id'])
? $this->config['cache_id'] : 'fuel');
// check for an expiration override
$this->expiration = $this->_validate_config('expiration', isset($this->config['expiration'])
? $this->config['expiration'] : $this->expiration);
// do we have the PHP APC extension available
if ( ! function_exists('apc_store') )
{
throw new \FuelException('Your PHP installation doesn\'t have APC loaded.');
}
}
// ---------------------------------------------------------------------
/**
* Check if other caches or files have been changed since cache creation
*
* @param array
* @return bool
*/
public function check_dependencies(array $dependencies)
{
foreach($dependencies as $dep)
{
// get the section name and identifier
$sections = explode('.', $dep);
if (count($sections) > 1)
{
$identifier = array_pop($sections);
$sections = '.'.implode('.', $sections);
}
else
{
$identifier = $dep;
$sections = '';
}
// get the cache index
$index = apc_fetch($this->config['cache_id'].$sections);
// get the key from the index
$key = isset($index[$identifier][0]) ? $index[$identifier] : false;
// key found and newer?
if ($key === false or $key[1] > $this->created)
{
return false;
}
}
return true;
}
/**
* Delete Cache
*/
public function delete()
{
// get the APC key for the cache identifier
$key = $this->_get_key(true);
// delete the key from the apc store
$key and apc_delete($key);
$this->reset();
}
/**
* Purge all caches
*
* @param string $section limit purge to subsection
* @return bool
*/
public function delete_all($section)
{
// determine the section index name
$section = $this->config['cache_id'].(empty($section) ? '' : '.'.$section);
// get the directory index
$index = apc_fetch($this->config['cache_id'].'__DIR__');
if (is_array($index))
{
// limit the delete if we have a valid section
if ( ! empty($section))
{
$dirs = in_array($section, $index) ? array($section) : array();
}
else
{
$dirs = $index;
}
// loop through the indexes, delete all stored keys, then delete the indexes
foreach ($dirs as $dir)
{
$list = apc_fetch($dir);
foreach ($list as $item)
{
apc_delete($item[0]);
}
apc_delete($dir);
}
// update the directory index
$index = array_diff($index, $dirs);
apc_store($this->config['cache_id'].'__DIR__', $index);
}
}
// ---------------------------------------------------------------------
/**
* Prepend the cache properties
*
* @return string
*/
protected function prep_contents()
{
$properties = array(
'created' => $this->created,
'expiration' => $this->expiration,
'dependencies' => $this->dependencies,
'content_handler' => $this->content_handler,
);
$properties = '{{'.static::PROPS_TAG.'}}'.json_encode($properties).'{{/'.static::PROPS_TAG.'}}';
return $properties.$this->contents;
}
/**
* Remove the prepended cache properties and save them in class properties
*
* @param string
* @throws UnexpectedValueException
*/
protected function unprep_contents($payload)
{
$properties_end = strpos($payload, '{{/'.static::PROPS_TAG.'}}');
if ($properties_end === FALSE)
{
throw new \UnexpectedValueException('Cache has bad formatting');
}
$this->contents = substr($payload, $properties_end + strlen('{{/'.static::PROPS_TAG.'}}'));
$props = substr(substr($payload, 0, $properties_end), strlen('{{'.static::PROPS_TAG.'}}'));
$props = json_decode($props, true);
if ($props === NULL)
{
throw new \UnexpectedValueException('Cache properties retrieval failed');
}
$this->created = $props['created'];
$this->expiration = is_null($props['expiration']) ? null : (int) ($props['expiration'] - time());
$this->dependencies = $props['dependencies'];
$this->content_handler = $props['content_handler'];
}
/**
* Save a cache, this does the generic pre-processing
*
* @return bool success
*/
protected function _set()
{
// get the apc key for the cache identifier
$key = $this->_get_key();
$payload = $this->prep_contents();
// adjust the expiration, apc uses a TTL instead of a timestamp
$expiration = is_null($this->expiration) ? 0 : (int) ($this->expiration - $this->created);
// write it to the apc store
if (apc_store($key, $payload, $expiration) === false)
{
throw new \RuntimeException('APC returned failed to write. Check your configuration.');
}
// update the index
$this->_update_index($key);
return true;
}
/**
* Load a cache, this does the generic post-processing
*
* @return bool success
*/
protected function _get()
{
// get the apc key for the cache identifier
$key = $this->_get_key();
// fetch the cached data from the apc store
$payload = apc_fetch($key);
try
{
$this->unprep_contents($payload);
}
catch (\UnexpectedValueException $e)
{
return false;
}
return true;
}
/**
* validate a driver config value
*
* @param string name of the config variable to validate
* @param mixed value
* @return mixed
*/
private function _validate_config($name, $value)
{
switch ($name)
{
case 'cache_id':
if (empty($value) or ! is_string($value))
{
$value = 'fuel';
}
break;
case 'expiration':
if (empty($value) or ! is_numeric($value))
{
$value = null;
}
break;
default:
break;
}
return $value;
}
/**
* get's the apc key belonging to the cache identifier
*
* @param bool if true, remove the key retrieved from the index
* @return string
*/
protected function _get_key($remove = false)
{
// get the current index information
list($identifier, $sections, $index) = $this->_get_index();
// get the key from the index
$key = isset($index[$identifier][0]) ? $index[$identifier][0] : false;
if ($remove === true)
{
if ( $key !== false )
{
unset($index[$identifier]);
apc_store($this->config['cache_id'].$sections, $index);
}
}
else
{
// create a new key if needed
$key === false and $key = $this->_new_key();
}
return $key;
}
/**
* generate a new unique key for the current identifier
*
* @return string
*/
protected function _new_key()
{
$key = '';
while (strlen($key) < 32)
{
$key .= mt_rand(0, mt_getrandmax());
}
return md5($this->config['cache_id'].'_'.uniqid($key, TRUE));
}
/**
* Get the section index
*
* @return array containing the identifier, the sections, and the section index
*/
protected function _get_index()
{
// get the section name and identifier
$sections = explode('.', $this->identifier);
if (count($sections) > 1)
{
$identifier = array_pop($sections);
$sections = '.'.implode('.', $sections);
}
else
{
$identifier = $this->identifier;
$sections = '';
}
// get the cache index and return it
return array($identifier, $sections, apc_fetch($this->config['cache_id'].$sections));
}
/**
* Update the section index
*
* @param string cache key
*/
protected function _update_index($key)
{
// get the current index information
list($identifier, $sections, $index) = $this->_get_index();
// store the key in the index and write the index back
$index[$identifier] = array($key, $this->created);
apc_store($this->config['cache_id'].$sections, array_merge($index, array($identifier => array($key, $this->created))), 0);
// get the directory index
$index = apc_fetch($this->config['cache_id'].'__DIR__');
if (is_array($index))
{
if (!in_array($this->config['cache_id'].$sections, $index))
{
$index[] = $this->config['cache_id'].$sections;
}
}
else
{
$index = array($this->config['cache_id'].$sections);
}
// update the directory index
apc_store($this->config['cache_id'].'__DIR__', $index, 0);
}
}

@ -1,426 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
abstract class Cache_Storage_Driver
{
/**
* @var array defines which class properties are gettable with get_... in the __call() method
*/
protected static $_gettable = array('created', 'expiration', 'dependencies', 'identifier');
/**
* @var array defines which class properties are settable with set_... in the __call() method
*/
protected static $_settable = array('expiration', 'dependencies', 'identifier');
/**
* @var string name of the content handler driver
*/
protected $content_handler = null;
/**
* @var Cache_Handler_Driver handles and formats the cache's contents
*/
protected $handler_object = null;
/**
* @var string the cache's name, either string or md5'd serialization of something else
*/
protected $identifier = null;
/**
* @var int timestamp of creation of the cache
*/
protected $created = null;
/**
* @var int timestamp when this cache will expire
*/
protected $expiration = null;
/**
* @var array contains identifiers of other caches this one depends on
*/
protected $dependencies = array();
/**
* @var mixed the contents of this
*/
protected $contents = null;
/**
* @var string loaded driver
*/
protected $driver = null;
/**
* Abstract method that should take care of the storage engine specific reading. Needs to set the object properties:
* - created
* - expiration
* - dependencies
* - contents
* - content_handler
*
* @return bool success of the operation
*/
abstract protected function _get();
/**
* Abstract method that should take care of the storage engine specific writing. Needs to write the object properties:
* - created
* - expiration
* - dependencies
* - contents
* - content_handler
*/
abstract protected function _set();
/**
* Should delete this cache instance, should also run reset() afterwards
*/
abstract public function delete();
/**
* Flushes the whole cache for a specific storage type or just a part of it when $section is set
* (might not work with all storage drivers), defaults to the default storage type
*
* @param string
*/
abstract public function delete_all($section);
/**
* Should check all dependencies against the creation timestamp.
* This is static to make it possible in the future to check dependencies from other storages then the current one,
* though I don't have a clue yet how to make that possible.
*
* @param array $dependencies
* @return bool either true or false on any failure
*/
abstract public function check_dependencies(array $dependencies);
/**
* Default constructor, any extension should either load this first or act similar
*
* @param string $identifier the identifier for this cache
* @param array $config additional config values
*/
public function __construct($identifier, $config)
{
$this->identifier = $identifier;
// fetch options from config and set them
$this->expiration = array_key_exists('expiration', $config) ? $config['expiration'] : \Config::get('cache.expiration', null);
$this->dependencies = array_key_exists('dependencies', $config) ? $config['dependencies'] : array();
$this->content_handler = array_key_exists('content_handler', $config) ? new $config['content_handler']() : null;
$this->driver = array_key_exists('driver', $config) ? $config['driver'] : 'file';
}
/**
* Allows for default getting and setting
*
* @param string
* @param array
* @return void|mixed
*/
public function __call($method, $args = array())
{
// Allow getting any properties set in static::$_gettable
if (substr($method, 0, 3) == 'get')
{
$name = substr($method, 4);
if (in_array($name, static::$_gettable))
{
return $this->{$name};
}
else
{
throw new \BadMethodCallException('This property doesn\'t exist or can\'t be read.');
}
}
// Allow setting any properties set in static::$_settable
elseif (substr($method, 0, 3) == 'set')
{
$name = substr($method, 4);
if (in_array($name, static::$_settable))
{
$this->{$name} = @$args[0];
}
else
{
throw new \BadMethodCallException('This property doesn\'t exist or can\'t be set.');
}
return $this;
}
else
{
throw new \BadMethodCallException('Illegal method call: ' . $method);
}
}
/**
* Converts the identifier to a string when necessary:
* A int is just converted to a string, all others are serialized and then md5'd
*
* @param mixed $identifier
* @return string
* @throws \FuelException
*/
public static function stringify_identifier($identifier)
{
// Identifier may not be empty, but can be false or 0
if ($identifier === '' || $identifier === null)
{
throw new \FuelException('The identifier cannot be empty, must contain a value of any kind other than null or an empty string.');
}
// In case of string or int just return it as a string
if (is_string($identifier) || is_int($identifier))
{
// cleanup to only allow alphanumeric chars, dashes, dots & underscores
if (preg_match('/^([a-z0-9_\.\-]*)$/iuD', $identifier) === 0)
{
throw new \FuelException('Cache identifier can only contain alphanumeric characters, underscores, dashes & dots.');
}
return (string) $identifier;
}
// In case of array, bool or object return the md5 of the $identifier's serialization
else
{
return '_hashes.'.md5(serialize($identifier));
}
}
/**
* Resets all properties except for the identifier, should be run by default when a delete() is triggered
*/
public function reset()
{
$this->contents = null;
$this->created = null;
$this->expiration = null;
$this->dependencies = array();
$this->content_handler = null;
$this->handler_object = null;
}
/**
* Front for writing the cache, ensures interchangeability of storage engines. Actual writing
* is being done by the _set() method which needs to be extended.
*
* @param mixed $contents The content to be cached
* @param bool $expiration The time in seconds until the cache will expire, =< 0 or null means no expiration
* @param array $dependencies array of names on which this cache depends for
*/
final public function set($contents = null, $expiration = false, $dependencies = array())
{
$contents = \Fuel::value($contents);
// save the current expiration
$current_expiration = $this->expiration;
// Use either the given value or the class property
if ( ! is_null($contents))
{
$this->set_contents($contents);
}
$this->expiration = ($expiration !== false) ? $expiration : $this->expiration;
$this->dependencies = ( ! empty($dependencies)) ? $dependencies : $this->dependencies;
$this->created = time();
// Create expiration timestamp when other then null
if ( ! is_null($this->expiration))
{
if ( ! is_numeric($this->expiration))
{
throw new \InvalidArgumentException('Expiration must be a valid number.');
}
$this->expiration = $this->created + intval($this->expiration);
}
// Convert dependency identifiers to string when set
$this->dependencies = ( ! is_array($this->dependencies)) ? array($this->dependencies) : $this->dependencies;
if ( ! empty( $this->dependencies ) )
{
foreach($this->dependencies as $key => $id)
{
$this->dependencies[$key] = $this->stringify_identifier($id);
}
}
// Turn everything over to the storage specific method
$this->_set();
// restore the expiration
$this->expiration = $current_expiration;
}
/**
* Front for reading the cache, ensures interchangeability of storage engines. Actual reading
* is being done by the _get() method which needs to be extended.
*
* @param bool $use_expiration
* @return Cache_Storage_Driver
* @throws \CacheExpiredException
* @throws \CacheNotFoundException
*/
final public function get($use_expiration = true)
{
if ( ! $this->_get())
{
throw new \CacheNotFoundException('not found');
}
if ($use_expiration)
{
if ( ! is_null($this->expiration) and $this->expiration < 0)
{
$this->delete();
throw new \CacheExpiredException('expired');
}
// Check dependencies and handle as expired on failure
if ( ! $this->check_dependencies($this->dependencies))
{
$this->delete();
throw new \CacheExpiredException('expired');
}
}
return $this->get_contents();
}
/**
* Does get() & set() in one call that takes a callback and it's arguments to generate the contents
*
* @param string|array $callback Valid PHP callback
* @param array $args Arguments for the above function/method
* @param int|null $expiration Cache expiration in seconds
* @param array $dependencies Contains the identifiers of caches this one will depend on
* @return mixed
*/
final public function call($callback, $args = array(), $expiration = null, $dependencies = array())
{
try
{
$this->get();
}
catch (\CacheNotFoundException $e)
{
// Create the contents
$contents = call_fuel_func_array($callback, $args);
$this->set($contents, $expiration, $dependencies);
}
return $this->get_contents();
}
/**
* Set the contents with optional handler instead of the default
*
* @param mixed
* @param string
* @return Cache_Storage_Driver
*/
public function set_contents($contents, $handler = NULL)
{
$this->contents = $contents;
$this->set_content_handler($handler);
$this->contents = $this->handle_writing($contents);
return $this;
}
/**
* Fetches contents
*
* @return mixed
*/
public function get_contents()
{
return $this->handle_reading($this->contents);
}
/**
* Decides a content handler that makes it possible to write non-strings to a file
*
* @param string
* @return Cache_Storage_Driver
*/
protected function set_content_handler($handler)
{
$this->handler_object = null;
$this->content_handler = (string) $handler;
return $this;
}
/**
* Gets a specific content handler
*
* @param string
* @return Cache_Handler_Driver
*/
public function get_content_handler($handler = null)
{
if ( ! empty($this->handler_object))
{
return $this->handler_object;
}
// When not yet set, use $handler or detect the preferred handler (string = string, otherwise serialize)
if (empty($this->content_handler) && empty($handler))
{
if ( ! empty($handler))
{
$this->content_handler = $handler;
}
if (is_string($this->contents))
{
$this->content_handler = \Config::get('cache.string_handler', 'string');
}
else
{
$type = is_object($this->contents) ? get_class($this->contents) : gettype($this->contents);
$this->content_handler = \Config::get('cache.'.$type.'_handler', 'serialized');
}
}
$class = '\\Cache_Handler_'.ucfirst($this->content_handler);
$this->handler_object = new $class();
return $this->handler_object;
}
/**
* Converts the contents the cachable format
*
* @param $contents
* @return string
*/
protected function handle_writing($contents)
{
return $this->get_content_handler()->writable($contents);
}
/**
* Converts the cachable format to the original value
*
* @param $contents
* @return mixed
*/
protected function handle_reading($contents)
{
return $this->get_content_handler()->readable($contents);
}
}

@ -1,389 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Cache_Storage_File extends \Cache_Storage_Driver
{
/**
* @const string Tag used for opening & closing cache properties
*/
const PROPS_TAG = 'Fuel_Cache_Properties';
/**
* @var string File caching basepath
*/
protected static $path = '';
/**
* @var array driver specific configuration
*/
protected $config = array();
// ---------------------------------------------------------------------
public static function _init()
{
\Config::load('file', true);
// make sure the configured chmod values are octal
$chmod = \Config::get('file.chmod.folders', 0777);
is_string($chmod) and \Config::set('file.chmod.folders', octdec($chmod));
$chmod = \Config::get('file.chmod.files', 0666);
is_string($chmod) and \Config::set('file.chmod.files', octdec($chmod));
}
// ---------------------------------------------------------------------
public function __construct($identifier, $config)
{
parent::__construct($identifier, $config);
$this->config = isset($config['file']) ? $config['file'] : array();
// check for an expiration override
$this->expiration = $this->_validate_config('expiration', isset($this->config['expiration'])
? $this->config['expiration'] : $this->expiration);
// determine the file cache path
static::$path = !empty($this->config['path'])
? $this->config['path'] : \Config::get('cache_dir', APPPATH.'cache'.DS);
if ( ! is_dir(static::$path) || ! is_writable(static::$path))
{
throw new \FuelException('Cache directory does not exist or is not writable.');
}
}
/**
* Check if other caches or files have been changed since cache creation
*
* @param array
* @return bool
*/
public function check_dependencies(array $dependencies)
{
foreach($dependencies as $dep)
{
if (is_file($file = static::$path.str_replace('.', DS, $dep).'.cache'))
{
$filemtime = filemtime($file);
if ($filemtime === false || $filemtime > $this->created)
{
return false;
}
}
elseif (is_file($dep))
{
$filemtime = filemtime($dep);
if ($filemtime === false || $filemtime > $this->created)
{
return false;
}
}
else
{
return false;
}
}
return true;
}
/**
* Delete Cache
*/
public function delete()
{
if (is_file($file = static::$path.$this->identifier_to_path($this->identifier).'.cache'))
{
unlink($file);
$this->reset();
}
}
/**
* Purge all caches
*
* @param string $section limit purge to subsection
* @return bool
*/
public function delete_all($section)
{
// get the cache root path and prep the requested section
$path = rtrim(static::$path, '\\/').DS;
$section = $section === null ? '' : static::identifier_to_path($section).DS;
// if the path does not exist, bail out immediately
if ( ! is_dir($path.$section))
{
return true;
}
// get all files in this section
$files = \File::read_dir($path.$section, -1, array('\.cache$' => 'file'));
// closure to recusively delete the files
$delete = function($folder, $files) use(&$delete, $path)
{
$folder = rtrim($folder, '\\/').DS;
foreach ($files as $dir => $file)
{
if (is_numeric($dir))
{
if ( ! $result = \File::delete($folder.$file))
{
return $result;
}
}
else
{
if ( ! $result = ($delete($folder.$dir, $file)))
{
return $result;
}
}
}
// if we're processing a sub directory
if ($folder != $path)
{
// remove the folder if no more files are left
$files = \File::read_dir($folder);
empty($files) and rmdir($folder);
}
return true;
};
return $delete($path.$section, $files);
}
// ---------------------------------------------------------------------
/**
* Translates a given identifier to a valid path
*
* @param string
* @return string
*/
protected function identifier_to_path($identifier)
{
// replace dots with dashes
$identifier = str_replace('.', DS, $identifier);
return $identifier;
}
/**
* Prepend the cache properties
*
* @return string
*/
protected function prep_contents()
{
$properties = array(
'created' => $this->created,
'expiration' => $this->expiration,
'dependencies' => $this->dependencies,
'content_handler' => $this->content_handler,
);
$properties = '{{'.self::PROPS_TAG.'}}'.json_encode($properties).'{{/'.self::PROPS_TAG.'}}';
return $properties.$this->contents;
}
/**
* Remove the prepended cache properties and save them in class properties
*
* @param string
* @throws \UnexpectedValueException
*/
protected function unprep_contents($payload)
{
$properties_end = strpos($payload, '{{/'.self::PROPS_TAG.'}}');
if ($properties_end === false)
{
throw new \UnexpectedValueException('Cache has bad formatting');
}
$this->contents = substr($payload, $properties_end + strlen('{{/'.self::PROPS_TAG.'}}'));
$props = substr(substr($payload, 0, $properties_end), strlen('{{'.self::PROPS_TAG.'}}'));
$props = json_decode($props, true);
if ($props === null)
{
throw new \UnexpectedValueException('Cache properties retrieval failed');
}
$this->created = $props['created'];
$this->expiration = is_null($props['expiration']) ? null : (int) ($props['expiration'] - time());
$this->dependencies = $props['dependencies'];
$this->content_handler = $props['content_handler'];
}
/**
* Save a cache, this does the generic pre-processing
*
* @return bool success
*/
protected function _set()
{
$payload = $this->prep_contents();
$id_path = $this->identifier_to_path($this->identifier);
// create directory if necessary
$subdirs = explode(DS, $id_path);
if (count($subdirs) > 1)
{
array_pop($subdirs);
// check if specified subdir exists
if ( ! @is_dir(static::$path.implode(DS, $subdirs)))
{
// recursively create the directory. we can't use mkdir permissions or recursive
// due to the fact that mkdir is restricted by the current users umask
$basepath = rtrim(static::$path, DS);
$chmod = \Config::get('file.chmod.folders', 0775);
foreach ($subdirs as $dir)
{
$basepath .= DS.$dir;
if ( ! is_dir($basepath))
{
try
{
if ( ! mkdir($basepath))
{
return false;
}
chmod($basepath, $chmod);
}
catch (\PHPErrorException $e)
{
return false;
}
}
}
}
}
// write the cache
$file = static::$path.$id_path.'.cache';
$handle = fopen($file, 'c');
if ( ! $handle)
{
return false;
}
// wait for a lock
while ( ! flock($handle, LOCK_EX));
// truncate the file
ftruncate($handle, 0);
// write the cache data
fwrite($handle, $payload);
// flush any pending output
fflush($handle);
//release the lock
flock($handle, LOCK_UN);
// close the file
fclose($handle);
// set the correct rights on the file
chmod($file, \Config::get('file.chmod.files', 0666));
return true;
}
/**
* Load a cache, this does the generic post-processing
*
* @return bool success
*/
protected function _get()
{
$payload = false;
$id_path = $this->identifier_to_path( $this->identifier );
$file = static::$path.$id_path.'.cache';
// normalize the file
$file = realpath($file);
// make sure it exists
if (is_file($file))
{
$handle = fopen($file, 'r');
if ($handle)
{
// wait for a lock
while( ! flock($handle, LOCK_SH));
// read the cache data
$payload = file_get_contents($file);
//release the lock
flock($handle, LOCK_UN);
// close the file
fclose($handle);
}
}
try
{
$this->unprep_contents($payload);
}
catch (\UnexpectedValueException $e)
{
return false;
}
return true;
}
/**
* validate a driver config value
*
* @param string $name name of the config variable to validate
* @param mixed $value
* @return mixed
*/
protected function _validate_config($name, $value)
{
switch ($name)
{
case 'cache_id':
if (empty($value) or ! is_string($value))
{
$value = 'fuel';
}
break;
case 'expiration':
if (empty($value) or ! is_numeric($value))
{
$value = null;
}
break;
}
return $value;
}
}

@ -1,454 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Cache_Storage_Memcached extends \Cache_Storage_Driver
{
/**
* @const string Tag used for opening & closing cache properties
*/
const PROPS_TAG = 'Fuel_Cache_Properties';
/**
* @var array driver specific configuration
*/
protected $config = array();
/*
* @var Memcached storage for the memcached object
*/
protected static $memcached = false;
// ---------------------------------------------------------------------
public function __construct($identifier, $config)
{
parent::__construct($identifier, $config);
$this->config = isset($config['memcached']) ? $config['memcached'] : array();
// make sure we have a memcache id
$this->config['cache_id'] = $this->_validate_config('cache_id', isset($this->config['cache_id'])
? $this->config['cache_id'] : 'fuel');
// check for an expiration override
$this->expiration = $this->_validate_config('expiration', isset($this->config['expiration'])
? $this->config['expiration'] : $this->expiration);
if (static::$memcached === false)
{
// make sure we have memcached servers configured
$this->config['servers'] = $this->_validate_config('servers', $this->config['servers']);
// do we have the PHP memcached extension available
if ( ! class_exists('Memcached') )
{
throw new \FuelException('Memcached cache are configured, but your PHP installation doesn\'t have the Memcached extension loaded.');
}
// instantiate the memcached object
static::$memcached = new \Memcached();
// add the configured servers
static::$memcached->addServers($this->config['servers']);
// check if we can connect to all the server(s)
$added = static::$memcached->getStats();
foreach ($this->config['servers'] as $server)
{
$server = $server['host'].':'.$server['port'];
if ( ! isset($added[$server]) or $added[$server]['pid'] == -1)
{
throw new \FuelException('Memcached cache is configured, but there is no connection possible. Check your configuration.');
}
}
}
}
// ---------------------------------------------------------------------
/**
* Check if other caches or files have been changed since cache creation
*
* @param array
* @return bool
*/
public function check_dependencies(array $dependencies)
{
foreach($dependencies as $dep)
{
// get the section name and identifier
$sections = explode('.', $dep);
if (count($sections) > 1)
{
$identifier = array_pop($sections);
$sections = '.'.implode('.', $sections);
}
else
{
$identifier = $dep;
$sections = '';
}
// get the cache index
$index = static::$memcached->get($this->config['cache_id'].$sections);
// get the key from the index
$key = isset($index[$identifier][0]) ? $index[$identifier] : false;
// key found and newer?
if ($key === false or $key[1] > $this->created)
{
return false;
}
}
return true;
}
/**
* Delete Cache
*/
public function delete()
{
// get the memcached key for the cache identifier
$key = $this->_get_key(true);
// delete the key from the memcached server
if ($key and static::$memcached->delete($key) === false)
{
if (static::$memcached->getResultCode() !== \Memcached::RES_NOTFOUND)
{
throw new \FuelException('Memcached returned error code "'.static::$memcached->getResultCode().'" on delete. Check your configuration.');
}
}
$this->reset();
}
/**
* Purge all caches
*
* @param string $section limit purge to subsection
* @return bool
*/
public function delete_all($section)
{
// determine the section index name
$section = $this->config['cache_id'].(empty($section) ? '' : '.'.$section);
// get the directory index
$index = static::$memcached->get($this->config['cache_id'].'__DIR__');
if (is_array($index))
{
// limit the delete if we have a valid section
if ( ! empty($section))
{
$dirs = in_array($section, $index) ? array($section) : array();
}
else
{
$dirs = $index;
}
// loop through the indexes, delete all stored keys, then delete the indexes
foreach ($dirs as $dir)
{
$list = static::$memcached->get($dir);
foreach ($list as $item)
{
static::$memcached->delete($item[0]);
}
static::$memcached->delete($dir);
}
// update the directory index
$index = array_diff($index, $dirs);
static::$memcached->set($this->config['cache_id'].'__DIR__', $index);
}
}
// ---------------------------------------------------------------------
/**
* Prepend the cache properties
*
* @return string
*/
protected function prep_contents()
{
$properties = array(
'created' => $this->created,
'expiration' => $this->expiration,
'dependencies' => $this->dependencies,
'content_handler' => $this->content_handler,
);
$properties = '{{'.static::PROPS_TAG.'}}'.json_encode($properties).'{{/'.static::PROPS_TAG.'}}';
return $properties.$this->contents;
}
/**
* Remove the prepended cache properties and save them in class properties
*
* @param string
* @throws \UnexpectedValueException
*/
protected function unprep_contents($payload)
{
$properties_end = strpos($payload, '{{/'.static::PROPS_TAG.'}}');
if ($properties_end === FALSE)
{
throw new \UnexpectedValueException('Cache has bad formatting');
}
$this->contents = substr($payload, $properties_end + strlen('{{/'.static::PROPS_TAG.'}}'));
$props = substr(substr($payload, 0, $properties_end), strlen('{{'.static::PROPS_TAG.'}}'));
$props = json_decode($props, true);
if ($props === NULL)
{
throw new \UnexpectedValueException('Cache properties retrieval failed');
}
$this->created = $props['created'];
$this->expiration = is_null($props['expiration']) ? null : (int) ($props['expiration'] - time());
$this->dependencies = $props['dependencies'];
$this->content_handler = $props['content_handler'];
}
/**
* Save a cache, this does the generic pre-processing
*
* @return bool success
* @throws \FuelException
*/
protected function _set()
{
// get the memcached key for the cache identifier
$key = $this->_get_key();
$payload = $this->prep_contents();
// calculate relative expiration time (eg. 60s)
$expiration = !is_null($this->expiration) ? $this->expiration - time() : 0;
// if expiration value is less than 30 days, use relative value, otherwise use unix timestamp:
$expiration = $expiration <= 2592000 ? (int) $expiration : (int) $this->expiration;
// write it to the memcached server
if (static::$memcached->set($key, $payload, $expiration) === false)
{
throw new \FuelException('Memcached returned error code "'.static::$memcached->getResultCode().'" on write. Check your configuration.');
}
// update the index
$this->_update_index($key);
return true;
}
/**
* Load a cache, this does the generic post-processing
*
* @return bool success
*/
protected function _get()
{
// get the memcached key for the cache identifier
$key = $this->_get_key();
// fetch the cached data from the Memcached server
$payload = static::$memcached->get($key);
try
{
$this->unprep_contents($payload);
}
catch (\UnexpectedValueException $e)
{
return false;
}
return true;
}
/**
* validate a driver config value
*
* @param string $name name of the config variable to validate
* @param mixed $value
* @return mixed
* @throws \FuelException
*/
protected function _validate_config($name, $value)
{
switch ($name)
{
case 'cache_id':
if (empty($value) or ! is_string($value))
{
$value = 'fuel';
}
break;
case 'expiration':
if (empty($value) or ! is_numeric($value))
{
$value = null;
}
break;
case 'servers':
// do we have a servers config
if ( empty($value) OR ! is_array($value))
{
$value = array('default' => array('host' => '127.0.0.1', 'port' => '11211'));
}
// validate the servers
foreach ($value as $key => $server)
{
// do we have a host?
if ( ! isset($server['host']) OR ! is_string($server['host']))
{
throw new \FuelException('Invalid Memcached server definition in the cache configuration.');
}
// do we have a port number?
if ( ! isset($server['port']) OR ! is_numeric($server['port']) OR $server['port'] < 1025 OR $server['port'] > 65535)
{
throw new \FuelException('Invalid Memcached server definition in the cache configuration.');
}
// do we have a relative server weight?
if ( ! isset($server['weight']) OR ! is_numeric($server['weight']) OR $server['weight'] < 0)
{
// set a default
$value[$key]['weight'] = 0;
}
}
break;
default:
break;
}
return $value;
}
/**
* Get's the memcached key belonging to the cache identifier
*
* @param bool $remove if true, remove the key retrieved from the index
* @return string
*/
protected function _get_key($remove = false)
{
// get the current index information
list($identifier, $sections, $index) = $this->_get_index();
// get the key from the index
$key = isset($index[$identifier][0]) ? $index[$identifier][0] : false;
if ($remove === true)
{
if ( $key !== false )
{
unset($index[$identifier]);
static::$memcached->set($this->config['cache_id'].$sections, $index);
}
}
else
{
// create a new key if needed
$key === false and $key = $this->_new_key();
}
return $key;
}
/**
* Generate a new unique key for the current identifier
*
* @return string
*/
protected function _new_key()
{
$key = '';
while (strlen($key) < 32)
{
$key .= mt_rand(0, mt_getrandmax());
}
return md5($this->config['cache_id'].'_'.uniqid($key, TRUE));
}
/**
* Get the section index
*
* @return array containing the identifier, the sections, and the section index
*/
protected function _get_index()
{
// get the section name and identifier
$sections = explode('.', $this->identifier);
if (count($sections) > 1)
{
$identifier = array_pop($sections);
$sections = '.'.implode('.', $sections);
}
else
{
$identifier = $this->identifier;
$sections = '';
}
// get the cache index and return it
return array($identifier, $sections, static::$memcached->get($this->config['cache_id'].$sections));
}
/**
* Update the section index
*
* @param string cache key
*/
protected function _update_index($key)
{
// get the current index information
list($identifier, $sections, $index) = $this->_get_index();
// create a new index and store the key
is_array($index) or $index = array();
// store the key in the index and write the index back
$index[$identifier] = array($key, $this->created);
static::$memcached->set($this->config['cache_id'].$sections, $index, 0);
// get the directory index
$index = static::$memcached->get($this->config['cache_id'].'__DIR__');
if (is_array($index))
{
if (!in_array($this->config['cache_id'].$sections, $index))
{
$index[] = $this->config['cache_id'].$sections;
}
}
else
{
$index = array($this->config['cache_id'].$sections);
}
// update the directory index
static::$memcached->set($this->config['cache_id'].'__DIR__', $index, 0);
}
}

@ -1,509 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Cache_Storage_Redis extends \Cache_Storage_Driver
{
/**
* @const string Tag used for opening & closing cache properties
*/
const PROPS_TAG = 'Fuel_Cache_Properties';
/**
* @var array driver specific configuration
*/
protected $config = array();
/*
* @var Redis storage for the redis object
*/
protected static $redis = false;
// ---------------------------------------------------------------------
public function __construct($identifier, $config)
{
parent::__construct($identifier, $config);
$this->config = isset($config['redis']) ? $config['redis'] : array();
// make sure we have a redis id
$this->config['cache_id'] = $this->_validate_config('cache_id', isset($this->config['cache_id'])
? $this->config['cache_id'] : 'fuel');
// check for an expiration override
$this->expiration = $this->_validate_config('expiration', isset($this->config['expiration'])
? $this->config['expiration'] : $this->expiration);
// make sure we have a redis database configured
$this->config['database'] = $this->_validate_config('database', isset($this->config['database'])
? $this->config['database'] : 'default');
if (static::$redis === false)
{
// get the redis database instance
try
{
static::$redis = \Redis_Db::instance($this->config['database']);
}
catch (\Exception $e)
{
throw new \FuelException('Can not connect to the Redis engine. The error message says "'.$e->getMessage().'".');
}
// get the redis version
preg_match('/redis_version:(.*?)\n/', static::$redis->info(), $info);
if (version_compare(trim($info[1]), '1.2') < 0)
{
throw new \FuelException('Version 1.2 or higher of the Redis NoSQL engine is required to use the redis cache driver.');
}
}
}
// ---------------------------------------------------------------------
/**
* Check if other caches or files have been changed since cache creation
*
* @param array
* @return bool
*/
public function check_dependencies(array $dependencies)
{
foreach($dependencies as $dep)
{
// get the section name and identifier
$sections = explode('.', $dep);
if (count($sections) > 1)
{
$identifier = array_pop($sections);
$sections = '.'.implode('.', $sections);
}
else
{
$identifier = $dep;
$sections = '';
}
// get the cache index
$index = static::$redis->get($this->config['cache_id'].':index:'.$sections);
is_null($index) or $index = $this->_unserialize($index);
// get the key from the index
$key = isset($index[$identifier][0]) ? $index[$identifier] : false;
// key found and newer?
if ($key === false or $key[1] > $this->created)
{
return false;
}
}
return true;
}
/**
* Delete Cache
*/
public function delete()
{
// get the key for the cache identifier
$key = $this->_get_key(true);
// delete the key from the redis server
if ($key and static::$redis->del($key) === false)
{
// do something here?
}
$this->reset();
}
/**
* Purge all caches
*
* @param string $section limit purge to subsection
* @return bool
*/
public function delete_all($section)
{
// determine the section index name
$section = empty($section) ? '' : '.'.$section;
// get the directory index
$index = static::$redis->get($this->config['cache_id'].':dir:');
is_null($index) or $index = $this->_unserialize($index);
if (is_array($index))
{
if (!empty($section))
{
// limit the delete if we have a valid section
$dirs = array();
foreach ($index as $entry)
{
if ($entry == $section or strpos($entry, $section.'.') === 0)
{
$dirs[] = $entry;
}
}
}
else
{
// else delete the entire contents of the cache
$dirs = $index;
}
// loop through the selected indexes
foreach ($dirs as $dir)
{
// get the stored cache entries for this index
$list = static::$redis->get($this->config['cache_id'].':index:'.$dir);
if (is_null($list))
{
$list = array();
}
else
{
$list = $this->_unserialize($list);
}
// delete all stored keys
foreach($list as $item)
{
static::$redis->del($item[0]);
}
// and delete the index itself
static::$redis->del($this->config['cache_id'].':index:'.$dir);
}
// update the directory index
static::$redis->set($this->config['cache_id'].':dir:', $this->_serialize(array_diff($index, $dirs)));
}
}
// ---------------------------------------------------------------------
/**
* Translates a given identifier to a valid redis key
*
* @param string
* @return string
*/
protected function identifier_to_key( $identifier )
{
return $this->config['cache_id'].':'.$identifier;
}
/**
* Prepend the cache properties
*
* @return string
*/
protected function prep_contents()
{
$properties = array(
'created' => $this->created,
'expiration' => $this->expiration,
'dependencies' => $this->dependencies,
'content_handler' => $this->content_handler,
);
$properties = '{{'.static::PROPS_TAG.'}}'.json_encode($properties).'{{/'.static::PROPS_TAG.'}}';
return $properties.$this->contents;
}
/**
* Remove the prepended cache properties and save them in class properties
*
* @param string
* @throws \UnexpectedValueException
*/
protected function unprep_contents($payload)
{
$properties_end = strpos($payload, '{{/'.static::PROPS_TAG.'}}');
if ($properties_end === FALSE)
{
throw new \UnexpectedValueException('Cache has bad formatting');
}
$this->contents = substr($payload, $properties_end + strlen('{{/'.static::PROPS_TAG.'}}'));
$props = substr(substr($payload, 0, $properties_end), strlen('{{'.static::PROPS_TAG.'}}'));
$props = json_decode($props, true);
if ($props === NULL)
{
throw new \UnexpectedValueException('Cache properties retrieval failed');
}
$this->created = $props['created'];
$this->expiration = is_null($props['expiration']) ? null : (int) ($props['expiration'] - time());
$this->dependencies = $props['dependencies'];
$this->content_handler = $props['content_handler'];
}
/**
* Save a cache, this does the generic pre-processing
*
* @return bool success
*/
protected function _set()
{
// get the key for the cache identifier
$key = $this->_get_key();
// write the cache
static::$redis->set($key, $this->prep_contents());
if ( ! empty($this->expiration))
{
static::$redis->expireat($key, $this->expiration);
}
// update the index
$this->_update_index($key);
return true;
}
/**
* Load a cache, this does the generic post-processing
*
* @return bool success
*/
protected function _get()
{
// get the key for the cache identifier
$key = $this->_get_key();
// fetch the cache data from the redis server
$payload = static::$redis->get($key);
try
{
$this->unprep_contents($payload);
}
catch (\UnexpectedValueException $e)
{
return false;
}
return true;
}
/**
* validate a driver config value
*
* @param string $name name of the config variable to validate
* @param mixed $value value
* @return mixed
*/
protected function _validate_config($name, $value)
{
switch ($name)
{
case 'database':
// do we have a database config
if (empty($value) or ! is_string($value))
{
$value = 'default';
}
break;
case 'cache_id':
if (empty($value) or ! is_string($value))
{
$value = 'fuel';
}
break;
case 'expiration':
if (empty($value) or ! is_numeric($value))
{
$value = null;
}
break;
default:
break;
}
return $value;
}
/**
* get's the redis key belonging to the cache identifier
*
* @param bool $remove if true, remove the key retrieved from the index
* @return string
*/
protected function _get_key($remove = false)
{
// get the current index information
list($identifier, $sections, $index) = $this->_get_index();
$index = $index === null ? array() : $index = $this->_unserialize($index);
// get the key from the index
$key = isset($index[$identifier][0]) ? $index[$identifier][0] : false;
if ($remove === true)
{
if ( $key !== false )
{
unset($index[$identifier]);
static::$redis->set($this->config['cache_id'].':index:'.$sections, $this->_serialize($index));
}
}
else
{
// create a new key if needed
$key === false and $key = $this->_new_key();
}
return $key;
}
/**
* generate a new unique key for the current identifier
*
* @return string
*/
protected function _new_key()
{
$key = '';
while (strlen($key) < 32)
{
$key .= mt_rand(0, mt_getrandmax());
}
return md5($this->config['cache_id'].'_'.uniqid($key, TRUE));
}
/**
* Get the section index
*
* @return array containing the identifier, the sections, and the section index
*/
protected function _get_index()
{
// get the section name and identifier
$sections = explode('.', $this->identifier);
if (count($sections) > 1)
{
$identifier = array_pop($sections);
$sections = '.'.implode('.', $sections);
}
else
{
$identifier = $this->identifier;
$sections = '';
}
// get the cache index and return it
return array($identifier, $sections, static::$redis->get($this->config['cache_id'].':index:'.$sections));
}
/**
* Update the section index
*
* @param string cache key
*/
protected function _update_index($key)
{
// get the current index information
list($identifier, $sections, $index) = $this->_get_index();
$index = $index === null ? array() : $index = $this->_unserialize($index);
// store the key in the index and write the index back
$index[$identifier] = array($key, $this->created);
static::$redis->set($this->config['cache_id'].':index:'.$sections, $this->_serialize($index));
// get the directory index
$index = static::$redis->get($this->config['cache_id'].':dir:');
$index = $index === null ? array() : $index = $this->_unserialize($index);
if (is_array($index))
{
if ( ! in_array($sections, $index))
{
$index[] = $sections;
}
}
else
{
$index = array($sections);
}
// update the directory index
static::$redis->set($this->config['cache_id'].':dir:', $this->_serialize($index));
}
/**
* Serialize an array
*
* This function first converts any slashes found in the array to a temporary
* marker, so when it gets unserialized the slashes will be preserved
*
* @param array
* @return string
*/
protected function _serialize($data)
{
if (is_array($data))
{
foreach ($data as $key => $val)
{
if (is_string($val))
{
$data[$key] = str_replace('\\', '{{slash}}', $val);
}
}
}
else
{
if (is_string($data))
{
$data = str_replace('\\', '{{slash}}', $data);
}
}
return serialize($data);
}
/**
* Unserialize
*
* This function unserializes a data string, then converts any
* temporary slash markers back to actual slashes
*
* @param array
* @return string
*/
protected function _unserialize($data)
{
$data = @unserialize(stripslashes($data));
if (is_array($data))
{
foreach ($data as $key => $val)
{
if (is_string($val))
{
$data[$key] = str_replace('{{slash}}', '\\', $val);
}
}
return $data;
}
return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data;
}
}

@ -1,375 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Cache_Storage_Xcache extends \Cache_Storage_Driver
{
/**
* @const string Tag used for opening & closing cache properties
*/
const PROPS_TAG = 'Fuel_Cache_Properties';
/**
* @var array driver specific configuration
*/
protected $config = array();
// ---------------------------------------------------------------------
public function __construct($identifier, $config)
{
parent::__construct($identifier, $config);
$this->config = isset($config['xcache']) ? $config['xcache'] : array();
// make sure we have an id
$this->config['cache_id'] = $this->_validate_config('cache_id', isset($this->config['cache_id'])
? $this->config['cache_id'] : 'fuel');
// check for an expiration override
$this->expiration = $this->_validate_config('expiration', isset($this->config['expiration'])
? $this->config['expiration'] : $this->expiration);
// do we have the PHP XCache extension available
if ( ! function_exists('xcache_set') )
{
throw new \FuelException('Your PHP installation doesn\'t have XCache loaded.');
}
}
// ---------------------------------------------------------------------
/**
* Check if other caches or files have been changed since cache creation
*
* @param array
* @return bool
*/
public function check_dependencies(array $dependencies)
{
foreach($dependencies as $dep)
{
// get the section name and identifier
$sections = explode('.', $dep);
if (count($sections) > 1)
{
$identifier = array_pop($sections);
$sections = '.'.implode('.', $sections);
}
else
{
$identifier = $dep;
$sections = '';
}
// get the cache index
$index = xcache_get($this->config['cache_id'].$sections);
// get the key from the index
$key = isset($index[$identifier][0]) ? $index[$identifier] : false;
// key found and newer?
if ($key === false or $key[1] > $this->created)
{
return false;
}
}
return true;
}
/**
* Delete Cache
*/
public function delete()
{
// get the XCache key for the cache identifier
$key = $this->_get_key(true);
// delete the key from the xcache store
$key and xcache_unset($key);
$this->reset();
}
/**
* Purge all caches
*
* @param string $section limit purge to subsection
* @return bool
*/
public function delete_all($section)
{
// determine the section index name
$section = $this->config['cache_id'].(empty($section) ? '' : '.'.$section);
// get the directory index
$index = xcache_get($this->config['cache_id'].'__DIR__');
if (is_array($index))
{
$dirs = array();
foreach ($index as $dir)
{
if (strpos($dir, $section) === 0)
{
$dirs[] = $dir;
$list = xcache_get($dir);
foreach ($list as $item)
{
xcache_unset($item[0]);
}
xcache_unset($dir);
}
}
// update the directory index
$dirs and xcache_set($this->config['cache_id'].'__DIR__', array_diff($index, $dirs));
}
}
// ---------------------------------------------------------------------
/**
* Prepend the cache properties
*
* @return string
*/
protected function prep_contents()
{
$properties = array(
'created' => $this->created,
'expiration' => $this->expiration,
'dependencies' => $this->dependencies,
'content_handler' => $this->content_handler,
);
$properties = '{{'.static::PROPS_TAG.'}}'.json_encode($properties).'{{/'.static::PROPS_TAG.'}}';
return $properties.$this->contents;
}
/**
* Remove the prepended cache properties and save them in class properties
*
* @param string $payload
* @throws \UnexpectedValueException
*/
protected function unprep_contents($payload)
{
$properties_end = strpos($payload, '{{/'.static::PROPS_TAG.'}}');
if ($properties_end === FALSE)
{
throw new \UnexpectedValueException('Cache has bad formatting');
}
$this->contents = substr($payload, $properties_end + strlen('{{/'.static::PROPS_TAG.'}}'));
$props = substr(substr($payload, 0, $properties_end), strlen('{{'.static::PROPS_TAG.'}}'));
$props = json_decode($props, true);
if ($props === NULL)
{
throw new \UnexpectedValueException('Cache properties retrieval failed');
}
$this->created = $props['created'];
$this->expiration = is_null($props['expiration']) ? null : (int) ($props['expiration'] - time());
$this->dependencies = $props['dependencies'];
$this->content_handler = $props['content_handler'];
}
/**
* Save a cache, this does the generic pre-processing
*
* @return bool success
*/
protected function _set()
{
// get the xcache key for the cache identifier
$key = $this->_get_key();
$payload = $this->prep_contents();
// adjust the expiration, xcache uses a TTL instead of a timestamp
$expiration = is_null($this->expiration) ? 0 : (int) ($this->expiration - $this->created);
// write it to the xcache store
if (xcache_set($key, $payload, $expiration) === false)
{
throw new \RuntimeException('Xcache returned failed to write. Check your configuration.');
}
// update the index
$this->_update_index($key);
return true;
}
/**
* Load a cache, this does the generic post-processing
*
* @return bool success
*/
protected function _get()
{
// get the xcache key for the cache identifier
$key = $this->_get_key();
// fetch the cached data from the xcache store
$payload = xcache_get($key);
try
{
$this->unprep_contents($payload);
}
catch (\UnexpectedValueException $e)
{
return false;
}
return true;
}
/**
* validate a driver config value
*
* @param string $name name of the config variable to validate
* @param mixed $value
* @return mixed
*/
private function _validate_config($name, $value)
{
switch ($name)
{
case 'cache_id':
if (empty($value) or ! is_string($value))
{
$value = 'fuel';
}
break;
case 'expiration':
if (empty($value) or ! is_numeric($value))
{
$value = null;
}
break;
default:
break;
}
return $value;
}
/**
* get's the xcache key belonging to the cache identifier
*
* @param bool $remove if true, remove the key retrieved from the index
* @return string
*/
protected function _get_key($remove = false)
{
// get the current index information
list($identifier, $sections, $index) = $this->_get_index();
// get the key from the index
$key = isset($index[$identifier][0]) ? $index[$identifier][0] : false;
if ($remove === true)
{
if ( $key !== false )
{
unset($index[$identifier]);
xcache_set($this->config['cache_id'].$sections, $index);
}
}
else
{
// create a new key if needed
$key === false and $key = $this->_new_key();
}
return $key;
}
/**
* generate a new unique key for the current identifier
*
* @return string
*/
protected function _new_key()
{
$key = '';
while (strlen($key) < 32)
{
$key .= mt_rand(0, mt_getrandmax());
}
return md5($this->config['cache_id'].'_'.uniqid($key, TRUE));
}
/**
* Get the section index
*
* @return array containing the identifier, the sections, and the section index
*/
protected function _get_index()
{
// get the section name and identifier
$sections = explode('.', $this->identifier);
if (count($sections) > 1)
{
$identifier = array_pop($sections);
$sections = '.'.implode('.', $sections);
}
else
{
$identifier = $this->identifier;
$sections = '';
}
// get the cache index and return it
return array($identifier, $sections, xcache_get($this->config['cache_id'].$sections));
}
/**
* Update the section index
*
* @param string cache key
*/
protected function _update_index($key)
{
// get the current index information
list($identifier, $sections, $index) = $this->_get_index();
// store the key in the index and write the index back
$index[$identifier] = array($key, $this->created);
xcache_set($this->config['cache_id'].$sections, array_merge($index, array($identifier => array($key, $this->created))));
// get the directory index
$index = xcache_get($this->config['cache_id'].'__DIR__');
if (is_array($index))
{
if (!in_array($this->config['cache_id'].$sections, $index))
{
$index[] = $this->config['cache_id'].$sections;
}
}
else
{
$index = array($this->config['cache_id'].$sections);
}
// update the directory index
xcache_set($this->config['cache_id'].'__DIR__', $index, 0);
}
}

@ -1,532 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Cli class
*
* Interact with the command line by accepting input options, parameters and output text
*
* @package Fuel
* @category Core
* @author Phil Sturgeon
* @link http://docs.fuelphp.com/classes/cli.html
*/
class Cli
{
public static $readline_support = false;
public static $wait_msg = 'Press any key to continue...';
public static $nocolor = false;
protected static $args = array();
protected static $foreground_colors = array(
'black' => '0;30',
'dark_gray' => '1;30',
'blue' => '0;34',
'dark_blue' => '1;34',
'light_blue' => '1;34',
'green' => '0;32',
'light_green' => '1;32',
'cyan' => '0;36',
'light_cyan' => '1;36',
'red' => '0;31',
'light_red' => '1;31',
'purple' => '0;35',
'light_purple' => '1;35',
'light_yellow' => '0;33',
'yellow' => '1;33',
'light_gray' => '0;37',
'white' => '1;37',
);
protected static $background_colors = array(
'black' => '40',
'red' => '41',
'green' => '42',
'yellow' => '43',
'blue' => '44',
'magenta' => '45',
'cyan' => '46',
'light_gray' => '47',
);
protected static $STDOUT;
protected static $STDERR;
/**
* Static constructor. Parses all the CLI params.
*/
public static function _init()
{
if ( ! \Fuel::$is_cli)
{
throw new \Exception('Cli class cannot be used outside of the command line.');
}
for ($i = 1; $i < $_SERVER['argc']; $i++)
{
$arg = explode('=', $_SERVER['argv'][$i]);
static::$args[$i] = $arg[0];
if (count($arg) > 1 || strncmp($arg[0], '-', 1) === 0)
{
static::$args[ltrim($arg[0], '-')] = isset($arg[1]) ? $arg[1] : true;
}
}
// Readline is an extension for PHP that makes interactive with PHP much more bash-like
// http://www.php.net/manual/en/readline.installation.php
static::$readline_support = extension_loaded('readline');
static::$STDERR = STDERR;
static::$STDOUT = STDOUT;
}
/**
* Returns the option with the given name. You can also give the option
* number.
*
* Named options must be in the following formats:
* php index.php user -v --v -name=John --name=John
*
* @param string|int $name the name of the option (int if unnamed)
* @param mixed $default value to return if the option is not defined
* @return mixed
*/
public static function option($name, $default = null)
{
if ( ! isset(static::$args[$name]))
{
return \Fuel::value($default);
}
return static::$args[$name];
}
/**
* Allows you to set a commandline option from code
*
* @param string|int $name the name of the option (int if unnamed)
* @param mixed|null $value value to set, or null to delete the option
* @return mixed
*/
public static function set_option($name, $value = null)
{
if ($value === null)
{
if (isset(static::$args[$name]))
{
unset(static::$args[$name]);
}
}
else
{
static::$args[$name] = $value;
}
}
/**
* Get input from the shell, using readline or the standard STDIN
*
* Named options must be in the following formats:
* php index.php user -v --v -name=John --name=John
*
* @param string|int $prefix the name of the option (int if unnamed)
* @return string
*/
public static function input($prefix = '')
{
if (static::$readline_support)
{
return readline($prefix);
}
echo $prefix;
return fgets(STDIN);
}
/**
* Asks the user for input. This can have either 1 or 2 arguments.
*
* Usage:
*
* // Waits for any key press
* CLI::prompt();
*
* // Takes any input
* $color = CLI::prompt('What is your favorite color?');
*
* // Takes any input, but offers default
* $color = CLI::prompt('What is your favourite color?', 'white');
*
* // Will only accept the options in the array
* $ready = CLI::prompt('Are you ready?', array('y','n'));
*
* @return string the user input
*/
public static function prompt()
{
$args = func_get_args();
$options = array();
$output = '';
$default = null;
// How many we got
$arg_count = count($args);
// Is the last argument a boolean? True means required
$required = end($args) === true;
// Reduce the argument count if required was passed, we don't care about that anymore
$required === true and --$arg_count;
// This method can take a few crazy combinations of arguments, so lets work it out
switch ($arg_count)
{
case 2:
// E.g: $ready = CLI::prompt('Are you ready?', array('y','n'));
if (is_array($args[1]))
{
list($output, $options)=$args;
}
// E.g: $color = CLI::prompt('What is your favourite color?', 'white');
elseif (is_string($args[1]))
{
list($output, $default)=$args;
}
break;
case 1:
// No question (probably been asked already) so just show options
// E.g: $ready = CLI::prompt(array('y','n'));
if (is_array($args[0]))
{
$options = $args[0];
}
// Question without options
// E.g: $ready = CLI::prompt('What did you do today?');
elseif (is_string($args[0]))
{
$output = $args[0];
}
break;
}
// If a question has been asked with the read
if ($output !== '')
{
$extra_output = '';
if ($default !== null)
{
$extra_output = ' [ Default: "'.$default.'" ]';
}
elseif ($options !== array())
{
$extra_output = ' [ '.implode(', ', $options).' ]';
}
fwrite(static::$STDOUT, $output.$extra_output.': ');
}
// Read the input from keyboard.
$input = trim(static::input()) ?: $default;
// No input provided and we require one (default will stop this being called)
if (empty($input) and $required === true)
{
static::write('This is required.');
static::new_line();
$input = forward_static_call_array(array(__CLASS__, 'prompt'), $args);
}
// If options are provided and the choice is not in the array, tell them to try again
if ( ! empty($options) and ! in_array($input, $options))
{
static::write('This is not a valid option. Please try again.');
static::new_line();
$input = forward_static_call_array(array(__CLASS__, 'prompt'), $args);
}
return $input;
}
/**
* Outputs a string to the cli. If you send an array it will implode them
* with a line break.
*
* @param string|array $text the text to output, or array of lines
* @param string $foreground the foreground color
* @param string $background the foreground color
* @throws \FuelException
*/
public static function write($text = '', $foreground = null, $background = null)
{
if (is_array($text))
{
$text = implode(PHP_EOL, $text);
}
if ($foreground or $background)
{
$text = static::color($text, $foreground, $background);
}
fwrite(static::$STDOUT, $text.PHP_EOL);
}
/**
* Outputs an error to the CLI using STDERR instead of STDOUT
*
* @param string|array $text the text to output, or array of errors
* @param string $foreground the foreground color
* @param string $background the foreground color
* @throws \FuelException
*/
public static function error($text = '', $foreground = 'light_red', $background = null)
{
if (is_array($text))
{
$text = implode(PHP_EOL, $text);
}
if ($foreground OR $background)
{
$text = static::color($text, $foreground, $background);
}
fwrite(static::$STDERR, $text.PHP_EOL);
}
/**
* Beeps a certain number of times.
*
* @param int $num the number of times to beep
*/
public static function beep($num = 1)
{
echo str_repeat("\x07", $num);
}
/**
* Waits a certain number of seconds, optionally showing a wait message and
* waiting for a key press.
*
* @param int $seconds number of seconds
* @param bool $countdown show a countdown or not
*/
public static function wait($seconds = 0, $countdown = false)
{
if ($countdown === true)
{
$time = $seconds;
while ($time > 0)
{
fwrite(static::$STDOUT, $time.'... ');
sleep(1);
$time--;
}
static::write();
}
else
{
if ($seconds > 0)
{
sleep($seconds);
}
else
{
static::write(static::$wait_msg);
static::input();
}
}
}
/**
* if operating system === windows
*/
public static function is_windows()
{
return 'win' === strtolower(substr(php_uname("s"), 0, 3));
}
/**
* Enter a number of empty lines
*
* @param integer Number of lines to output
* @return void
*/
public static function new_line($num = 1)
{
// Do it once or more, write with empty string gives us a new line
for($i = 0; $i < $num; $i++)
{
static::write();
}
}
/**
* Clears the screen of output
*
* @return void
*/
public static function clear_screen()
{
static::is_windows()
// Windows is a bit crap at this, but their terminal is tiny so shove this in
? static::new_line(40)
// Anything with a flair of Unix will handle these magic characters
: fwrite(static::$STDOUT, chr(27)."[H".chr(27)."[2J");
}
/**
* Returns the given text with the correct color codes for a foreground and
* optionally a background color.
*
* @param string $text the text to color
* @param string $foreground the foreground color
* @param string $background the background color
* @param string $format other formatting to apply. Currently only 'underline' is understood
* @return string the color coded string
* @throws \FuelException
*/
public static function color($text, $foreground, $background = null, $format=null)
{
if (static::is_windows() and ! \Input::server('ANSICON'))
{
return $text;
}
if (static::$nocolor)
{
return $text;
}
if ( ! array_key_exists($foreground, static::$foreground_colors))
{
throw new \FuelException('Invalid CLI foreground color: '.$foreground);
}
if ( $background !== null and ! array_key_exists($background, static::$background_colors))
{
throw new \FuelException('Invalid CLI background color: '.$background);
}
$string = "\033[".static::$foreground_colors[$foreground]."m";
if ($background !== null)
{
$string .= "\033[".static::$background_colors[$background]."m";
}
if ($format === 'underline')
{
$string .= "\033[4m";
}
$string .= $text."\033[0m";
return $string;
}
/**
* Spawn Background Process
*
* Launches a background process (note, provides no security itself, $call must be sanitised prior to use)
* @param string $call the system call to make
* @param string $output
* @return void
* @author raccettura
* @link http://robert.accettura.com/blog/2006/09/14/asynchronous-processing-with-php/
*/
public static function spawn($call, $output = '/dev/null')
{
// Windows
if(static::is_windows())
{
pclose(popen('start /b '.$call, 'r'));
}
// Some sort of UNIX
else
{
pclose(popen($call.' > '.$output.' &', 'r'));
}
}
/**
* Redirect STDERR writes to this file or fh
*
* Call with no argument to retrieve the current filehandle.
*
* Is not smart about opening the file if it's a string. Existing files will be truncated.
*
* @param resource|string $fh Opened filehandle or string filename.
*
* @return resource
*/
public static function stderr($fh = null)
{
$orig = static::$STDERR;
if (! is_null($fh)) {
if (is_string($fh)) {
$fh = fopen($fh, "w");
}
static::$STDERR = $fh;
}
return $orig;
}
/**
* Redirect STDOUT writes to this file or fh
*
* Call with no argument to retrieve the current filehandle.
*
* Is not smart about opening the file if it's a string. Existing files will be truncated.
*
* @param resource|string|null $fh Opened filehandle or string filename.
*
* @return resource
*/
public static function stdout($fh = null)
{
$orig = static::$STDOUT;
if (! is_null($fh)) {
if (is_string($fh)) {
$fh = fopen($fh, "w");
}
static::$STDOUT = $fh;
}
return $orig;
}
}

@ -1,231 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class ConfigException extends \FuelException { }
class Config
{
/**
* @var array $loaded_files array of loaded files
*/
public static $loaded_files = array();
/**
* @var array $items the master config array
*/
public static $items = array();
/**
* @var array $itemcache the dot-notated item cache
*/
protected static $itemcache = array();
/**
* Loads a config file.
*
* @param mixed $file string file | config array | Config_Interface instance
* @param mixed $group null for no group, true for group is filename, false for not storing in the master config
* @param bool $reload true to force a reload even if the file is already loaded
* @param bool $overwrite true for array_merge, false for \Arr::merge
* @return array the (loaded) config array
* @throws \FuelException
*/
public static function load($file, $group = null, $reload = false, $overwrite = false)
{
if ( ! $reload and
! is_array($file) and
! is_object($file) and
array_key_exists($file, static::$loaded_files))
{
$group === true and $group = $file;
if ($group === null or $group === false or ! isset(static::$items[$group]))
{
return false;
}
return static::$items[$group];
}
$config = array();
if (is_array($file))
{
$config = $file;
}
elseif (is_string($file))
{
$info = pathinfo($file);
$type = 'php';
if (isset($info['extension']))
{
$type = $info['extension'];
// Keep extension when it's an absolute path, because the finder won't add it
if ($file[0] !== '/' and $file[1] !== ':')
{
$file = substr($file, 0, -(strlen($type) + 1));
}
}
$class = '\\Config_'.ucfirst($type);
if (class_exists($class))
{
static::$loaded_files[$file] = true;
$file = new $class($file);
}
else
{
throw new \FuelException(sprintf('Invalid config type "%s".', $type));
}
}
if ($file instanceof Config_Interface)
{
try
{
$config = $file->load($overwrite, ! $reload);
}
catch (\ConfigException $e)
{
$config = array();
}
$group = $group === true ? $file->group() : $group;
}
if ($group === null)
{
static::$items = $reload ? $config : ($overwrite ? array_merge(static::$items, $config) : \Arr::merge(static::$items, $config));
static::$itemcache = array();
}
else
{
$group = ($group === true) ? $file : $group;
if ( ! isset(static::$items[$group]) or $reload)
{
static::$items[$group] = array();
}
static::$items[$group] = $overwrite ? array_merge(static::$items[$group], $config) : \Arr::merge(static::$items[$group], $config);
$group .= '.';
foreach (static::$itemcache as $key => $value)
{
if (strpos($key, $group) === 0)
{
unset(static::$itemcache[$key]);
}
}
}
return $config;
}
/**
* Save a config array to disc.
*
* @param string $file desired file name
* @param string|array $config master config array key or config array
* @return bool false when config is empty or invalid else \File::update result
* @throws \FuelException
*/
public static function save($file, $config)
{
if ( ! is_array($config))
{
if ( ! isset(static::$items[$config]))
{
return false;
}
$config = static::$items[$config];
}
$info = pathinfo($file);
$type = 'php';
if (isset($info['extension']))
{
$type = $info['extension'];
// Keep extension when it's an absolute path, because the finder won't add it
if ($file[0] !== '/' and $file[1] !== ':')
{
$file = substr($file, 0, -(strlen($type) + 1));
}
}
$class = '\\Config_'.ucfirst($type);
if ( ! class_exists($class))
{
throw new \FuelException(sprintf('Invalid config type "%s".', $type));
}
$driver = new $class($file);
return $driver->save($config);
}
/**
* Returns a (dot notated) config setting
*
* @param string $item name of the config item, can be dot notated
* @param mixed $default the return value if the item isn't found
* @return mixed the config setting or default if not found
*/
public static function get($item, $default = null)
{
if (array_key_exists($item, static::$items))
{
return static::$items[$item];
}
elseif ( ! array_key_exists($item, static::$itemcache))
{
// cook up something unique
$miss = new \stdClass();
$val = \Arr::get(static::$items, $item, $miss);
// so we can detect a miss here...
if ($val === $miss)
{
return $default;
}
static::$itemcache[$item] = $val;
}
return \Fuel::value(static::$itemcache[$item]);
}
/**
* Sets a (dot notated) config item
*
* @param string $item a (dot notated) config key
* @param mixed $value the config value
*/
public static function set($item, $value)
{
strpos($item, '.') === false or static::$itemcache[$item] = $value;
\Arr::set(static::$items, $item, $value);
}
/**
* Deletes a (dot notated) config item
*
* @param string $item a (dot notated) config key
* @return array|bool the \Arr::delete result, success boolean or array of success booleans
*/
public static function delete($item)
{
if (isset(static::$itemcache[$item]))
{
unset(static::$itemcache[$item]);
}
return \Arr::delete(static::$items, $item);
}
}

@ -1,158 +0,0 @@
<?php
namespace Fuel\Core;
/**
* DB config data parser
*/
class Config_Db implements Config_Interface
{
protected $identifier;
protected $ext = '.db';
protected $vars = array();
protected $database;
protected $table;
/**
* Sets up the file to be parsed and variables
*
* @param string $identifier Config identifier name
* @param array $vars Variables to parse in the data retrieved
*/
public function __construct($identifier = null, $vars = array())
{
$this->identifier = $identifier;
$this->vars = array(
'APPPATH' => APPPATH,
'COREPATH' => COREPATH,
'PKGPATH' => PKGPATH,
'DOCROOT' => DOCROOT,
) + $vars;
$this->database = \Config::get('config.database', null);
$this->table = \Config::get('config.table_name', 'config');
}
/**
* Loads the config file(s).
*
* @param bool $overwrite Whether to overwrite existing values
* @param bool $cache This parameter will ignore in this implement.
* @return array the config array
* @throws \Database_Exception
*/
public function load($overwrite = false, $cache = true)
{
$config = array();
// try to retrieve the config from the database
try
{
$result = \DB::select('config')->from($this->table)->where('identifier', '=', $this->identifier)->execute($this->database);
}
catch (Database_Exception $e)
{
// strip the actual query from the message
$msg = $e->getMessage();
$msg = substr($msg, 0, strlen($msg) - strlen(strrchr($msg, ':')));
// and rethrow it
throw new \Database_Exception($msg);
}
// did we succeed?
if ($result->count())
{
empty($result[0]['config']) or $config = unserialize($this->parse_vars($result[0]['config']));
}
return $config;
}
/**
* Gets the default group name.
*
* @return string
*/
public function group()
{
return $this->identifier;
}
/**
* Parses a string using all of the previously set variables. Allows you to
* use something like %APPPATH% in non-PHP files.
*
* @param string $string String to parse
* @return string
*/
protected function parse_vars($string)
{
foreach ($this->vars as $var => $val)
{
$string = str_replace("%$var%", $val, $string);
}
return $string;
}
/**
* Replaces FuelPHP's path constants to their string counterparts.
*
* @param array $array array to be prepped
* @return array prepped array
*/
protected function prep_vars(&$array)
{
static $replacements = false;
if ($replacements === false)
{
foreach ($this->vars as $i => $v)
{
$replacements['#^('.preg_quote($v).'){1}(.*)?#'] = "%".$i."%$2";
}
}
foreach ($array as $i => $value)
{
if (is_string($value))
{
$array[$i] = preg_replace(array_keys($replacements), array_values($replacements), $value);
}
elseif(is_array($value))
{
$this->prep_vars($array[$i]);
}
}
}
/**
* Formats the output and saved it to disc.
*
* @param $contents $contents config array to save
* @return bool DB result
*/
public function save($contents)
{
// prep the contents
$this->prep_vars($contents);
$contents = serialize($contents);
// update the config in the database
$result = \DB::update($this->table)->set(array('config' => $contents, 'hash' => uniqid()))->where('identifier', '=', $this->identifier)->execute($this->database);
// if there wasn't an update, do an insert
if ($result === 0)
{
list($notused, $result) = \DB::insert($this->table)->set(array('identifier' => $this->identifier, 'config' => $contents, 'hash' => uniqid()))->execute($this->database);
}
return $result === 1;
}
}

@ -1,227 +0,0 @@
<?php
namespace Fuel\Core;
/**
* A base Config File class for File based configs.
*/
abstract class Config_File implements Config_Interface
{
protected $file;
protected $vars = array();
/**
* Sets up the file to be parsed and variables
*
* @param string $file Config file name
* @param array $vars Variables to parse in the file
*/
public function __construct($file = null, $vars = array())
{
$this->file = $file;
$this->vars = array(
'APPPATH' => APPPATH,
'COREPATH' => COREPATH,
'PKGPATH' => PKGPATH,
'DOCROOT' => DOCROOT,
) + $vars;
}
/**
* Loads the config file(s).
*
* @param bool $overwrite Whether to overwrite existing values
* @param bool $cache Whether to cache this path or not
* @return array the config array
*/
public function load($overwrite = false, $cache = true)
{
$paths = $this->find_file($cache);
$config = array();
foreach ($paths as $path)
{
$config = $overwrite ?
array_merge($config, $this->load_file($path)) :
\Arr::merge($config, $this->load_file($path));
}
return $config;
}
/**
* Gets the default group name.
*
* @return string
*/
public function group()
{
return $this->file;
}
/**
* Parses a string using all of the previously set variables. Allows you to
* use something like %APPPATH% in non-PHP files.
*
* @param string $string String to parse
* @return string
*/
protected function parse_vars($string)
{
foreach ($this->vars as $var => $val)
{
$string = str_replace("%$var%", $val, $string);
}
return $string;
}
/**
* Replaces FuelPHP's path constants to their string counterparts.
*
* @param array $array array to be prepped
* @return array prepped array
*/
protected function prep_vars(&$array)
{
static $replacements = false;
if ($replacements === false)
{
foreach ($this->vars as $i => $v)
{
$replacements['#^('.preg_quote($v).'){1}(.*)?#'] = "%".$i."%$2";
}
}
foreach ($array as $i => $value)
{
if (is_string($value))
{
$array[$i] = preg_replace(array_keys($replacements), array_values($replacements), $value);
}
elseif(is_array($value))
{
$this->prep_vars($array[$i]);
}
}
}
/**
* Finds the given config files
*
* @param bool $cache Whether to cache this path or not
* @return array
* @throws \ConfigException
*/
protected function find_file($cache = true)
{
if (($this->file[0] === '/' or (isset($this->file[1]) and $this->file[1] === ':')) and is_file($this->file))
{
$paths = array($this->file);
}
else
{
$paths = array_merge(
\Finder::search('config/'.\Fuel::$env, $this->file, $this->ext, true, $cache),
\Finder::search('config', $this->file, $this->ext, true, $cache)
);
}
if (empty($paths))
{
throw new \ConfigException(sprintf('File "%s" does not exist.', $this->file));
}
return array_reverse($paths);
}
/**
* Formats the output and saved it to disc.
*
* @param array $contents config array to save
* @return bool \File::update result
*/
public function save($contents)
{
// get the formatted output
$output = $this->export_format($contents);
if ( ! $output)
{
return false;
}
if ( ! $path = \Finder::search('config', $this->file, $this->ext))
{
if ($pos = strripos($this->file, '::'))
{
// get the namespace path
if ($path = \Autoloader::namespace_path('\\'.ucfirst(substr($this->file, 0, $pos))))
{
// strip the namespace from the filename
$this->file = substr($this->file, $pos+2);
// strip the classes directory as we need the module root
$path = substr($path, 0, -8).'config'.DS.$this->file.$this->ext;
}
else
{
// invalid namespace requested
return false;
}
}
}
// absolute path requested?
if ($this->file[0] === '/' or (isset($this->file[1]) and $this->file[1] === ':'))
{
$path = $this->file;
}
// make sure we have a fallback
$path or $path = APPPATH.'config'.DS.$this->file.$this->ext;
$path = pathinfo($path);
if ( ! is_dir($path['dirname']))
{
mkdir($path['dirname'], 0777, true);
}
$return = \File::update($path['dirname'], $path['basename'], $output);
if ($return)
{
try
{
\Config::load('file', true);
chmod($path['dirname'].DS.$path['basename'], \Config::get('file.chmod.files', 0666));
}
catch (\PhpErrorException $e)
{
// if we get something else then a chmod error, bail out
if (substr($e->getMessage(), 0, 8) !== 'chmod():')
{
throw new $e;
}
}
}
return $return;
}
/**
* Must be implemented by child class. Gets called for each file to load.
*
* @param string $file the path to the file
*/
abstract protected function load_file($file);
/**
* Must be implemented by child class. Gets called when saving a config file.
*
* @param array $contents config array to save
* @return string formatted output
*/
abstract protected function export_format($contents);
}

@ -1,38 +0,0 @@
<?php
namespace Fuel\Core;
/**
* INI Config file parser
*/
class Config_Ini extends \Config_File
{
/**
* @var string the extension used by this ini file parser
*/
protected $ext = '.ini';
/**
* Loads in the given file and parses it.
*
* @param string $file File to load
* @return array
*/
protected function load_file($file)
{
$contents = $this->parse_vars(file_get_contents($file));
return parse_ini_string($contents, true);
}
/**
* Returns the formatted config file contents.
*
* @param array $contents config array
* @return string formatted config file contents
* @throws \ConfigException
*/
protected function export_format($contents)
{
throw new \ConfigException('Saving config to ini is not supported at this time');
}
}

@ -1,10 +0,0 @@
<?php
namespace Fuel\Core;
interface Config_Interface
{
public function load($overwrite = false);
public function group();
public function save($contents);
}

@ -1,38 +0,0 @@
<?php
namespace Fuel\Core;
/**
* JSON Config file parser
*/
class Config_Json extends \Config_File
{
/**
* @var string the extension used by this JSON file parser
*/
protected $ext = '.json';
/**
* Loads in the given file and parses it.
*
* @param string $file File to load
* @return array
*/
protected function load_file($file)
{
$contents = $this->parse_vars(file_get_contents($file));
return json_decode($contents, true);
}
/**
* Returns the formatted config file contents.
*
* @param array $contents config array
* @return string formatted config file contents
*/
protected function export_format($contents)
{
$this->prep_vars($contents);
return \Format::forge()->to_json($contents, true);
}
}

@ -1,174 +0,0 @@
<?php
namespace Fuel\Core;
/**
* DB config data parser
*/
class Config_Memcached implements Config_Interface
{
/**
* @var array of driver config defaults
*/
protected static $config = array(
'identifier' => 'config',
'servers' => array(
array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100),
),
);
/**
* @var \Memcached storage for the memcached object
*/
protected static $memcached = false;
/**
* driver initialisation
*
* @throws \FuelException
*/
public static function _init()
{
static::$config = array_merge(static::$config, \Config::get('config.memcached', array()));
if (static::$memcached === false)
{
// do we have the PHP memcached extension available
if ( ! class_exists('Memcached') )
{
throw new \FuelException('Memcached config storage is required, but your PHP installation doesn\'t have the Memcached extension loaded.');
}
// instantiate the memcached object
static::$memcached = new \Memcached();
// add the configured servers
static::$memcached->addServers(static::$config['servers']);
// check if we can connect to all the server(s)
$added = static::$memcached->getStats();
foreach (static::$config['servers'] as $server)
{
$server = $server['host'].':'.$server['port'];
if ( ! isset($added[$server]) or $added[$server]['pid'] == -1)
{
throw new \FuelException('Memcached config storage is required, but there is no connection possible. Check your configuration.');
}
}
}
}
// --------------------------------------------------------------------
protected $identifier;
protected $ext = '.mem';
protected $vars = array();
/**
* Sets up the file to be parsed and variables
*
* @param string $identifier Config identifier name
* @param array $vars Variables to parse in the data retrieved
*/
public function __construct($identifier = null, $vars = array())
{
$this->identifier = $identifier;
$this->vars = array(
'APPPATH' => APPPATH,
'COREPATH' => COREPATH,
'PKGPATH' => PKGPATH,
'DOCROOT' => DOCROOT,
) + $vars;
}
/**
* Loads the config file(s).
*
* @param bool $overwrite Whether to overwrite existing values
* @param bool $cache This parameter will ignore in this implement.
* @return array the config array
*/
public function load($overwrite = false, $cache = true)
{
// fetch the config data from the Memcached server
$result = static::$memcached->get(static::$config['identifier'].'_'.$this->identifier);
return $result === false ? array() : $result;
}
/**
* Gets the default group name.
*
* @return string
*/
public function group()
{
return $this->identifier;
}
/**
* Parses a string using all of the previously set variables. Allows you to
* use something like %APPPATH% in non-PHP files.
*
* @param string $string String to parse
* @return string
*/
protected function parse_vars($string)
{
foreach ($this->vars as $var => $val)
{
$string = str_replace("%$var%", $val, $string);
}
return $string;
}
/**
* Replaces FuelPHP's path constants to their string counterparts.
*
* @param array $array array to be prepped
* @return array prepped array
*/
protected function prep_vars(&$array)
{
static $replacements = false;
if ($replacements === false)
{
foreach ($this->vars as $i => $v)
{
$replacements['#^('.preg_quote($v).'){1}(.*)?#'] = "%".$i."%$2";
}
}
foreach ($array as $i => $value)
{
if (is_string($value))
{
$array[$i] = preg_replace(array_keys($replacements), array_values($replacements), $value);
}
elseif(is_array($value))
{
$this->prep_vars($array[$i]);
}
}
}
/**
* Formats the output and saved it to disc.
*
* @param $contents $contents config array to save
* @throws \FuelException
*/
public function save($contents)
{
// write it to the memcached server
if (static::$memcached->set(static::$config['identifier'].'_'.$this->identifier, $contents, 0) === false)
{
throw new \FuelException('Memcached returned error code "'.static::$memcached->getResultCode().'" on write. Check your configuration.');
}
}
}

@ -1,105 +0,0 @@
<?php
namespace Fuel\Core;
/**
* PHP Config file parser
*/
class Config_Php extends \Config_File
{
/**
* @var bool whether or not opcache is in use
*/
protected static $uses_opcache = false;
/**
* @var bool whether or not APC is in use
*/
protected static $uses_apc = false;
/**
* @var bool whether or not we need to flush the opcode cache after a save
*/
protected static $flush_needed = false;
/**
* check the status of any opcache mechanism in use
*/
public static function _init()
{
// do we have Opcache active?
static::$uses_opcache = (PHP_VERSION_ID >= 50500 and function_exists('opcache_invalidate'));
// do we have APC active?
static::$uses_apc = function_exists('apc_compile_file');
// determine if we have an opcode cache active
static::$flush_needed = static::$uses_opcache or static::$uses_apc;
}
/**
* @var string the extension used by this config file parser
*/
protected $ext = '.php';
/**
* Formats the output and saved it to disk.
*
* @param $contents $contents config array to save
* @return bool \File::update result
*/
public function save($contents)
{
// store the current filename
$file = $this->file;
// save it
$return = parent::save($contents);
// existing file? saved? and do we need to flush the opcode cache?
if ($file == $this->file and $return and static::$flush_needed)
{
if ($this->file[0] !== '/' and ( ! isset($this->file[1]) or $this->file[1] !== ':'))
{
// locate the file
$file = \Finder::search('config', $this->file, $this->ext);
}
// make sure we have a fallback
$file or $file = APPPATH.'config'.DS.$this->file.$this->ext;
// flush the opcode caches that are active
static::$uses_opcache and opcache_invalidate($file, true);
static::$uses_apc and apc_compile_file($file);
}
return $return;
}
/**
* Loads in the given file and parses it.
*
* @param string $file File to load
* @return array
*/
protected function load_file($file)
{
return \Fuel::load($file);
}
/**
* Returns the formatted config file contents.
*
* @param array $contents config array
* @return string formatted config file contents
*/
protected function export_format($contents)
{
$output = <<<CONF
<?php
CONF;
$output .= 'return '.str_replace(array('array ('.PHP_EOL, '\''.APPPATH, '\''.DOCROOT, '\''.COREPATH, '\''.PKGPATH), array('array('.PHP_EOL, 'APPPATH.\'', 'DOCROOT.\'', 'COREPATH.\'', 'PKGPATH.\''), var_export($contents, true)).";\n";
return $output;
}
}

@ -1,43 +0,0 @@
<?php
namespace Fuel\Core;
/**
* Yaml Config file parser
*/
class Config_Yml extends \Config_File
{
/**
* @var string the extension used by this yaml file parser
*/
protected $ext = '.yml';
/**
* Loads in the given file and parses it.
*
* @param string $file File to load
* @return array
*/
protected function load_file($file)
{
$contents = $this->parse_vars(file_get_contents($file));
return \Format::forge($contents, 'yaml')->to_array();
}
/**
* Returns the formatted config file contents.
*
* @param array $contents config array
* @return string formatted config file contents
*/
protected function export_format($contents)
{
if ( ! function_exists('spyc_load'))
{
import('spyc/spyc', 'vendor');
}
$this->prep_vars($contents);
return \Spyc::YAMLDump($contents);
}
}

@ -1,80 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
abstract class Controller
{
/**
* @var Request The current Request object
*/
public $request;
/**
* @var Integer The default response status
*/
public $response_status = 200;
/**
* Sets the controller request object.
*
* @param \Request $request The current request object
*/
public function __construct(\Request $request)
{
$this->request = $request;
}
/**
* This method gets called before the action is called
*/
public function before() {}
/**
* This method gets called after the action is called
* @param \Response|string $response
* @return \Response
*/
public function after($response)
{
// Make sure the $response is a Response object
if ( ! $response instanceof Response)
{
$response = \Response::forge($response, $this->response_status);
}
return $response;
}
/**
* This method returns the named parameter requested, or all of them
* if no parameter is given.
*
* @param string $param The name of the parameter
* @param mixed $default Default value
* @return mixed
*/
public function param($param, $default = null)
{
return $this->request->param($param, $default);
}
/**
* This method returns all of the named parameters.
*
* @return array
*/
public function params()
{
return $this->request->params();
}
}

@ -1,136 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Hybrid Controller class
*
* A base controller that combines both templated and REST output
*
* @package Fuel
* @category Core
* @author Fuel Development Team
*/
abstract class Controller_Hybrid extends \Controller_Rest
{
/**
* @var string page template
*/
public $template = 'template';
/**
* Load the template and create the $this->template object if needed
*/
public function before()
{
// setup the template if this isn't a RESTful call
if ( ! $this->is_restful())
{
if ( ! empty($this->template) and is_string($this->template))
{
// Load the template
$this->template = \View::forge($this->template);
}
}
return parent::before();
}
/**
* router
*
* this router will call action methods for normal requests,
* and REST methods for RESTful calls
*
* @param string $resource
* @param array $arguments
* @return mixed
* @throws \HttpNotFoundException
*/
public function router($resource, $arguments)
{
// if this is an ajax call
if ($this->is_restful())
{
// have the Controller_Rest router deal with it
return parent::router($resource, $arguments);
}
// check if a input specific method exists
$controller_method = strtolower(\Input::method()) . '_' . $resource;
// fall back to action_ if no rest method is provided
if ( ! method_exists($this, $controller_method))
{
$controller_method = 'action_'.$resource;
}
// check if the action method exists
if (method_exists($this, $controller_method))
{
return call_fuel_func_array(array($this, $controller_method), $arguments);
}
// if not, we got ourselfs a genuine 404!
throw new \HttpNotFoundException();
}
/**
* After controller method has run output the template
*
* @param Response $response
*/
public function after($response)
{
// return the template if no response is present and this isn't a RESTful call
if ( ! $this->is_restful())
{
// do we have a response passed?
if ($response === null)
{
// maybe one in the rest body?
$response = $this->response->body;
if ($response === null)
{
// fall back to the defined template
$response = $this->template;
}
}
// deal with returned array's in non-restful calls
elseif (is_array($response))
{
$response = \Format::forge()->to_json($response, true);
}
// and make sure we have a valid Response object
if ( ! $response instanceof Response)
{
$response = \Response::forge($response, $this->response_status);
}
}
return parent::after($response);
}
/**
* Decide whether to return RESTful or templated response
* Override in subclass to introduce custom switching logic.
*
* @param boolean
*/
public function is_restful()
{
return \Input::is_ajax();
}
}

@ -1,515 +0,0 @@
<?php
namespace Fuel\Core;
abstract class Controller_Rest extends \Controller
{
/**
* @var null|string Set this in a controller to use a default format
*/
protected $rest_format = null;
/**
* @var array contains a list of method properties such as limit, log and level
*/
protected $methods = array();
/**
* @var integer status code to return in case a not defined action is called
*/
protected $no_method_status = 405;
/**
* @var integer status code to return in case the called action doesn't return data
*/
protected $no_data_status = 204;
/**
* @var string authentication to be used for this controller
*/
protected $auth = null;
/**
* @var string the detected response format
*/
protected $format = null;
/**
* @var integer default response http status
*/
protected $http_status = 200;
/**
* @var string xml basenode name
*/
protected $xml_basenode = null;
/**
* @var array List all supported methods
*/
protected $_supported_formats = array(
'xml' => 'application/xml',
'rawxml' => 'application/xml',
'json' => 'application/json',
'jsonp'=> 'text/javascript',
'serialized' => 'application/vnd.php.serialized',
'php' => 'text/plain',
'html' => 'text/html',
'csv' => 'application/csv',
);
public function before()
{
parent::before();
// Some Methods cant have a body
$this->request->body = null;
// Which format should the data be returned in?
$this->request->lang = $this->_detect_lang();
$this->response = \Response::forge();
}
public function after($response)
{
// If the response is an array
if (is_array($response))
{
// set the response
$response = $this->response($response);
}
// If the response is a Response object, we will use their
// instead of ours.
if ( ! $response instanceof \Response)
{
$response = $this->response;
}
return parent::after($response);
}
/**
* Router
*
* Requests are not made to methods directly The request will be for an "object".
* this simply maps the object and method to the correct Controller method.
*
* @param string $resource
* @param array $arguments
* @return bool|mixed
*/
public function router($resource, $arguments)
{
\Config::load('rest', true);
// If no (or an invalid) format is given, auto detect the format
if (is_null($this->format) or ! array_key_exists($this->format, $this->_supported_formats))
{
// auto-detect the format
$this->format = array_key_exists(\Input::extension(), $this->_supported_formats) ? \Input::extension() : $this->_detect_format();
}
// Get the configured auth method if none is defined
$this->auth === null and $this->auth = \Config::get('rest.auth');
//Check method is authorized if required, and if we're authorized
if ($this->auth == 'basic')
{
$valid_login = $this->_prepare_basic_auth();
}
elseif ($this->auth == 'digest')
{
$valid_login = $this->_prepare_digest_auth();
}
elseif (method_exists($this, $this->auth))
{
if (($valid_login = $this->{$this->auth}()) instanceOf \Response)
{
return $valid_login;
}
}
else
{
$valid_login = false;
}
//If the request passes auth then execute as normal
if(empty($this->auth) or $valid_login)
{
// If they call user, go to $this->post_user();
$controller_method = strtolower(\Input::method()) . '_' . $resource;
// Fall back to action_ if no rest method is provided
if ( ! method_exists($this, $controller_method))
{
$controller_method = 'action_'.$resource;
}
// If method is not available, set status code to 404
if (method_exists($this, $controller_method))
{
return call_fuel_func_array(array($this, $controller_method), $arguments);
}
else
{
$this->response->status = $this->no_method_status;
return;
}
}
else
{
$this->response(array('status'=> 0, 'error'=> 'Not Authorized'), 401);
}
}
/**
* Response
*
* Takes pure data and optionally a status code, then creates the response
*
* @param mixed
* @param int
* @return object Response instance
*/
protected function response($data = array(), $http_status = null)
{
// set the correct response header
if (method_exists('Format', 'to_'.$this->format))
{
$this->response->set_header('Content-Type', $this->_supported_formats[$this->format]);
}
// no data returned?
if ((is_array($data) and empty($data)) or ($data == ''))
{
// override the http status with the NO CONTENT status
$http_status = $this->no_data_status;
}
// make sure we have a valid return status
$http_status or $http_status = $this->http_status;
// If the format method exists, call and return the output in that format
if (method_exists('Format', 'to_'.$this->format))
{
// Handle XML output
if ($this->format === 'xml')
{
// Detect basenode
$xml_basenode = $this->xml_basenode;
$xml_basenode or $xml_basenode = \Config::get('rest.xml_basenode', 'xml');
// Set the XML response
$this->response->body(\Format::forge($data)->{'to_'.$this->format}(null, null, $xml_basenode));
}
else
{
// Set the formatted response
$this->response->body(\Format::forge($data)->{'to_'.$this->format}());
}
}
// Format not supported, but the output is an array or an object that can not be cast to string
elseif (is_array($data) or (is_object($data) and ! method_exists($data, '__toString')))
{
if (\Fuel::$env == \Fuel::PRODUCTION)
{
// not acceptable in production
if ($http_status == 200)
{ $http_status = 406;
}
$this->response->body('The requested REST method returned an array or object, which is not compatible with the output format "'.$this->format.'"');
}
else
{
// convert it to json so we can at least read it while we're developing
$this->response->body('The requested REST method returned an array or object:<br /><br />'.\Format::forge($data)->to_json(null, true));
}
}
// Format not supported, output directly
else
{
$this->response->body($data);
}
// Set the reponse http status
$http_status and $this->response->status = $http_status;
return $this->response;
}
/**
* Set the Response http status.
*
* @param integer $status response http status code
* @return void
*/
protected function http_status($status)
{
$this->http_status = $status;
}
/**
* Detect format
*
* Detect which format should be used to output the data
*
* @return string
*/
protected function _detect_format()
{
// A format has been passed as a named parameter in the route
if ($this->param('format') and array_key_exists($this->param('format'), $this->_supported_formats))
{
return $this->param('format');
}
// A format has been passed as an argument in the URL and it is supported
if (\Input::param('format') and array_key_exists(\Input::param('format'), $this->_supported_formats))
{
return \Input::param('format');
}
// Otherwise, check the HTTP_ACCEPT (if it exists and we are allowed)
if ($acceptable = \Input::server('HTTP_ACCEPT') and \Config::get('rest.ignore_http_accept') !== true)
{
// If anything is accepted, and we have a default, return that
if ($acceptable == '*/*' and ! empty($this->rest_format))
{
return $this->rest_format;
}
// Split the Accept header and build an array of quality scores for each format
$fragments = new \CachingIterator(new \ArrayIterator(preg_split('/[,;]/', \Input::server('HTTP_ACCEPT'))));
$acceptable = array();
$next_is_quality = false;
foreach ($fragments as $fragment)
{
$quality = 1;
// Skip the fragment if it is a quality score
if ($next_is_quality)
{
$next_is_quality = false;
continue;
}
// If next fragment exists and is a quality score, set the quality score
elseif ($fragments->hasNext())
{
$next = $fragments->getInnerIterator()->current();
if (strpos($next, 'q=') === 0)
{
list($key, $quality) = explode('=', $next);
$next_is_quality = true;
}
}
$acceptable[$fragment] = $quality;
}
// Sort the formats by score in descending order
uasort($acceptable, function($a, $b)
{
$a = (float) $a;
$b = (float) $b;
return ($a > $b) ? -1 : 1;
});
// Check each of the acceptable formats against the supported formats
$find = array('\*', '/');
$replace = array('.*', '\/');
foreach ($acceptable as $pattern => $quality)
{
// The Accept header can contain wildcards in the format
$pattern = '/^' . str_replace($find, $replace, preg_quote($pattern)) . '$/';
foreach ($this->_supported_formats as $format => $mime)
{
if (preg_match($pattern, $mime))
{
return $format;
}
}
}
} // End HTTP_ACCEPT checking
// Well, none of that has worked! Let's see if the controller has a default
if ( ! empty($this->rest_format))
{
return $this->rest_format;
}
// Just use the default format
return \Config::get('rest.default_format');
}
/**
* Detect language(s)
*
* What language do they want it in?
*
* @return null|array|string
*/
protected function _detect_lang()
{
if (!$lang = \Input::server('HTTP_ACCEPT_LANGUAGE'))
{
return null;
}
// They might have sent a few, make it an array
if (strpos($lang, ',') !== false)
{
$langs = explode(',', $lang);
$return_langs = array();
foreach ($langs as $lang)
{
// Remove weight and strip space
list($lang) = explode(';', $lang);
$return_langs[] = trim($lang);
}
return $return_langs;
}
// Nope, just return the string
return $lang;
}
// SECURITY FUNCTIONS ---------------------------------------------------------
protected function _check_login($username = '', $password = null)
{
if (empty($username))
{
return false;
}
$valid_logins = \Config::get('rest.valid_logins');
if (!array_key_exists($username, $valid_logins))
{
return false;
}
// If actually null (not empty string) then do not check it
if ($password !== null and $valid_logins[$username] != $password)
{
return false;
}
return true;
}
protected function _prepare_basic_auth()
{
$username = null;
$password = null;
// mod_php
if (\Input::server('PHP_AUTH_USER'))
{
$username = \Input::server('PHP_AUTH_USER');
$password = \Input::server('PHP_AUTH_PW');
}
// most other servers
elseif (\Input::server('HTTP_AUTHENTICATION'))
{
if (strpos(strtolower(\Input::server('HTTP_AUTHENTICATION')), 'basic') === 0)
{
list($username, $password) = explode(':', base64_decode(substr(\Input::server('HTTP_AUTHORIZATION'), 6)));
}
}
if ( ! static::_check_login($username, $password))
{
static::_force_login();
return false;
}
return true;
}
protected function _prepare_digest_auth()
{
// Empty argument for backward compatibility
$uniqid = uniqid("");
// We need to test which server authentication variable to use
// because the PHP ISAPI module in IIS acts different from CGI
if (\Input::server('PHP_AUTH_DIGEST'))
{
$digest_string = \Input::server('PHP_AUTH_DIGEST');
}
elseif (\Input::server('HTTP_AUTHORIZATION'))
{
$digest_string = \Input::server('HTTP_AUTHORIZATION');
}
else
{
$digest_string = '';
}
// Prompt for authentication if we don't have a digest string
if (empty($digest_string))
{
static::_force_login($uniqid);
return false;
}
// We need to retrieve authentication informations from the $digest_string variable
$digest_params = explode(', ', $digest_string);
foreach ($digest_params as $digest_param)
{
$digest_param = explode('=', $digest_param, 2);
if (isset($digest_param[1]))
{
$digest[$digest_param[0]] = trim($digest_param[1], '"');
}
}
// if no username, or an invalid username found, re-authenticate
if ( ! array_key_exists('username', $digest) or ! static::_check_login($digest['username']))
{
static::_force_login($uniqid);
return false;
}
// validate the configured login/password
$valid_logins = \Config::get('rest.valid_logins');
$valid_pass = $valid_logins[$digest['username']];
// This is the valid response expected
$A1 = md5($digest['username'] . ':' . \Config::get('rest.realm') . ':' . $valid_pass);
$A2 = md5(strtoupper(\Input::method()) . ':' . $digest['uri']);
$valid_response = md5($A1 . ':' . $digest['nonce'] . ':' . $digest['nc'] . ':' . $digest['cnonce'] . ':' . $digest['qop'] . ':' . $A2);
if ($digest['response'] != $valid_response)
{
return false;
}
return true;
}
protected function _force_login($nonce = '')
{
// Get the configured auth method if none is defined
$this->auth === null and $this->auth = \Config::get('rest.auth');
if ($this->auth == 'basic')
{
$this->response->set_header('WWW-Authenticate', 'Basic realm="'. \Config::get('rest.realm') . '"');
}
elseif ($this->auth == 'digest')
{
$this->response->set_header('WWW-Authenticate', 'Digest realm="' . \Config::get('rest.realm') . '", qop="auth", nonce="' . $nonce . '", opaque="' . md5(\Config::get('rest.realm')) . '"');
}
}
}

@ -1,61 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Template Controller class
*
* A base controller for easily creating templated output.
*
* @package Fuel
* @category Core
* @author Fuel Development Team
*/
abstract class Controller_Template extends \Controller
{
/**
* @var string page template
*/
public $template = 'template';
/**
* Load the template and create the $this->template object
*/
public function before()
{
if ( ! empty($this->template) and is_string($this->template))
{
// Load the template
$this->template = \View::forge($this->template);
}
return parent::before();
}
/**
* After controller method has run output the template
*
* @param Response $response
*/
public function after($response)
{
// If nothing was returned default to the template
if ($response === null)
{
$response = $this->template;
}
return parent::after($response);
}
}

@ -1,124 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Cookie class
*
* @package Fuel
* @category Helpers
* @author Kohana Team
* @modified Fuel Development Team
* @copyright (c) 2008-2010 Kohana Team
* @license http://kohanaframework.org/license
* @link http://docs.fuelphp.com/classes/cookie.html
*/
class Cookie
{
/**
* @var array Cookie class configuration defaults
*/
protected static $config = array(
'expiration' => 0,
'path' => '/',
'domain' => null,
'secure' => false,
'http_only' => false,
);
/*
* initialisation and auto configuration
*/
public static function _init()
{
static::$config = array_merge(static::$config, \Config::get('cookie', array()));
}
/**
* 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 $name cookie name
* @param mixed $default default value to return
* @return string
*/
public static function get($name = null, $default = null)
{
return \Input::cookie($name, $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
* @param string $path path of the cookie
* @param string $domain domain of the cookie
* @param boolean $secure if true, the cookie should only be transmitted over a secure HTTPS connection
* @param boolean $http_only if true, the cookie will be made accessible only through the HTTP protocol
* @return boolean
*/
public static function set($name, $value, $expiration = null, $path = null, $domain = null, $secure = null, $http_only = null)
{
// you can't set cookies in CLi mode
if (\Fuel::$is_cli)
{
return false;
}
$value = \Fuel::value($value);
// use the class defaults for the other parameters if not provided
is_null($expiration) and $expiration = static::$config['expiration'];
is_null($path) and $path = static::$config['path'];
is_null($domain) and $domain = static::$config['domain'];
is_null($secure) and $secure = static::$config['secure'];
is_null($http_only) and $http_only = static::$config['http_only'];
// add the current time so we have an offset
$expiration = $expiration > 0 ? $expiration + time() : 0;
return setcookie($name, $value, $expiration, $path, $domain, $secure, $http_only);
}
/**
* Deletes a cookie by making the value null and expiring it.
*
* Cookie::delete('theme');
*
* @param string $name cookie name
* @param string $path path of the cookie
* @param string $domain domain of the cookie
* @param boolean $secure if true, the cookie should only be transmitted over a secure HTTPS connection
* @param boolean $http_only if true, the cookie will be made accessible only through the HTTP protocol
* @return boolean
* @uses static::set
*/
public static function delete($name, $path = null, $domain = null, $secure = null, $http_only = null)
{
// Remove the cookie
unset($_COOKIE[$name]);
// Nullify the cookie and make it expire
return static::set($name, null, -86400, $path, $domain, $secure, $http_only);
}
}

@ -1,332 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
use \phpseclib\Crypt\AES;
use \phpseclib\Crypt\Hash;
class Crypt
{
/**
* Crypto default configuration
*
* @var array
*/
protected static $defaults = array();
/**
* Defined Crypto instances
*
* @var array
*/
protected static $_instances = array();
/**
* initialisation and auto configuration
*/
public static function _init()
{
// load the config
\Config::load('crypt', true);
static::$defaults = \Config::get('crypt', array());
// generate random crypto keys if we don't have them or they are incorrect length
$update = false;
foreach(array('crypto_key', 'crypto_iv', 'crypto_hmac') as $key)
{
if ( empty(static::$defaults[$key]) or (strlen(static::$defaults[$key]) % 4) != 0)
{
$crypto = '';
for ($i = 0; $i < 8; $i++)
{
$crypto .= static::safe_b64encode(pack('n', mt_rand(0, 0xFFFF)));
}
static::$defaults[$key] = $crypto;
$update = true;
}
}
// update the config if needed
if ($update === true)
{
try
{
\Config::save('crypt', static::$defaults);
}
catch (\FileAccessException $e)
{
// failed to write the config file, inform the user
echo \View::forge('errors/crypt_keys', array(
'keys' => static::$defaults,
));
die();
}
}
}
/**
* forge
*
* create a new named instance
*
* @param string $name instance name
* @param array $config optional runtime configuration
* @return \Crypt
*/
public static function forge($name = '__default__', array $config = array())
{
if ( ! array_key_exists($name, static::$_instances))
{
static::$_instances[$name] = new static($config);
}
return static::$_instances[$name];
}
/**
* Return a specific named instance
*
* @param string $name instance name
* @return mixed Crypt if the instance exists, false if not
*/
public static function instance($name = '__default__')
{
if ( ! array_key_exists($name, static::$_instances))
{
return static::forge($name);
}
return static::$_instances[$name];
}
/**
* capture static calls to methods
*
* @param mixed $method
* @param array $args The arguments will passed to $method.
* @return mixed return value of $method.
*/
public static function __callstatic($method, $args)
{
// static method calls are called on the default instance
return call_user_func_array(array(static::instance(), $method), $args);
}
// --------------------------------------------------------------------
/**
* generate a URI safe base64 encoded string
*
* @param string $value
* @return string
*/
protected static function safe_b64encode($value)
{
$data = base64_encode($value);
$data = str_replace(array('+', '/', '='), array('-', '_', ''), $data);
return $data;
}
/**
* decode a URI safe base64 encoded string
*
* @param string $value
* @return string
*/
protected static function safe_b64decode($value)
{
$data = str_replace(array('-', '_'), array('+', '/'), $value);
$mod4 = strlen($data) % 4;
if ($mod4)
{
$data .= substr('====', $mod4);
}
return base64_decode($data);
}
/**
* compare two strings in a timing-insensitive way to prevent time-based attacks
*
* @param string $a
* @param string $b
* @return bool
*/
protected static function secure_compare($a, $b)
{
// make sure we're only comparing equal length strings
if (strlen($a) !== strlen($b))
{
return false;
}
// and that all comparisons take equal time
$result = 0;
for ($i = 0; $i < strlen($a); $i++)
{
$result |= ord($a[$i]) ^ ord($b[$i]);
}
return $result === 0;
}
// --------------------------------------------------------------------
/**
* Crypto object used to encrypt/decrypt
*
* @var object
*/
protected $crypter = null;
/**
* Hash object used to generate hashes
*
* @var object
*/
protected $hasher = null;
/**
* Crypto configuration
*
* @var array
*/
protected $config = array();
/**
* Class constructor
*
* @param array $config
*/
public function __construct(array $config = array())
{
$this->config = array_merge(static::$defaults, $config);
$this->crypter = new AES();
$this->hasher = new Hash('sha256');
$this->crypter->enableContinuousBuffer();
$this->hasher->setKey(static::safe_b64decode($this->config['crypto_hmac']));
}
/**
* encrypt a string value, optionally with a custom key
*
* @param string $value value to encrypt
* @param string|bool $key optional custom key to be used for this encryption
* @param int|bool $keylength optional key length
* @return string encrypted value
*/
protected function encode($value, $key = false, $keylength = false)
{
if ( ! $key)
{
$key = static::safe_b64decode($this->config['crypto_key']);
// Used for backwards compatibility with encrypted data prior
// to FuelPHP 1.7.2, when phpseclib was updated, and became a
// bit smarter about figuring out key lengths.
$keylength = 128;
}
if ($keylength)
{
$this->crypter->setKeyLength($keylength);
}
$this->crypter->setKey($key);
$this->crypter->setIV(static::safe_b64decode($this->config['crypto_iv']));
$value = $this->crypter->encrypt($value);
return static::safe_b64encode($this->add_hmac($value));
}
/**
* capture calls to normal methods
*
* @param mixed $method
* @param array $args The arguments will passed to $method.
* @return mixed return value of $method.
* @throws \ErrorException
*/
public function __call($method, $args)
{
// validate the method called
if ( ! in_array($method, array('encode', 'decode')))
{
throw new \ErrorException('Call to undefined method '.__CLASS__.'::'.$method.'()', E_ERROR, 0, __FILE__, __LINE__);
}
// static method calls are called on the default instance
return call_user_func_array(array($this, $method), $args);
}
/**
* decrypt a string value, optionally with a custom key
*
* @param string $value value to decrypt
* @param string|bool $key optional custom key to be used for this encryption
* @param int|bool $keylength optional key length
* @access public
* @return string encrypted value
*/
protected function decode($value, $key = false, $keylength = false)
{
if ( ! $key)
{
$key = static::safe_b64decode($this->config['crypto_key']);
// Used for backwards compatibility with encrypted data prior
// to FuelPHP 1.7.2, when phpseclib was updated, and became a
// bit smarter about figuring out key lengths.
$keylength = 128;
}
if ($keylength)
{
$this->crypter->setKeyLength($keylength);
}
$this->crypter->setKey($key);
$this->crypter->setIV(static::safe_b64decode($this->config['crypto_iv']));
$value = static::safe_b64decode($value);
if ($value = $this->validate_hmac($value))
{
return $this->crypter->decrypt($value);
}
else
{
return false;
}
}
protected function add_hmac($value)
{
// calculate the hmac-sha256 hash of this value
$hmac = static::safe_b64encode($this->hasher->hash($value));
// append it and return the hmac protected string
return $value.$hmac;
}
protected function validate_hmac($value)
{
// strip the hmac-sha256 hash from the value
$hmac = substr($value, strlen($value)-43);
// and remove it from the value
$value = substr($value, 0, strlen($value)-43);
// only return the value if it wasn't tampered with
return (static::secure_compare(static::safe_b64encode($this->hasher->hash($value)), $hmac)) ? $value : false;
}
}

File diff suppressed because it is too large Load Diff

@ -1,154 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @author cocteau666@gmail.com
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_Dblib_Connection extends \Database_PDO_Connection
{
/**
* Stores the database configuration locally and name the instance.
*
* [!!] This method cannot be accessed directly, you must use [static::instance].
*
* @param string $name
* @param array $config
*/
protected function __construct($name, array $config)
{
// this driver only works on Windows
if (php_uname('s') === 'Windows')
{
throw new \Database_Exception('The "Dblib" database driver does not work well on Windows. Use the "Sqlsrv" driver instead.');
}
parent::__construct($name, $config);
}
/**
* List tables
*
* @param string $like
*
* @throws \FuelException
*/
public function list_tables($like = null)
{
$query = "SELECT name FROM sys.objects WHERE type = 'U' AND name != 'sysdiagrams'";
if (is_string($like))
{
$query .= " AND name LIKE ".$this->quote($like);
}
// Find all table names
$result = $this->query(\DB::SELECT, $query, false);
$tables = array();
foreach ($result as $row)
{
$tables[] = reset($row);
}
return $tables;
}
/**
* List table columns
*
* @param string $table table name
* @param string $like column name pattern
* @return array array of column structure
*/
public function list_columns($table, $like = null)
{
$query = "SELECT * FROM Sys.Columns WHERE id = object_id('" . $this->quote_table($table) . "')";
if (is_string($like))
{
// Search for column names
$query .= " AND name LIKE ".$this->quote($like);
}
// Find all column names
$result = $this->query(\DB::SELECT, $query, false);
$count = 0;
$columns = array();
foreach ($result as $row)
{
list($type, $length) = $this->_parse_type($row['Type']);
$column = $this->datatype($type);
$column['name'] = $row['Field'];
$column['default'] = $row['Default'];
$column['data_type'] = $type;
$column['null'] = ($row['Null'] == 'YES');
$column['ordinal_position'] = ++$count;
switch ($column['type'])
{
case 'float':
if (isset($length))
{
list($column['numeric_precision'], $column['numeric_scale']) = explode(',', $length);
}
break;
case 'int':
if (isset($length))
{
$column['display'] = $length;
}
break;
case 'string':
switch ($column['data_type'])
{
case 'binary':
case 'varbinary':
$column['character_maximum_length'] = $length;
break;
case 'char':
case 'varchar':
$column['character_maximum_length'] = $length;
case 'text':
case 'tinytext':
case 'mediumtext':
case 'longtext':
$column['collation_name'] = $row['Collation'];
break;
case 'enum':
case 'set':
$column['collation_name'] = $row['Collation'];
$column['options'] = explode('\',\'', substr($length, 1, -1));
break;
}
break;
}
$column['comment'] = $row['Comment'];
$column['extra'] = $row['Extra'];
$column['key'] = $row['Key'];
$column['privileges'] = $row['Privileges'];
$columns[$row['Field']] = $column;
}
return $columns;
}
/**
* Set the charset
*
* @param string $charset
*/
public function set_charset($charset)
{
// does not support charsets
}
}

@ -1,16 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_Exception extends \FuelException {}

@ -1,59 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_Expression
{
// Raw expression string
protected $_value;
/**
* Sets the expression string.
*
* $expression = new Database_Expression('COUNT(users.id)');
*
* @param string $value expression string
*/
public function __construct($value)
{
// Set the expression string
$this->_value = $value;
}
/**
* Get the expression value as a string.
*
* $sql = $expression->value();
*
* @return string
*/
public function value()
{
return (string) $this->_value;
}
/**
* Return the value of the expression as a string.
*
* echo $expression;
*
* @return string
* @uses Database_Expression::value
*/
public function __toString()
{
return $this->value();
}
}

@ -1,70 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_MySQL_Connection extends \Database_PDO_Connection
{
/**
* List tables
*
* @param string $like
*
* @throws \FuelException
*/
public function list_tables($like = null)
{
$query = 'SHOW TABLES';
if (is_string($like))
{
$query .= ' LIKE ' . $this->quote($like);
}
$q = $this->_connection->prepare($query);
$q->execute();
$result = $q->fetchAll();
$tables = array();
foreach ($result as $row)
{
$tables[] = reset($row);
}
return $tables;
}
/**
* Create a new PDO instance
*
* @return PDO
*/
protected function _connect()
{
// enable compression if needed
if ($this->_config['connection']['compress'])
{
// use client compression with mysql or mysqli (doesn't work with mysqlnd)
$this->_config['attrs'][\PDO::MYSQL_ATTR_COMPRESS] = true;
}
// add the charset to the DSN if needed
if ($this->_config['charset'] and strpos($this->_config['connection']['dsn'], ';charset=') === false)
{
$config['dsn'] .= ';charset='.$this->_config['charset'];
}
// create the PDO instance
parent::_connect();
}
}

@ -1,582 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_MySQLi_Connection extends \Database_Connection
{
/**
* @var \MySQLi Raw server connection
*/
protected $_connection;
/**
* @var array Database in use by each connection
*/
protected static $_current_databases = array();
/**
* @var bool Use SET NAMES to set the character set
*/
protected static $_set_names;
/**
* @var string Identifier for this connection within the PHP driver
*/
protected $_connection_id;
/**
* @var string MySQL uses a backtick for identifiers
*/
protected $_identifier = '`';
/**
* @var string Which kind of DB is used
*/
public $_db_type = 'mysql';
public function connect()
{
if ($this->_connection)
{
return;
}
if (static::$_set_names === null)
{
// Determine if we can use mysqli_set_charset(), which is only
// available on PHP 5.2.3+ when compiled against MySQL 5.0+
static::$_set_names = ! function_exists('mysqli_set_charset');
}
// Extract the connection parameters, adding required variables
extract($this->_config['connection'] + array(
'database' => '',
'hostname' => '',
'port' => '',
'socket' => '',
'username' => '',
'password' => '',
'persistent' => false,
'compress' => true,
));
try
{
if ($socket != '')
{
$port = null;
}
elseif ($port != '')
{
$socket = null;
}
else
{
$socket = null;
$port = null;
}
if ($persistent)
{
// Create a persistent connection
if ($compress)
{
$mysqli = mysqli_init();
$mysqli->real_connect('p:'.$hostname, $username, $password, $database, $port, $socket, MYSQLI_CLIENT_COMPRESS);
$this->_connection = $mysqli;
}
else
{
$this->_connection = new \MySQLi('p:'.$hostname, $username, $password, $database, $port, $socket);
}
}
else
{
// Create a connection and force it to be a new link
if ($compress)
{
$mysqli = mysqli_init();
$mysqli->real_connect($hostname, $username, $password, $database, $port, $socket, MYSQLI_CLIENT_COMPRESS);
$this->_connection = $mysqli;
}
else
{
$this->_connection = new \MySQLi($hostname, $username, $password, $database, $port, $socket);
}
}
if ($this->_connection->error)
{
// Unable to connect, select database, etc
throw new \Database_Exception(str_replace($password, str_repeat('*', 10), $this->_connection->error), $this->_connection->errno);
}
}
catch (\ErrorException $e)
{
// No connection exists
$this->_connection = null;
$error_code = is_numeric($e->getCode()) ? $e->getCode() : 0;
throw new \Database_Exception(str_replace($password, str_repeat('*', 10), $e->getMessage()), $error_code, $e);
}
// \xFF is a better delimiter, but the PHP driver uses underscore
$this->_connection_id = sha1($hostname.'_'.$username.'_'.$password);
if ( ! empty($this->_config['charset']))
{
// Set the character set
$this->set_charset($this->_config['charset']);
}
static::$_current_databases[$this->_connection_id] = $database;
}
/**
* Select the database
*
* @param string Database
* @return void
*/
protected function _select_db($database)
{
if ($this->_config['connection']['database'] !== static::$_current_databases[$this->_connection_id])
{
if ($this->_connection->select_db($database) !== true)
{
// Unable to select database
throw new \Database_Exception($this->_connection->error, $this->_connection->errno);
}
}
static::$_current_databases[$this->_connection_id] = $database;
}
/**
* Disconnect from the database
*
* @throws \Exception when the mysql database is not disconnected properly
*/
public function disconnect()
{
try
{
// Database is assumed disconnected
$status = true;
if ($this->_connection instanceof \MySQLi)
{
if ($status = $this->_connection->close())
{
// clear the connection
$this->_connection = null;
// and reset the savepoint depth
$this->_transaction_depth = 0;
}
}
}
catch (\Exception $e)
{
// Database is probably not disconnected
$status = ! ($this->_connection instanceof \MySQLi);
}
return $status;
}
public function set_charset($charset)
{
// Make sure the database is connected
$this->_connection or $this->connect();
$status = $this->_connection->set_charset($charset);
if ($status === false)
{
throw new \Database_Exception($this->_connection->error, $this->_connection->errno);
}
}
/**
* Execute query
*
* @param integer $type query type (\DB::SELECT, \DB::INSERT, etc.)
* @param string $sql SQL string
* @param mixed $as_object used when query type is SELECT
*
* @throws \Database_Exception
*
* @return mixed when SELECT then return an iterator of results,<br>
* when UPDATE then return a list of insert id and rows created,<br>
* in other case return the number of rows affected
*/
public function query($type, $sql, $as_object)
{
// Make sure the database is connected
if ($this->_connection)
{
// Make sure the connection is still alive
if ( ! $this->_connection->ping())
{
throw new \Database_Exception($this->_connection->error.' [ '.$sql.' ]', $this->_connection->errno);
}
}
else
{
$this->connect();
}
if ( ! empty($this->_config['profiling']))
{
// Get the paths defined in config
$paths = \Config::get('profiling_paths');
// Storage for the trace information
$stacktrace = array();
// Get the execution trace of this query
$include = false;
foreach (debug_backtrace() as $index => $page)
{
// Skip first entry and entries without a filename
if ($index > 0 and empty($page['file']) === false)
{
// Checks to see what paths you want backtrace
foreach($paths as $index => $path)
{
if (strpos($page['file'], $path) !== false)
{
$include = true;
break;
}
}
// Only log if no paths we defined, or we have a path match
if ($include or empty($paths))
{
$stacktrace[] = array('file' => \Fuel::clean_path($page['file']), 'line' => $page['line']);
}
}
}
$benchmark = \Profiler::start($this->_instance, $sql, $stacktrace);
}
if ( ! empty($this->_config['connection']['persistent']) and $this->_config['connection']['database'] !== static::$_current_databases[$this->_connection_id])
{
// Select database on persistent connections
$this->_select_db($this->_config['connection']['database']);
}
// Execute the query
if (($result = $this->_connection->query($sql)) === false)
{
if (isset($benchmark))
{
// This benchmark is worthless
\Profiler::delete($benchmark);
}
throw new \Database_Exception($this->_connection->error.' [ '.$sql.' ]', $this->_connection->errno);
}
// check for multiresults, we don't support those at the moment
while($this->_connection->more_results() and $this->_connection->next_result())
{
if ($more_result = $this->_connection->use_result())
{
throw new \Database_Exception('The MySQLi driver does not support multiple resultsets', 0);
}
}
if (isset($benchmark))
{
\Profiler::stop($benchmark);
}
// Set the last query
$this->last_query = $sql;
if ($type === \DB::SELECT)
{
// Return an iterator of results
return new \Database_MySQLi_Result($result, $sql, $as_object);
}
elseif ($type === \DB::INSERT)
{
// Return a list of insert id and rows created
return array(
$this->_connection->insert_id,
$this->_connection->affected_rows,
);
}
elseif ($type === \DB::UPDATE or $type === \DB::DELETE)
{
// Return the number of rows affected
return $this->_connection->affected_rows;
}
return $result;
}
public function datatype($type)
{
static $types = array(
'blob' => array('type' => 'string', 'binary' => true, 'character_maximum_length' => '65535'),
'bool' => array('type' => 'bool'),
'bigint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '18446744073709551615'),
'datetime' => array('type' => 'string'),
'decimal unsigned' => array('type' => 'float', 'exact' => true, 'min' => '0'),
'double' => array('type' => 'float'),
'double precision unsigned' => array('type' => 'float', 'min' => '0'),
'double unsigned' => array('type' => 'float', 'min' => '0'),
'enum' => array('type' => 'string'),
'fixed' => array('type' => 'float', 'exact' => true),
'fixed unsigned' => array('type' => 'float', 'exact' => true, 'min' => '0'),
'float unsigned' => array('type' => 'float', 'min' => '0'),
'int unsigned' => array('type' => 'int', 'min' => '0', 'max' => '4294967295'),
'integer unsigned' => array('type' => 'int', 'min' => '0', 'max' => '4294967295'),
'longblob' => array('type' => 'string', 'binary' => true, 'character_maximum_length' => '4294967295'),
'longtext' => array('type' => 'string', 'character_maximum_length' => '4294967295'),
'mediumblob' => array('type' => 'string', 'binary' => true, 'character_maximum_length' => '16777215'),
'mediumint' => array('type' => 'int', 'min' => '-8388608', 'max' => '8388607'),
'mediumint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '16777215'),
'mediumtext' => array('type' => 'string', 'character_maximum_length' => '16777215'),
'national varchar' => array('type' => 'string'),
'numeric unsigned' => array('type' => 'float', 'exact' => true, 'min' => '0'),
'nvarchar' => array('type' => 'string'),
'point' => array('type' => 'string', 'binary' => true),
'real unsigned' => array('type' => 'float', 'min' => '0'),
'set' => array('type' => 'string'),
'smallint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '65535'),
'text' => array('type' => 'string', 'character_maximum_length' => '65535'),
'tinyblob' => array('type' => 'string', 'binary' => true, 'character_maximum_length' => '255'),
'tinyint' => array('type' => 'int', 'min' => '-128', 'max' => '127'),
'tinyint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '255'),
'tinytext' => array('type' => 'string', 'character_maximum_length' => '255'),
'varchar' => array('type' => 'string', 'exact' => true),
'year' => array('type' => 'string'),
);
$type = str_replace(' zerofill', '', $type);
if (isset($types[$type]))
{
return $types[$type];
}
return parent::datatype($type);
}
/**
* List tables
*
* @param string $like pattern of table name
* @return array array of table names
*/
public function list_tables($like = null)
{
if (is_string($like))
{
// Search for table names
$result = $this->query(\DB::SELECT, 'SHOW TABLES LIKE '.$this->quote($like), false);
}
else
{
// Find all table names
$result = $this->query(\DB::SELECT, 'SHOW TABLES', false);
}
$tables = array();
foreach ($result as $row)
{
$tables[] = reset($row);
}
return $tables;
}
/**
* List table columns
*
* @param string $table table name
* @param string $like column name pattern
* @return array array of column structure
*/
public function list_columns($table, $like = null)
{
// Quote the table name
$table = $this->quote_table($table);
if (is_string($like))
{
// Search for column names
$result = $this->query(\DB::SELECT, 'SHOW FULL COLUMNS FROM '.$table.' LIKE '.$this->quote($like), false);
}
else
{
// Find all column names
$result = $this->query(\DB::SELECT, 'SHOW FULL COLUMNS FROM '.$table, false);
}
$count = 0;
$columns = array();
foreach ($result as $row)
{
list($type, $length) = $this->_parse_type($row['Type']);
$column = $this->datatype($type);
$column['name'] = $row['Field'];
$column['default'] = $row['Default'];
$column['data_type'] = $type;
$column['null'] = ($row['Null'] == 'YES');
$column['ordinal_position'] = ++$count;
switch ($column['type'])
{
case 'float':
if (isset($length))
{
list($column['numeric_precision'], $column['numeric_scale']) = explode(',', $length);
}
break;
case 'int':
if (isset($length))
{
// MySQL attribute
$column['display'] = $length;
}
break;
case 'string':
switch ($column['data_type'])
{
case 'binary':
case 'varbinary':
$column['character_maximum_length'] = $length;
break;
case 'char':
case 'varchar':
$column['character_maximum_length'] = $length;
case 'text':
case 'tinytext':
case 'mediumtext':
case 'longtext':
$column['collation_name'] = $row['Collation'];
break;
case 'enum':
case 'set':
$column['collation_name'] = $row['Collation'];
$column['options'] = explode('\',\'', substr($length, 1, -1));
break;
}
break;
}
// MySQL attributes
$column['comment'] = $row['Comment'];
$column['extra'] = $row['Extra'];
$column['key'] = $row['Key'];
$column['privileges'] = $row['Privileges'];
$columns[$row['Field']] = $column;
}
return $columns;
}
/**
* Escape query for sql
*
* @param mixed $value value of string castable
* @return string escaped sql string
*/
public function escape($value)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if (($value = $this->_connection->real_escape_string((string) $value)) === false)
{
throw new \Database_Exception($this->_connection->error, $this->_connection->errno);
}
// SQL standard is to use single-quotes for all values
return "'$value'";
}
public function error_info()
{
$errno = $this->_connection->errno;
return array($errno, empty($errno) ? null : $errno, empty($errno) ? null : $this->_connection->error);
}
protected function driver_start_transaction()
{
$this->query(0, 'START TRANSACTION', false);
return true;
}
protected function driver_commit()
{
$this->query(0, 'COMMIT', false);
return true;
}
protected function driver_rollback()
{
$this->query(0, 'ROLLBACK', false);
return true;
}
/**
* Sets savepoint of the transaction
*
* @param string $name name of the savepoint
* @return boolean true - savepoint was set successfully;
* false - failed to set savepoint;
*/
protected function set_savepoint($name) {
$this->query(0, 'SAVEPOINT LEVEL'.$name, false);
return true;
}
/**
* Release savepoint of the transaction
*
* @param string $name name of the savepoint
* @return boolean true - savepoint was set successfully;
* false - failed to set savepoint;
*/
protected function release_savepoint($name) {
$this->query(0, 'RELEASE SAVEPOINT LEVEL'.$name, false);
return true;
}
/**
* Rollback savepoint of the transaction
*
* @param string $name name of the savepoint
* @return boolean true - savepoint was set successfully;
* false - failed to set savepoint;
*/
protected function rollback_savepoint($name) {
$this->query(0, 'ROLLBACK TO SAVEPOINT LEVEL'.$name, false);
return true;
}
}

@ -1,79 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_MySQLi_Result extends \Database_Result
{
protected $_internal_row = 0;
public function __construct($result, $sql, $as_object)
{
parent::__construct($result, $sql, $as_object);
// Find the number of rows in the result
$this->_total_rows = $result->num_rows;
}
public function __destruct()
{
if ($this->_result instanceof \MySQLi_Result)
{
$this->_result->free();
}
}
public function seek($offset)
{
if ($this->offsetExists($offset) and $this->_result->data_seek($offset))
{
// Set the current row to the offset
$this->_current_row = $this->_internal_row = $offset;
return true;
}
else
{
return false;
}
}
public function current()
{
if ($this->_current_row !== $this->_internal_row and ! $this->seek($this->_current_row))
{
return false;
}
// Increment internal row for optimization assuming rows are fetched in order
$this->_internal_row++;
if ($this->_as_object === true)
{
// Return an stdClass
return $this->_result->fetch_object();
}
elseif (is_string($this->_as_object))
{
// Return an object of given class name
//! TODO: add the $params parameter
return $this->_result->fetch_object($this->_as_object);
}
else
{
// Return an array of the row
return $this->_result->fetch_assoc();
}
}
}

@ -1,562 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*
*/
namespace Fuel\Core;
class Database_PDO_Connection extends \Database_Connection
{
/**
* @var \PDO $_connection raw server connection
*/
protected $_connection;
/**
* @var string $_identifier PDO uses no quoting by default for identifiers
*/
protected $_identifier = '';
/**
* @param string $name
* @param array $config
*/
protected function __construct($name, array $config)
{
// construct a custom schema driver
// $this->_schema = new \Database_Drivername_Schema($name, $this);
// call the parent consructor
parent::__construct($name, $config);
if (isset($config['identifier']))
{
// Allow the identifier to be overloaded per-connection
$this->_identifier = (string) $this->_config['identifier'];
}
}
/**
* Connects to the database
*
* @throws \Database_Exception
*/
public function connect()
{
if ($this->_connection)
{
return;
}
// make sure we have all connection parameters
$this->_config = array_merge(array(
'connection' => array(
'dsn' => '',
'hostname' => '',
'username' => null,
'password' => null,
'database' => '',
'persistent' => false,
'compress' => false,
),
'identifier' => '`',
'table_prefix' => '',
'charset' => 'utf8',
'collation' => false,
'enable_cache' => true,
'profiling' => false,
'readonly' => false,
'attrs' => array(),
), $this->_config);
// Force PDO to use exceptions for all errors
$this->_config['attrs'] = array(
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
);
if ( ! empty($this->_config['connection']['persistent']))
{
// Make the connection persistent
$this->_config['attrs'][\PDO::ATTR_PERSISTENT] = true;
}
try
{
// Create a new PDO connection
$this->_connect();
}
catch (\PDOException $e)
{
// and convert the exception in a database exception
if ( ! is_numeric($error_code = $e->getCode()))
{
if ($this->_connection)
{
$error_code = $this->_connection->errorinfo();
$error_code = $error_code[1];
}
else
{
$error_code = 0;
}
}
throw new \Database_Exception(str_replace($this->_config['connection']['password'], str_repeat('*', 10), $e->getMessage()), $error_code, $e);
}
}
/**
* @return bool
*/
public function disconnect()
{
// destroy the PDO object
$this->_connection = null;
// and reset the savepoint depth
$this->_transaction_depth = 0;
return true;
}
/**
* Get the current PDO Driver name
*
* @return string
*/
public function driver_name()
{
// Make sure the database is connected
$this->_connection or $this->connect();
// Getting driver name
return $this->_connection->getAttribute(\PDO::ATTR_DRIVER_NAME);
}
/**
* Set the charset
*
* @param string $charset
*/
public function set_charset($charset)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if ($charset)
{
$this->_connection->exec('SET NAMES '.$this->quote($charset));
}
}
/**
* Query the database
*
* @param integer $type
* @param string $sql
* @param mixed $as_object
*
* @return mixed
*
* @throws \Database_Exception
*/
public function query($type, $sql, $as_object)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if ( ! empty($this->_config['profiling']))
{
// Get the paths defined in config
$paths = \Config::get('profiling_paths');
// Storage for the trace information
$stacktrace = array();
// Get the execution trace of this query
$include = false;
foreach (debug_backtrace() as $index => $page)
{
// Skip first entry and entries without a filename
if ($index > 0 and empty($page['file']) === false)
{
// Checks to see what paths you want backtrace
foreach($paths as $index => $path)
{
if (strpos($page['file'], $path) !== false)
{
$include = true;
break;
}
}
// Only log if no paths we defined, or we have a path match
if ($include or empty($paths))
{
$stacktrace[] = array('file' => \Fuel::clean_path($page['file']), 'line' => $page['line']);
}
}
}
$benchmark = \Profiler::start($this->_instance, $sql, $stacktrace);
}
// run the query. if the connection is lost, try 3 times to reconnect
$attempts = 3;
do
{
try
{
// try to run the query
$result = $this->_connection->query($sql);
break;
}
catch (\Exception $e)
{
// if failed and we have attempts left
if ($attempts > 0)
{
// try reconnecting if it was a MySQL disconnected error
if (strpos($e->getMessage(), '2006 MySQL') !== false)
{
$this->disconnect();
$this->connect();
}
else
{
// other database error, cleanup the profiler
isset($benchmark) and \Profiler::delete($benchmark);
// and convert the exception in a database exception
if ( ! is_numeric($error_code = $e->getCode()))
{
if ($this->_connection)
{
$error_code = $this->_connection->errorinfo();
$error_code = $error_code[1];
}
else
{
$error_code = 0;
}
}
throw new \Database_Exception($e->getMessage().' with query: "'.$sql.'"', $error_code, $e);
}
}
// no more attempts left, bail out
else
{
// and convert the exception in a database exception
if ( ! is_numeric($error_code = $e->getCode()))
{
if ($this->_connection)
{
$error_code = $this->_connection->errorinfo();
$error_code = $error_code[1];
}
else
{
$error_code = 0;
}
}
throw new \Database_Exception($e->getMessage().' with query: "'.$sql.'"', $error_code, $e);
}
}
}
while ($attempts-- > 0);
if (isset($benchmark))
{
\Profiler::stop($benchmark);
}
// Set the last query
$this->last_query = $sql;
if ($type === \DB::SELECT)
{
// Convert the result into an array, as PDOStatement::rowCount is not reliable
if ($as_object === false)
{
$result = $result->fetchAll(\PDO::FETCH_ASSOC);
}
elseif (is_string($as_object))
{
$result = $result->fetchAll(\PDO::FETCH_CLASS, $as_object);
}
else
{
$result = $result->fetchAll(\PDO::FETCH_CLASS, 'stdClass');
}
// Return an iterator of results
return new \Database_Result_Cached($result, $sql, $as_object);
}
elseif ($type === \DB::INSERT)
{
// Return a list of insert id and rows created
return array(
$this->_connection->lastInsertId(),
$result->rowCount(),
);
}
elseif ($type === \DB::UPDATE or $type === \DB::DELETE)
{
// Return the number of rows affected
return $result->errorCode() === '00000' ? $result->rowCount() : -1;
}
return $result->errorCode() === '00000' ? true : false;
}
/**
* List tables
*
* @param string $like
*
* @throws \FuelException
*/
public function list_tables($like = null)
{
throw new \FuelException('Database method '.__METHOD__.' is not supported by '.__CLASS__);
}
/**
* List table columns
*
* @param string $table
* @param string $like
*
* @return array
*/
public function list_columns($table, $like = null)
{
$this->_connection or $this->connect();
$q = $this->_connection->prepare("DESCRIBE ".$table);
$q->execute();
$result = $q->fetchAll();
$count = 0;
$columns = array();
! is_null($like) and $like = str_replace('%', '.*', $like);
foreach ($result as $row)
{
if ( ! is_null($like) and ! preg_match('#'.$like.'#', $row['Field']))
{
continue;
}
list($type, $length) = $this->_parse_type($row['Type']);
$column = $this->datatype($type);
$column['name'] = $row['Field'];
$column['default'] = $row['Default'];
$column['data_type'] = $type;
$column['null'] = ($row['Null'] == 'YES');
$column['ordinal_position'] = ++$count;
switch ($column['type'])
{
case 'float':
if (isset($length))
{
list($column['numeric_precision'], $column['numeric_scale']) = explode(',', $length);
}
break;
case 'int':
if (isset($length))
{
// MySQL attribute
$column['display'] = $length;
}
break;
case 'string':
switch ($column['data_type'])
{
case 'binary':
case 'varbinary':
$column['character_maximum_length'] = $length;
break;
case 'char':
case 'varchar':
$column['character_maximum_length'] = $length;
case 'text':
case 'tinytext':
case 'mediumtext':
case 'longtext':
$column['collation_name'] = isset($row['Collation']) ? $row['Collation'] : null;
break;
case 'enum':
case 'set':
$column['collation_name'] = isset($row['Collation']) ? $row['Collation'] : null;
$column['options'] = explode('\',\'', substr($length, 1, - 1));
break;
}
break;
}
// MySQL attributes
$column['comment'] = isset($row['Comment']) ? $row['Comment'] : null;
$column['extra'] = $row['Extra'];
$column['key'] = $row['Key'];
$column['privileges'] = isset($row['Privileges']) ? $row['Privileges'] : null;
$columns[$row['Field']] = $column;
}
return $columns;
}
/**
* Resolve a datatype
*
* @param integer $type
*
* @return array
*/
public function datatype($type)
{
// try to determine the datatype
$datatype = parent::datatype($type);
// if not an ANSI database, assume it's string
return empty($datatype) ? array('type' => 'string') : $datatype;
}
/**
* Escape a value
*
* @param mixed $value
*
* @return string
*/
public function escape($value)
{
// Make sure the database is connected
$this->_connection or $this->connect();
$result = $this->_connection->quote($value);
// poor-mans workaround for the fact that not all drivers implement quote()
if (empty($result))
{
if ( ! is_numeric($value))
{
$result = "'".str_replace("'", "''", $value)."'";
}
}
return $result;
}
/**
* Retrieve error info
*
* @return array
*/
public function error_info()
{
return $this->_connection->errorInfo();
}
/**
* Create a new PDO instance
*
* @return PDO
*/
protected function _connect()
{
$this->_connection = new \PDO(
$this->_config['connection']['dsn'],
$this->_config['connection']['username'],
$this->_config['connection']['password'],
$this->_config['attrs']
);
// set the DB charset if needed
$this->set_charset($this->_config['charset']);
}
/**
* Start a transaction
*
* @return bool
*/
protected function driver_start_transaction()
{
$this->_connection or $this->connect();
return $this->_connection->beginTransaction();
}
/**
* Commit a transaction
*
* @return bool
*/
protected function driver_commit()
{
return $this->_connection->commit();
}
/**
* Rollback a transaction
* @return bool
*/
protected function driver_rollback()
{
return $this->_connection->rollBack();
}
/**
* Sets savepoint of the transaction
*
* @param string $name name of the savepoint
* @return boolean true - savepoint was set successfully;
* false - failed to set savepoint;
* null - RDBMS does not support savepoints
*/
protected function set_savepoint($name)
{
$result = $this->_connection->exec('SAVEPOINT '.$name);
return $result !== false;
}
/**
* Release savepoint of the transaction
*
* @param string $name name of the savepoint
* @return boolean true - savepoint was set successfully;
* false - failed to set savepoint;
* null - RDBMS does not support savepoints
*/
protected function release_savepoint($name)
{
$result = $this->_connection->exec('RELEASE SAVEPOINT '.$name);
return $result !== false;
}
/**
* Rollback savepoint of the transaction
*
* @param string $name name of the savepoint
* @return boolean true - savepoint was set successfully;
* false - failed to set savepoint;
* null - RDBMS does not support savepoints
*/
protected function rollback_savepoint($name)
{
$result = $this->_connection->exec('ROLLBACK TO SAVEPOINT '.$name);
return $result !== false;
}
}

@ -1,325 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_Query
{
/**
* @var int Query type
*/
protected $_type;
/**
* @var int Cache lifetime
*/
protected $_lifetime;
/**
* @var string Cache key
*/
protected $_cache_key = null;
/**
* @var boolean Cache all results
*/
protected $_cache_all = true;
/**
* @var string SQL statement
*/
protected $_sql;
/**
* @var array Quoted query parameters
*/
protected $_parameters = array();
/**
* @var bool Return results as associative arrays or objects
*/
protected $_as_object = false;
/**
* @var Database_Connection Connection to use when compiling the SQL
*/
protected $_connection = null;
/**
* Creates a new SQL query of the specified type.
*
* @param string $sql query string
* @param integer $type query type: DB::SELECT, DB::INSERT, etc
*/
public function __construct($sql, $type = null)
{
$this->_type = $type;
$this->_sql = $sql;
}
/**
* Return the SQL query string.
*
* @return string
*/
final public function __toString()
{
try
{
// Return the SQL string
return $this->compile();
}
catch (\Exception $e)
{
return $e->getMessage();
}
}
/**
* Get the type of the query.
*
* @return integer
*/
public function type()
{
return $this->_type;
}
/**
* Enables the query to be cached for a specified amount of time.
*
* @param integer $lifetime number of seconds to cache or null for default
* @param string $cache_key name of the cache key to be used or null for default
* @param boolean $cache_all if true, cache all results, even empty ones
*
* @return $this
*/
public function cached($lifetime = null, $cache_key = null, $cache_all = true)
{
$this->_lifetime = $lifetime;
$this->_cache_all = (bool) $cache_all;
is_string($cache_key) and $this->_cache_key = $cache_key;
return $this;
}
/**
* Returns results as associative arrays
*
* @return $this
*/
public function as_assoc()
{
$this->_as_object = false;
return $this;
}
/**
* Returns results as objects
*
* @param mixed $class classname or true for stdClass
*
* @return $this
*/
public function as_object($class = true)
{
$this->_as_object = $class;
return $this;
}
/**
* Set the value of a parameter in the query.
*
* @param string $param parameter key to replace
* @param mixed $value value to use
*
* @return $this
*/
public function param($param, $value)
{
// Add or overload a new parameter
$this->_parameters[$param] = $value;
return $this;
}
/**
* Bind a variable to a parameter in the query.
*
* @param string $param parameter key to replace
* @param mixed $var variable to use
*
* @return $this
*/
public function bind($param, & $var)
{
// Bind a value to a variable
$this->_parameters[$param] =& $var;
return $this;
}
/**
* Add multiple parameters to the query.
*
* @param array $params list of parameters
*
* @return $this
*/
public function parameters(array $params)
{
// Merge the new parameters in
$this->_parameters = $params + $this->_parameters;
return $this;
}
/**
* Set a DB connection to use when compiling the SQL
*
* @param mixed $db
*
* @return $this
*/
public function set_connection($db)
{
if ( ! $db instanceof \Database_Connection)
{
// Get the database instance
$db = \Database_Connection::instance($db);
}
$this->_connection = $db;
return $this;
}
/**
* Compile the SQL query and return it. Replaces any parameters with their
* given values.
*
* @param mixed $db Database instance or instance name
*
* @return string
*/
public function compile($db = null)
{
if ($this->_connection !== null and $db === null)
{
$db = $this->_connection;
}
if ( ! $db instanceof \Database_Connection)
{
// Get the database instance
$db = $this->_connection ?: \Database_Connection::instance($db);
}
// Import the SQL locally
$sql = $this->_sql;
if ( ! empty($this->_parameters))
{
// Quote all of the values
$values = array_map(array($db, 'quote'), $this->_parameters);
// Replace the values in the SQL
$sql = \Str::tr($sql, $values);
}
return trim($sql);
}
/**
* Execute the current query on the given database.
*
* @param mixed $db Database instance or name of instance
*
* @return object Database_Result for SELECT queries
* @return mixed the insert id for INSERT queries
* @return integer number of affected rows for all other queries
*/
public function execute($db = null)
{
if ($this->_connection !== null and $db === null)
{
$db = $this->_connection;
}
if ( ! is_object($db))
{
// Get the database instance. If this query is a instance of
// Database_Query_Builder_Select then use the slave connection if configured
$db = \Database_Connection::instance($db, null, ! $this instanceof \Database_Query_Builder_Select);
}
// Compile the SQL query
$sql = $this->compile($db);
// make sure we have a SQL type to work with
if (is_null($this->_type))
{
// get the SQL statement type without having to duplicate the entire statement
$stmt = preg_split("/[\s]+/", substr($sql, 0, 10), 2);
switch(strtoupper(reset($stmt)))
{
case 'DESCRIBE':
case 'EXECUTE':
case 'EXPLAIN':
case 'SELECT':
case 'SHOW':
$this->_type = \DB::SELECT;
break;
case 'INSERT':
case 'REPLACE':
$this->_type = \DB::INSERT;
break;
case 'UPDATE':
$this->_type = \DB::UPDATE;
break;
case 'DELETE':
$this->_type = \DB::DELETE;
break;
default:
$this->_type = 0;
}
}
if ($db->caching() and ! empty($this->_lifetime) and $this->_type === \DB::SELECT)
{
$cache_key = empty($this->_cache_key) ?
'db.'.md5('Database_Connection::query("'.$db.'", "'.$sql.'")') : $this->_cache_key;
$cache = \Cache::forge($cache_key);
try
{
$result = $cache->get();
return new \Database_Result_Cached($result, $sql, $this->_as_object);
}
catch (\CacheNotFoundException $e) {}
}
// Execute the query
\DB::$query_count++;
$result = $db->query($this->_type, $sql, $this->_as_object);
// Cache the result if needed
if (isset($cache) and ($this->_cache_all or $result->count()))
{
$cache->set_expiration($this->_lifetime)->set_contents($result->as_array())->set();
}
return $result;
}
}

@ -1,217 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
abstract class Database_Query_Builder extends \Database_Query
{
/**
* Compiles an array of JOIN statements into an SQL partial.
*
* @param object $db Database instance
* @param array $joins join statements
*
* @return string
*/
protected function _compile_join(\Database_Connection$db, array $joins)
{
$statements = array();
foreach ($joins as $join)
{
// Compile each of the join statements
$statements[] = $join->compile($db);
}
return implode(' ', $statements);
}
/**
* Compiles an array of conditions into an SQL partial. Used for WHERE
* and HAVING.
*
* @param object $db Database instance
* @param array $conditions condition statements
*
* @return string
*/
protected function _compile_conditions(\Database_Connection$db, array $conditions)
{
$last_condition = NULL;
$sql = '';
foreach ($conditions as $group)
{
// Process groups of conditions
foreach ($group as $logic => $condition)
{
if ($condition === '(')
{
if ( ! empty($sql) AND $last_condition !== '(')
{
// Include logic operator
$sql .= ' '.$logic.' ';
}
$sql .= '(';
}
elseif ($condition === ')')
{
$sql .= ')';
}
else
{
if ( ! empty($sql) AND $last_condition !== '(')
{
// Add the logic operator
$sql .= ' '.$logic.' ';
}
// Split the condition
list($column, $op, $value) = $condition;
// Support DB::expr() as where clause
if ($column instanceOf Database_Expression and $op === null and $value === null)
{
$sql .= (string) $column;
}
else
{
if ($value === NULL)
{
if ($op === '=')
{
// Convert "val = NULL" to "val IS NULL"
$op = 'IS';
}
elseif ($op === '!=')
{
// Convert "val != NULL" to "valu IS NOT NULL"
$op = 'IS NOT';
}
}
// Database operators are always uppercase
$op = strtoupper($op);
if (($op === 'BETWEEN' OR $op === 'NOT BETWEEN') AND is_array($value))
{
// BETWEEN always has exactly two arguments
list($min, $max) = $value;
if (is_string($min) AND array_key_exists($min, $this->_parameters))
{
// Set the parameter as the minimum
$min = $this->_parameters[$min];
}
if (is_string($max) AND array_key_exists($max, $this->_parameters))
{
// Set the parameter as the maximum
$max = $this->_parameters[$max];
}
// Quote the min and max value
$value = $db->quote($min).' AND '.$db->quote($max);
}
else
{
if (is_string($value) AND array_key_exists($value, $this->_parameters))
{
// Set the parameter as the value
$value = $this->_parameters[$value];
}
// Quote the entire value normally
$value = $db->quote($value);
}
// Append the statement to the query
$sql .= $db->quote_identifier($column).' '.$op.' '.$value;
}
}
$last_condition = $condition;
}
}
return $sql;
}
/**
* Compiles an array of set values into an SQL partial. Used for UPDATE.
*
* @param object $db Database instance
* @param array $values updated values
*
* @return string
*/
protected function _compile_set(\Database_Connection$db, array $values)
{
$set = array();
foreach ($values as $group)
{
// Split the set
list($column, $value) = $group;
// Quote the column name
$column = $db->quote_identifier($column);
if (is_string($value) AND array_key_exists($value, $this->_parameters))
{
// Use the parameter value
$value = $this->_parameters[$value];
}
$set[$column] = $column.' = '.$db->quote($value);
}
return implode(', ', $set);
}
/**
* Compiles an array of ORDER BY statements into an SQL partial.
*
* @param object $db Database instance
* @param array $columns sorting columns
*
* @return string
*/
protected function _compile_order_by(\Database_Connection $db, array $columns)
{
$sort = array();
foreach ($columns as $group)
{
list($column, $direction) = $group;
$direction = strtoupper($direction);
if ( ! empty($direction))
{
// Make the direction uppercase
$direction = ' '.($direction == 'ASC' ? 'ASC' : 'DESC');
}
$sort[] = $db->quote_identifier($column).$direction;
}
return 'ORDER BY '.implode(', ', $sort);
}
/**
* Reset the current builder status.
*
* @return $this
*/
abstract public function reset();
}

@ -1,109 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_Query_Builder_Delete extends \Database_Query_Builder_Where
{
// DELETE FROM ...
protected $_table;
/**
* Set the table for a delete.
*
* @param mixed $table table name or array($table, $alias) or object
*/
public function __construct($table = null)
{
if ($table)
{
// Set the initial table name
$this->_table = $table;
}
// Start the query with no SQL
parent::__construct('', \DB::DELETE);
}
/**
* Sets the table to delete from.
*
* @param mixed $table table name or array($table, $alias) or object
*
* @return $this
*/
public function table($table)
{
$this->_table = $table;
return $this;
}
/**
* Compile the SQL query and return it.
*
* @param mixed $db Database_Connection instance or instance name
*
* @return string
*/
public function compile($db = null)
{
if ( ! $db instanceof \Database_Connection)
{
// Get the database instance
$db = \Database_Connection::instance($db);
}
// Start a deletion query
$query = 'DELETE FROM '.$db->quote_table($this->_table);
if ( ! empty($this->_where))
{
// Add deletion conditions
$query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
}
if ( ! empty($this->_order_by))
{
// Add sorting
$query .= ' '.$this->_compile_order_by($db, $this->_order_by);
}
if ($this->_limit !== null)
{
// Add limiting
$query .= ' LIMIT '.$this->_limit;
}
return $query;
}
/**
* Reset the query parameters
*
* @return $this
*/
public function reset()
{
$this->_table = NULL;
$this->_where = array();
$this->_order_by = array();
$this->_parameters = array();
$this->_limit = NULL;
return $this;
}
}

@ -1,219 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_Query_Builder_Insert extends \Database_Query_Builder
{
/**
* @var string $_table table
*/
protected $_table;
/**
* @var array $_columns columns
*/
protected $_columns = array();
/**
* @var array $_values values
*/
protected $_values = array();
/**
* Set the table and columns for an insert.
*
* @param mixed $table table name or array($table, $alias) or object
* @param array $columns column names
*/
public function __construct($table = null, array $columns = null)
{
if ($table)
{
// Set the initial table name
$this->_table = $table;
}
if ($columns)
{
// Set the column names
$this->_columns = $columns;
}
// Start the query with no SQL
parent::__construct('', \DB::INSERT);
}
/**
* Sets the table to insert into.
*
* @param mixed $table table name or array($table, $alias) or object
* @return $this
*/
public function table($table)
{
$this->_table = $table;
return $this;
}
/**
* Set the columns that will be inserted.
*
* @param array $columns column names
* @return $this
*/
public function columns(array $columns)
{
$this->_columns = array_merge($this->_columns, $columns);
return $this;
}
/**
* Adds values. Multiple value sets can be added.
*
* @throws \FuelException
* @param array $values
* @return $this
*/
public function values(array $values)
{
if ( ! is_array($this->_values))
{
throw new \FuelException('INSERT INTO ... SELECT statements cannot be combined with INSERT INTO ... VALUES');
}
// Get all of the passed values
$values = func_get_args();
// And process them
foreach ($values as $value)
{
if (is_array(reset($value)))
{
$this->_values = array_merge($this->_values, $value);
}
else
{
$this->_values[] = $value;
}
}
return $this;
}
/**
* This is a wrapper function for calling columns() and values().
*
* @param array $pairs column value pairs
*
* @return $this
*/
public function set(array $pairs)
{
$this->columns(array_keys($pairs));
$this->values($pairs);
return $this;
}
/**
* Use a sub-query to for the inserted values.
*
* @param Database_Query $query Database_Query of SELECT type
*
* @return $this
*
* @throws \FuelException
*/
public function select(Database_Query $query)
{
if ($query->type() !== \DB::SELECT)
{
throw new \FuelException('Only SELECT queries can be combined with INSERT queries');
}
$this->_values = $query;
return $this;
}
/**
* Compile the SQL query and return it.
*
* @param mixed $db Database instance or instance name
*
* @return string
*/
public function compile($db = null)
{
if ( ! $db instanceof \Database_Connection)
{
// Get the database instance
$db = \Database_Connection::instance($db);
}
// Start an insertion query
$query = 'INSERT INTO '.$db->quote_table($this->_table);
// Add the column names
$query .= ' ('.implode(', ', array_map(array($db, 'quote_identifier'), $this->_columns)).') ';
if (is_array($this->_values))
{
// Callback for quoting values
$quote = array($db, 'quote');
$groups = array();
foreach ($this->_values as $group)
{
foreach ($group as $i => $value)
{
if (is_string($value) AND isset($this->_parameters[$value]))
{
// Use the parameter value
$group[$i] = $this->_parameters[$value];
}
}
$groups[] = '('.implode(', ', array_map($quote, $group)).')';
}
// Add the values
$query .= 'VALUES '.implode(', ', $groups);
}
else
{
// Add the sub-query
$query .= (string) $this->_values;
}
return $query;
}
/**
* Reset the query parameters
*
* @return $this
*/
public function reset()
{
$this->_table = null;
$this->_columns = array();
$this->_values = array();
$this->_parameters = array();
return $this;
}
}

@ -1,165 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_Query_Builder_Join extends \Database_Query_Builder
{
/**
* @var string $_type join type
*/
protected $_type;
/**
* @var string $_table join table
*/
protected $_table;
/**
* @var array $_on ON clauses
*/
protected $_on = array();
/**
* Creates a new JOIN statement for a table. Optionally, the type of JOIN
* can be specified as the second parameter.
*
* @param mixed $table column name or array($column, $alias) or object
* @param string $type type of JOIN: INNER, RIGHT, LEFT, etc
*/
public function __construct($table, $type = null)
{
// Set the table to JOIN on
$this->_table = $table;
if ($type !== null)
{
// Set the JOIN type
$this->_type = (string) $type;
}
}
/**
* Adds a new OR condition for joining.
*
* @param mixed $c1 column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $c2 column name or array($column, $alias) or object
*
* @return $this
*/
public function or_on($c1, $op, $c2)
{
$this->_on[] = array($c1, $op, $c2, 'OR');
return $this;
}
/**
* Adds a new AND condition for joining.
*
* @param mixed $c1 column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $c2 column name or array($column, $alias) or object
*
* @return $this
*/
public function on($c1, $op, $c2)
{
$this->_on[] = array($c1, $op, $c2, 'AND');
return $this;
}
/**
* Adds a new AND condition for joining.
*
* @param mixed $c1 column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $c2 column name or array($column, $alias) or object
*
* @return $this
*/
public function and_on($c1, $op, $c2)
{
return $this->on($c1, $op, $c2);
}
/**
* Compile the SQL partial for a JOIN statement and return it.
*
* @param mixed $db Database_Connection instance or instance name
*
* @return string
*/
public function compile($db = null)
{
if ( ! $db instanceof \Database_Connection)
{
// Get the database instance
$db = \Database_Connection::instance($db);
}
if ($this->_type)
{
$sql = strtoupper($this->_type).' JOIN';
}
else
{
$sql = 'JOIN';
}
// Quote the table name that is being joined
$sql .= ' '.$db->quote_table($this->_table);
$conditions = array();
foreach ($this->_on as $condition)
{
// Split the condition
list($c1, $op, $c2, $chaining) = $condition;
// Add chain type
$conditions[] = ' '.$chaining.' ';
if ($op)
{
// Make the operator uppercase and spaced
$op = ' '.strtoupper($op);
}
// Quote each of the identifiers used for the condition
$conditions[] = $db->quote_identifier($c1).$op.' '.(is_null($c2) ? 'NULL' : $db->quote_identifier($c2));
}
// remove the first chain type
array_shift($conditions);
// if there are conditions, concat the conditions "... AND ..." and glue them on...
empty($conditions) or $sql .= ' ON ('.implode('', $conditions).')';
return $sql;
}
/**
* Resets the join values.
*
* @return $this
*/
public function reset()
{
$this->_type =
$this->_table = NULL;
$this->_on = array();
}
}

@ -1,502 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
use Fuel\Core\Database_Query_Builder_Where;
class Database_Query_Builder_Select extends Database_Query_Builder_Where
{
/**
* @var array $_select columns to select
*/
protected $_select = array();
/**
* @var bool $_distinct whether to select distinct values
*/
protected $_distinct = false;
/**
* @var array $_from table name
*/
protected $_from = array();
/**
* @var array $_join join objects
*/
protected $_join = array();
/**
* @var array $_group_by group by clauses
*/
protected $_group_by = array();
/**
* @var array $_having having clauses
*/
protected $_having = array();
/**
* @var integer $_offset offset
*/
protected $_offset = null;
/**
* @var Database_Query_Builder_Join $_last_join last join statement
*/
protected $_last_join;
/**
* Sets the initial columns to select from.
*
* @param array $columns column list
*/
public function __construct(array $columns = null)
{
if ( ! empty($columns))
{
// Set the initial columns
$this->_select = $columns;
}
// Start the query with no actual SQL statement
parent::__construct('', \DB::SELECT);
}
/**
* Enables or disables selecting only unique columns using "SELECT DISTINCT"
*
* @param boolean $value enable or disable distinct columns
* @return $this
*/
public function distinct($value = true)
{
$this->_distinct = (bool) $value;
return $this;
}
/**
* Choose the columns to select from.
*
* @param mixed $columns column name or array($column, $alias) or object
* @param ...
*
* @return $this
*/
public function select($columns = null)
{
$columns = func_get_args();
$this->_select = array_merge($this->_select, $columns);
return $this;
}
/**
* Choose the columns to select from, using an array.
*
* @param array $columns list of column names or aliases
* @param bool $reset if true, don't merge but overwrite
*
* @return $this
*/
public function select_array(array $columns, $reset = false)
{
$this->_select = $reset ? $columns : array_merge($this->_select, $columns);
return $this;
}
/**
* Choose the tables to select "FROM ..."
*
* @param mixed $tables table name or array($table, $alias)
* @param ...
*
* @return $this
*/
public function from($tables)
{
$tables = func_get_args();
$this->_from = array_merge($this->_from, $tables);
return $this;
}
/**
* Adds addition tables to "JOIN ...".
*
* @param mixed $table column name or array($column, $alias)
* @param string $type join type (LEFT, RIGHT, INNER, etc)
*
* @return $this
*/
public function join($table, $type = NULL)
{
$this->_join[] = $this->_last_join = new \Database_Query_Builder_Join($table, $type);
return $this;
}
/**
* Adds "ON ..." conditions for the last created JOIN statement.
*
* @param mixed $c1 column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $c2 column name or array($column, $alias) or object
*
* @return $this
*/
public function on($c1, $op, $c2)
{
$this->_last_join->on($c1, $op, $c2);
return $this;
}
/**
* Adds "AND ON ..." conditions for the last created JOIN statement.
*
* @param mixed $c1 column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $c2 column name or array($column, $alias) or object
*
* @return $this
*/
public function and_on($c1, $op, $c2)
{
$this->_last_join->and_on($c1, $op, $c2);
return $this;
}
/**
* Adds "OR ON ..." conditions for the last created JOIN statement.
*
* @param mixed $c1 column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $c2 column name or array($column, $alias) or object
*
* @return $this
*/
public function or_on($c1, $op, $c2)
{
$this->_last_join->or_on($c1, $op, $c2);
return $this;
}
/**
* Creates a "GROUP BY ..." filter.
*
* @param mixed $columns column name or array($column, $column) or object
* @param ...
*
* @return $this
*/
public function group_by($columns)
{
$columns = func_get_args();
foreach($columns as $idx => $column)
{
// if an array of columns is passed, flatten it
if (is_array($column))
{
foreach($column as $c)
{
$columns[] = $c;
}
unset($columns[$idx]);
}
}
$this->_group_by = array_merge($this->_group_by, $columns);
return $this;
}
/**
* Alias of and_having()
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $value column value
*
* @return $this
*/
public function having($column, $op = null, $value = null)
{
return call_fuel_func_array(array($this, 'and_having'), func_get_args());
}
/**
* Creates a new "AND HAVING" condition for the query.
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $value column value
*
* @return $this
*/
public function and_having($column, $op = null, $value = null)
{
if($column instanceof \Closure)
{
$this->and_having_open();
$column($this);
$this->and_having_close();
return $this;
}
if(func_num_args() === 2)
{
$value = $op;
$op = '=';
}
$this->_having[] = array('AND' => array($column, $op, $value));
return $this;
}
/**
* Creates a new "OR HAVING" condition for the query.
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $value column value
*
* @return $this
*/
public function or_having($column, $op = null, $value = null)
{
if($column instanceof \Closure)
{
$this->or_having_open();
$column($this);
$this->or_having_close();
return $this;
}
if(func_num_args() === 2)
{
$value = $op;
$op = '=';
}
$this->_having[] = array('OR' => array($column, $op, $value));
return $this;
}
/**
* Alias of and_having_open()
*
* @return $this
*/
public function having_open()
{
return $this->and_having_open();
}
/**
* Opens a new "AND HAVING (...)" grouping.
*
* @return $this
*/
public function and_having_open()
{
$this->_having[] = array('AND' => '(');
return $this;
}
/**
* Opens a new "OR HAVING (...)" grouping.
*
* @return $this
*/
public function or_having_open()
{
$this->_having[] = array('OR' => '(');
return $this;
}
/**
* Closes an open "AND HAVING (...)" grouping.
*
* @return $this
*/
public function having_close()
{
return $this->and_having_close();
}
/**
* Closes an open "AND HAVING (...)" grouping.
*
* @return $this
*/
public function and_having_close()
{
$this->_having[] = array('AND' => ')');
return $this;
}
/**
* Closes an open "OR HAVING (...)" grouping.
*
* @return $this
*/
public function or_having_close()
{
$this->_having[] = array('OR' => ')');
return $this;
}
/**
* Start returning results after "OFFSET ..."
*
* @param integer $number starting result number
*
* @return $this
*/
public function offset($number)
{
$this->_offset = (int) $number;
return $this;
}
/**
* Compile the SQL query and return it.
*
* @param mixed $db Database_Connection instance or instance name
*
* @return string
*/
public function compile($db = null)
{
if ( ! $db instanceof \Database_Connection)
{
// Get the database instance
$db = $this->_connection ?: \Database_Connection::instance($db);
}
// Callback to quote identifiers
$quote_ident = array($db, 'quote_identifier');
// Callback to quote tables
$quote_table = array($db, 'quote_table');
// Start a selection query
$query = 'SELECT ';
if ($this->_distinct === TRUE)
{
// Select only unique results
$query .= 'DISTINCT ';
}
if (empty($this->_select))
{
// Select all columns
$query .= '*';
}
else
{
// Select all columns
$query .= implode(', ', array_unique(array_map($quote_ident, $this->_select)));
}
if ( ! empty($this->_from))
{
// Set tables to select from
$query .= ' FROM '.implode(', ', array_unique(array_map($quote_table, $this->_from)));
}
if ( ! empty($this->_join))
{
// Add tables to join
$query .= ' '.$this->_compile_join($db, $this->_join);
}
if ( ! empty($this->_where))
{
// Add selection conditions
$query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
}
if ( ! empty($this->_group_by))
{
// Add sorting
$query .= ' GROUP BY '.implode(', ', array_map($quote_ident, $this->_group_by));
}
if ( ! empty($this->_having))
{
// Add filtering conditions
$query .= ' HAVING '.$this->_compile_conditions($db, $this->_having);
}
if ( ! empty($this->_order_by))
{
// Add sorting
$query .= ' '.$this->_compile_order_by($db, $this->_order_by);
}
if ($this->_limit !== NULL)
{
// Add limiting
$query .= ' LIMIT '.$this->_limit;
}
if ($this->_offset !== NULL)
{
// Add offsets
$query .= ' OFFSET '.$this->_offset;
}
return $query;
}
/**
* Reset the query parameters
* @return $this
*/
public function reset()
{
$this->_select = array();
$this->_from = array();
$this->_join = array();
$this->_where = array();
$this->_group_by = array();
$this->_having = array();
$this->_order_by = array();
$this->_distinct = false;
$this->_limit = null;
$this->_offset = null;
$this->_last_join = null;
$this->_parameters = array();
return $this;
}
}

@ -1,200 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_Query_Builder_Update extends \Database_Query_Builder_Where
{
/**
* @var string $_table table name
*/
protected $_table;
/**
* @var array $_set update values
*/
protected $_set = array();
/**
* @var array $_join join statements
*/
protected $_join = array();
/**
* @var Database_Query_Builder_Join $_last_join last join statement
*/
protected $_last_join;
/**
* Set the table for a update.
*
* @param mixed $table table name or array($table, $alias) or object
*
* @return void
*/
public function __construct($table = NULL)
{
if ($table)
{
// Set the initial table name
$this->_table = $table;
}
// Start the query with no SQL
parent::__construct('', \DB::UPDATE);
}
/**
* Sets the table to update.
*
* @param mixed $table table name or array($table, $alias)
*
* @return $this
*/
public function table($table)
{
$this->_table = $table;
return $this;
}
/**
* Set the values to update with an associative array.
*
* @param array $pairs associative (column => value) list
*
* @return $this
*/
public function set(array $pairs)
{
foreach ($pairs as $column => $value)
{
$this->_set[] = array($column, $value);
}
return $this;
}
/**
* Set the value of a single column.
*
* @param mixed $column table name or array($table, $alias) or object
* @param mixed $value column value
*
* @return $this
*/
public function value($column, $value)
{
$this->_set[] = array($column, $value);
return $this;
}
/**
* Compile the SQL query and return it.
*
* @param mixed $db Database instance or instance name
*
* @return string
*/
public function compile($db = null)
{
if ( ! $db instanceof \Database_Connection)
{
// Get the database instance
$db = \Database_Connection::instance($db);
}
// Start an update query
$query = 'UPDATE '.$db->quote_table($this->_table);
if ( ! empty($this->_join))
{
// Add tables to join
$query .= ' '.$this->_compile_join($db, $this->_join);
}
// Add the columns to update
$query .= ' SET '.$this->_compile_set($db, $this->_set);
if ( ! empty($this->_where))
{
// Add selection conditions
$query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
}
if ( ! empty($this->_order_by))
{
// Add sorting
$query .= ' '.$this->_compile_order_by($db, $this->_order_by);
}
if ($this->_limit !== null)
{
// Add limiting
$query .= ' LIMIT '.$this->_limit;
}
return $query;
}
/**
* Reset the query parameters
*
* @return $this
*/
public function reset()
{
$this->_table = null;
$this->_join = array();
$this->_set = array();
$this->_where = array();
$this->_order_by = array();
$this->_limit = null;
$this->_last_join = null;
$this->_parameters = array();
return $this;
}
/**
* Adds addition tables to "JOIN ...".
*
* @param mixed $table column name or array($column, $alias) or object
* @param string $type join type (LEFT, RIGHT, INNER, etc)
*
* @return $this
*/
public function join($table, $type = null)
{
$this->_join[] = $this->_last_join = new \Database_Query_Builder_Join($table, $type);
return $this;
}
/**
* Adds "ON ..." conditions for the last created JOIN statement.
*
* @param mixed $c1 column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $c2 column name or array($column, $alias) or object
*
* @return $this
*/
public function on($c1, $op, $c2)
{
$this->_last_join->on($c1, $op, $c2);
return $this;
}
}

@ -1,230 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
abstract class Database_Query_Builder_Where extends \Database_Query_Builder
{
/**
* @var array $_where where statements
*/
protected $_where = array();
/**
* @var array $_order_by order by clause
*/
protected $_order_by = array();
/**
* @var integer $_limit
*/
protected $_limit = null;
/**
* Alias of and_where()
*
* @return $this
*/
public function where()
{
return call_fuel_func_array(array($this, 'and_where'), func_get_args());
}
/**
* Creates a new "AND WHERE" condition for the query.
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $value column value
*
* @return $this
*/
public function and_where($column, $op = null, $value = null)
{
if($column instanceof \Closure)
{
$this->and_where_open();
$column($this);
$this->and_where_close();
return $this;
}
if (is_array($column))
{
foreach ($column as $key => $val)
{
if (is_array($val))
{
$this->and_where($val[0], $val[1], $val[2]);
}
else
{
$this->and_where($key, '=', $val);
}
}
}
else
{
if(func_num_args() === 2)
{
$value = $op;
$op = '=';
}
$this->_where[] = array('AND' => array($column, $op, $value));
}
return $this;
}
/**
* Creates a new "OR WHERE" condition for the query.
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $op logic operator
* @param mixed $value column value
*
* @return $this
*/
public function or_where($column, $op = null, $value = null)
{
if($column instanceof \Closure)
{
$this->or_where_open();
$column($this);
$this->or_where_close();
return $this;
}
if (is_array($column))
{
foreach ($column as $key => $val)
{
if (is_array($val))
{
$this->or_where($val[0], $val[1], $val[2]);
}
else
{
$this->or_where($key, '=', $val);
}
}
}
else
{
if(func_num_args() === 2)
{
$value = $op;
$op = '=';
}
$this->_where[] = array('OR' => array($column, $op, $value));
}
return $this;
}
/**
* Alias of and_where_open()
*
* @return $this
*/
public function where_open()
{
return $this->and_where_open();
}
/**
* Opens a new "AND WHERE (...)" grouping.
*
* @return $this
*/
public function and_where_open()
{
$this->_where[] = array('AND' => '(');
return $this;
}
/**
* Opens a new "OR WHERE (...)" grouping.
*
* @return $this
*/
public function or_where_open()
{
$this->_where[] = array('OR' => '(');
return $this;
}
/**
* Closes an open "AND WHERE (...)" grouping.
*
* @return $this
*/
public function where_close()
{
return $this->and_where_close();
}
/**
* Closes an open "AND WHERE (...)" grouping.
*
* @return $this
*/
public function and_where_close()
{
$this->_where[] = array('AND' => ')');
return $this;
}
/**
* Closes an open "OR WHERE (...)" grouping.
*
* @return $this
*/
public function or_where_close()
{
$this->_where[] = array('OR' => ')');
return $this;
}
/**
* Applies sorting with "ORDER BY ..."
*
* @param mixed $column column name or array($column, $alias) or object
* @param string $direction direction of sorting
*
* @return $this
*/
public function order_by($column, $direction = null)
{
$this->_order_by[] = array($column, $direction);
return $this;
}
/**
* Return up to "LIMIT ..." results
*
* @param integer $number maximum results to return
*
* @return $this
*/
public function limit($number)
{
$this->_limit = (int) $number;
return $this;
}
}

@ -1,417 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
abstract class Database_Result implements \Countable, \Iterator, \SeekableIterator, \ArrayAccess, \Sanitization
{
/**
* @var string Executed SQL for this result
*/
protected $_query;
/**
* @var resource $_result raw result resource
*/
protected $_result;
/**
* @var int $_total_rows total number of rows
*/
protected $_total_rows = 0;
/**
* @var int $_current_row current row number
*/
protected $_current_row = 0;
/**
* @var bool $_as_object return rows as an object or associative array
*/
protected $_as_object;
/**
* @var bool $_sanitization_enabled If this is a records data will be sanitized on get
*/
protected $_sanitization_enabled = false;
/**
* Sets the total number of rows and stores the result locally.
*
* @param mixed $result query result
* @param string $sql SQL query
* @param mixed $as_object object
*/
public function __construct($result, $sql, $as_object)
{
// Store the result locally
$this->_result = $result;
// Store the SQL locally
$this->_query = $sql;
if (is_object($as_object))
{
// Get the object class name
$as_object = get_class($as_object);
}
// Results as objects or associative arrays
$this->_as_object = $as_object;
}
/**
* Result destruction cleans up all open result sets.
*
* @return void
*/
abstract public function __destruct();
/**
* Get a cached database result from the current result iterator.
*
* $cachable = serialize($result->cached());
*
* @return Database_Result_Cached
* @since 3.0.5
*/
public function cached()
{
return new \Database_Result_Cached($this->as_array(), $this->_query, $this->_as_object);
}
/**
* Return all of the rows in the result as an array.
*
* // Indexed array of all rows
* $rows = $result->as_array();
*
* // Associative array of rows by "id"
* $rows = $result->as_array('id');
*
* // Associative array of rows, "id" => "name"
* $rows = $result->as_array('id', 'name');
*
* @param string $key column for associative keys
* @param string $value column for values
* @return array
*/
public function as_array($key = null, $value = null)
{
$results = array();
if ($key === null and $value === null)
{
// Indexed rows
foreach ($this as $row)
{
$results[] = $row;
}
}
elseif ($key === null)
{
// Indexed columns
if ($this->_as_object)
{
foreach ($this as $row)
{
$results[] = $row->$value;
}
}
else
{
foreach ($this as $row)
{
$results[] = $row[$value];
}
}
}
elseif ($value === null)
{
// Associative rows
if ($this->_as_object)
{
foreach ($this as $row)
{
$results[$row->$key] = $row;
}
}
else
{
foreach ($this as $row)
{
$results[$row[$key]] = $row;
}
}
}
else
{
// Associative columns
if ($this->_as_object)
{
foreach ($this as $row)
{
$results[$row->$key] = $row->$value;
}
}
else
{
foreach ($this as $row)
{
$results[$row[$key]] = $row[$value];
}
}
}
$this->rewind();
return $results;
}
/**
* Return the named column from the current row.
*
* // Get the "id" value
* $id = $result->get('id');
*
* @param string $name column to get
* @param mixed $default default value if the column does not exist
*
* @return mixed
*/
public function get($name, $default = null)
{
$row = $this->current();
if ($this->_as_object)
{
if (isset($row->$name))
{
// sanitize the data if needed
if ( ! $this->_sanitization_enabled)
{
$result = $row->$name;
}
else
{
$result = \Security::clean($row->$name, null, 'security.output_filter');
}
return $result;
}
}
else
{
if (isset($row[$name]))
{
// sanitize the data if needed
if ( ! $this->_sanitization_enabled)
{
$result = $row[$name];
}
else
{
$result = \Security::clean($row[$name], null, 'security.output_filter');
}
return $result;
}
}
return \Fuel::value($default);
}
/**
* Implements [Countable::count], returns the total number of rows.
*
* echo count($result);
*
* @return integer
*/
public function count()
{
return $this->_total_rows;
}
/**
* Implements [ArrayAccess::offsetExists], determines if row exists.
*
* if (isset($result[10]))
* {
* // Row 10 exists
* }
*
* @param integer $offset
*
* @return boolean
*/
public function offsetExists($offset)
{
return ($offset >= 0 and $offset < $this->_total_rows);
}
/**
* Implements [ArrayAccess::offsetGet], gets a given row.
*
* $row = $result[10];
*
* @param integer $offset
*
* @return mixed
*/
public function offsetGet($offset)
{
if ( ! $this->seek($offset))
{
return null;
}
$result = $this->current();
// sanitize the data if needed
if ($this->_sanitization_enabled)
{
$result = \Security::clean($result, null, 'security.output_filter');
}
return $result;
}
/**
* Implements [ArrayAccess::offsetSet], throws an error.
* [!!] You cannot modify a database result.
*
* @param integer $offset
* @param mixed $value
*
* @throws \FuelException
*/
final public function offsetSet($offset, $value)
{
throw new \FuelException('Database results are read-only');
}
/**
* Implements [ArrayAccess::offsetUnset], throws an error.
* [!!] You cannot modify a database result.
*
* @param integer $offset
*
* @throws \FuelException
*/
final public function offsetUnset($offset)
{
throw new \FuelException('Database results are read-only');
}
/**
* Implements [Iterator::key], returns the current row number.
*
* echo key($result);
*
* @return integer
*/
public function key()
{
return $this->_current_row;
}
/**
* Implements [Iterator::next], moves to the next row.
*
* next($result);
*
* @return $this
*/
public function next()
{
++$this->_current_row;
return $this;
}
/**
* Implements [Iterator::prev], moves to the previous row.
*
* prev($result);
*
* @return $this
*/
public function prev()
{
--$this->_current_row;
return $this;
}
/**
* Implements [Iterator::rewind], sets the current row to zero.
*
* rewind($result);
*
* @return $this
*/
public function rewind()
{
$this->_current_row = 0;
return $this;
}
/**
* Implements [Iterator::valid], checks if the current row exists.
*
* [!!] This method is only used internally.
*
* @return boolean
*/
public function valid()
{
return $this->offsetExists($this->_current_row);
}
/**
* Enable sanitization mode in the object
*
* @return $this
*/
public function sanitize()
{
$this->_sanitization_enabled = true;
return $this;
}
/**
* Disable sanitization mode in the object
*
* @return $this
*/
public function unsanitize()
{
$this->_sanitization_enabled = false;
return $this;
}
/**
* Returns the current sanitization state of the object
*
* @return bool
*/
public function sanitized()
{
return $this->_sanitization_enabled;
}
}

@ -1,81 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_Result_Cached extends \Database_Result
{
/**
* @param array $result
* @param string $sql
* @param mixed $as_object
*/
public function __construct(array $result, $sql, $as_object = null)
{
parent::__construct($result, $sql, $as_object);
// Find the number of rows in the result
$this->_total_rows = count($result);
}
public function __destruct()
{
// Cached results do not use resources
}
/**
* @return $this
*/
public function cached()
{
return $this;
}
/**
* @param integer $offset
*
* @return bool
*/
public function seek($offset)
{
if ( ! $this->offsetExists($offset))
{
return false;
}
$this->_current_row = $offset;
return true;
}
/**
* @return mixed
*/
public function current()
{
if ($this->valid())
{
// sanitize the data if needed
if ( ! $this->_sanitization_enabled)
{
$result = $this->_result[$this->_current_row];
}
else
{
$result = \Security::clean($this->_result[$this->_current_row], null, 'security.output_filter');
}
return $result;
}
}
}

@ -1,647 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_Schema
{
/**
* @var Database_Connection database connection instance
*/
protected $_connection;
/**
* @var string database connection config name
*/
protected $_name;
/**
* Stores the database instance to be used.
*
* @param string database connection instance
*/
public function __construct($name, $connection)
{
// Set the connection config name
$this->_name = $name;
// Set the connection instance
$this->_connection = $connection;
}
/**
* Creates a database. Will throw a Database_Exception if it cannot.
*
* @throws Fuel\Database_Exception
* @param string $database the database name
* @param string $charset the character set
* @param boolean $if_not_exists whether to add an IF NOT EXISTS statement.
* @return int the number of affected rows
*/
public function create_database($database, $charset = null, $if_not_exists = true)
{
$sql = 'CREATE DATABASE';
$sql .= $if_not_exists ? ' IF NOT EXISTS ' : ' ';
$sql .= $this->_connection->quote_identifier($database).$this->process_charset($charset, true);
return $this->_connection->query(0, $sql, false);
}
/**
* Drops a database. Will throw a Database_Exception if it cannot.
*
* @throws Fuel\Database_Exception
* @param string $database the database name
* @return int the number of affected rows
*/
public function drop_database($database)
{
$sql = 'DROP DATABASE ';
$sql .= $this->_connection->quote_identifier($database);
return $this->_connection->query(0, $sql, false);
}
/**
* Drops a table. Will throw a Database_Exception if it cannot.
*
* @throws Fuel\Database_Exception
* @param string $table the table name
* @return int the number of affected rows
*/
public function drop_table($table)
{
$sql = 'DROP TABLE IF EXISTS ';
$sql .= $this->_connection->quote_identifier($this->_connection->table_prefix($table));
return $this->_connection->query(0, $sql, false);
}
/**
* Renames a table. Will throw a Database_Exception if it cannot.
*
* @throws \Database_Exception
* @param string $table the old table name
* @param string $new_table_name the new table name
* @return int the number of affected
*/
public function rename_table($table, $new_table_name)
{
$sql = 'RENAME TABLE ';
$sql .= $this->_connection->quote_identifier($this->_connection->table_prefix($table));
$sql .= ' TO ';
$sql .= $this->_connection->quote_identifier($this->_connection->table_prefix($new_table_name));
return $this->_connection->query(0, $sql, false);
}
/**
* Creates a table.
*
* @throws \Database_Exception
* @param string $table the table name
* @param array $fields the fields array
* @param array $primary_keys an array of primary keys
* @param boolean $if_not_exists whether to add an IF NOT EXISTS statement.
* @param string|boolean $engine storage engine overwrite
* @param string $charset default charset overwrite
* @param array $foreign_keys an array of foreign keys
* @return int number of affected rows.
*/
public function create_table($table, $fields, $primary_keys = array(), $if_not_exists = true, $engine = false, $charset = null, $foreign_keys = array())
{
$sql = 'CREATE TABLE';
$sql .= $if_not_exists ? ' IF NOT EXISTS ' : ' ';
$sql .= $this->_connection->quote_identifier($this->_connection->table_prefix($table)).' (';
$sql .= $this->process_fields($fields, '');
if ( ! empty($primary_keys))
{
foreach ($primary_keys as $index => $primary_key)
{
$primary_keys[$index] = $this->_connection->quote_identifier($primary_key);
}
$sql .= ",\n\tPRIMARY KEY (".implode(', ', $primary_keys).')';
}
empty($foreign_keys) or $sql .= $this->process_foreign_keys($foreign_keys);
$sql .= "\n)";
$sql .= ($engine !== false) ? ' ENGINE = '.$engine.' ' : '';
$sql .= $this->process_charset($charset, true).";";
return $this->_connection->query(0, $sql, false);
}
/**
* Truncates a table.
*
* @throws Fuel\Database_Exception
* @param string $table the table name
* @return int the number of affected rows
*/
public function truncate_table($table)
{
$sql = 'TRUNCATE TABLE ';
$sql .= $this->_connection->quote_identifier($this->_connection->table_prefix($table));
return $this->_connection->query(\DB::DELETE, $sql, false);
}
/**
* Generic check if a given table exists.
*
* @throws \Database_Exception
* @param string $table Table name
* @return bool
*/
public function table_exists($table)
{
$sql = 'SELECT * FROM ';
$sql .= $this->_connection->quote_identifier($this->_connection->table_prefix($table));
$sql .= ' LIMIT 1';
try
{
$this->_connection->query(\DB::SELECT, $sql, false);
return true;
}
catch (\Database_Exception $e)
{
// check if we have a DB connection at all
if ( ! $this->_connection->has_connection())
{
// if no connection could be made, re throw the exception
throw $e;
}
return false;
}
}
/**
* Checks if given field(s) in a given table exists.
*
* @throws \Database_Exception
* @param string $table Table name
* @param string|array $columns columns to check
* @return bool
*/
public function field_exists($table, $columns)
{
if ( ! is_array($columns))
{
$columns = array($columns);
}
$sql = 'SELECT ';
$sql .= implode(', ', array_unique(array_map(array($this->_connection, 'quote_identifier'), $columns)));
$sql .= ' FROM ';
$sql .= $this->_connection->quote_identifier($this->_connection->table_prefix($table));
$sql .= ' LIMIT 1';
try
{
$this->_connection->query(\DB::SELECT, $sql, false);
return true;
}
catch (\Database_Exception $e)
{
// check if we have a DB connection at all
if ( ! $this->_connection->has_connection())
{
// if no connection could be made, re throw the exception
throw $e;
}
return false;
}
}
/**
* Creates an index on that table.
*
* @access public
* @param string $table
* @param string $index_name
* @param string $index_columns
* @param string $index (should be 'unique', 'fulltext', 'spatial' or 'nonclustered')
* @return bool
* @author Thomas Edwards
*/
public function create_index($table, $index_columns, $index_name = '', $index = '')
{
static $accepted_index = array('UNIQUE', 'FULLTEXT', 'SPATIAL', 'NONCLUSTERED', 'PRIMARY');
// make sure the index type is uppercase
$index !== '' and $index = strtoupper($index);
if (empty($index_name))
{
if (is_array($index_columns))
{
foreach ($index_columns as $key => $value)
{
if (is_numeric($key))
{
$index_name .= ($index_name == '' ? '' : '_').$value;
}
else
{
$index_name .= ($index_name == '' ? '' : '_').str_replace(array('(', ')', ' '), '', $key);
}
}
}
else
{
$index_name = $index_columns;
}
}
if ($index == 'PRIMARY')
{
$sql = 'ALTER TABLE ';
$sql .= $this->_connection->quote_identifier($this->_connection->table_prefix($table));
$sql .= ' ADD PRIMARY KEY ';
if (is_array($index_columns))
{
$columns = '';
foreach ($index_columns as $key => $value)
{
if (is_numeric($key))
{
$columns .= ($columns=='' ? '' : ', ').$this->_connection->quote_identifier($value);
}
else
{
$columns .= ($columns=='' ? '' : ', ').$this->_connection->quote_identifier($key).' '.strtoupper($value);
}
}
$sql .= ' ('.$columns.')';
}
}
else
{
$sql = 'CREATE ';
$index !== '' and $sql .= (in_array($index, $accepted_index)) ? $index.' ' : '';
$sql .= 'INDEX ';
$sql .= $this->_connection->quote_identifier($index_name);
$sql .= ' ON ';
$sql .= $this->_connection->quote_identifier($this->_connection->table_prefix($table));
if (is_array($index_columns))
{
$columns = '';
foreach ($index_columns as $key => $value)
{
if (is_numeric($key))
{
$columns .= ($columns=='' ? '' : ', ').$this->_connection->quote_identifier($value);
}
else
{
$columns .= ($columns=='' ? '' : ', ').$this->_connection->quote_identifier($key).' '.strtoupper($value);
}
}
$sql .= ' ('.$columns.')';
}
else
{
$sql .= ' ('.$this->_connection->quote_identifier($index_columns).')';
}
}
return $this->_connection->query(0, $sql, false);
}
/**
* Drop an index from a table.
*
* @access public
* @param string $table
* @param string $index_name
* @return bool
* @author Thomas Edwards
*/
public function drop_index($table, $index_name)
{
if (strtoupper($index_name) == 'PRIMARY')
{
$sql = 'ALTER TABLE '.$this->_connection->quote_identifier($this->_connection->table_prefix($table));
$sql .= ' DROP PRIMARY KEY';
}
else
{
$sql = 'DROP INDEX '.$this->_connection->quote_identifier($index_name);
$sql .= ' ON '.$this->_connection->quote_identifier($this->_connection->table_prefix($table));
}
return $this->_connection->query(0, $sql, false);
}
/**
* Adds a single foreign key to a table
*
* @param string $table the table name
* @param array $foreign_key a single foreign key
* @return int number of affected rows
*/
public function add_foreign_key($table, $foreign_key)
{
if ( ! is_array($foreign_key))
{
throw new \InvalidArgumentException('Foreign key for add_foreign_key() must be specified as an array');
}
$sql = 'ALTER TABLE ';
$sql .= $this->_connection->quote_identifier($this->_connection->table_prefix($table)).' ';
$sql .= 'ADD ';
$sql .= ltrim($this->process_foreign_keys(array($foreign_key), $this->_connection), ',');
return $this->_connection->query(0, $sql, false);
}
/**
* Drops a foreign key from a table
*
* @param string $table the table name
* @param string $fk_name the foreign key name
* @return int number of affected rows
*/
public function drop_foreign_key($table, $fk_name)
{
$sql = 'ALTER TABLE ';
$sql .= $this->_connection->quote_identifier($this->_connection->table_prefix($table)).' ';
$sql .= 'DROP FOREIGN KEY '.$this->_connection->quote_identifier($fk_name);
return $this->_connection->query(0, $sql, false);
}
/**
* Returns string of foreign keys
*
* @throws \Database_Exception
* @param array $foreign_keys Array of foreign key rules
* @return string the formatted foreign key string
*/
public function process_foreign_keys($foreign_keys)
{
if ( ! is_array($foreign_keys))
{
throw new \Database_Exception('Foreign keys on create_table() must be specified as an array');
}
$fk_list = array();
foreach($foreign_keys as $definition)
{
// some sanity checks
if (empty($definition['key']))
{
throw new \Database_Exception('Foreign keys on create_table() must specify a foreign key name');
}
if ( empty($definition['reference']))
{
throw new \Database_Exception('Foreign keys on create_table() must specify a foreign key reference');
}
if (empty($definition['reference']['table']) or empty($definition['reference']['column']))
{
throw new \Database_Exception('Foreign keys on create_table() must specify a reference table and column name');
}
$sql = '';
! empty($definition['constraint']) and $sql .= " CONSTRAINT ".$this->_connection->quote_identifier($definition['constraint']);
$sql .= " FOREIGN KEY (".$this->_connection->quote_identifier($definition['key']).')';
$sql .= " REFERENCES ".$this->_connection->quote_identifier($this->_connection->table_prefix($definition['reference']['table'])).' (';
if (is_array($definition['reference']['column']))
{
$sql .= implode(', ', $this->_connection->quote_identifier($definition['reference']['column']));
}
else
{
$sql .= $this->_connection->quote_identifier($definition['reference']['column']);
}
$sql .= ')';
! empty($definition['on_update']) and $sql .= " ON UPDATE ".$definition['on_update'];
! empty($definition['on_delete']) and $sql .= " ON DELETE ".$definition['on_delete'];
$fk_list[] = "\n\t".ltrim($sql);
}
return ', '.implode(',', $fk_list);
}
/**
*
*/
public function alter_fields($type, $table, $fields)
{
$sql = 'ALTER TABLE '.$this->_connection->quote_identifier($this->_connection->table_prefix($table)).' ';
if ($type === 'DROP')
{
if ( ! is_array($fields))
{
$fields = array($fields);
}
$drop_fields = array();
foreach ($fields as $field)
{
$drop_fields[] = 'DROP '.$this->_connection->quote_identifier($field);
}
$sql .= implode(', ', $drop_fields);
}
else
{
$use_brackets = ! in_array($type, array('ADD', 'CHANGE', 'MODIFY'));
$use_brackets and $sql .= $type.' ';
$use_brackets and $sql .= '(';
$sql .= $this->process_fields($fields, (( ! $use_brackets) ? $type.' ' : ''));
$use_brackets and $sql .= ')';
}
return $this->_connection->query(0, $sql, false);
}
/*
* Executes table maintenance. Will throw FuelException when the operation is not supported.
*
* @throws FuelException
* @param string $table the table name
* @return bool whether the operation has succeeded
*/
public function table_maintenance($operation, $table)
{
$sql = $operation.' '.$this->_connection->quote_identifier($this->_connection->table_prefix($table));
$result = $this->_connection->query(\DB::SELECT, $sql, false);
$type = $result->get('Msg_type');
$message = $result->get('Msg_text');
$table = $result->get('Table');
if ($type === 'status' and in_array(strtolower($message), array('ok', 'table is already up to date')))
{
return true;
}
// make sure we have a type logger can handle
if (in_array($type, array('info', 'warning', 'error')))
{
$type = strtoupper($type);
}
else
{
$type = \Fuel::L_INFO;
}
logger($type, 'Table: '.$table.', Operation: '.$operation.', Message: '.$result->get('Msg_text'), 'DBUtil::table_maintenance');
return false;
}
/**
* Formats the default charset.
*
* @param string $charset the character set
* @param bool $is_default whether to use default
* @param string $collation the collating sequence to be used
* @return string the formatted charset sql
*/
protected function process_charset($charset = null, $is_default = false, $collation = null)
{
$charset or $charset = \Config::get('db.'.$this->_name.'.charset', null);
if (empty($charset))
{
return '';
}
$collation or $collation = \Config::get('db.'.$this->_name.'.collation', null);
if (empty($collation) and ($pos = stripos($charset, '_')) !== false)
{
$collation = $charset;
$charset = substr($charset, 0, $pos);
}
$charset = 'CHARACTER SET '.$charset;
if ($is_default)
{
$charset = 'DEFAULT '.$charset;
}
if ( ! empty($collation))
{
if ($is_default)
{
$charset .= ' DEFAULT';
}
$charset .= ' COLLATE '.$collation;
}
return $charset;
}
/**
*
*/
protected function process_fields($fields, $prefix = '')
{
$sql_fields = array();
foreach ($fields as $field => $attr)
{
$attr = array_change_key_case($attr, CASE_UPPER);
$_prefix = $prefix;
if(array_key_exists('NAME', $attr) and $field !== $attr['NAME'] and $_prefix === 'MODIFY ')
{
$_prefix = 'CHANGE ';
}
$sql = "\n\t".$_prefix;
$sql .= $this->_connection->quote_identifier($field);
$sql .= (array_key_exists('NAME', $attr) and $attr['NAME'] !== $field) ? ' '.$this->_connection->quote_identifier($attr['NAME']).' ' : '';
$sql .= array_key_exists('TYPE', $attr) ? ' '.$attr['TYPE'] : '';
if(array_key_exists('CONSTRAINT', $attr))
{
if(is_array($attr['CONSTRAINT']))
{
$sql .= "(";
foreach($attr['CONSTRAINT'] as $constraint)
{
$sql .= (is_string($constraint) ? "'".$constraint."'" : $constraint).", ";
}
$sql = rtrim($sql, ', '). ")";
}
else
{
$sql .= '('.$attr['CONSTRAINT'].')';
}
}
$sql .= array_key_exists('CHARSET', $attr) ? $this->process_charset($attr['CHARSET'], false) : '';
if (array_key_exists('UNSIGNED', $attr) and $attr['UNSIGNED'] === true)
{
$sql .= ' UNSIGNED';
}
if(array_key_exists('DEFAULT', $attr))
{
$sql .= ' DEFAULT '.(($attr['DEFAULT'] instanceof \Database_Expression) ? $attr['DEFAULT'] : $this->_connection->quote($attr['DEFAULT']));
}
if(array_key_exists('NULL', $attr) and $attr['NULL'] === true)
{
$sql .= ' NULL';
}
else
{
$sql .= ' NOT NULL';
}
if (array_key_exists('AUTO_INCREMENT', $attr) and $attr['AUTO_INCREMENT'] === true)
{
$sql .= ' AUTO_INCREMENT';
}
if (array_key_exists('PRIMARY_KEY', $attr) and $attr['PRIMARY_KEY'] === true)
{
$sql .= ' PRIMARY KEY';
}
if (array_key_exists('COMMENT', $attr))
{
$sql .= ' COMMENT '.$this->_connection->escape($attr['COMMENT']);
}
if (array_key_exists('FIRST', $attr) and $attr['FIRST'] === true)
{
$sql .= ' FIRST';
}
elseif (array_key_exists('AFTER', $attr) and strval($attr['AFTER']))
{
$sql .= ' AFTER '.$this->_connection->quote_identifier($attr['AFTER']);
}
$sql_fields[] = $sql;
}
return implode(',', $sql_fields);
}
}

@ -1,50 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_SQLite_Builder_Delete extends \Database_Query_Builder_Delete
{
/**
* Compile the SQL query and return it.
*
* @param mixed $db Database_Connection instance or instance name
*
* @return string
*/
public function compile($db = null)
{
if ( ! $db instanceof \Database_Connection)
{
// Get the database instance
$db = \Database_Connection::instance($db);
}
// Start a deletion query
$query = 'DELETE FROM '.$db->quote_table($this->_table);
if ( ! empty($this->_where))
{
// Add deletion conditions
$query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
}
if ( ! empty($this->_order_by))
{
// Add sorting
$query .= ' '.$this->_compile_order_by($db, $this->_order_by);
}
return $query;
}
}

@ -1,59 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_SQLite_Builder_Update extends \Database_Query_Builder_Update
{
/**
* Compile the SQL query and return it.
*
* @param mixed $db Database instance or instance name
*
* @return string
*/
public function compile($db = null)
{
if ( ! $db instanceof \Database_Connection)
{
// Get the database instance
$db = \Database_Connection::instance($db);
}
// Start an update query
$query = 'UPDATE '.$db->quote_table($this->_table);
if ( ! empty($this->_join))
{
// Add tables to join
$query .= ' '.$this->_compile_join($db, $this->_join);
}
// Add the columns to update
$query .= ' SET '.$this->_compile_set($db, $this->_set);
if ( ! empty($this->_where))
{
// Add selection conditions
$query .= ' WHERE '.$this->_compile_conditions($db, $this->_where);
}
if ( ! empty($this->_order_by))
{
// Add sorting
$query .= ' '.$this->_compile_order_by($db, $this->_order_by);
}
return $query;
}
}

@ -1,130 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_SQLite_Connection extends \Database_PDO_Connection
{
/**
* Create a new [Database_Query_Builder_Update].
*
* // UPDATE users
* $query = $db->update('users');
*
* @param string table to update
* @return Database_Query_Builder_Update
*/
public function update($table = null)
{
return new Database_SQLite_Builder_Update($table);
}
/**
* Create a new [Database_Query_Builder_Delete].
*
* // DELETE FROM users
* $query = $db->delete('users');
*
* @param string table to delete from
* @return Database_Query_Builder_Delete
*/
public function delete($table = null)
{
return new Database_SQLite_Builder_Delete($table);
}
/**
* List tables
*
* @param string $like
*
* @throws \FuelException
*/
public function list_tables($like = null)
{
$query = 'SELECT name FROM sqlite_master WHERE type = "table" AND name != "sqlite_sequence" AND name != "geometry_columns" AND name != "spatial_ref_sys"'
. 'UNION ALL SELECT name FROM sqlite_temp_master '
. 'WHERE type = "table"';
if (is_string($like))
{
$query .= ' AND name LIKE ' . $this->quote($like);
}
$query .= ' ORDER BY name';
$q = $this->_connection->prepare($query);
$q->execute();
$result = $q->fetchAll();
$tables = array();
foreach ($result as $row)
{
$tables[] = reset($row);
}
return $tables;
}
/**
* List table columns
*
* @param string $table table name
* @param string $like column name pattern
* @return array array of column structure
*/
public function list_columns($table, $like = null)
{
$query = "PRAGMA table_info('" . $this->quote_table($table) . "')";
$q = $this->_connection->prepare($query);
$q->execute();
$result = $q->fetchAll();
$count = 0;
$columns = array();
foreach ($result as $row)
{
$column = $this->datatype($row['type']);
$column['name'] = $row['name'];
$column['default'] = $row['dflt_value'];
$column['data_type'] = $row['type'];
$column['null'] = $row['notnull'];
$column['ordinal_position'] = ++$count;
$column['comment'] = '';
$column['extra'] = $row['cid'];
$column['key'] = $row['pk'];
$column['privileges'] = '';
$columns[$row['name']] = $column;
}
return $columns;
}
/**
* Set the charset
*
* @param string $charset
*/
public function set_charset($charset)
{
// Make sure the database is connected
$this->_connection or $this->connect();
if ($charset)
{
$this->_connection->exec('PRAGMA encoding = ' . $this->quote($charset));
}
}
}

@ -1,170 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @author cocteau666@gmail.com
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @copyright 2008 - 2009 Kohana Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Database_Sqlsrv_Connection extends \Database_PDO_Connection
{
/**
* Stores the database configuration locally and name the instance.
*
* [!!] This method cannot be accessed directly, you must use [static::instance].
*
* @param string $name
* @param array $config
*/
protected function __construct($name, array $config)
{
// this driver only works on Windows
if (php_uname('s') !== 'Windows')
{
throw new \Database_Exception('The "SQLSRV" database driver works only on Windows. On *nix, use the "DBLib" driver instead.');
}
parent::__construct($name, $config);
}
/**
* List tables
*
* @param string $like
*
* @throws \FuelException
*/
public function list_tables($like = null)
{
$query = "SELECT name FROM sys.objects WHERE type = 'U' AND name != 'sysdiagrams'";
if (is_string($like))
{
$query .= " AND name LIKE ".$this->quote($like);
}
// Find all table names
$result = $this->query(\DB::SELECT, $query, false);
$tables = array();
foreach ($result as $row)
{
$tables[] = reset($row);
}
return $tables;
}
/**
* List table columns
*
* @param string $table table name
* @param string $like column name pattern
* @return array array of column structure
*/
public function list_columns($table, $like = null)
{
$query = "SELECT * FROM Sys.Columns WHERE id = object_id('" . $this->quote_table($table) . "')";
if (is_string($like))
{
// Search for column names
$query .= " AND name LIKE ".$this->quote($like);
}
$count = 0;
$columns = array();
foreach ($result as $row)
{
list($type, $length) = $this->_parse_type($row['Type']);
$column = $this->datatype($type);
$column['name'] = $row['Field'];
$column['default'] = $row['Default'];
$column['data_type'] = $type;
$column['null'] = ($row['Null'] == 'YES');
$column['ordinal_position'] = ++$count;
switch ($column['type'])
{
case 'float':
if (isset($length))
{
list($column['numeric_precision'], $column['numeric_scale']) = explode(',', $length);
}
break;
case 'int':
if (isset($length))
{
$column['display'] = $length;
}
break;
case 'string':
switch ($column['data_type'])
{
case 'binary':
case 'varbinary':
$column['character_maximum_length'] = $length;
break;
case 'char':
case 'varchar':
$column['character_maximum_length'] = $length;
case 'text':
case 'tinytext':
case 'mediumtext':
case 'longtext':
$column['collation_name'] = $row['Collation'];
break;
case 'enum':
case 'set':
$column['collation_name'] = $row['Collation'];
$column['options'] = explode('\',\'', substr($length, 1, -1));
break;
}
break;
}
$column['comment'] = $row['Comment'];
$column['extra'] = $row['Extra'];
$column['key'] = $row['Key'];
$column['privileges'] = $row['Privileges'];
$columns[$row['Field']] = $column;
}
return $columns;
}
/**
* Set the charset
*
* @param string $charset
*/
public function set_charset($charset)
{
if ($charset == 'utf8' or $charset = 'utf-8')
{
// use utf8 encoding
$this->_connection->setAttribute(\PDO::SQLSRV_ATTR_ENCODING, \PDO::SQLSRV_ENCODING_UTF8);
}
elseif ($charset == 'system')
{
// use system encoding
$this->_connection->setAttribute(\PDO::SQLSRV_ATTR_ENCODING, \PDO::SQLSRV_ENCODING_SYSTEM);
}
elseif (is_numeric($charset))
{
// charset code passed directly
$this->_connection->setAttribute(\PDO::SQLSRV_ATTR_ENCODING, $charset);
}
else
{
// unknown charset, use the default encoding
$this->_connection->setAttribute(\PDO::SQLSRV_ATTR_ENCODING, \PDO::SQLSRV_ENCODING_DEFAULT);
}
}
}

@ -1,429 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Date Class
*
* DateTime replacement that supports internationalization and does correction to GMT
* when your webserver isn't configured correctly.
*
* @package Fuel
* @subpackage Core
* @category Core
* @link http://docs.fuelphp.com/classes/date.html
*
* Notes:
* - Always returns Date objects, will accept both Date objects and UNIX timestamps
* - create_time() uses strptime and has currently a very bad hack to use strtotime for windows servers
* - Uses strftime formatting for dates www.php.net/manual/en/function.strftime.php
*/
class Date
{
/**
* Time constants (and only those that are constant, thus not MONTH/YEAR)
*/
const WEEK = 604800;
const DAY = 86400;
const HOUR = 3600;
const MINUTE = 60;
/**
* @var int server's time() offset from gmt in seconds
*/
protected static $server_gmt_offset = 0;
/**
* @var string the timezone to be used to output formatted data
*/
public static $display_timezone = null;
public static function _init()
{
static::$server_gmt_offset = \Config::get('server_gmt_offset', 0);
static::$display_timezone = \Config::get('default_timezone') ?: date_default_timezone_get();
// Ugly temporary windows fix because windows doesn't support strptime()
// It attempts conversion between glibc style formats and PHP's internal style format (no 100% match!)
if ( ! function_exists('strptime') && ! function_exists('Fuel\Core\strptime'))
{
function strptime($input, $format)
{
// convert the format string from glibc to date format (where possible)
$new_format = str_replace(
array('%a', '%A', '%d', '%e', '%j', '%u', '%w', '%U', '%V', '%W', '%b', '%B', '%h', '%m', '%C', '%g', '%G', '%y', '%Y', '%H', '%k', '%I', '%l', '%M', '%p', '%P', '%r', '%R', '%S', '%T', '%X', '%z', '%Z', '%c', '%D', '%F', '%s', '%x', '%n', '%t', '%%'),
array('D', 'l', 'd', 'j', 'N', 'z', 'w', '[^^]', 'W', '[^^]', 'M', 'F', 'M', 'm', '[^^]', 'Y', 'o', 'y', 'Y', 'H', 'G', 'h', 'g', 'i', 'A', 'a', 'H:i:s A', 'H:i', 's', 'H:i:s', '[^^]', 'O', 'T ', '[^^]', 'm/d/Y', 'Y-m-d', 'U', '[^^]', "\n", "\t", '%'),
$format
);
// parse the input
$parsed = date_parse_from_format($new_format, $input);
// parse succesful?
if (is_array($parsed) and empty($parsed['errors']))
{
return array(
'tm_year' => $parsed['year'] - 1900,
'tm_mon' => $parsed['month'] - 1,
'tm_mday' => $parsed['day'],
'tm_hour' => $parsed['hour'] ?: 0,
'tm_min' => $parsed['minute'] ?: 0,
'tm_sec' => $parsed['second'] ?: 0,
);
}
else
{
$masks = array(
'%d' => '(?P<d>[0-9]{2})',
'%m' => '(?P<m>[0-9]{2})',
'%Y' => '(?P<Y>[0-9]{4})',
'%H' => '(?P<H>[0-9]{2})',
'%M' => '(?P<M>[0-9]{2})',
'%S' => '(?P<S>[0-9]{2})',
);
$rexep = "#" . strtr(preg_quote($format), $masks) . "#";
if ( ! preg_match($rexep, $input, $result))
{
return false;
}
return array(
"tm_sec" => isset($result['S']) ? (int) $result['S'] : 0,
"tm_min" => isset($result['M']) ? (int) $result['M'] : 0,
"tm_hour" => isset($result['H']) ? (int) $result['H'] : 0,
"tm_mday" => isset($result['d']) ? (int) $result['d'] : 0,
"tm_mon" => isset($result['m']) ? ($result['m'] ? $result['m'] - 1 : 0) : 0,
"tm_year" => isset($result['Y']) ? ($result['Y'] > 1900 ? $result['Y'] - 1900 : 0) : 0,
);
}
}
// This really is some fugly code, but someone at PHP HQ decided strptime should
// output this awful array instead of a timestamp LIKE EVERYONE ELSE DOES!!!
}
}
/**
* Create Date object from timestamp, timezone is optional
*
* @param int $timestamp UNIX timestamp from current server
* @param string $timezone valid PHP timezone from www.php.net/timezones
* @return Date
*/
public static function forge($timestamp = null, $timezone = null)
{
return new static($timestamp, $timezone);
}
/**
* Returns the current time with offset
*
* @param string $timezone valid PHP timezone from www.php.net/timezones
* @return Date
*/
public static function time($timezone = null)
{
return static::forge(null, $timezone);
}
/**
* Returns the current time with offset
*
* @param string $timezone valid PHP timezone from www.php.net/timezones
* @return string
*/
public static function display_timezone($timezone = null)
{
is_string($timezone) and static::$display_timezone = $timezone;
return static::$display_timezone;
}
/**
* Uses the date config file to translate string input to timestamp
*
* @param string $input date/time input
* @param string $pattern_key key name of pattern in config file
* @return Date
*/
public static function create_from_string($input, $pattern_key = 'local')
{
\Config::load('date', 'date');
$pattern = \Config::get('date.patterns.'.$pattern_key, null);
empty($pattern) and $pattern = $pattern_key;
$time = strptime($input, $pattern);
if ($time === false)
{
throw new \UnexpectedValueException('Input was not recognized by pattern.');
}
// convert it into a timestamp
$timestamp = mktime($time['tm_hour'], $time['tm_min'], $time['tm_sec'],
$time['tm_mon'] + 1, $time['tm_mday'], $time['tm_year'] + 1900);
if ($timestamp === false)
{
throw new \OutOfBoundsException('Input was invalid.'.(PHP_INT_SIZE == 4 ? ' A 32-bit system only supports dates between 1901 and 2038.' : ''));
}
return static::forge($timestamp);
}
/**
* Fetches an array of Date objects per interval within a range
*
* @param int|Date $start start of the range
* @param int|Date $end end of the range
* @param int|string $interval Length of the interval in seconds or valid strtotime time difference
* @return array array of Date objects
*/
public static function range_to_array($start, $end, $interval = '+1 Day')
{
// make sure start and end are date objects
$start = ( ! $start instanceof Date) ? static::forge($start) : $start;
$end = ( ! $end instanceof Date) ? static::forge($end) : $end;
$range = array();
// if end > start, the range is empty
if ($end->get_timestamp() >= $start->get_timestamp())
{
$current = $start;
$increment = $interval;
do
{
$range[] = $current;
if ( ! is_int($interval))
{
$increment = strtotime($interval, $current->get_timestamp()) - $current->get_timestamp();
if ($increment <= 0)
{
throw new \UnexpectedValueException('Input was not recognized by pattern.');
}
}
$current = static::forge($current->get_timestamp() + $increment);
}
while ($current->get_timestamp() <= $end->get_timestamp());
}
return $range;
}
/**
* Returns the number of days in the requested month
*
* @param int $month month as a number (1-12)
* @param int $year the year, leave empty for current
* @return int the number of days in the month
*/
public static function days_in_month($month, $year = null)
{
$year = ! empty($year) ? (int) $year : (int) date('Y');
$month = (int) $month;
if ($month < 1 or $month > 12)
{
throw new \UnexpectedValueException('Invalid input for month given.');
}
elseif ($month == 2)
{
if ($year % 400 == 0 or ($year % 4 == 0 and $year % 100 != 0))
{
return 29;
}
}
$days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
return $days_in_month[$month-1];
}
/**
* Returns the time ago
*
* @param int $timestamp UNIX timestamp from current server
* @param int $from_timestamp UNIX timestamp to compare against. Default to the current time
* @param string $unit Unit to return the result in
* @return string Time ago
*/
public static function time_ago($timestamp, $from_timestamp = null, $unit = null)
{
if ($timestamp === null)
{
return '';
}
! is_numeric($timestamp) and $timestamp = static::create_from_string($timestamp)->get_timestamp();
$from_timestamp == null and $from_timestamp = time();
\Lang::load('date', true);
$difference = $from_timestamp - $timestamp;
$periods = array('second', 'minute', 'hour', 'day', 'week', 'month', 'year', 'decade');
$lengths = array(60, 60, 24, 7, 4.35, 12, 10);
for ($j = 0; isset($lengths[$j]) and $difference >= $lengths[$j] and (empty($unit) or $unit != $periods[$j]); $j++)
{
$difference /= $lengths[$j];
}
$difference = round($difference);
if ($difference != 1)
{
$periods[$j] = \Inflector::pluralize($periods[$j]);
}
$text = \Lang::get('date.text', array(
'time' => \Lang::get('date.'.$periods[$j], array('t' => $difference)),
));
return $text;
}
/**
* @var int instance timestamp
*/
protected $timestamp;
/**
* @var string output timezone
*/
protected $timezone;
public function __construct($timestamp = null, $timezone = null)
{
is_null($timestamp) and $timestamp = time() + static::$server_gmt_offset;
! $timezone and $timezone = \Fuel::$timezone;
$this->timestamp = $timestamp;
$this->set_timezone($timezone);
}
/**
* Returns the date formatted according to the current locale
*
* @param string $pattern_key either a named pattern from date config file or a pattern, defaults to 'local'
* @param mixed $timezone vald timezone, or if true, output the time in local time instead of system time
* @return string
*/
public function format($pattern_key = 'local', $timezone = null)
{
\Config::load('date', 'date');
$pattern = \Config::get('date.patterns.'.$pattern_key, $pattern_key);
// determine the timezone to switch to
$timezone === true and $timezone = static::$display_timezone;
is_string($timezone) or $timezone = $this->timezone;
// Temporarily change timezone when different from default
if (\Fuel::$timezone != $timezone)
{
date_default_timezone_set($timezone);
}
// Create output
$output = strftime($pattern, $this->timestamp);
// Change timezone back to default if changed previously
if (\Fuel::$timezone != $timezone)
{
date_default_timezone_set(\Fuel::$timezone);
}
return $output;
}
/**
* Returns the internal timestamp
*
* @return int
*/
public function get_timestamp()
{
return $this->timestamp;
}
/**
* Returns the internal timezone
*
* @return string
*/
public function get_timezone()
{
return $this->timezone;
}
/**
* Returns the internal timezone or the display timezone abbreviation
*
* @param boolean $display_timezone
*
* @return string
*/
public function get_timezone_abbr($display_timezone = false)
{
// determine the timezone to switch to
$display_timezone and $timezone = static::$display_timezone;
empty($timezone) and $timezone = $this->timezone;
// Temporarily change timezone when different from default
if (\Fuel::$timezone != $timezone)
{
date_default_timezone_set($timezone);
}
// Create output
$output = date('T');
// Change timezone back to default if changed previously
if (\Fuel::$timezone != $timezone)
{
date_default_timezone_set(\Fuel::$timezone);
}
return $output;
}
/**
* Change the timezone
*
* @param string $timezone timezone from www.php.net/timezones
* @return Date
*/
public function set_timezone($timezone)
{
$this->timezone = $timezone;
return $this;
}
/**
* Allows you to just put the object in a string and get it inserted in the default pattern
*
* @return string
*/
public function __toString()
{
return $this->format();
}
}

@ -1,415 +0,0 @@
<?php
/**
* Database object creation helper methods.
*
* @package Fuel\Database
* @author Kohana Team
* @copyright (c) 2009 Kohana Team
* @license http://kohanaphp.com/license
*/
namespace Fuel\Core;
class DB
{
// Query types
const SELECT = 1;
const INSERT = 2;
const UPDATE = 3;
const DELETE = 4;
public static $query_count = 0;
/**
* Create a new [Database_Query] of the given type.
*
* // Create a new SELECT query
* $query = DB::query('SELECT * FROM users');
*
* // Create a new DELETE query
* $query = DB::query('DELETE FROM users WHERE id = 5');
*
* Specifying the type changes the returned result. When using
* `DB::SELECT`, a [Database_Query_Result] will be returned.
* `DB::INSERT` queries will return the insert id and number of rows.
* For all other queries, the number of affected rows is returned.
*
* @param string SQL statement
* @param integer type: DB::SELECT, DB::UPDATE, etc
* @return Database_Query
*/
public static function query($sql, $type = null)
{
return new \Database_Query($sql, $type);
}
/*
* Returns the last query
*
* @return string the last query
*/
public static function last_query($db = null)
{
return \Database_Connection::instance($db)->last_query;
}
/*
* Returns the DB drivers error info
*
* @return mixed the DB drivers error info
*/
public static function error_info($db = null)
{
return \Database_Connection::instance($db)->error_info();
}
/*
* Returns a database instance
*
* @return Database_Connection
*/
public static function instance($db = null)
{
return \Database_Connection::instance($db);
}
/**
* Create a new [Database_Query_Builder_Select]. Each argument will be
* treated as a column. To generate a `foo AS bar` alias, use an array.
*
* // SELECT id, username
* $query = DB::select('id', 'username');
*
* // SELECT id AS user_id
* $query = DB::select(array('id', 'user_id'));
*
* @param mixed column name or array($column, $alias) or object
* @param ...
* @return Database_Query_Builder_Select
*/
public static function select($args = null)
{
return \Database_Connection::instance()->select(func_get_args());
}
/**
* Create a new [Database_Query_Builder_Select] from an array of columns.
*
* // SELECT id, username
* $query = DB::select_array(array('id', 'username'));
*
* @param array columns to select
* @return Database_Query_Builder_Select
*/
public static function select_array(array $columns = null)
{
return \Database_Connection::instance()->select($columns);
}
/**
* Create a new [Database_Query_Builder_Insert].
*
* // INSERT INTO users (id, username)
* $query = DB::insert('users', array('id', 'username'));
*
* @param string table to insert into
* @param array list of column names or array($column, $alias) or object
* @return Database_Query_Builder_Insert
*/
public static function insert($table = null, array $columns = null)
{
return \Database_Connection::instance()->insert($table, $columns);
}
/**
* Create a new [Database_Query_Builder_Update].
*
* // UPDATE users
* $query = DB::update('users');
*
* @param string table to update
* @return Database_Query_Builder_Update
*/
public static function update($table = null)
{
return \Database_Connection::instance()->update($table);
}
/**
* Create a new [Database_Query_Builder_Delete].
*
* // DELETE FROM users
* $query = DB::delete('users');
*
* @param string table to delete from
* @return Database_Query_Builder_Delete
*/
public static function delete($table = null)
{
return \Database_Connection::instance()->delete($table);
}
/**
* Create a new [Database_Expression] which is not escaped. An expression
* is the only way to use SQL functions within query builders.
*
* $expression = DB::expr('COUNT(users.id)');
*
* @param string $string expression
* @return Database_Expression
*/
public static function expr($string)
{
return new \Database_Expression($string);
}
/**
* Create a new [Database_Expression] containing a quoted identifier. An expression
* is the only way to use SQL functions within query builders.
*
* $expression = DB::identifier('users.id'); // returns `users`.`id` for MySQL
*
* @param string $string the string to quote
* @param string $db the database connection to use
* @return Database_Expression
*/
public static function identifier($string, $db = null)
{
return new \Database_Expression(static::quote_identifier($string, $db));
}
/**
* Quote a value for an SQL query.
*
* @param string $string the string to quote
* @param string $db the database connection to use
* @return string the quoted value
*/
public static function quote($string, $db = null)
{
if (is_array($string))
{
foreach ($string as $k => $s)
{
$string[$k] = static::quote($s, $db);
}
return $string;
}
return \Database_Connection::instance($db)->quote($string);
}
/**
* Quotes an identifier so it is ready to use in a query.
*
* @param string $string the string to quote
* @param string $db the database connection to use
* @return string the quoted identifier
*/
public static function quote_identifier($string, $db = null)
{
if (is_array($string))
{
foreach ($string as $k => $s)
{
$string[$k] = static::quote_identifier($s, $db);
}
return $string;
}
return \Database_Connection::instance($db)->quote_identifier($string);
}
/**
* Quote a database table name and adds the table prefix if needed.
*
* @param string $string the string to quote
* @param string $db the database connection to use
* @return string the quoted identifier
*/
public static function quote_table($string, $db = null)
{
if (is_array($string))
{
foreach ($string as $k => $s)
{
$string[$k] = static::quote_table($s, $db);
}
return $string;
}
return \Database_Connection::instance($db)->quote_table($string);
}
/**
* Escapes a string to be ready for use in a sql query
*
* @param string $string the string to escape
* @param string $db the database connection to use
* @return string the escaped string
*/
public static function escape($string, $db = null)
{
return \Database_Connection::instance($db)->escape($string);
}
/**
* If a table name is given it will return the table name with the configured
* prefix. If not, then just the prefix is returned
*
* @param string $table the table name to prefix
* @param string $db the database connection to use
* @return string the prefixed table name or the prefix
*/
public static function table_prefix($table = null, $db = null)
{
return \Database_Connection::instance($db)->table_prefix($table);
}
/**
* Lists all of the columns in a table. Optionally, a LIKE string can be
* used to search for specific fields.
*
* // Get all columns from the "users" table
* $columns = DB::list_columns('users');
*
* // Get all name-related columns
* $columns = DB::list_columns('users', '%name%');
*
* @param string table to get columns from
* @param string column to search for
* @param string the database connection to use
* @return array
*/
public static function list_columns($table = null, $like = null, $db = null)
{
return \Database_Connection::instance($db)->list_columns($table, $like);
}
/**
* If a table name is given it will return the table name with the configured
* prefix. If not, then just the prefix is returned
*
* @param string $table the table name to prefix
* @param string $db the database connection to use
* @return string the prefixed table name or the prefix
*/
public static function list_tables($like = null, $db = null)
{
return \Database_Connection::instance($db)->list_tables($like);
}
/**
* Returns a normalized array describing the SQL data type
*
* DB::datatype('char');
*
* @param string SQL data type
* @param string db connection
* @return array
*/
public static function datatype($type, $db = null)
{
return \Database_Connection::instance($db)->datatype($type);
}
/**
* Count the number of records in a table.
*
* // Get the total number of records in the "users" table
* $count = DB::count_records('users');
*
* @param mixed table name string or array(query, alias)
* @param string db connection
* @return integer
*/
public static function count_records($table, $db = null)
{
return \Database_Connection::instance($db)->count_records($table);
}
/**
* Count the number of records in the last query, without LIMIT or OFFSET applied.
*
* // Get the total number of records that match the last query
* $count = $db->count_last_query();
*
* @param string db connection
* @return integer
*/
public static function count_last_query($db = null)
{
return \Database_Connection::instance($db)->count_last_query();
}
/**
* Set the connection character set. This is called automatically by [static::connect].
*
* DB::set_charset('utf8');
*
* @throws Database_Exception
* @param string character set name
* @param string db connection
* @return void
*/
public static function set_charset($charset, $db = null)
{
\Database_Connection::instance($db)->set_charset($charset);
}
/**
* Checks whether a connection is in transaction.
*
* DB::in_transaction();
*
* @param string db connection
* @return bool
*/
public static function in_transaction($db = null)
{
return \Database_Connection::instance($db)->in_transaction();
}
/**
* Begins a transaction on instance
*
* DB::start_transaction();
*
* @param string db connection
* @return bool
*/
public static function start_transaction($db = null)
{
return \Database_Connection::instance($db)->start_transaction();
}
/**
* Commits all pending transactional queries
*
* DB::commit_transaction();
*
* @param string db connection
* @return bool
*/
public static function commit_transaction($db = null)
{
return \Database_Connection::instance($db)->commit_transaction();
}
/**
* Rollsback pending transactional queries
* Rollback to the current level uses SAVEPOINT,
* it does not work if current RDBMS does not support them.
* In this case system rollsback all queries and closes the transaction
*
* DB::rollback_transaction();
*
* @param string $db connection
* @param bool $rollback_all:
* true - rollback everything and close transaction;
* false - rollback only current level
* @return bool
*/
public static function rollback_transaction($db = null, $rollback_all = true)
{
return \Database_Connection::instance($db)->rollback_transaction($rollback_all);
}
}

@ -1,445 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* DBUtil Class
*
* @package Fuel
* @category Core
* @author Dan Horrigan
*/
class DBUtil
{
/**
* @var string $connection the database connection (identifier)
*/
protected static $connection = null;
/*
* Load the db config, the Database_Connection might not have fired jet.
*
*/
public static function _init()
{
\Config::load('db', true);
}
/**
* Sets the database connection to use for following DBUtil calls.
*
* @throws \FuelException
* @param string $connection connection name, null for default
*/
public static function set_connection($connection)
{
if ($connection !== null and ! is_string($connection))
{
throw new \FuelException('A connection must be supplied as a string.');
}
static::$connection = $connection;
}
/**
* Creates a database. Will throw a Database_Exception if it cannot.
*
* @throws Fuel\Database_Exception
* @param string $database the database name
* @param string $charset the character set
* @param boolean $if_not_exists whether to add an IF NOT EXISTS statement.
* @param string $db the database connection to use
* @return int the number of affected rows
*/
public static function create_database($database, $charset = null, $if_not_exists = true, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'create_database',
array(
$database,
$charset,
$if_not_exists,
)
);
}
/**
* Drops a database. Will throw a Database_Exception if it cannot.
*
* @throws Fuel\Database_Exception
* @param string $database the database name
* @param string $db the database connection to use
* @return int the number of affected rows
*/
public static function drop_database($database, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'drop_database',
array(
$database,
)
);
}
/**
* Drops a table. Will throw a Database_Exception if it cannot.
*
* @throws Fuel\Database_Exception
* @param string $table the table name
* @param string $db the database connection to use
* @return int the number of affected rows
*/
public static function drop_table($table, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'drop_table',
array(
$table,
)
);
}
/**
* Renames a table. Will throw a Database_Exception if it cannot.
*
* @throws \Database_Exception
* @param string $table the old table name
* @param string $new_table_name the new table name
* @param string $db the database connection to use
* @return int the number of affected
*/
public static function rename_table($table, $new_table_name, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'rename_table',
array(
$table,
$new_table_name,
)
);
}
/**
* Creates a table.
*
* @throws \Database_Exception
* @param string $table the table name
* @param array $fields the fields array
* @param array $primary_keys an array of primary keys
* @param boolean $if_not_exists whether to add an IF NOT EXISTS statement.
* @param string|boolean $engine storage engine overwrite
* @param string $charset default charset overwrite
* @param array $foreign_keys an array of foreign keys
* @param string $db the database connection to use
* @return int number of affected rows.
*/
public static function create_table($table, $fields, $primary_keys = array(), $if_not_exists = true, $engine = false, $charset = null, $foreign_keys = array(), $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'create_table',
array(
$table,
$fields,
$primary_keys,
$if_not_exists,
$engine,
$charset,
$foreign_keys,
)
);
}
/**
* Adds fields to a table a table. Will throw a Database_Exception if it cannot.
*
* @throws Fuel\Database_Exception
* @param string $table the table name
* @param array $fields the new fields
* @param string $db the database connection to use
* @return int the number of affected
*/
public static function add_fields($table, $fields, $db = null)
{
return static::alter_fields('ADD', $table, $fields, $db);
}
/**
* Modifies fields in a table. Will throw a Database_Exception if it cannot.
*
* @throws Fuel\Database_Exception
* @param string $table the table name
* @param array $fields the modified fields
* @param string $db the database connection to use
* @return int the number of affected
*/
public static function modify_fields($table, $fields, $db = null)
{
return static::alter_fields('MODIFY', $table, $fields, $db);
}
/**
* Drops fields from a table a table. Will throw a Database_Exception if it cannot.
*
* @throws Fuel\Database_Exception
* @param string $table the table name
* @param string|array $fields the fields
* @param string $db the database connection to use
* @return int the number of affected
*/
public static function drop_fields($table, $fields, $db = null)
{
return static::alter_fields('DROP', $table, $fields, $db);
}
/**
* Creates an index on that table.
*
* @access public
* @static
* @param string $table
* @param string $index_name
* @param string $index_columns
* @param string $index (should be 'unique', 'fulltext', 'spatial' or 'nonclustered')
* @param string $db the database connection to use
* @return bool
* @author Thomas Edwards
*/
public static function create_index($table, $index_columns, $index_name = '', $index = '', $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'create_index',
array(
$table,
$index_columns,
$index_name,
$index,
)
);
}
/**
* Drop an index from a table.
*
* @access public
* @static
* @param string $table
* @param string $index_name
* @param string $db the database connection to use
* @return bool
* @author Thomas Edwards
*/
public static function drop_index($table, $index_name, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'drop_index',
array(
$table,
$index_name,
)
);
}
/**
* Adds a single foreign key to a table
*
* @param string $table the table name
* @param array $foreign_key a single foreign key
* @param string $db the database connection to use
* @return int number of affected rows
*/
public static function add_foreign_key($table, $foreign_key, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'add_foreign_key',
array(
$table,
$foreign_key,
)
);
}
/**
* Drops a foreign key from a table
*
* @param string $table the table name
* @param string $fk_name the foreign key name
* @param string $db the database connection to use
* @return int number of affected rows
*/
public static function drop_foreign_key($table, $fk_name, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'drop_foreign_key',
array(
$table,
$fk_name,
)
);
}
/**
* Returns string of foreign keys
*
* @throws \Database_Exception
* @param array $foreign_keys Array of foreign key rules
* @param string $db the database connection to use
* @return string the formatted foreign key string
*/
public static function process_foreign_keys($foreign_keys, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'process_foreign_keys',
array(
$foreign_keys,
)
);
}
/**
* Truncates a table.
*
* @throws Fuel\Database_Exception
* @param string $table the table name
* @param string $db the database connection to use
* @return int the number of affected rows
*/
public static function truncate_table($table, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'truncate_table',
array(
$table,
)
);
}
/**
* Analyzes a table.
*
* @param string $table the table name
* @param string $db the database connection to use
* @return bool whether the table is OK
*/
public static function analyze_table($table, $db = null)
{
return static::table_maintenance('ANALYZE TABLE', $table, $db);
}
/**
* Checks a table.
*
* @param string $table the table name
* @param string $db the database connection to use
* @return bool whether the table is OK
*/
public static function check_table($table, $db = null)
{
return static::table_maintenance('CHECK TABLE', $table, $db);
}
/**
* Optimizes a table.
*
* @param string $table the table name
* @param string $db the database connection to use
* @return bool whether the table has been optimized
*/
public static function optimize_table($table, $db = null)
{
return static::table_maintenance('OPTIMIZE TABLE', $table, $db);
}
/**
* Repairs a table.
*
* @param string $table the table name
* @param string $db the database connection to use
* @return bool whether the table has been repaired
*/
public static function repair_table($table, $db = null)
{
return static::table_maintenance('REPAIR TABLE', $table, $db);
}
/**
* Checks if a given table exists.
*
* @throws \Database_Exception
* @param string $table Table name
* @param string $db the database connection to use
* @return bool
*/
public static function table_exists($table, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'table_exists',
array(
$table,
)
);
}
/**
* Checks if given field(s) in a given table exists.
*
* @throws \Database_Exception
* @param string $table Table name
* @param string|array $columns columns to check
* @param string $db the database connection to use
* @return bool
*/
public static function field_exists($table, $columns, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'field_exists',
array(
$table,
$columns,
)
);
}
/**
*
*/
protected static function alter_fields($type, $table, $fields, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'alter_fields',
array(
$type,
$table,
$fields,
)
);
}
/*
* Executes table maintenance. Will throw FuelException when the operation is not supported.
*
* @throws FuelException
* @param string $table the table name
* @param string $db the database connection to use
* @return bool whether the operation has succeeded
*/
protected static function table_maintenance($operation, $table, $db = null)
{
return \Database_Connection::instance($db ? $db : static::$connection)->schema(
'table_maintenance',
array(
$operation,
$table,
)
);
}
}

@ -1,551 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Debug class
*
* The Debug class is a simple utility for debugging variables, objects, arrays, etc by outputting information to the display.
*
* @package Fuel
* @category Core
* @link http://docs.fuelphp.com/classes/debug.html
*/
class Debug
{
public static $max_nesting_level = 5;
public static $js_toggle_open = false;
protected static $js_displayed = false;
protected static $files = array();
/**
* Quick and nice way to output a mixed variable to the browser
*
* @static
* @access public
* @return string
*/
public static function dump()
{
if (\Fuel::$is_cli)
{
// no fancy flying, jump dump 'm
foreach (func_get_args() as $arg)
{
var_dump($arg);
}
}
else
{
$backtrace = debug_backtrace();
// locate the first file entry that isn't this class itself
foreach ($backtrace as $stack => $trace)
{
if (isset($trace['file']))
{
// If being called from within, show the file above in the backtrack
if (strpos($trace['file'], 'core/classes/debug.php') !== false)
{
$callee = $backtrace[$stack+1];
$label = \Inflector::humanize($backtrace[$stack+1]['function']);
}
else
{
$callee = $trace;
$label = 'Debug';
}
$callee['file'] = \Fuel::clean_path($callee['file']);
break;
}
}
$arguments = func_get_args();
if ( ! static::$js_displayed)
{
echo <<<JS
<script type="text/javascript">function fuel_debug_toggle(a){if(document.getElementById){if(document.getElementById(a).style.display=="none"){document.getElementById(a).style.display="block"}else{document.getElementById(a).style.display="none"}}else{if(document.layers){if(document.id.display=="none"){document.id.display="block"}else{document.id.display="none"}}else{if(document.all.id.style.display=="none"){document.all.id.style.display="block"}else{document.all.id.style.display="none"}}}};</script>
JS;
static::$js_displayed = true;
}
echo '<div class="fuelphp-dump" style="font-size: 13px;background: #EEE !important; border:1px solid #666; color: #000 !important; padding:10px;">';
echo '<h1 style="border-bottom: 1px solid #CCC; padding: 0 0 5px 0; margin: 0 0 5px 0; font: bold 120% sans-serif;">'.$callee['file'].' @ line: '.$callee['line'].'</h1>';
echo '<pre style="overflow:auto;font-size:100%;">';
$count = count($arguments);
for ($i = 1; $i <= $count; $i++)
{
echo '<strong>Variable #'.$i.':</strong>'.PHP_EOL;
echo static::format('', $arguments[$i - 1]);
echo PHP_EOL.PHP_EOL;
}
echo "</pre>";
echo "</div>";
}
}
/**
* Quick and nice way to output a mixed variable to the browser
*
* @static
* @access public
* @return string
*/
public static function inspect()
{
$backtrace = debug_backtrace();
// If being called from within, show the file above in the backtrack
if (strpos($backtrace[0]['file'], 'core/classes/debug.php') !== false)
{
$callee = $backtrace[1];
$label = \Inflector::humanize($backtrace[1]['function']);
}
else
{
$callee = $backtrace[0];
$label = 'Debug';
}
$arguments = func_get_args();
$total_arguments = count($arguments);
$callee['file'] = \Fuel::clean_path($callee['file']);
if ( ! static::$js_displayed)
{
echo <<<JS
<script type="text/javascript">function fuel_debug_toggle(a){if(document.getElementById){if(document.getElementById(a).style.display=="none"){document.getElementById(a).style.display="block"}else{document.getElementById(a).style.display="none"}}else{if(document.layers){if(document.id.display=="none"){document.id.display="block"}else{document.id.display="none"}}else{if(document.all.id.style.display=="none"){document.all.id.style.display="block"}else{document.all.id.style.display="none"}}}};</script>
JS;
static::$js_displayed = true;
}
echo '<div class="fuelphp-inspect" style="font-size: 13px;background: #EEE !important; border:1px solid #666; color: #000 !important; padding:10px;">';
echo '<h1 style="border-bottom: 1px solid #CCC; padding: 0 0 5px 0; margin: 0 0 5px 0; font: bold 120% sans-serif;">'.$callee['file'].' @ line: '.$callee['line'].'</h1>';
echo '<pre style="overflow:auto;font-size:100%;">';
$i = 0;
foreach ($arguments as $argument)
{
echo '<strong>'.$label.' #'.(++$i).' of '.$total_arguments.'</strong>:<br />';
echo static::format('...', $argument);
echo '<br />';
}
echo "</pre>";
echo "</div>";
}
/**
* Formats the given $var's output in a nice looking, Foldable interface.
*
* @param string $name the name of the var
* @param mixed $var the variable
* @param int $level the indentation level
* @param string $indent_char the indentation character
* @param string $scope
* @return string the formatted string.
*/
public static function format($name, $var, $level = 0, $indent_char = '&nbsp;&nbsp;&nbsp;&nbsp;', $scope = '')
{
$return = str_repeat($indent_char, $level);
if (is_array($var))
{
$id = 'fuel_debug_'.mt_rand();
$return .= "<i>{$scope}</i> <strong>".htmlentities($name)."</strong>";
$return .= " (Array, ".count($var)." element".(count($var)!=1 ? "s" : "").")";
if (count($var) > 0 and static::$max_nesting_level > $level)
{
$return .= " <a href=\"javascript:fuel_debug_toggle('$id');\" title=\"Click to ".(static::$js_toggle_open ? "close" : "open")."\">&crarr;</a>\n";
}
else
{
$return .= "\n";
}
if (static::$max_nesting_level <= $level)
{
$return .= str_repeat($indent_char, $level + 1)."...\n";
}
else
{
$sub_return = '';
foreach ($var as $key => $val)
{
$sub_return .= static::format($key, $val, $level + 1);
}
if (count($var) > 0)
{
$return .= "<span id=\"$id\" style=\"display: ".(static::$js_toggle_open ? "block" : "none").";\">$sub_return</span>";
}
else
{
$return .= $sub_return;
}
}
}
elseif (is_string($var))
{
$return .= "<i>{$scope}</i> <strong>".htmlentities($name)."</strong> (String): <span style=\"color:#E00000;\">\"".\Security::htmlentities($var)."\"</span> (".strlen($var)." characters)\n";
}
elseif (is_float($var))
{
$return .= "<i>{$scope}</i> <strong>".htmlentities($name)."</strong> (Float): {$var}\n";
}
elseif (is_long($var))
{
$return .= "<i>{$scope}</i> <strong>".htmlentities($name)."</strong> (Integer): {$var}\n";
}
elseif (is_null($var))
{
$return .= "<i>{$scope}</i> <strong>".htmlentities($name)."</strong> : null\n";
}
elseif (is_bool($var))
{
$return .= "<i>{$scope}</i> <strong>".htmlentities($name)."</strong> (Boolean): ".($var ? 'true' : 'false')."\n";
}
elseif (is_double($var))
{
$return .= "<i>{$scope}</i> <strong>".htmlentities($name)."</strong> (Double): {$var}\n";
}
elseif (is_object($var))
{
// dirty hack to get the object id
ob_start();
var_dump($var);
$contents = ob_get_contents();
ob_end_clean();
// process it based on the xdebug presence and configuration
if (extension_loaded('xdebug') and ini_get('xdebug.overload_var_dump') === '1')
{
if (ini_get('html_errors'))
{
preg_match('~(.*?)\)\[<i>(\d+)(.*)~', $contents, $matches);
}
else
{
preg_match('~class (.*?)#(\d+)(.*)~', $contents, $matches);
}
}
else
{
preg_match('~object\((.*?)#(\d+)(.*)~', $contents, $matches);
}
$id = 'fuel_debug_'.mt_rand();
$rvar = new \ReflectionObject($var);
$vars = $rvar->getProperties();
$return .= "<i>{$scope}</i> <strong>{$name}</strong> (Object #".$matches[2]."): ".get_class($var);
if (count($vars) > 0 and static::$max_nesting_level > $level)
{
$return .= " <a href=\"javascript:fuel_debug_toggle('$id');\" title=\"Click to ".(static::$js_toggle_open ? "close" : "open")."\">&crarr;</a>\n";
}
$return .= "\n";
$sub_return = '';
foreach ($rvar->getProperties() as $prop)
{
$prop->isPublic() or $prop->setAccessible(true);
if ($prop->isPrivate())
{
$scope = 'private';
}
elseif ($prop->isProtected())
{
$scope = 'protected';
}
else
{
$scope = 'public';
}
if (static::$max_nesting_level <= $level)
{
$sub_return .= str_repeat($indent_char, $level + 1)."...\n";
}
else
{
$sub_return .= static::format($prop->name, $prop->getValue($var), $level + 1, $indent_char, $scope);
}
}
if (count($vars) > 0)
{
$return .= "<span id=\"$id\" style=\"display: ".(static::$js_toggle_open ? "block" : "none").";\">$sub_return</span>";
}
else
{
$return .= $sub_return;
}
}
else
{
$return .= "<i>{$scope}</i> <strong>".htmlentities($name)."</strong>: {$var}\n";
}
return $return;
}
/**
* Returns the debug lines from the specified file
*
* @access protected
* @param string $filepath the file path
* @param int $line_num the line number
* @param bool $highlight whether to use syntax highlighting or not
* @param int $padding the amount of line padding
* @return array
*/
public static function file_lines($filepath, $line_num, $highlight = true, $padding = 5)
{
// deal with eval'd code and runtime-created function
if (strpos($filepath, 'eval()\'d code') !== false or strpos($filepath, 'runtime-created function') !== false)
{
return '';
}
// We cache the entire file to reduce disk IO for multiple errors
if ( ! isset(static::$files[$filepath]))
{
static::$files[$filepath] = file($filepath, FILE_IGNORE_NEW_LINES);
array_unshift(static::$files[$filepath], '');
}
$start = $line_num - $padding;
if ($start < 0)
{
$start = 0;
}
$length = ($line_num - $start) + $padding + 1;
if (($start + $length) > count(static::$files[$filepath]) - 1)
{
$length = NULL;
}
$debug_lines = array_slice(static::$files[$filepath], $start, $length, TRUE);
if ($highlight)
{
$to_replace = array('<code>', '</code>', '<span style="color: #0000BB">&lt;?php&nbsp;', "\n");
$replace_with = array('', '', '<span style="color: #0000BB">', '');
foreach ($debug_lines as & $line)
{
$line = str_replace($to_replace, $replace_with, highlight_string('<?php ' . $line, TRUE));
}
}
return $debug_lines;
}
/**
* Output the call stack from here, or the supplied one.
*
* @param array $trace (optional) A backtrace to output
* @return string Formatted backtrace
*/
public static function backtrace($trace = null)
{
$trace or $trace = debug_backtrace();
if (\Fuel::$is_cli) {
// Special case for CLI since the var_dump of a backtrace is of little use.
$str = '';
foreach ($trace as $i => $frame)
{
$line = "#$i\t";
if ( ! isset($frame['file']))
{
$line .= "[internal function]";
}
else
{
$line .= $frame['file'] . ":" . $frame['line'];
}
$line .= "\t";
if (isset($frame['function']))
{
if (isset($frame['class']))
{
$line .= $frame['class'] . '::';
}
$line .= $frame['function'] . "()";
}
$str .= $line . "\n";
}
return $str;
}
else
{
return static::dump($trace);
}
}
/**
* Prints a list of all currently declared classes.
*
* @access public
* @static
*/
public static function classes()
{
return static::dump(get_declared_classes());
}
/**
* Prints a list of all currently declared interfaces (PHP5 only).
*
* @access public
* @static
*/
public static function interfaces()
{
return static::dump(get_declared_interfaces());
}
/**
* Prints a list of all currently included (or required) files.
*
* @access public
* @static
*/
public static function includes()
{
return static::dump(get_included_files());
}
/**
* Prints a list of all currently declared functions.
*
* @access public
* @static
*/
public static function functions()
{
return static::dump(get_defined_functions());
}
/**
* Prints a list of all currently declared constants.
*
* @access public
* @static
*/
public static function constants()
{
return static::dump(get_defined_constants());
}
/**
* Prints a list of all currently loaded PHP extensions.
*
* @access public
* @static
*/
public static function extensions()
{
return static::dump(get_loaded_extensions());
}
/**
* Prints a list of all HTTP request headers.
*
* @access public
* @static
*/
public static function headers()
{
// get the current request headers and dump them
return static::dump(\Input::headers());
}
/**
* Prints a list of the configuration settings read from <i>php.ini</i>
*
* @access public
* @static
*/
public static function phpini()
{
if ( ! is_readable(get_cfg_var('cfg_file_path')))
{
return false;
}
// render it
return static::dump(parse_ini_file(get_cfg_var('cfg_file_path'), true));
}
/**
* Benchmark anything that is callable
*
* @access public
* @param callable $callable
* @param array $params
* @static
* @return array
*/
public static function benchmark($callable, array $params = array())
{
// get the before-benchmark time
if (function_exists('getrusage'))
{
$dat = getrusage();
$utime_before = $dat['ru_utime.tv_sec'] + round($dat['ru_utime.tv_usec']/1000000, 4);
$stime_before = $dat['ru_stime.tv_sec'] + round($dat['ru_stime.tv_usec']/1000000, 4);
}
else
{
list($usec, $sec) = explode(" ", microtime());
$utime_before = ((float) $usec + (float) $sec);
$stime_before = 0;
}
// call the function to be benchmarked
$result = is_callable($callable) ? call_fuel_func_array($callable, $params) : null;
// get the after-benchmark time
if (function_exists('getrusage'))
{
$dat = getrusage();
$utime_after = $dat['ru_utime.tv_sec'] + round($dat['ru_utime.tv_usec']/1000000, 4);
$stime_after = $dat['ru_stime.tv_sec'] + round($dat['ru_stime.tv_usec']/1000000, 4);
}
else
{
list($usec, $sec) = explode(" ", microtime());
$utime_after = ((float) $usec + (float) $sec);
$stime_after = 0;
}
return array(
'user' => sprintf('%1.6f', $utime_after - $utime_before),
'system' => sprintf('%1.6f', $stime_after - $stime_before),
'result' => $result,
);
}
}

@ -1,325 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Exception class for standard PHP errors, this will make them catchable
*/
class PhpErrorException extends \ErrorException
{
public static $count = 0;
public static $loglevel = \Fuel::L_ERROR;
/**
* Allow the error handler from recovering from error types defined in the config
*/
public function recover()
{
// handle the error based on the config and the environment we're in
if (static::$count <= \Config::get('errors.throttle', 10))
{
logger(static::$loglevel, $this->code.' - '.$this->message.' in '.$this->file.' on line '.$this->line);
if (\Fuel::$env != \Fuel::PRODUCTION and ($this->code & error_reporting()) == $this->code)
{
static::$count++;
\Errorhandler::exception_handler(new \ErrorException($this->message, $this->code, 0, $this->file, $this->line));
}
}
elseif (\Fuel::$env != \Fuel::PRODUCTION
and static::$count == (\Config::get('errors.throttle', 10) + 1)
and ($this->severity & error_reporting()) == $this->severity)
{
static::$count++;
\Errorhandler::notice('Error throttling threshold was reached, no more full error reports are shown.', true);
}
}
}
/**
*
*/
class Errorhandler
{
public static $loglevel = \Fuel::L_ERROR;
public static $levels = array(
0 => 'Error',
E_ERROR => 'Fatal Error',
E_WARNING => 'Warning',
E_PARSE => 'Parsing Error',
E_NOTICE => 'Notice',
E_CORE_ERROR => 'Core Error',
E_CORE_WARNING => 'Core Warning',
E_COMPILE_ERROR => 'Compile Error',
E_COMPILE_WARNING => 'Compile Warning',
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
E_STRICT => 'Runtime Notice',
E_RECOVERABLE_ERROR => 'Runtime Recoverable error',
E_DEPRECATED => 'Runtime Deprecated code usage',
E_USER_DEPRECATED => 'User Deprecated code usage',
);
public static $fatal_levels = array(E_PARSE, E_ERROR, E_USER_ERROR, E_COMPILE_ERROR);
public static $non_fatal_cache = array();
/**
* Native PHP shutdown handler
*
* @return string
*/
public static function shutdown_handler()
{
$last_error = error_get_last();
// Only show valid fatal errors
if ($last_error AND in_array($last_error['type'], static::$fatal_levels))
{
$severity = static::$levels[$last_error['type']];
logger(static::$loglevel, $severity.' - '.$last_error['message'].' in '.$last_error['file'].' on line '.$last_error['line']);
$error = new \ErrorException($last_error['message'], $last_error['type'], 0, $last_error['file'], $last_error['line']);
if (\Fuel::$env != \Fuel::PRODUCTION)
{
static::show_php_error($error);
}
else
{
static::show_production_error($error);
}
exit(1);
}
}
/**
* PHP Exception handler
*
* @param Exception $e the exception
* @return bool
*/
public static function exception_handler($e)
{
// make sure we've got something useful passed
if ($e instanceOf \Exception or (PHP_VERSION_ID >= 70000 and $e instanceOf \Error))
{
if (method_exists($e, 'handle'))
{
return $e->handle();
}
$severity = ( ! isset(static::$levels[$e->getCode()])) ? $e->getCode() : static::$levels[$e->getCode()];
logger(static::$loglevel, $severity.' - '.$e->getMessage().' in '.$e->getFile().' on line '.$e->getLine());
if (\Fuel::$env != \Fuel::PRODUCTION)
{
static::show_php_error($e);
}
else
{
static::show_production_error($e);
}
}
else
{
die('Something was passed to the Exception handler that was neither an Error or an Exception !!!');
}
return true;
}
/**
* PHP Error handler
*
* @param int $severity the severity code
* @param string $message the error message
* @param string $filepath the path to the file throwing the error
* @param int $line the line number of the error
* @return bool whether to continue with execution
*/
public static function error_handler($severity, $message, $filepath, $line)
{
// don't do anything if error reporting is disabled
if (error_reporting() !== 0)
{
$fatal = (bool) ( ! in_array($severity, \Config::get('errors.continue_on', array())));
if ($fatal)
{
throw new \PhpErrorException($message, $severity, 0, $filepath, $line);
}
else
{
// non-fatal, recover from the error
$e = new \PhpErrorException($message, $severity, 0, $filepath, $line);
$e->recover();
}
}
return true;
}
/**
* Shows a small notice error, only when not in production or when forced.
* This is used by several libraries to notify the developer of certain things.
*
* @param string $msg the message to display
* @param bool $always_show whether to force display the notice or not
* @return void
*/
public static function notice($msg, $always_show = false)
{
$trace = array_merge(array('file' => '(unknown)', 'line' => '(unknown)'), \Arr::get(debug_backtrace(), 1));
logger(\Fuel::L_DEBUG, 'Notice - '.$msg.' in '.$trace['file'].' on line '.$trace['line']);
if (\Fuel::$is_test or ( ! $always_show and (\Fuel::$env == \Fuel::PRODUCTION or \Config::get('errors.notices', true) === false)))
{
return;
}
$data['message'] = $msg;
$data['type'] = 'Notice';
$data['filepath'] = \Fuel::clean_path($trace['file']);
$data['line'] = $trace['line'];
$data['function'] = $trace['function'];
echo \View::forge('errors'.DS.'php_short', $data, false);
}
/**
* Shows an error. It will stop script execution if the error code is not
* in the errors.continue_on whitelist.
*
* @param Exception $e the exception to show
* @return void
*/
protected static function show_php_error($e)
{
$fatal = (bool) ( ! in_array($e->getCode(), \Config::get('errors.continue_on', array())));
$data = static::prepare_exception($e, $fatal);
if ($fatal)
{
$data['contents'] = ob_get_contents();
while (ob_get_level() > 0)
{
ob_end_clean();
}
ob_start(\Config::get('ob_callback', null));
}
else
{
static::$non_fatal_cache[] = $data;
}
if (\Fuel::$is_cli)
{
\Cli::write(\Cli::color($data['severity'].' - '.$data['message'].' in '.\Fuel::clean_path($data['filepath']).' on line '.$data['error_line'], 'red'));
if (\Config::get('cli_backtrace'))
{
\Cli::write('Stack trace:');
\Cli::write(\Debug::backtrace($e->getTrace()));
}
return;
}
if ($fatal)
{
if ( ! headers_sent())
{
$protocol = \Input::server('SERVER_PROTOCOL') ? \Input::server('SERVER_PROTOCOL') : 'HTTP/1.1';
header($protocol.' 500 Internal Server Error');
}
$data['non_fatal'] = static::$non_fatal_cache;
try
{
exit(\View::forge('errors'.DS.'php_fatal_error', $data, false));
}
catch (\FuelException $view_exception)
{
exit($data['severity'].' - '.$data['message'].' in '.\Fuel::clean_path($data['filepath']).' on line '.$data['error_line']);
}
}
try
{
echo \View::forge('errors'.DS.'php_error', $data, false);
}
catch (\FuelException $e)
{
echo $e->getMessage().'<br />';
}
}
/**
* Shows the errors/production view and exits. This only gets
* called when an error occurs in production mode.
*
* @return void
*/
protected static function show_production_error($e)
{
// when we're on CLI, always show the php error
if (\Fuel::$is_cli)
{
return static::show_php_error($e);
}
if ( ! headers_sent())
{
$protocol = \Input::server('SERVER_PROTOCOL') ? \Input::server('SERVER_PROTOCOL') : 'HTTP/1.1';
header($protocol.' 500 Internal Server Error');
}
exit(\View::forge('errors'.DS.'production'));
}
protected static function prepare_exception($e, $fatal = true)
{
$data = array();
$data['type'] = get_class($e);
$data['severity'] = $e->getCode();
$data['message'] = $e->getMessage();
$data['filepath'] = $e->getFile();
$data['error_line'] = $e->getLine();
$data['backtrace'] = $e->getTrace();
$data['severity'] = ( ! isset(static::$levels[$data['severity']])) ? $data['severity'] : static::$levels[$data['severity']];
foreach ($data['backtrace'] as $key => $trace)
{
if ( ! isset($trace['file']))
{
unset($data['backtrace'][$key]);
}
elseif ($trace['file'] == COREPATH.'classes/error.php')
{
unset($data['backtrace'][$key]);
}
}
$data['debug_lines'] = \Debug::file_lines($data['filepath'], $data['error_line'], $fatal);
$data['orig_filepath'] = $data['filepath'];
$data['filepath'] = \Fuel::clean_path($data['filepath']);
$data['filepath'] = str_replace("\\", "/", $data['filepath']);
return $data;
}
}

@ -1,87 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Event Class
*
* @package Fuel
* @category Core
* @author Eric Barnes
* @author Harro "WanWizard" Verton
*/
abstract class Event
{
/**
* @var array $instances Event_Instance container
*/
protected static $instances = array();
/**
* Event instance forge.
*
* @param array $events events array
* @return object new Event_Instance instance
*/
public static function forge(array $events = array())
{
return new \Event_Instance($events);
}
/**
* Multiton Event instance.
*
* @param string $name instance name
* @param array $events events array
* @return object Event_Instance object
*/
public static function instance($name = 'fuelphp', array $events = array())
{
if ( ! array_key_exists($name, static::$instances))
{
$events = array_merge(\Config::get('event.'.$name, array()), $events);
$instance = static::forge($events);
static::$instances[$name] = &$instance;
}
return static::$instances[$name];
}
/**
* Static call forwarder
*
* @param string $func method name
* @param array $args passed arguments
* @return mixed
* @throws \BadMethodCallException
*/
public static function __callStatic($func, $args)
{
$instance = static::instance();
if (method_exists($instance, $func))
{
return call_fuel_func_array(array($instance, $func), $args);
}
throw new \BadMethodCallException('Call to undefined method: '.get_called_class().'::'.$func);
}
/**
* Load events config
*/
public static function _init()
{
\Config::load('event', true);
}
}

@ -1,223 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Event Class
*
* @package Fuel
* @category Core
* @author Eric Barnes
* @author Harro "WanWizard" Verton
*/
class Event_Instance
{
/**
* @var array An array of listeners
*/
protected $_events = array();
// --------------------------------------------------------------------
/**
* Constructor, sets all initial events.
*
* @param array $events events array
*/
public function __construct(array $events = array())
{
foreach($events as $event => $callback)
{
$this->register($event, $callback);
}
}
// --------------------------------------------------------------------
/**
* Register
*
* Registers a Callback for a given event
*
* @return void
*/
public function register()
{
// get any arguments passed
$callback = func_get_args();
// if the arguments are valid, register the event
if (isset($callback[0]) and is_string($callback[0]) and isset($callback[1]) and is_callable($callback[1]))
{
// make sure we have an array for this event
isset($this->_events[$callback[0]]) or $this->_events[$callback[0]] = array();
// store the callback on the call stack
if (empty($callback[2]))
{
array_unshift($this->_events[$callback[0]], $callback);
}
else
{
$this->_events[$callback[0]][] = $callback;
}
// and report success
return true;
}
else
{
// can't register the event
return false;
}
}
// --------------------------------------------------------------------
/**
* Unregister/remove one or all callbacks from event
*
* @param string $event event to remove from
* @param mixed $callback callback to remove [optional, null for all]
* @return boolean whether one or all callbacks have been removed
*/
public function unregister($event, $callback = null)
{
if (isset($this->_events[$event]))
{
if ($callback === null)
{
unset($this->_events[$event]);
return true;
}
foreach ($this->_events[$event] as $i => $arguments)
{
if($callback === $arguments[1])
{
unset($this->_events[$event][$i]);
return true;
}
}
}
return false;
}
// --------------------------------------------------------------------
/**
* Trigger
*
* Triggers an event and returns the results. The results can be returned
* in the following formats:
*
* 'array'
* 'json'
* 'serialized'
* 'string'
*
* @param string $event The name of the event
* @param mixed $data Any data that is to be passed to the listener
* @param string $return_type The return type
* @param boolean $reversed Whether to fire events ordered LIFO instead of FIFO
* @return mixed The return of the listeners, in the return type
*/
public function trigger($event, $data = '', $return_type = 'string', $reversed = false)
{
$calls = array();
// check if we have events registered
if ($this->has_events($event))
{
$events = $reversed ? array_reverse($this->_events[$event], true) : $this->_events[$event];
// process them
foreach ($events as $arguments)
{
// get rid of the event name
array_shift($arguments);
// get the callback method
$callback = array_shift($arguments);
// call the callback event
if (is_callable($callback))
{
$calls[] = call_user_func($callback, $data, $arguments);
}
}
}
return $this->_format_return($calls, $return_type);
}
// --------------------------------------------------------------------
/**
* Has Listeners
*
* Checks if the event has listeners
*
* @param string $event The name of the event
* @return bool Whether the event has listeners
*/
public function has_events($event)
{
if (isset($this->_events[$event]) and count($this->_events[$event]) > 0)
{
return true;
}
return false;
}
// --------------------------------------------------------------------
/**
* Format Return
*
* Formats the return in the given type
*
* @param array $calls The array of returns
* @param string $return_type The return type
* @return mixed The formatted return
*/
protected function _format_return(array $calls, $return_type)
{
switch ($return_type)
{
case 'array':
return $calls;
break;
case 'json':
return json_encode($calls);
break;
case 'none':
return null;
case 'serialized':
return serialize($calls);
break;
case 'string':
$str = '';
foreach ($calls as $call)
{
$str .= $call;
}
return $str;
break;
default:
return $calls;
break;
}
}
}

@ -1,888 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
// ------------------------------------------------------------------------
/**
* Fieldset Class
*
* Define a set of fields that can be used to generate a form or to validate input.
*
* @package Fuel
* @category Core
*/
class Fieldset
{
/**
* @var Fieldset
*/
protected static $_instance;
/**
* @var array contains references to all instantiations of Fieldset
*/
protected static $_instances = array();
/**
* Create Fieldset object
*
* @param string $name Identifier for this fieldset
* @param array $config Configuration array
* @return Fieldset
*/
public static function forge($name = 'default', array $config = array())
{
if ($exists = static::instance($name))
{
\Errorhandler::notice('Fieldset with this name exists already, cannot be overwritten.');
return $exists;
}
static::$_instances[$name] = new static($name, $config);
if ($name == 'default')
{
static::$_instance = static::$_instances[$name];
}
return static::$_instances[$name];
}
/**
* Return a specific instance, or the default instance (is created if necessary)
*
* @param Fieldset $instance
* @return Fieldset
*/
public static function instance($instance = null)
{
if ($instance !== null)
{
if ( ! array_key_exists($instance, static::$_instances))
{
return false;
}
return static::$_instances[$instance];
}
if (static::$_instance === null)
{
static::$_instance = static::forge();
}
return static::$_instance;
}
/**
* @var string instance id
*/
protected $name;
/**
* @var string tag used to wrap this instance
*/
protected $fieldset_tag = null;
/**
* @var Fieldset instance to which this instance belongs
*/
protected $fieldset_parent = null;
/**
* @var array instances that belong to this one
*/
protected $fieldset_children = array();
/**
* @var array array of Fieldset_Field objects
*/
protected $fields = array();
/**
* @var Validation instance of validation
*/
protected $validation;
/**
* @var Form instance of form
*/
protected $form;
/**
* @var array configuration array
*/
protected $config = array();
/**
* @var array disabled fields array
*/
protected $disabled = array();
/**
* @var string name of class providing the tabular form
*/
protected $tabular_form_model = null;
/**
* @var string name of the relation of the parent object this tabular form is modeled on
*/
protected $tabular_form_relation = null;
/**
* Object constructor
*
* @param string
* @param array
*/
public function __construct($name = '', array $config = array())
{
// support new Fieldset($config) syntax
if (is_array($name))
{
$config = $name;
$name = '';
}
if (isset($config['validation_instance']))
{
$this->validation($config['validation_instance']);
unset($config['validation_instance']);
}
if (isset($config['form_instance']))
{
$this->form($config['form_instance']);
unset($config['form_instance']);
}
$this->name = (string) $name;
$this->config = $config;
}
/**
* Get related Validation instance or create it
*
* @param bool|Validation $instance
* @return Validation
*/
public function validation($instance = true)
{
if ($instance instanceof Validation)
{
$this->validation = $instance;
return $instance;
}
if (empty($this->validation) and $instance === true)
{
$this->validation = \Validation::forge($this);
}
return $this->validation;
}
/**
* Get related Form instance or create it
*
* @param bool|Form $instance
* @return Form
*/
public function form($instance = true)
{
if ($instance instanceof Form)
{
$this->form = $instance;
return $instance;
}
if (empty($this->form) and $instance === true)
{
$this->form = \Form::forge($this);
}
return $this->form;
}
/**
* Set the tag to be used for this fieldset
*
* @param string $tag
* @return Fieldset this, to allow chaining
*/
public function set_fieldset_tag($tag)
{
$this->fieldset_tag = $tag;
return $this;
}
/**
* Set the parent Fieldset instance
*
* @param Fieldset $fieldset parent fieldset to which this belongs
* @return Fieldset
*/
public function set_parent(Fieldset $fieldset)
{
if ( ! empty($this->fieldset_parent))
{
throw new \RuntimeException('Fieldset already has a parent, belongs to "'.$this->parent()->name.'".');
}
$children = $fieldset->children();
while ($child = array_shift($children))
{
if ($child === $this)
{
throw new \RuntimeException('Circular reference detected, adding a Fieldset that\'s already a child as a parent.');
}
$children = array_merge($child->children(), $children);
}
$this->fieldset_parent = $fieldset;
$fieldset->add_child($this);
return $this;
}
/**
* Add a child Fieldset instance
*
* @param Fieldset $fieldset
* @return Fieldset
*/
protected function add_child(Fieldset $fieldset)
{
if (is_null($fieldset->fieldset_tag))
{
$fieldset->fieldset_tag = 'fieldset';
}
$this->fieldset_children[$fieldset->name] = $fieldset;
return $this;
}
/**
* Factory for Fieldset_Field objects
*
* @param string
* @param string
* @param array
* @param array
* @return Fieldset_Field
*/
public function add($name, $label = '', array $attributes = array(), array $rules = array())
{
if ($name instanceof Fieldset_Field)
{
if ($name->name == '' or $this->field($name->name) !== false)
{
throw new \RuntimeException('Fieldname empty or already exists in this Fieldset: "'.$name->name.'".');
}
$name->set_fieldset($this);
$this->fields[$name->name] = $name;
return $name;
}
elseif ($name instanceof Fieldset)
{
if (empty($name->name) or $this->field($name->name) !== false)
{
throw new \RuntimeException('Fieldset name empty or already exists in this Fieldset: "'.$name->name.'".');
}
$name->set_parent($this);
$this->fields[$name->name] = $name;
return $name;
}
if (empty($name) || (is_array($name) and empty($name['name'])))
{
throw new \InvalidArgumentException('Cannot create field without name.');
}
// Allow passing the whole config in an array, will overwrite other values if that's the case
if (is_array($name))
{
$attributes = $name;
$label = isset($name['label']) ? $name['label'] : '';
$rules = isset($name['rules']) ? $name['rules'] : array();
$name = $name['name'];
}
// Check if it exists already, if so: return and give notice
if ($field = $this->field($name))
{
\Errorhandler::notice('Field with this name exists already in this fieldset: "'.$name.'".');
return $field;
}
$this->fields[$name] = new \Fieldset_Field($name, $label, $attributes, $rules, $this);
return $this->fields[$name];
}
/**
* Add a new Fieldset_Field before an existing field in a Fieldset
*
* @param string $name
* @param string $label
* @param array $attributes
* @param array $rules
* @param string $fieldname fieldname before which the new field is inserted in the fieldset
* @return Fieldset_Field
*/
public function add_before($name, $label = '', array $attributes = array(), array $rules = array(), $fieldname = null)
{
$field = $this->add($name, $label, $attributes, $rules);
// Remove from tail and reinsert at correct location
unset($this->fields[$field->name]);
if ( ! \Arr::insert_before_key($this->fields, array($field->name => $field), $fieldname, true))
{
throw new \RuntimeException('Field "'.$fieldname.'" does not exist in this Fieldset. Field "'.$name.'" can not be added.');
}
return $field;
}
/**
* Add a new Fieldset_Field after an existing field in a Fieldset
*
* @param string $name
* @param string $label
* @param array $attributes
* @param array $rules
* @param string $fieldname fieldname after which the new field is inserted in the fieldset
* @return Fieldset_Field
*/
public function add_after($name, $label = '', array $attributes = array(), array $rules = array(), $fieldname = null)
{
$field = $this->add($name, $label, $attributes, $rules);
// Remove from tail and reinsert at correct location
unset($this->fields[$field->name]);
if ( ! \Arr::insert_after_key($this->fields, array($field->name => $field), $fieldname, true))
{
throw new \RuntimeException('Field "'.$fieldname.'" does not exist in this Fieldset. Field "'.$name.'" can not be added.');
}
return $field;
}
/**
* Delete a field instance
*
* @param string field name or null to fetch an array of all
* @return Fieldset this fieldset, for chaining
*/
public function delete($name)
{
if (isset($this->fields[$name]))
{
unset($this->fields[$name]);
}
return $this;
}
/**
* Get Field instance
*
* @param string|null $name field name or null to fetch an array of all
* @param bool $flatten whether to get the fields array or flattened array
* @param bool $tabular_form whether to include tabular form fields in the flattened array
* @return Fieldset_Field|false returns false when field wasn't found
*/
public function field($name = null, $flatten = false, $tabular_form = true)
{
if ($name === null)
{
$fields = $this->fields;
if ($flatten)
{
foreach ($this->fieldset_children as $fs_name => $fieldset)
{
if ($tabular_form or ! $fieldset->get_tabular_form())
{
\Arr::insert_after_key($fields, $fieldset->field(null, true), $fs_name);
}
unset($fields[$fs_name]);
}
}
return $fields;
}
if ( ! array_key_exists($name, $this->fields))
{
if ($flatten)
{
foreach ($this->fieldset_children as $fieldset)
{
if (($field = $fieldset->field($name)) !== false)
{
return $field;
}
}
}
return false;
}
return $this->fields[$name];
}
/**
* Add a model's fields
* The model must have a method "set_form_fields" that takes this Fieldset instance
* and adds fields to it.
*
* @param string|Object $class either a full classname (including full namespace) or object instance
* @param array|Object $instance array or object that has the exactly same named properties to populate the fields
* @param string $method method name to call on model for field fetching
* @return Fieldset this, to allow chaining
*/
public function add_model($class, $instance = null, $method = 'set_form_fields')
{
// Add model to validation callables for validation rules
$this->validation()->add_callable($class);
if ((is_string($class) and is_callable($callback = array('\\'.$class, $method)))
|| is_callable($callback = array($class, $method)))
{
$instance ? call_user_func($callback, $this, $instance) : call_user_func($callback, $this);
}
return $this;
}
/**
* Sets a config value on the fieldset
*
* @param string $config
* @param mixed $value
* @return Fieldset this, to allow chaining
*/
public function set_config($config, $value = null)
{
$config = is_array($config) ? $config : array($config => $value);
foreach ($config as $key => $value)
{
if (strpos($key, '.') === false)
{
$this->config[$key] = $value;
}
else
{
\Arr::set($this->config, $key, $value);
}
}
return $this;
}
/**
* Get a single or multiple config values by key
*
* @param string|array $key a single key or multiple in an array, empty to fetch all
* @param mixed $default default output when config wasn't set
* @return mixed|array a single config value or multiple in an array when $key input was an array
*/
public function get_config($key = null, $default = null)
{
if ($key === null)
{
return $this->config;
}
if (is_array($key))
{
$output = array();
foreach ($key as $k)
{
$output[$k] = $this->get_config($k, $default);
}
return $output;
}
if (strpos($key, '.') === false)
{
return array_key_exists($key, $this->config) ? $this->config[$key] : $default;
}
else
{
return \Arr::get($this->config, $key, $default);
}
}
/**
* Populate the form's values using an input array or object
*
* @param array|object $input
* @param bool $repopulate
* @return Fieldset this, to allow chaining
*/
public function populate($input, $repopulate = false)
{
$fields = $this->field(null, true, false);
foreach ($fields as $f)
{
if (is_array($input) or $input instanceof \ArrayAccess)
{
// convert form field array's to Fuel dotted notation
$name = str_replace(array('[', ']'), array('.', ''), $f->name);
// fetch the value for this field, and set it if found
$value = \Arr::get($input, $name, null);
$value === null and $value = \Arr::get($input, $f->basename, null);
$value !== null and $f->set_value($value, true);
}
elseif (is_object($input) and property_exists($input, $f->basename))
{
$f->set_value($input->{$f->basename}, true);
}
}
// Optionally overwrite values using post/get
if ($repopulate)
{
$this->repopulate();
}
return $this;
}
/**
* Set all fields to the input from get or post (depends on the form method attribute)
*
* @return Fieldset this, to allow chaining
*/
public function repopulate()
{
$fields = $this->field(null, true);
foreach ($fields as $f)
{
// Don't repopulate the CSRF field
if ($f->name === \Config::get('security.csrf_token_key', 'fuel_csrf_token'))
{
continue;
}
if (($value = $f->input()) !== null)
{
$f->set_value($value, true);
}
}
return $this;
}
/**
* Build the fieldset HTML
*
* @param mixed $action
* @return string
*/
public function build($action = null)
{
$attributes = $this->get_config('form_attributes');
if ($action and ($this->fieldset_tag == 'form' or empty($this->fieldset_tag)))
{
$attributes['action'] = $action;
}
$open = ($this->fieldset_tag == 'form' or empty($this->fieldset_tag))
? $this->form()->open($attributes).PHP_EOL
: $this->form()->{$this->fieldset_tag.'_open'}($attributes);
$fields_output = '';
// construct the tabular form table header
if ($this->tabular_form_relation)
{
$properties = call_user_func($this->tabular_form_model.'::properties');
$primary_keys = call_user_func($this->tabular_form_model.'::primary_key');
$fields_output .= '<thead><tr>'.PHP_EOL;
foreach ($properties as $field => $settings)
{
if ((isset($settings['skip']) and $settings['skip']) or in_array($field, $primary_keys))
{
continue;
}
if (isset($settings['form']['type']) and ($settings['form']['type'] === false or $settings['form']['type'] === 'hidden'))
{
continue;
}
$fields_output .= "\t".'<th class="'.$this->tabular_form_relation.'_col_'.$field.'">'.(isset($settings['label']) ? \Lang::get($settings['label'], array(), $settings['label']) : '').'</th>'.PHP_EOL;
}
$fields_output .= "\t".'<th>'.\Config::get('form.tabular_delete_label', 'Delete?').'</th>'.PHP_EOL;
$fields_output .= '</tr></thead>'.PHP_EOL;
}
foreach ($this->field() as $f)
{
in_array($f->name, $this->disabled) or $fields_output .= $f->build().PHP_EOL;
}
$close = ($this->fieldset_tag == 'form' or empty($this->fieldset_tag))
? $this->form()->close($attributes).PHP_EOL
: $this->form()->{$this->fieldset_tag.'_close'}($attributes);
$template = $this->form()->get_config((empty($this->fieldset_tag) ? 'form' : $this->fieldset_tag).'_template',
"\n\t\t{open}\n\t\t<table>\n{fields}\n\t\t</table>\n\t\t{close}\n");
$template = str_replace(array('{form_open}', '{open}', '{fields}', '{form_close}', '{close}'),
array($open, $open, $fields_output, $close, $close),
$template);
return $template;
}
/**
* Enable a disabled field from being build
*
* @param mixed $name
* @return Fieldset this, to allow chaining
*/
public function enable($name = null)
{
// Check if it exists. if not, bail out
if ( ! $this->field($name))
{
throw new \RuntimeException('Field "'.$name.'" does not exist in this Fieldset.');
}
if (isset($this->disabled[$name]))
{
unset($this->disabled[$name]);
}
return $this;
}
/**
* Disable a field from being build
*
* @param mixed $name
* @return Fieldset this, to allow chaining
*/
public function disable($name = null)
{
// Check if it exists. if not, bail out
if ( ! $this->field($name))
{
throw new \RuntimeException('Field "'.$name.'" does not exist in this Fieldset.');
}
isset($this->disabled[$name]) or $this->disabled[$name] = $name;
return $this;
}
/**
* Magic method toString that will build this as a form
*
* @return string
*/
public function __toString()
{
return $this->build();
}
/**
* Return parent Fieldset
*
* @return Fieldset
*/
public function parent()
{
return $this->fieldset_parent;
}
/**
* Return the child fieldset instances
*
* @return array
*/
public function children()
{
return $this->fieldset_children;
}
/**
* Alias for $this->validation()->input()
*
* @param string $field
* @return mixed
*/
public function input($field = null)
{
return $this->validation()->input($field);
}
/**
* Alias for $this->validation()->validated()
*
* @param string $field
* @return mixed
*/
public function validated($field = null)
{
return $this->validation()->validated($field);
}
/**
* Alias for $this->validation()->error()
*
* @param string $field
* @return Validation_Error|array
*/
public function error($field = null)
{
return $this->validation()->error($field);
}
/**
* Alias for $this->validation()->show_errors()
*
* @param array $config
* @return string
*/
public function show_errors(array $config = array())
{
return $this->validation()->show_errors($config);
}
/**
* Get the fieldset name
*
* @return string
*/
public function get_name()
{
return $this->name;
}
/**
* Enable or disable the tabular form feature of this fieldset
*
* @param string $model Model on which to define the tabular form
* @param string $relation Relation of the Model on the tabular form is modeled
* @param array $parent Collection of Model objects from a many relation
* @param int $blanks Number of empty rows to generate
*
* @return Fieldset this, to allow chaining
*/
public function set_tabular_form($model, $relation, $parent, $blanks = 1)
{
// make sure our parent is an ORM model instance
if ( ! $parent instanceOf \Orm\Model)
{
throw new \RuntimeException('Parent passed to set_tabular_form() is not an ORM model object.');
}
// validate the model and relation
// fetch the relations of the parent model
$relations = call_user_func(array($parent, 'relations'));
if ( ! array_key_exists($relation, $relations))
{
throw new \RuntimeException('Relation passed to set_tabular_form() is not a valid relation of the ORM parent model object.');
}
// check for compound primary keys
try
{
// fetch the relations of the parent model
$primary_key = call_user_func($model.'::primary_key');
// we don't support compound primary keys
if (count($primary_key) !== 1)
{
throw new \RuntimeException('set_tabular_form() does not supports models with compound primary keys.');
}
// store the primary key name, we need that later
$primary_key = reset($primary_key);
}
catch (\Exception $e)
{
throw new \RuntimeException('Unable to fetch the models primary key information.');
}
// store the tabular form class name
$this->tabular_form_model = $model;
// and the relation on which we model the rows
$this->tabular_form_relation = $relation;
// load the form config if not loaded yet
\Config::load('form', true);
// load the config for embedded forms
$this->set_config(array(
'form_template' => \Config::get('form.tabular_form_template', "<table>{fields}</table>\n"),
'field_template' => \Config::get('form.tabular_field_template', "{field}"),
));
// add the rows to the tabular form fieldset
foreach ($parent->{$relation} as $row)
{
// add the row fieldset to the tabular form fieldset
$this->add($fieldset = \Fieldset::forge($this->tabular_form_relation.'_row_'.$row->{$primary_key}));
// and add the model fields to the row fielset
$fieldset->add_model($model, $row)->set_fieldset_tag(false);
$fieldset->set_config(array(
'form_template' => \Config::get('form.tabular_row_template', "<table>{fields}</table>\n"),
'field_template' => \Config::get('form.tabular_row_field_template', "{field}"),
));
$fieldset->add($this->tabular_form_relation.'['.$row->{$primary_key}.'][_delete]', '', array('type' => 'checkbox', 'value' => 1));
}
// and finish with zero or more empty rows so we can add new data
if ( ! is_numeric($blanks) or $blanks < 0)
{
$blanks = 1;
}
for ($i = 0; $i < $blanks; $i++)
{
$this->add($fieldset = \Fieldset::forge($this->tabular_form_relation.'_new_'.$i));
$fieldset->add_model($model)->set_fieldset_tag(false);
$fieldset->set_config(array(
'form_template' => \Config::get('form.tabular_row_template', "<tr>{fields}</tr>"),
'field_template' => \Config::get('form.tabular_row_field_template', "{field}"),
));
$fieldset->add($this->tabular_form_relation.'_new['.$i.'][_delete]', '', array('type' => 'checkbox', 'value' => 0, 'disabled' => 'disabled'));
// no required rules on this row
foreach ($fieldset->field() as $f)
{
$f->delete_rule('required', false)->delete_rule('required_with', false);
}
}
return $this;
}
/**
* return the tabular form relation of this fieldset
*
* @return bool
*/
public function get_tabular_form()
{
return $this->tabular_form_relation;
}
}

@ -1,666 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Fieldset Class
*
* Define a set of fields that can be used to generate a form or to validate input.
*
* @package Fuel
* @category Core
*/
class Fieldset_Field
{
/**
* @var Fieldset Fieldset this field belongs to
*/
protected $fieldset;
/**
* @var string Name of this field
*/
protected $name = '';
/**
* @var string Base name of this field
*/
protected $basename = '';
/**
* @var string Field type for form generation, false to prevent it showing
*/
protected $type = 'text';
/**
* @var string Field label for validation errors and form label generation
*/
protected $label = '';
/**
* @var mixed (Default) value of this field
*/
protected $value;
/**
* @var string Description text to show with the field
*/
protected $description = '';
/**
* @var array Rules for validation
*/
protected $rules = array();
/**
* @var array Attributes for form generation
*/
protected $attributes = array();
/**
* @var array Options, only available for select, radio & checkbox types
*/
protected $options = array();
/**
* @var string Template for form building
*/
protected $template;
/**
* @var array overwrites for default error messages
*/
protected $error_messages = array();
/**
* Constructor
*
* @param string $name
* @param string $label
* @param array $attributes
* @param array $rules
* @param Fieldset $fieldset
* @throws \RuntimeException
*/
public function __construct($name, $label = '', array $attributes = array(), array $rules = array(), $fieldset = null)
{
$this->name = (string) $name;
if ($this->name === "")
{
throw new \RuntimeException('Fieldset field name may not be empty.');
}
// determine the field's base name (for fields with array indices)
$this->basename = ($pos = strpos($this->name, '[')) ? rtrim(substr(strrchr($this->name, '['), 1), ']') : $this->name;
$this->fieldset = $fieldset instanceof Fieldset ? $fieldset : null;
// Don't allow name in attributes
unset($attributes['name']);
// Take rules out of attributes
unset($attributes['rules']);
// Use specific setter when available
foreach ($attributes as $attr => $val)
{
if (method_exists($this, $method = 'set_'.$attr))
{
$this->{$method}($val);
unset($attributes[$attr]);
}
}
// Add default "type" attribute if not specified
empty($attributes['type']) and $this->set_type($this->type);
// only when non-empty, will supersede what was given in $attributes
$label and $this->set_label($label);
$this->attributes = array_merge($this->attributes, $attributes);
foreach ($rules as $rule)
{
call_fuel_func_array(array($this, 'add_rule'), (array) $rule);
}
}
/**
* @param Fieldset $fieldset Fieldset to assign the field to
* @return Fieldset_Field
* @throws \RuntimeException
*/
public function set_fieldset(Fieldset $fieldset)
{
// if we currently have a fieldset
if ($this->fieldset)
{
// remove the field from the fieldset
$this->fieldset->delete($this->name);
// reset the fieldset
$this->fieldset = null;
// add this field to the new fieldset
$fieldset->add($this);
}
// assign the new fieldset
$this->fieldset = $fieldset;
return $this;
}
/**
* Change the field label
*
* @param string $label
* @return Fieldset_Field this, to allow chaining
*/
public function set_label($label)
{
$this->label = $label;
$this->set_attribute('label', $label);
return $this;
}
/**
* Change the field type for form generation
*
* @param string $type
* @return Fieldset_Field this, to allow chaining
*/
public function set_type($type)
{
$this->type = $type;
$this->set_attribute('type', $type);
return $this;
}
/**
* Change the field's current or default value
*
* @param string $value
* @param bool $repopulate
* @return Fieldset_Field this, to allow chaining
*/
public function set_value($value, $repopulate = false)
{
// Repopulation is handled slightly different in some cases
if ($repopulate)
{
if (($this->type == 'radio' or $this->type == 'checkbox') and empty($this->options))
{
if ($this->value == $value)
{
$this->set_attribute('checked', 'checked');
}
return $this;
}
}
$this->value = $value;
$this->set_attribute('value', $value);
return $this;
}
/**
* Change the field description
*
* @param string $description
* @return Fieldset_Field this, to allow chaining
*/
public function set_description($description)
{
$this->description = strval($description);
return $this;
}
/**
* Template the output
*
* @param string $template
* @return Fieldset_Field this, to allow chaining
*/
public function set_template($template = null)
{
$this->template = $template;
return $this;
}
/**
* Overwrite a default error message
*
* @param string $rule
* @param string $msg
* @return Fieldset_Field
*/
public function set_error_message($rule, $msg)
{
empty($rule) and $rule = 0;
$this->error_messages[$rule] = strval($msg);
return $this;
}
/**
* Check if a rule has an error message overwrite
*
* @param string $rule
* @return null|string
*/
public function get_error_message($rule)
{
if (isset($this->error_messages[$rule]))
{
return $this->error_messages[$rule];
}
elseif (isset($this->error_messages[0]))
{
return $this->error_messages[0];
}
return null;
}
/**
* Add a validation rule
* any further arguements after the callback will be used as arguements for the callback
*
* @param string|Callback either a validation rule or full callback
* @return Fieldset_Field this, to allow chaining
*/
public function add_rule($callback)
{
$args = array_slice(func_get_args(), 1);
$this->rules[] = array($callback, $args);
// Set required setting for forms when rule was applied
if ($callback === 'required')
{
$this->set_attribute('required', 'required');
}
return $this;
}
/**
* Delete a validation rule
*
* @param string|Callback either a validation rule or full callback
* @param bool whether to also reset related attributes
* @return Fieldset_Field this, to allow chaining
*/
public function delete_rule($callback, $set_attr = true)
{
foreach($this->rules as $index => $rule)
{
if ($rule[0] === $callback)
{
unset($this->rules[$index]);
break;
}
}
if ($callback === 'required' and $set_attr)
{
unset($this->attributes[$callback]);
}
return $this;
}
/**
* Sets an attribute on the field
*
* @param string
* @param mixed new value or null to unset
* @return Fieldset_Field this, to allow chaining
*/
public function set_attribute($attr, $value = null)
{
$attr = is_array($attr) ? $attr : array($attr => $value);
foreach ($attr as $key => $value)
{
if ($value === null)
{
unset($this->attributes[$key]);
}
else
{
$this->attributes[$key] = $value;
}
}
return $this;
}
/**
* Get a single or multiple attributes by key
*
* @param string|array a single key or multiple in an array, empty to fetch all
* @param mixed default output when attribute wasn't set
* @return mixed|array a single attribute or multiple in an array when $key input was an array
*/
public function get_attribute($key = null, $default = null)
{
if ($key === null)
{
return $this->attributes;
}
if (is_array($key))
{
$output = array();
foreach ($key as $k)
{
$output[$k] = array_key_exists($k, $this->attributes) ? $this->attributes[$k] : $default;
}
return $output;
}
return array_key_exists($key, $this->attributes) ? $this->attributes[$key] : $default;
}
/**
* Add an option value with label
*
* @param string|array one option value, or multiple value=>label pairs in an array
* @param string
* @param bool Whether or not to replace the current options
* @return Fieldset_Field this, to allow chaining
*/
public function set_options($value, $label = null, $replace_options = false)
{
if ( ! is_array($value))
{
\Arr::set($this->options, $value, $label);
return $this;
}
$merge = function(&$array, $new, $merge)
{
foreach ($new as $k => $v)
{
if (isset($array[$k]) and is_array($array[$k]) and is_array($v))
{
$merge($array[$k], $v);
}
else
{
$array[$k] = $v;
}
}
};
($replace_options or empty($this->options)) ? $this->options = $value : $merge($this->options, $value, $merge);
return $this;
}
/**
* Magic get method to allow getting class properties but still having them protected
* to disallow writing.
*
* @return mixed
*/
public function __get($property)
{
return $this->$property;
}
/**
* Build the field
*
* @return string
*/
public function __toString()
{
try
{
return $this->build();
}
catch (\Exception $e)
{
return $e->getMessage();
}
}
/**
* Return the parent Fieldset object
*
* @return Fieldset
*/
public function fieldset()
{
return $this->fieldset;
}
/**
* Alias for $this->fieldset->add() to allow chaining
*
* @return Fieldset_Field
*/
public function add($name, $label = '', array $attributes = array(), array $rules = array())
{
return $this->fieldset()->add($name, $label, $attributes, $rules);
}
/**
* Alias for $this->fieldset->add_before() to allow chaining
*
* @return Fieldset_Field
*/
public function add_before($name, $label = '', array $attributes = array(), array $rules = array(), $fieldname = null)
{
return $this->fieldset()->add_before($name, $label, $attributes, $rules, $fieldname);
}
/**
* Alias for $this->fieldset->add_after() to allow chaining
*
* @return Fieldset_Field
*/
public function add_after($name, $label = '', array $attributes = array(), array $rules = array(), $fieldname = null)
{
return $this->fieldset()->add_after($name, $label, $attributes, $rules, $fieldname);
}
/**
* Build the field
*
* @return string
*/
public function build()
{
$form = $this->fieldset()->form();
// Add IDs when auto-id is on
if ($form->get_config('auto_id', false) === true and $this->get_attribute('id') == '')
{
$auto_id = $form->get_config('auto_id_prefix', '')
.str_replace(array('[', ']'), array('-', ''), $this->name);
$this->set_attribute('id', $auto_id);
}
switch( ! empty($this->attributes['tag']) ? $this->attributes['tag'] : $this->type)
{
case 'hidden':
$build_field = $form->hidden($this->name, $this->value, $this->attributes);
break;
case 'radio':
case 'checkbox':
if ($this->options)
{
$build_field = array();
$i = 0;
foreach ($this->options as $value => $label)
{
$attributes = $this->attributes;
$attributes['name'] = $this->name;
$this->type == 'checkbox' and $attributes['name'] .= '['.$i.']';
$attributes['value'] = $value;
$attributes['label'] = $label;
if (is_array($this->value) ? in_array($value, $this->value) : $value == $this->value)
{
$attributes['checked'] = 'checked';
}
if( ! empty($attributes['id']))
{
$attributes['id'] .= '_'.$i;
}
else
{
$attributes['id'] = null;
}
$build_field[$form->label($label, null, array('for' => $attributes['id']))] = $this->type == 'radio'
? $form->radio($attributes)
: $form->checkbox($attributes);
$i++;
}
}
else
{
$build_field = $this->type == 'radio'
? $form->radio($this->name, $this->value, $this->attributes)
: $form->checkbox($this->name, $this->value, $this->attributes);
}
break;
case 'select':
$attributes = $this->attributes;
$name = $this->name;
unset($attributes['type']);
array_key_exists('multiple', $attributes) and $name .= '[]';
$build_field = $form->select($name, $this->value, $this->options, $attributes);
break;
case 'textarea':
$attributes = $this->attributes;
unset($attributes['type']);
$build_field = $form->textarea($this->name, $this->value, $attributes);
break;
case 'button':
$build_field = $form->button($this->name, $this->value, $this->attributes);
break;
case false:
$build_field = '';
break;
default:
$build_field = $form->input($this->name, $this->value, $this->attributes);
break;
}
if (empty($build_field) or $this->type == 'hidden')
{
return $build_field;
}
return $this->template($build_field);
}
protected function template($build_field)
{
$form = $this->fieldset()->form();
$required_mark = $this->get_attribute('required', null) ? $form->get_config('required_mark', null) : null;
$label = $this->label ? $form->label($this->label, null, array('id' => 'label_'.$this->name, 'for' => $this->get_attribute('id', null), 'class' => $form->get_config('label_class', null))) : '';
$error_template = $form->get_config('error_template', '');
$error_msg = ($form->get_config('inline_errors') && $this->error()) ? str_replace('{error_msg}', $this->error(), $error_template) : '';
$error_class = $this->error() ? $form->get_config('error_class') : '';
if (is_array($build_field))
{
$label = $this->label ? str_replace('{label}', $this->label, $form->get_config('group_label', '<span>{label}</span>')) : '';
$template = $this->template ?: $form->get_config('multi_field_template', "\t\t<tr>\n\t\t\t<td class=\"{error_class}\">{group_label}{required}</td>\n\t\t\t<td class=\"{error_class}\">{fields}\n\t\t\t\t{field} {label}<br />\n{fields}\t\t\t{error_msg}\n\t\t\t</td>\n\t\t</tr>\n");
if ($template && preg_match('#\{fields\}(.*)\{fields\}#Dus', $template, $match) > 0)
{
$build_fields = '';
foreach ($build_field as $lbl => $bf)
{
$bf_temp = str_replace('{label}', $lbl, $match[1]);
$bf_temp = str_replace('{required}', $required_mark, $bf_temp);
$bf_temp = str_replace('{field}', $bf, $bf_temp);
$build_fields .= $bf_temp;
}
$template = str_replace($match[0], '{fields}', $template);
$template = str_replace(array('{group_label}', '{required}', '{fields}', '{error_msg}', '{error_class}', '{description}'), array($label, $required_mark, $build_fields, $error_msg, $error_class, $this->description), $template);
return $template;
}
// still here? wasn't a multi field template available, try the normal one with imploded $build_field
$build_field = implode(' ', $build_field);
}
// determine the field_id, which allows us to identify the field for CSS purposes
$field_id = 'col_'.$this->name;
if ($parent = $this->fieldset()->parent())
{
$parent->get_tabular_form() and $field_id = $parent->get_tabular_form().'_col_'.$this->basename;
}
$template = $this->template ?: $form->get_config('field_template', "\t\t<tr>\n\t\t\t<td class=\"{error_class}\">{label}{required}</td>\n\t\t\t<td class=\"{error_class}\">{field} {description} {error_msg}</td>\n\t\t</tr>\n");
$template = str_replace(array('{label}', '{required}', '{field}', '{error_msg}', '{error_class}', '{description}', '{field_id}'),
array($label, $required_mark, $build_field, $error_msg, $error_class, $this->description, $field_id),
$template);
return $template;
}
/**
* Alias for $this->fieldset->validation->input() for this field
*
* @return mixed
*/
public function input()
{
return $this->fieldset()->validation()->input($this->name);
}
/**
* Alias for $this->fieldset->validation->validated() for this field
*
* @return mixed
*/
public function validated()
{
return $this->fieldset()->validation()->validated($this->name);
}
/**
* Alias for $this->fieldset->validation->error() for this field
*
* @return Validation_Error
*/
public function error()
{
return $this->fieldset()->validation()->error($this->name);
}
}

@ -1,922 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class FileAccessException extends \FuelException {}
class OutsideAreaException extends \OutOfBoundsException {}
class InvalidPathException extends \FileAccessException {}
// ------------------------------------------------------------------------
/**
* File Class
*
* @package Fuel
* @subpackage Core
* @category Core
*/
class File
{
/**
* @var array loaded area's
*/
protected static $areas = array();
public static function _init()
{
\Config::load('file', true);
// make sure the configured chmod values are octal
$chmod = \Config::get('file.chmod.folders', 0777);
is_string($chmod) and \Config::set('file.chmod.folders', octdec($chmod));
$chmod = \Config::get('file.chmod.files', 0666);
is_string($chmod) and \Config::set('file.chmod.files', octdec($chmod));
static::$areas[null] = \File_Area::forge(\Config::get('file.base_config', array()));
foreach (\Config::get('file.areas', array()) as $name => $config)
{
static::$areas[$name] = \File_Area::forge($config);
}
}
public static function forge(array $config = array())
{
return \File_Area::forge($config);
}
/**
* Instance
*
* @param string|File_Area|null $area file area name, object or null for base area
* @return File_Area
*/
public static function instance($area = null)
{
if ($area instanceof File_Area)
{
return $area;
}
$instance = array_key_exists($area, static::$areas) ? static::$areas[$area] : false;
if ($instance === false)
{
throw new \InvalidArgumentException('There is no file instance named "'.$area.'".');
}
return $instance;
}
/**
* File & directory objects factory
*
* @param string $path path to the file or directory
* @param array $config configuration items
* @param string|File_Area|null $area file area name, object or null for base area
* @return File_Handler_File
*/
public static function get($path, array $config = array(), $area = null)
{
return static::instance($area)->get_handler($path, $config);
}
/**
* Get the url.
*
* @param string $path
* @param array $config
* @param null $area
* @return bool
*/
public static function get_url($path, array $config = array(), $area = null)
{
return static::get($path, $config, $area)->get_url();
}
/**
* Check for file existence
*
* @param string $path path to file to check
* @param string|File_Area|null $area file area name, object or null for base area
* @return bool
*/
public static function exists($path, $area = null)
{
$path = rtrim(static::instance($area)->get_path($path), '\\/');
// resolve symlinks
while ($path and is_link($path))
{
$path = readlink($path);
}
return is_file($path);
}
/**
* Create a file
*
* @param string $basepath directory where to create file
* @param string $name filename
* @param null $contents contents of file
* @param string|File_Area|null $area file area name, object or null for base area
* @return bool
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function create($basepath, $name, $contents = null, $area = null)
{
$basepath = rtrim(static::instance($area)->get_path($basepath), '\\/').DS;
$new_file = static::instance($area)->get_path($basepath.$name);
if ( ! is_dir($basepath) or ! is_writable($basepath))
{
throw new \InvalidPathException('Invalid basepath: "'.$basepath.'", cannot create file at this location.');
}
elseif (is_file($new_file))
{
throw new \FileAccessException('File: "'.$new_file.'" already exists, cannot be created.');
}
$file = static::open_file(@fopen($new_file, 'c'), true, $area);
fwrite($file, $contents);
static::close_file($file, $area);
return true;
}
/**
* Create an empty directory
*
* @param string directory where to create new dir
* @param string dirname
* @param int (octal) file permissions
* @param string|File_Area|null file area name, object or null for non-specific
* @return bool
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function create_dir($basepath, $name, $chmod = null, $area = null)
{
$basepath = rtrim(static::instance($area)->get_path($basepath), '\\/').DS;
$new_dir = static::instance($area)->get_path($basepath.trim($name, '\\/'));
is_null($chmod) and $chmod = \Config::get('file.chmod.folders', 0777);
if ( ! is_dir($basepath) or ! is_writable($basepath))
{
throw new \InvalidPathException('Invalid basepath: "'.$basepath.'", cannot create directory at this location.');
}
elseif (is_dir($new_dir))
{
throw new \FileAccessException('Directory: "'.$new_dir.'" exists already, cannot be created.');
}
// unify the path separators, and get the part we need to add to the basepath
$new_dir = str_replace(array('\\', '/'), DS, $new_dir);
// recursively create the directory. we can't use mkdir permissions or recursive
// due to the fact that mkdir is restricted by the current users umask
$path = '';
foreach (explode(DS, $new_dir) as $dir)
{
// some security checking
if ($dir == '.' or $dir == '..')
{
throw new \FileAccessException('Directory to be created contains illegal segments.');
}
$path .= DS.$dir;
if ( ! is_dir($path))
{
try
{
if ( ! mkdir($path))
{
return false;
}
chmod($path, $chmod);
}
catch (\PHPErrorException $e)
{
return false;
}
}
}
return true;
}
/**
* Read file
*
* @param string $path file to read
* @param bool $as_string whether to use readfile() or file_get_contents()
* @param string|File_Area|null $area file area name, object or null for base area
* @return IO|string file contents
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function read($path, $as_string = false, $area = null)
{
$path = static::instance($area)->get_path($path);
if ( ! is_file($path))
{
throw new \InvalidPathException('Cannot read file: "'.$path.'", file does not exists.');
}
$file = static::open_file(@fopen($path, 'r'), LOCK_SH, $area);
$return = $as_string ? file_get_contents($path) : readfile($path);
static::close_file($file, $area);
return $return;
}
/**
* Read directory
*
* @param string $path directory to read
* @param int $depth depth to recurse directory, 1 is only current and 0 or smaller is unlimited
* @param Array|null $filter array of partial regexps or non-array for default
* @param string|File_Area|null $area file area name, object or null for base area
* @return array
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function read_dir($path, $depth = 0, $filter = null, $area = null)
{
$path = rtrim(static::instance($area)->get_path($path), '\\/').DS;
if ( ! is_dir($path))
{
throw new \InvalidPathException('Invalid path: "'.$path.'", directory cannot be read.');
}
if ( ! $fp = @opendir($path))
{
throw new \FileAccessException('Could not open directory: "'.$path.'" for reading.');
}
// Use default when not set
if ( ! is_array($filter))
{
$filter = array('!^\.');
if ($extensions = static::instance($area)->extensions())
{
foreach($extensions as $ext)
{
$filter[] = '\.'.$ext.'$';
}
}
}
$files = array();
$dirs = array();
$new_depth = $depth - 1;
while (false !== ($file = readdir($fp)))
{
// Remove '.', '..'
if (in_array($file, array('.', '..')))
{
continue;
}
// use filters when given
elseif ( ! empty($filter))
{
$continue = false; // whether or not to continue
$matched = false; // whether any positive pattern matched
$positive = false; // whether positive filters are present
foreach($filter as $f => $type)
{
if (is_numeric($f))
{
// generic rule
$f = $type;
}
else
{
// type specific rule
$is_file = is_file($path.$file);
if (($type === 'file' and ! $is_file) or ($type !== 'file' and $is_file))
{
continue;
}
}
$not = substr($f, 0, 1) === '!'; // whether it's a negative condition
$f = $not ? substr($f, 1) : $f;
// on negative condition a match leads to a continue
if (($match = preg_match('/'.$f.'/uiD', $file) > 0) and $not)
{
$continue = true;
}
$positive = $positive ?: ! $not; // whether a positive condition was encountered
$matched = $matched ?: ($match and ! $not); // whether one of the filters has matched
}
// continue when negative matched or when positive filters and nothing matched
if ($continue or $positive and ! $matched)
{
continue;
}
}
if (@is_dir($path.$file))
{
// Use recursion when depth not depleted or not limited...
if ($depth < 1 or $new_depth > 0)
{
$dirs[$file.DS] = static::read_dir($path.$file.DS, $new_depth, $filter, $area);
}
// ... or set dir to false when not read
else
{
$dirs[$file.DS] = false;
}
}
else
{
$files[] = $file;
}
}
closedir($fp);
// sort dirs & files naturally and return array with dirs on top and files
uksort($dirs, 'strnatcasecmp');
natcasesort($files);
return array_merge($dirs, $files);
}
/**
* Update a file
*
* @param string $basepath directory where to write the file
* @param string $name filename
* @param string $contents contents of file
* @param string|File_Area|null $area file area name, object or null for base area
* @return bool
* @throws \InvalidPathException
* @throws \FileAccessException
* @throws \OutsideAreaException
*/
public static function update($basepath, $name, $contents = null, $area = null)
{
$basepath = rtrim(static::instance($area)->get_path($basepath), '\\/').DS;
$new_file = static::instance($area)->get_path($basepath.$name);
if ( ! $file = static::open_file(@fopen($new_file, 'w'), true, $area))
{
if ( ! is_dir($basepath) or ! is_writable($basepath))
{
throw new \InvalidPathException('Invalid basepath: "'.$basepath.'", cannot update a file at this location.');
}
throw new \FileAccessException('No write access to: "'.$basepath.'", cannot update a file.');
}
fwrite($file, $contents);
static::close_file($file, $area);
return true;
}
/**
* Append to a file
*
* @param string $basepath directory where to write the file
* @param string $name filename
* @param string $contents contents of file
* @param string|File_Area|null $area file area name, object or null for base area
* @return bool
* @throws \InvalidPathException
* @throws \FileAccessException
* @throws \OutsideAreaException
*/
public static function append($basepath, $name, $contents = null, $area = null)
{
$basepath = rtrim(static::instance($area)->get_path($basepath), '\\/').DS;
$new_file = static::instance($area)->get_path($basepath.$name);
if ( ! is_file($new_file))
{
throw new \FileAccessException('File: "'.$new_file.'" does not exist, cannot be appended.');
}
if ( ! $file = static::open_file(@fopen($new_file, 'a'), true, $area))
{
if ( ! is_dir($basepath) or ! is_writable($basepath))
{
throw new \InvalidPathException('Invalid basepath: "'.$basepath.'", cannot append to a file at this location.');
}
throw new \FileAccessException('No write access, cannot append to the file: "'.$file.'".');
}
fwrite($file, $contents);
static::close_file($file, $area);
return true;
}
/**
* Get the octal permissions for a file or directory
*
* @param string $path path to the file or directory
* @param string|File_Area|null $area file area name, object or null for base area
* @return string octal file permissions
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function get_permissions($path, $area = null)
{
$path = static::instance($area)->get_path($path);
if ( ! file_exists($path))
{
throw new \InvalidPathException('Path: "'.$path.'" is not a directory or a file, cannot get permissions.');
}
return substr(sprintf('%o', fileperms($path)), -4);
}
/**
* Get a file's or directory's created or modified timestamp.
*
* @param string $path path to the file or directory
* @param string $type modified or created
* @param string|File_Area|null $area file area name, object or null for base area
* @return int Unix Timestamp
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function get_time($path, $type = 'modified', $area = null)
{
$path = static::instance($area)->get_path($path);
if ( ! file_exists($path))
{
throw new \InvalidPathException('Path: "'.$path.'" is not a directory or a file, cannot get creation timestamp.');
}
if ($type === 'modified')
{
return filemtime($path);
}
elseif ($type === 'created')
{
return filectime($path);
}
else
{
throw new \UnexpectedValueException('File::time $type must be "modified" or "created".');
}
}
/**
* Get a file's size.
*
* @param string $path path to the file or directory
* @param mixed $area file area name, object or null for base area
* @return int the file's size in bytes
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function get_size($path, $area = null)
{
$path = static::instance($area)->get_path($path);
if ( ! file_exists($path))
{
throw new \InvalidPathException('Path: "'.$path.'" is not a directory or a file, cannot get size.');
}
return filesize($path);
}
/**
* Rename directory or file
*
* @param string $path path to file or directory to rename
* @param string $new_path new path (full path, can also cause move)
* @param string|File_Area|null $source_area source path file area name, object or null for non-specific
* @param string|File_Area|null $target_area target path file area name, object or null for non-specific. Defaults to source_area if not set.
* @return bool
* @throws \FileAccessException
* @throws \OutsideAreaException
*/
public static function rename($path, $new_path, $source_area = null, $target_area = null)
{
$path = static::instance($source_area)->get_path($path);
$new_path = static::instance($target_area ?: $source_area)->get_path($new_path);
return rename($path, $new_path);
}
/**
* Alias for rename(), not needed but consistent with other methods
*
* @param string $path path to directory to rename
* @param string $new_path new path (full path, can also cause move)
* @param string|File_Area|null $source_area source path file area name, object or null for non-specific
* @param string|File_Area|null $target_area target path file area name, object or null for non-specific. Defaults to source_area if not set.
* @return bool
* @throws \FileAccessException
* @throws \OutsideAreaException
*/
public static function rename_dir($path, $new_path, $source_area = null, $target_area = null)
{
return static::rename($path, $new_path, $source_area, $target_area);
}
/**
* Copy file
*
* @param string path path to file to copy
* @param string new_path new base directory (full path)
* @param string|File_Area|null source_area source path file area name, object or null for non-specific
* @param string|File_Area|null target_area target path file area name, object or null for non-specific. Defaults to source_area if not set.
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
* @return bool
*/
public static function copy($path, $new_path, $source_area = null, $target_area = null)
{
$path = static::instance($source_area)->get_path($path);
$new_path = static::instance($target_area ?: $source_area)->get_path($new_path);
if ( ! is_file($path))
{
throw new \InvalidPathException('Cannot copy file: given path: "'.$path.'" is not a file.');
}
elseif (file_exists($new_path))
{
throw new \FileAccessException('Cannot copy file: new path: "'.$new_path.'" already exists.');
}
return copy($path, $new_path);
}
/**
* Copy directory
*
* @param string $path path to directory which contents will be copied
* @param string $new_path new base directory (full path)
* @param string|File_Area|null $source_area source path file area name, object or null for non-specific
* @param string|File_Area|null $target_area target path file area name, object or null for non-specific. Defaults to source_area if not set.
* @throws \FileAccessException when something went wrong
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function copy_dir($path, $new_path, $source_area = null, $target_area = null)
{
$target_area = $target_area ?: $source_area;
$path = rtrim(static::instance($source_area)->get_path($path), '\\/').DS;
$new_path = rtrim(static::instance($target_area)->get_path($new_path), '\\/').DS;
if ( ! is_dir($path))
{
throw new \InvalidPathException('Cannot copy directory: given path: "'.$path.'" is not a directory: '.$path);
}
elseif ( ! file_exists($new_path))
{
$newpath_dirname = pathinfo($new_path, PATHINFO_DIRNAME);
static::create_dir($newpath_dirname, pathinfo($new_path, PATHINFO_BASENAME), fileperms($newpath_dirname) ?: 0777, $target_area);
}
$files = static::read_dir($path, -1, array(), $source_area);
foreach ($files as $dir => $file)
{
if (is_array($file))
{
$check = static::create_dir($new_path.DS, substr($dir, 0, -1), fileperms($path.$dir) ?: 0777, $target_area);
$check and static::copy_dir($path.$dir.DS, $new_path.$dir, $source_area, $target_area);
}
else
{
$check = static::copy($path.$file, $new_path.$file, $source_area, $target_area);
}
// abort if something went wrong
if ( ! $check)
{
throw new \FileAccessException('Directory copy aborted prematurely, part of the operation failed during copying: '.(is_array($file) ? $dir : $file));
}
}
}
/**
* Create a new symlink
*
* @param string $path target of symlink
* @param string $link_path destination of symlink
* @param bool $is_file true for file, false for directory
* @param string|File_Area|null $area file area name, object or null for base area
* @return bool
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function symlink($path, $link_path, $is_file = true, $area = null)
{
$path = rtrim(static::instance($area)->get_path($path), '\\/');
$link_path = rtrim(static::instance($area)->get_path($link_path), '\\/');
if ($is_file and ! is_file($path))
{
throw new \InvalidPathException('Cannot symlink: given file: "'.$path.'" does not exist.');
}
elseif ( ! $is_file and ! is_dir($path))
{
throw new \InvalidPathException('Cannot symlink: given directory: "'.$path.'" does not exist.');
}
elseif (file_exists($link_path))
{
throw new \FileAccessException('Cannot symlink: link: "'.$link_path.'" already exists.');
}
return symlink($path, $link_path);
}
/**
* Delete file
*
* @param string $path path to file to delete
* @param string|File_Area|null $area file area name, object or null for base area
* @return bool
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function delete($path, $area = null)
{
$path = rtrim(static::instance($area)->get_path($path), '\\/');
if ( ! is_file($path) and ! is_link($path))
{
throw new \InvalidPathException('Cannot delete file: given path "'.$path.'" is not a file.');
}
return unlink($path);
}
/**
* Delete directory
*
* @param string $path path to directory to delete
* @param bool $recursive whether to also delete contents of subdirectories
* @param bool $delete_top whether to delete the parent dir itself when empty
* @param string|File_Area|null $area file area name, object or null for base area
* @return bool
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function delete_dir($path, $recursive = true, $delete_top = true, $area = null)
{
$path = rtrim(static::instance($area)->get_path($path), '\\/').DS;
if ( ! is_dir($path))
{
throw new \InvalidPathException('Cannot delete directory: given path: "'.$path.'" is not a directory.');
}
$files = static::read_dir($path, -1, array(), $area);
$not_empty = false;
$check = true;
foreach ($files as $dir => $file)
{
if (is_array($file))
{
if ($recursive)
{
$check = static::delete_dir($path.$dir, true, true, $area);
}
else
{
$not_empty = true;
}
}
else
{
$check = static::delete($path.$file, $area);
}
// abort if something went wrong
if ( ! $check)
{
throw new \FileAccessException('Directory deletion aborted prematurely, part of the operation failed.');
}
}
if ( ! $not_empty and $delete_top)
{
return rmdir($path);
}
return true;
}
/**
* Open and lock file
*
* @param resource|string $path file resource or path
* @param constant|bool $lock either valid lock constant or true=LOCK_EX / false=LOCK_UN
* @param string|File_Area|null $area file area name, object or null for base area
* @return bool|resource
* @throws \FileAccessException
* @throws \OutsideAreaException
*/
public static function open_file($path, $lock = true, $area = null)
{
if (is_string($path))
{
$path = static::instance($area)->get_path($path);
$resource = fopen($path, 'r+');
}
else
{
$resource = $path;
}
// Make sure the parameter is a valid resource
if ( ! is_resource($resource))
{
return false;
}
// If locks aren't used, don't lock
if ( ! static::instance($area)->use_locks())
{
return $resource;
}
// Accept valid lock constant or set to LOCK_EX
$lock = in_array($lock, array(LOCK_SH, LOCK_EX, LOCK_NB)) ? $lock : LOCK_EX;
// Try to get a lock, timeout after 5 seconds
$lock_mtime = microtime(true);
while ( ! flock($resource, $lock))
{
if (microtime(true) - $lock_mtime > 5)
{
throw new \FileAccessException('Could not secure file lock, timed out after 5 seconds.');
}
}
return $resource;
}
/**
* Close file resource & unlock
*
* @param resource $resource open file resource
* @param string|File_Area|null $area file area name, object or null for base area
*/
public static function close_file($resource, $area = null)
{
// If locks aren't used, don't unlock
if ( static::instance($area)->use_locks())
{
flock($resource, LOCK_UN);
}
fclose($resource);
}
/**
* Get detailed information about a file
*
* @param string $path file path
* @param string|File_Area|null $area file area name, object or null for base area
* @return array
* @throws \FileAccessException
* @throws \InvalidPathException
* @throws \OutsideAreaException
*/
public static function file_info($path, $area = null)
{
$info = array(
'original' => $path,
'realpath' => '',
'dirname' => '',
'basename' => '',
'filename' => '',
'extension' => '',
'mimetype' => '',
'charset' => '',
'size' => 0,
'permissions' => '',
'time_created' => '',
'time_modified' => '',
);
if ( ! $info['realpath'] = static::instance($area)->get_path($path) or ! is_file($info['realpath']))
{
throw new \InvalidPathException('Filename given is not a valid file.');
}
$info = array_merge($info, pathinfo($info['realpath']));
if ( ! $fileinfo = new \finfo(FILEINFO_MIME, \Config::get('file.magic_file', null)))
{
throw new \InvalidArgumentException('Can not retrieve information about this file.');
}
$fileinfo = explode(';', $fileinfo->file($info['realpath']));
$info['mimetype'] = isset($fileinfo[0]) ? $fileinfo[0] : 'application/octet-stream';
if (isset($fileinfo[1]))
{
$fileinfo = explode('=', $fileinfo[1]);
$info['charset'] = isset($fileinfo[1]) ? $fileinfo[1] : '';
}
$info['size'] = static::get_size($info['realpath'], $area);
$info['permissions'] = static::get_permissions($info['realpath'], $area);
$info['time_created'] = static::get_time($info['realpath'], 'created', $area);
$info['time_modified'] = static::get_time($info['realpath'], 'modified', $area);
return $info;
}
/**
* Download a file
*
* @param string $path file path
* @param string|null $name custom name for the file to be downloaded
* @param string|null $mime custom mime type or null for file mime type
* @param string|File_Area|null $area file area name, object or null for base area
* @param bool $delete delete the file after download when true
* @param string $disposition disposition, must be 'attachment' or 'inline'
*/
public static function download($path, $name = null, $mime = null, $area = null, $delete = false, $disposition = 'attachment')
{
$info = static::file_info($path, $area);
$class = get_called_class();
empty($mime) or $info['mimetype'] = $mime;
empty($name) or $info['basename'] = $name;
in_array($disposition, array('inline', 'attachment')) or $disposition = 'attachment';
\Event::register('fuel-shutdown', function () use($info, $area, $class, $delete, $disposition) {
if ( ! $file = call_user_func(array($class, 'open_file'), @fopen($info['realpath'], 'rb'), LOCK_SH, $area))
{
throw new \FileAccessException('Filename given could not be opened for download.');
}
while (ob_get_level() > 0)
{
ob_end_clean();
}
ini_get('zlib.output_compression') and ini_set('zlib.output_compression', 0);
! ini_get('safe_mode') and set_time_limit(0);
header('Content-Type: '.$info['mimetype']);
header('Content-Disposition: '.$disposition.'; filename="'.$info['basename'].'"');
$disposition === 'attachment' and header('Content-Description: File Transfer');
header('Content-Length: '.$info['size']);
header('Content-Transfer-Encoding: binary');
$disposition === 'attachment' and header('Expires: 0');
$disposition === 'attachment' and header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
while( ! feof($file))
{
echo fread($file, 2048);
}
call_user_func(array($class, 'close_file'), $file, $area);
if ($delete)
{
call_user_func(array($class, 'delete'), $info['realpath'], $area);
}
});
exit;
}
}

@ -1,277 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class File_Area
{
/**
* @var string path to basedir restriction, null for no restriction
*/
protected $basedir = null;
/**
* @var array array of allowed extensions, null for all
*/
protected $extensions = null;
/**
* @var string base url for files, null for not available
*/
protected $url = null;
/**
* @var bool whether or not to use file locks when doing file operations
*/
protected $use_locks = false;
/**
* @var array contains file handler per file extension
*/
protected $file_handlers = array();
protected function __construct(array $config = array())
{
foreach ($config as $key => $value)
{
if (property_exists($this, $key))
{
$this->{$key} = $value;
}
}
if ( ! empty($this->basedir))
{
$this->basedir = realpath($this->basedir) ?: $this->basedir;
}
}
/**
* Factory for area objects
*
* @param array
* @return File_Area
*/
public static function forge(array $config = array())
{
return new static($config);
}
/**
* Handler factory for given path
*
* @param string $path path to file or directory
* @param array $config optional config
* @param array $content
* @return File_Handler_File
* @throws \FileAccessException when outside basedir restriction or disallowed file extension
* @throws \OutsideAreaException
*/
public function get_handler($path, array $config = array(), $content = array())
{
$path = $this->get_path($path);
if (is_file($path))
{
$info = pathinfo($path);
// deal with path names without an extension
isset($info['extension']) or $info['extension'] = '';
// check file extension
if ( ! empty($this->extensions) && ! in_array($info['extension'], $this->extensions))
{
throw new \FileAccessException('File operation not allowed: disallowed file extension.');
}
// create specific handler when available
if (array_key_exists($info['extension'], $this->file_handlers))
{
$class = '\\'.ltrim($this->file_handlers[$info['extension']], '\\');
return $class::forge($path, $config, $this);
}
return \File_Handler_File::forge($path, $config, $this);
}
elseif (is_dir($path))
{
return \File_Handler_Directory::forge($path, $config, $this, $content);
}
// still here? path is invalid
throw new \FileAccessException('Invalid path for file or directory.');
}
/**
* Does this area use file locks?
*
* @return bool
*/
public function use_locks()
{
return $this->use_locks;
}
/**
* Are the shown extensions limited, and if so to which?
*
* @return array
*/
public function extensions()
{
return $this->extensions;
}
/**
* Translate relative path to real path, throws error when operation is not allowed
*
* @param string $path
* @return string
* @throws \FileAccessException when outside basedir restriction or disallowed file extension
* @throws \OutsideAreaException
*/
public function get_path($path)
{
$pathinfo = is_dir($path) ? array('dirname' => $path, 'extension' => null, 'basename' => '') : pathinfo($path);
// make sure we have a dirname to work with
isset($pathinfo['dirname']) or $pathinfo['dirname'] = '';
// do we have a basedir, and is the path already prefixed by the basedir? then just deal with the double dots...
if ( ! empty($this->basedir) && substr($pathinfo['dirname'], 0, strlen($this->basedir)) == $this->basedir)
{
$pathinfo['dirname'] = realpath($pathinfo['dirname']);
}
else
{
// attempt to get the realpath(), otherwise just use path with any double dots taken out when basedir is set (for security)
$pathinfo['dirname'] = ( ! empty($this->basedir) ? realpath($this->basedir.DS.$pathinfo['dirname']) : realpath($pathinfo['dirname']) )
?: ( ! empty($this->basedir) ? $this->basedir.DS.str_replace('..', '', $pathinfo['dirname']) : $pathinfo['dirname']);
}
// basedir prefix is required when it is set (may cause unexpected errors when realpath doesn't work)
if ( ! empty($this->basedir) && substr($pathinfo['dirname'], 0, strlen($this->basedir)) != $this->basedir)
{
throw new \OutsideAreaException('File operation not allowed: given path is outside the basedir for this area.');
}
// check file extension
if ( ! empty(static::$extensions) && array_key_exists($pathinfo['extension'], static::$extensions))
{
throw new \FileAccessException('File operation not allowed: disallowed file extension.');
}
return $pathinfo['dirname'].DS.$pathinfo['basename'];
}
/**
* Translate relative path to accessible path, throws error when operation is not allowed
*
* @param string
* @return string
* @throws \LogicException when no url is set or no basedir is set and file is outside DOCROOT
*/
public function get_url($path)
{
if(empty($this->url))
{
throw new \LogicException('File operation now allowed: cannot create a file url without an area url.');
}
$path = $this->get_path($path);
$basedir = $this->basedir;
empty($basedir) and $basedir = DOCROOT;
if(stripos($path, $basedir) !== 0)
{
throw new \LogicException('File operation not allowed: cannot create file url whithout a basedir and file outside DOCROOT.');
}
return rtrim($this->url, '/').'/'.ltrim(str_replace(DS, '/', substr($path, strlen($basedir))), '/');
}
/* -------------------------------------------------------------------------------------
* Allow all File methods to be used from an area directly
* ------------------------------------------------------------------------------------- */
public function create($basepath, $name, $contents = null)
{
return \File::create($basepath, $name, $contents, $this);
}
public function create_dir($basepath, $name, $chmod = null)
{
return \File::create_dir($basepath, $name, $chmod, $this);
}
public function read($path, $as_string = false)
{
return \File::read($path, $as_string, $this);
}
public function read_dir($path, $depth = 0, $filter = null)
{
$content = \File::read_dir($path, $depth, $filter, $this);
return $this->get_handler($path, array(), $content);
}
public function rename($path, $new_path)
{
return \File::rename($path, $new_path, $this);
}
public function rename_dir($path, $new_path)
{
return \File::rename_dir($path, $new_path, $this);
}
public function copy($path, $new_path)
{
return \File::copy($path, $new_path, $this);
}
public function copy_dir($path, $new_path)
{
return \File::copy_dir($path, $new_path, $this);
}
public function delete($path)
{
return \File::delete($path, $this);
}
public function delete_dir($path, $recursive = true, $delete_top = true)
{
return \File::delete_dir($path, $recursive, $delete_top, $this);
}
public function update($basepath, $name, $new_content)
{
return \File::update($basepath, $name, $new_content, $this);
}
public function get_permissions($path)
{
return \File::get_permissions($path, $this);
}
public function get_time($path, $type)
{
return \File::get_time($path, $type, $this);
}
public function get_size($path)
{
return \File::get_size($path, $this);
}
}

@ -1,191 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class File_Handler_Directory
{
/**
* @var string path to the file
*/
protected $path;
/**
* @var File_Area
*/
protected $area;
/**
* @var array listing of files and directories within this directory
*/
protected $content = array();
protected function __construct($path, array &$config, File_Area $area, $content = array())
{
$this->path = rtrim($path, '\\/').DS;
$this->area = $area;
foreach ($content as $key => $value)
{
if ( ! is_int($key))
{
$this->content[$key] = $value === false ? false : $area->get_handler($path.DS.$key, $config, $value);
}
else
{
$this->content[$key] = $area->get_handler($path.DS.$value, $config);
}
}
}
public static function forge($path, array $config = array(), File_Area $area = null, $content = array())
{
return new static($path, $config, $area, $content);
}
/**
* Read directory
*
* @param int $depth whether or not to read recursive
* @param array $filters array of partial regexps or non-array for default
* @return array
*/
public function read($depth = 0, $filters = null)
{
return $this->area->read_dir($this->path, $depth, $filters, $this->area);
}
/**
* Rename file, only within current directory
*
* @param string $new_name new directory name
* @return bool
*/
public function rename($new_name)
{
$info = pathinfo($this->path);
$new_name = str_replace(array('..', '/', '\\'), array('', '', ''), $new_name);
$new_path = $info['dirname'].DS.$new_name;
$return = $this->area->rename_dir($this->path, $new_path);
$return and $this->path = $new_path;
return $return;
}
/**
* Move directory to new parent directory
*
* @param string $new_path path to new parent directory, must be valid
* @return bool
*/
public function move($new_path)
{
$info = pathinfo($this->path);
$new_path = $this->area->get_path($new_path);
$new_path = rtrim($new_path, '\\/').DS.$info['basename'];
$return = $this->area->rename_dir($this->path, $new_path);
$return and $this->path = $new_path;
return $return;
}
/**
* Copy directory
*
* @param string $new_path path to parent directory, must be valid
* @return bool
*/
public function copy($new_path)
{
$info = pathinfo($this->path);
$new_path = $this->area->get_path($new_path);
$new_path = rtrim($new_path, '\\/').DS.$info['basename'];
return $this->area->copy_dir($this->path, $new_path);
}
/**
* Update contents
*
* This method is unavailable on this implement, that will surely cause exception.
*
* @throws \BadMethodCallException
*/
public function update()
{
throw new \BadMethodCallException('Update method is unavailable on directories.');
}
/**
* Delete directory
*
* @param bool $recursive
* @param bool $delete_top
* @return bool
*/
public function delete($recursive = true, $delete_top = true)
{
// should also destroy object but not possible in PHP right?
return $this->area->delete_dir($this->path, $recursive, $delete_top);
}
/**
* Get the url.
*
* This method is unavailable on this implement, that will surely cause exception.
*
* @throws \BadMethodCallException
*/
public function get_url()
{
throw new \BadMethodCallException('Get_url method is unavailable on directories.');
}
/**
* Get the directory permissions.
*
* @return string file permissions
*/
public function get_permissions()
{
return $this->area->get_permissions($this->path);
}
/**
* Get directory's the created or modified timestamp.
*
* @param string $type modified or created
* @return int Unix Timestamp
*/
public function get_time($type = 'modified')
{
return $this->area->get_time($this->path, $type);
}
/**
* Get the size.
*
* This method is unavailable on this implement, that will surely cause exception.
*
* @throws \BadMethodCallException
*/
public function get_size()
{
throw new \BadMethodCallException('Get_size method is unavailable on directories.');
}
}

@ -1,205 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class File_Handler_File
{
/**
* @var string path to the file
*/
protected $path;
/**
* @var File_Area
*/
protected $area;
/**
* @var Resource file resource
*/
protected $resource;
/**
* @var bool whether the current object is read only
*/
protected $readonly = false;
protected function __construct($path, array $config, File_Area $area, $content = array())
{
$this->path = $path;
$this->area = $area;
}
public static function forge($path, array $config = array(), File_Area $area = null, $content = array())
{
$obj = new static($path, $config, \File::instance($area), $content);
$config['path'] = $path;
$config['area'] = $area;
foreach ($config as $key => $value)
{
if (property_exists($obj, $key) && empty($obj->$key))
{
$obj->$key = $value;
}
}
return $obj;
}
/**
* Read file
*
* @param bool $as_string whether to use file_get_contents() or readfile()
* @return string|IO
*/
public function read($as_string = false)
{
return $this->area->read($this->path, $as_string);
}
/**
* Rename file, only within current directory
*
* @param string $new_name new filename
* @param string|bool $new_extension new extension, false to keep current
* @return bool
*/
public function rename($new_name, $new_extension = false)
{
$info = pathinfo($this->path);
$new_name = str_replace(array('..', '/', '\\'), array('', '', ''), $new_name);
$extension = $new_extension === false
? $info['extension']
: ltrim($new_extension, '.');
$extension = ! empty($extension) ? '.'.$extension : '';
$new_path = $info['dirname'].DS.$new_name.$extension;
$return = $this->area->rename($this->path, $new_path);
$return and $this->path = $new_path;
return $return;
}
/**
* Move file to new directory
*
* @param string $new_path path to new directory, must be valid
* @return bool
*/
public function move($new_path)
{
$info = pathinfo($this->path);
$new_path = $this->area->get_path($new_path);
$new_path = rtrim($new_path, '\\/').DS.$info['basename'];
$return = $this->area->rename($this->path, $new_path);
$return and $this->path = $new_path;
return $return;
}
/**
* Copy file
*
* @param string $new_path path to target directory, must be valid
* @return bool
*/
public function copy($new_path)
{
$info = pathinfo($this->path);
$new_path = $this->area->get_path($new_path);
$new_path = rtrim($new_path, '\\/').DS.$info['basename'];
return $this->area->copy($this->path, $new_path);
}
/**
* Update contents
*
* @param mixed $new_content new file contents
* @return bool
*/
public function update($new_content)
{
$info = pathinfo($this->path);
return $this->area->update($info['dirname'], $info['basename'], $new_content, $this);
}
/**
* Delete file
*
* @return bool
*/
public function delete()
{
// should also destroy object but not possible in PHP right?
return $this->area->delete($this->path);
}
/**
* Get the url.
*
* @return bool
*/
public function get_url()
{
return $this->area->get_url($this->path);
}
/**
* Get the file's permissions.
*
* @return string file permissions
*/
public function get_permissions()
{
return $this->area->get_permissions($this->path);
}
/**
* Get the file's created or modified timestamp.
*
* @param string $type modified or created
* @return int Unix Timestamp
*/
public function get_time($type = 'modified')
{
return $this->area->get_time($this->path, $type);
}
/**
* Get the file's size.
*
* @return int File size
*/
public function get_size()
{
return $this->area->get_size($this->path);
}
/**
* Get the file's path.
*
* @return string File path
*/
public function get_path()
{
return $this->path;
}
}

@ -1,559 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* The Finder class allows for searching through a search path for a given
* file, as well as loading a given file.
*
* @package Fuel
* @subpackage Core
*/
class Finder
{
/**
* @var Finder $instance Singleton master instance
*/
protected static $instance = null;
public static function _init()
{
\Config::load('file', true);
// make sure the configured chmod values are octal
$chmod = \Config::get('file.chmod.folders', 0777);
is_string($chmod) and \Config::set('file.chmod.folders', octdec($chmod));
$chmod = \Config::get('file.chmod.files', 0666);
is_string($chmod) and \Config::set('file.chmod.files', octdec($chmod));
}
/**
* An alias for Finder::instance()->locate();
*
* @param string $dir Directory to look in
* @param string $file File to find
* @param string $ext File extension
* @param bool $multiple Whether to find multiple files
* @param bool $cache Whether to cache this path or not
* @return mixed Path, or paths, or false
*/
public static function search($dir, $file, $ext = '.php', $multiple = false, $cache = true)
{
return static::instance()->locate($dir, $file, $ext, $multiple, $cache);
}
/**
* Gets a singleton instance of Finder
*
* @return Finder
*/
public static function instance()
{
if ( ! static::$instance)
{
static::$instance = static::forge(array(APPPATH, COREPATH));
}
return static::$instance;
}
/**
* Forges new Finders.
*
* @param array $paths The paths to initialize with
* @return Finder
*/
public static function forge($paths = array())
{
return new static($paths);
}
/**
* @var array $paths Holds all of the search paths
*/
protected $paths = array();
/**
* @var array $flash_paths Search paths that only last for one lookup
*/
protected $flash_paths = array();
/**
* @var int $cache_lifetime the amount of time to cache in seconds
*/
protected $cache_lifetime = null;
/**
* @var string $cache_dir path to the cache file location
*/
protected $cache_dir = null;
/**
* @var array $cached_paths Cached lookup paths
*/
protected $cached_paths = array();
/**
* @var bool $cache_valid Whether the path cache is valid or not
*/
protected $cache_valid = true;
/**
* Takes in an array of paths, preps them and gets the party started.
*
* @param array $paths The paths to initialize with
*/
public function __construct($paths = array())
{
$this->add_path($paths);
}
/**
* Adds a path (or paths) to the search path at a given position.
*
* Possible positions:
* (null): Append to the end of the search path
* (-1): Prepend to the start of the search path
* (index): The path will get inserted AFTER the given index
*
* @param string|array $paths The path to add
* @param int $pos The position to add the path
* @return $this
* @throws \OutOfBoundsException
*/
public function add_path($paths, $pos = null)
{
if ( ! is_array($paths))
{
$paths = array($paths);
}
foreach ($paths as $path)
{
if ($pos === null)
{
$this->paths[] = $this->prep_path($path);
}
elseif ($pos === -1)
{
array_unshift($this->paths, $this->prep_path($path));
}
else
{
if ($pos > count($this->paths))
{
throw new \OutOfBoundsException(sprintf('Position "%s" is out of range.', $pos));
}
array_splice($this->paths, $pos, 0, $this->prep_path($path));
}
}
return $this;
}
/**
* Removes a path from the search path.
*
* @param string $path Path to remove
* @return $this
*/
public function remove_path($path)
{
foreach ($this->paths as $i => $p)
{
if ($p === $path)
{
unset($this->paths[$i]);
break;
}
}
return $this;
}
/**
* Adds multiple flash paths.
*
* @param array $paths The paths to add
* @return $this
*/
public function flash($paths)
{
if ( ! is_array($paths))
{
$paths = array($paths);
}
foreach ($paths as $path)
{
$this->flash_paths[] = $this->prep_path($path);
}
return $this;
}
/**
* Clears the flash paths.
*
* @return $this
*/
public function clear_flash()
{
$this->flash_paths = array();
return $this;
}
/**
* Returns the current search paths...including flash paths.
*
* @return array Search paths
*/
public function paths()
{
return array_merge($this->flash_paths, $this->paths);
}
/**
* Prepares a path for usage. It ensures that the path has a trailing
* Directory Separator.
*
* @param string $path The path to prepare
* @return string
*/
public function prep_path($path)
{
$path = str_replace(array('/', '\\'), DS, $path);
return rtrim($path, DS).DS;
}
/**
* Prepares an array of paths.
*
* @param array $paths The paths to prepare
* @return array
*/
public function prep_paths(array $paths)
{
foreach ($paths as &$path)
{
$path = $this->prep_path($path);
}
return $paths;
}
/**
* Gets a list of all the files in a given directory inside all of the
* loaded search paths (e.g. the cascading file system). This is useful
* for things like finding all the config files in all the search paths.
*
* @param string $directory The directory to look in
* @param string $filter The file filter
* @return array the array of files
*/
public function list_files($directory = null, $filter = '*.php')
{
$paths = $this->paths;
// get extra information of the active request
if (class_exists('Request', false) and ($uri = \Uri::string()) !== null)
{
$paths = array_merge(\Request::active()->get_paths(), $paths);
}
// Merge in the flash paths then reset the flash paths
$paths = array_merge($this->flash_paths, $paths);
$this->clear_flash();
$found = array();
foreach ($paths as $path)
{
$files = new \GlobIterator(rtrim($path.$directory, DS).DS.$filter);
foreach($files as $file)
{
$found[] = $file->getPathname();
}
}
return $found;
}
/**
* Locates a given file in the search paths.
*
* @param string $dir Directory to look in
* @param string $file File to find
* @param string $ext File extension
* @param bool $multiple Whether to find multiple files
* @param bool $cache Whether to cache this path or not
* @return mixed Path, or paths, or false
*/
public function locate($dir, $file, $ext = '.php', $multiple = false, $cache = true)
{
$found = $multiple ? array() : false;
// absolute path requested?
if ($file[0] === '/' or substr($file, 1, 2) === ':\\')
{
// if the base file does not exist, stick the extension to the back of it
if ( ! is_file($file))
{
$file .= $ext;
}
if ( ! is_file($file))
{
// at this point, found would be either empty array or false
return $found;
}
return $multiple ? array($file) : $file;
}
// determine the cache prefix
if ($multiple)
{
// make sure cache is not used if the loaded package and module list is changed
$cachekey = '';
class_exists('Module', false) and $cachekey .= implode('|', \Module::loaded());
$cachekey .= '|';
class_exists('Package', false) and $cachekey .= implode('|', \Package::loaded());
$cache_id = md5($cachekey).'.';
}
else
{
$cache_id = 'S.';
}
$paths = array();
// If a filename contains a :: then it is trying to be found in a namespace.
// This is sometimes used to load a view from a non-loaded module.
if ($pos = strripos($file, '::'))
{
// get the namespace path
if ($path = \Autoloader::namespace_path('\\'.ucfirst(substr($file, 0, $pos))))
{
$cache_id .= substr($file, 0, $pos);
// and strip the classes directory as we need the module root
$paths = array(substr($path, 0, -8));
// strip the namespace from the filename
$file = substr($file, $pos + 2);
}
}
else
{
$paths = $this->paths;
// get extra information of the active request
if (class_exists('Request', false) and ($request = \Request::active()))
{
$request->module and $cache_id .= $request->module;
$paths = array_merge($request->get_paths(), $paths);
}
}
// Merge in the flash paths then reset the flash paths
$paths = array_merge($this->flash_paths, $paths);
$this->clear_flash();
$file = $this->prep_path($dir).$file.$ext;
$cache_id .= $file;
if ($cache and $cached_path = $this->from_cache($cache_id))
{
return $cached_path;
}
foreach ($paths as $dir)
{
$file_path = $dir.$file;
if (is_file($file_path))
{
if ( ! $multiple)
{
$found = $file_path;
break;
}
$found[] = $file_path;
}
}
if ( ! empty($found) and $cache)
{
$this->add_to_cache($cache_id, $found);
}
return $found;
}
/**
* Reads in the cached paths with the given cache id.
*
* @param string $cache_id Cache id to read
* @return void
*/
public function read_cache($cache_id)
{
// make sure we have all config data
empty($this->cache_dir) and $this->cache_dir = \Config::get('cache_dir', APPPATH.'cache/');
empty($this->cache_lifetime) and $this->cache_lifetime = \Config::get('cache_lifetime', 3600);
if ($cached = $this->cache($cache_id))
{
$this->cached_paths = $cached;
}
}
/**
* Writes out the cached paths if they need to be.
*
* @param string $cache_id Cache id to read
* @return void
*/
public function write_cache($cache_id)
{
$this->cache_valid or $this->cache($cache_id, $this->cached_paths);
}
/**
* Loads in the given cache_id from the cache if it exists.
*
* @param string $cache_id Cache id to load
* @return string|bool Path or false if not found
*/
protected function from_cache($cache_id)
{
$cache_id = md5($cache_id);
if (array_key_exists($cache_id, $this->cached_paths))
{
return $this->cached_paths[$cache_id];
}
return false;
}
/**
* Loads in the given cache_id from the cache if it exists.
*
* @param string $cache_id Cache id to load
* @return string|bool Path or false if not found
*/
protected function add_to_cache($cache_id, $path)
{
$cache_id = md5($cache_id);
$this->cached_paths[$cache_id] = $path;
$this->cache_valid = false;
}
/**
* This method does basic filesystem caching. It is used for things like path caching.
*
* This method is from KohanaPHP's Kohana class.
*
* @param string $name the cache name
* @param array $data the data to cache (if non given it returns)
* @param int $lifetime the number of seconds for the cache too live
* @return bool|null
*/
protected function cache($name, $data = null, $lifetime = null)
{
// Cache file is a hash of the name
$file = $name.'.pathcache';
// Cache directories are split by keys to prevent filesystem overload
$dir = rtrim($this->cache_dir, DS).DS;
if ($lifetime === NULL)
{
// Use the default lifetime
$lifetime = $this->cache_lifetime;
}
if ($data === null)
{
if (is_file($dir.$file))
{
if ((time() - filemtime($dir.$file)) < $lifetime)
{
// Return the cache
try
{
return unserialize(file_get_contents($dir.$file));
}
catch (\Exception $e)
{
// Cache exists but could not be read, ignore it
}
}
else
{
try
{
// Cache has expired
unlink($dir.$file);
}
catch (Exception $e)
{
// Cache has mostly likely already been deleted,
// let return happen normally.
}
}
}
// Cache not found
return null;
}
if ( ! is_dir($dir))
{
// Create the cache directory
mkdir($dir, \Config::get('file.chmod.folders', 0777), true);
// Set permissions (must be manually set to fix umask issues)
chmod($dir, \Config::get('file.chmod.folders', 0777));
}
// Force the data to be a string
$data = serialize($data);
try
{
// Write the cache, and set permissions
if ($result = (bool) file_put_contents($dir.$file, $data, LOCK_EX))
{
try
{
chmod($dir.$file, \Config::get('file.chmod.files', 0666));
}
catch (\PhpErrorException $e)
{
// if we get something else then a chmod error, bail out
if (substr($e->getMessage(), 0, 8) !== 'chmod():')
{
throw new $e;
}
}
}
return $result;
}
catch (\Exception $e)
{
// Failed to write cache
return false;
}
}
}

@ -1,312 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Form Class
*
* Helper for creating forms with support for creating dynamic form objects.
*
* @package Fuel
* @category Core
*/
class Form
{
/*
* @var Form_Instance the default form instance
*/
protected static $instance;
/**
* When autoloaded this will method will be fired, load once and once only
*
* @return void
*/
public static function _init()
{
\Config::load('form', true);
static::$instance = static::forge('_default_', \Config::get('form'));
}
public static function forge($fieldset = 'default', array $config = array())
{
if (is_string($fieldset))
{
($set = \Fieldset::instance($fieldset)) and $fieldset = $set;
}
if ($fieldset instanceof Fieldset)
{
if ($fieldset->form(false) != null)
{
throw new \DomainException('Form instance already exists, cannot be recreated. Use instance() instead of forge() to retrieve the existing instance.');
}
}
return new \Form_Instance($fieldset, $config);
}
/**
* Returns the 'default' instance of Form
*
* @param null|string $name
* @return Form_Instance
*/
public static function instance($name = null)
{
$fieldset = \Fieldset::instance($name);
return $fieldset === false ? false : $fieldset->form();
}
/**
* Create a form open tag
*
* @param string|array $attributes action string or array with more tag attribute settings
* @param array $hidden
* @return string
*/
public static function open($attributes = array(), array $hidden = array())
{
return static::$instance->open($attributes, $hidden);
}
/**
* Create a form close tag
*
* @return string
*/
public static function close()
{
return static::$instance->close();
}
/**
* Create a fieldset open tag
*
* @param array $attributes array with tag attribute settings
* @param string $legend string for the fieldset legend
* @return string
*/
public static function fieldset_open($attributes = array(), $legend = null)
{
return static::$instance->fieldset_open($attributes, $legend);
}
/**
* Create a fieldset close tag
*
* @return string
*/
public static function fieldset_close()
{
return static::$instance->fieldset_close();
}
/**
* Create a form input
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public static function input($field, $value = null, array $attributes = array())
{
return static::$instance->input($field, $value, $attributes);
}
/**
* Create a hidden field
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public static function hidden($field, $value = null, array $attributes = array())
{
return static::$instance->hidden($field, $value, $attributes);
}
/**
* Create a CSRF hidden field
*
* @return string
*/
public static function csrf()
{
return static::hidden(\Config::get('security.csrf_token_key', 'fuel_csrf_token'), \Security::fetch_token());
}
/**
* Create a password input field
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public static function password($field, $value = null, array $attributes = array())
{
return static::$instance->password($field, $value, $attributes);
}
/**
* Create a radio button
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param mixed $checked either attributes (array) or bool/string to set checked status
* @param array $attributes
* @return string
*/
public static function radio($field, $value = null, $checked = null, array $attributes = array())
{
return static::$instance->radio($field, $value, $checked, $attributes);
}
/**
* Create a checkbox
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param mixed $checked either attributes (array) or bool/string to set checked status
* @param array $attributes
* @return string
*/
public static function checkbox($field, $value = null, $checked = null, array $attributes = array())
{
return static::$instance->checkbox($field, $value, $checked, $attributes);
}
/**
* Create a file upload input field
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param array $attributes
* @return string
*/
public static function file($field, array $attributes = array())
{
return static::$instance->file($field, $attributes);
}
/**
* Create a button
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public static function button($field, $value = null, array $attributes = array())
{
return static::$instance->button($field, $value, $attributes);
}
/**
* Create a reset button
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public static function reset($field = 'reset', $value = 'Reset', array $attributes = array())
{
return static::$instance->reset($field, $value, $attributes);
}
/**
* Create a submit button
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public static function submit($field = 'submit', $value = 'Submit', array $attributes = array())
{
return static::$instance->submit($field, $value, $attributes);
}
/**
* Create a textarea field
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public static function textarea($field, $value = null, array $attributes = array())
{
return static::$instance->textarea($field, $value, $attributes);
}
/**
* Select
*
* Generates a html select element based on the given parameters
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $values selected value(s)
* @param array $options array of options and option groups
* @param array $attributes
* @return string
*/
public static function select($field, $values = null, array $options = array(), array $attributes = array())
{
return static::$instance->select($field, $values, $options, $attributes);
}
/**
* Create a label field
*
* @param string|array $label either fieldname or full attributes array (when array other params are ignored)
* @param string $id
* @param array $attributes
* @return string
*/
public static function label($label, $id = null, array $attributes = array())
{
return static::$instance->label($label, $id, $attributes);
}
/**
* Prep Value
*
* Prepares the value for display in the form
*
* @param string $value
* @return string
*/
public static function prep_value($value)
{
return static::$instance->prep_value($value);
}
/**
* Attr to String
*
* Wraps the global attributes function and does some form specific work
*
* @param array $attr
* @return string
*/
protected static function attr_to_string($attr)
{
return static::$instance->attr_to_string($attr);
}
}

@ -1,820 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Form Class
*
* Helper for creating forms with support for creating dynamic form objects.
*
* @package Fuel
* @category Core
*/
class Form_Instance
{
/**
* Valid types for input tags (including HTML5)
*/
protected static $_valid_inputs = array(
'button', 'checkbox', 'color', 'date', 'datetime',
'datetime-local', 'email', 'file', 'hidden', 'image',
'month', 'number', 'password', 'radio', 'range',
'reset', 'search', 'submit', 'tel', 'text', 'time',
'url', 'week',
);
/**
* @var Fieldset
*/
protected $fieldset;
public function __construct($fieldset, array $config = array())
{
if ($fieldset instanceof Fieldset)
{
$fieldset->form($this);
$this->fieldset = $fieldset;
}
else
{
$this->fieldset = \Fieldset::forge($fieldset, array('form_instance' => $this));
}
foreach ($config as $key => $val)
{
$this->set_config($key, $val);
}
}
/**
* Set form attribute
*
* @param string $key
* @param mixed $value
* @return \Form_Instance
*/
public function set_attribute($key, $value)
{
$attributes = $this->get_config('form_attributes', array());
$attributes[$key] = $value;
$this->set_config('form_attributes', $attributes);
return $this;
}
/**
* Get form attribute
*
* @param string $key
* @param mixed $default
* @return mixed
*/
public function get_attribute($key, $default = null)
{
$attributes = $this->get_config('form_attributes', array());
return array_key_exists($key, $attributes) ? $attributes[$key] : $default;
}
/**
* Magic method toString that will build this as a form
*
* @return string
*/
public function __toString()
{
return $this->build();
}
/**
* Create a form open tag
*
* @param string|array $attributes action string or array with more tag attribute settings
* @param array $hidden
* @return string
*/
public function open($attributes = array(), array $hidden = array())
{
$attributes = ! is_array($attributes) ? array('action' => $attributes) : $attributes;
// If there is still no action set, Form-post
if( ! array_key_exists('action', $attributes) or empty($attributes['action']))
{
$attributes['action'] = \Uri::main();
}
// If not a full URL, create one
elseif ( ! strpos($attributes['action'], '://'))
{
$attributes['action'] = \Uri::create($attributes['action']);
}
if (empty($attributes['accept-charset']))
{
$attributes['accept-charset'] = strtolower(\Fuel::$encoding);
}
// If method is empty, use POST
! empty($attributes['method']) || $attributes['method'] = $this->get_config('form_method', 'post');
$form = '<form';
foreach ($attributes as $prop => $value)
{
$form .= ' '.$prop.'="'.$value.'"';
}
$form .= '>';
// Add hidden fields when given
foreach ($hidden as $field => $value)
{
$form .= PHP_EOL.$this->hidden($field, $value);
}
// Add CSRF token automatically
if (Config::get('security.csrf_auto_token', false))
{
$form .= PHP_EOL.\Form::csrf();
}
return $form;
}
/**
* Create a form close tag
*
* @return string
*/
public function close()
{
return '</form>';
}
/**
* Create a fieldset open tag
*
* @param array $attributes array with tag attribute settings
* @param string $legend string for the fieldset legend
* @return string
*/
public function fieldset_open($attributes = array(), $legend = null)
{
$fieldset_open = '<fieldset ' . array_to_attr($attributes) . ' >';
! is_null($legend) and $attributes['legend'] = $legend;
if ( ! empty($attributes['legend']))
{
$fieldset_open.= "\n<legend>".$attributes['legend']."</legend>";
}
return $fieldset_open;
}
/**
* Create a fieldset close tag
*
* @return string
*/
public function fieldset_close()
{
return '</fieldset>';
}
/**
* Create a form input
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public function input($field, $value = null, array $attributes = array())
{
if (is_array($field))
{
$attributes = $field;
! array_key_exists('value', $attributes) and $attributes['value'] = '';
}
else
{
$attributes['name'] = (string) $field;
$attributes['value'] = (string) $value;
}
$attributes['type'] = empty($attributes['type']) ? 'text' : $attributes['type'];
if ( ! in_array($attributes['type'], static::$_valid_inputs))
{
throw new \InvalidArgumentException(sprintf('"%s" is not a valid input type.', $attributes['type']));
}
if ($this->get_config('prep_value', true) && empty($attributes['dont_prep']))
{
$attributes['value'] = $this->prep_value($attributes['value']);
}
unset($attributes['dont_prep']);
if (empty($attributes['id']) && $this->get_config('auto_id', false) == true)
{
$attributes['id'] = $this->get_config('auto_id_prefix', 'form_').$attributes['name'];
}
$tag = ! empty($attributes['tag']) ? $attributes['tag'] : 'input';
unset($attributes['tag']);
return html_tag($tag, $this->attr_to_string($attributes));
}
/**
* Create a hidden field
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public function hidden($field, $value = null, array $attributes = array())
{
if (is_array($field))
{
$attributes = $field;
}
else
{
$attributes['name'] = (string) $field;
$attributes['value'] = (string) $value;
}
$attributes['type'] = 'hidden';
return $this->input($attributes);
}
/**
* Create a password input field
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public function password($field, $value = null, array $attributes = array())
{
if (is_array($field))
{
$attributes = $field;
}
else
{
$attributes['name'] = (string) $field;
$attributes['value'] = (string) $value;
}
$attributes['type'] = 'password';
return $this->input($attributes);
}
/**
* Create a radio button
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param mixed $checked either attributes (array) or bool/string to set checked status
* @param array $attributes
* @return string
*/
public function radio($field, $value = null, $checked = null, array $attributes = array())
{
if (is_array($field))
{
$attributes = $field;
}
else
{
is_array($checked) and $attributes = $checked;
$attributes['name'] = (string) $field;
$attributes['value'] = (string) $value;
# Added for 1.2 to allow checked true/false. in 3rd argument, used to be attributes
if ( ! is_array($checked))
{
// If it's true, then go for it
if (is_bool($checked))
{
if($checked === true)
{
$attributes['checked'] = 'checked';
}
}
// Otherwise, if the string/number/whatever matches then do it
elseif (is_scalar($checked) and $checked == $value)
{
$attributes['checked'] = 'checked';
}
}
}
$attributes['type'] = 'radio';
return $this->input($attributes);
}
/**
* Create a checkbox
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param mixed $checked either attributes (array) or bool/string to set checked status
* @param array $attributes
* @return string
*/
public function checkbox($field, $value = null, $checked = null, array $attributes = array())
{
if (is_array($field))
{
$attributes = $field;
}
else
{
is_array($checked) and $attributes = $checked;
$attributes['name'] = (string) $field;
$attributes['value'] = (string) $value;
# Added for 1.2 to allow checked true/false. in 3rd argument, used to be attributes
if ( ! is_array($checked))
{
// If it's true, then go for it
if (is_bool($checked))
{
if($checked === true)
{
$attributes['checked'] = 'checked';
}
}
// Otherwise, if the string/number/whatever matches then do it
elseif (is_scalar($checked) and $checked == $value)
{
$attributes['checked'] = 'checked';
}
}
}
$attributes['type'] = 'checkbox';
return $this->input($attributes);
}
/**
* Create a file upload input field
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param array $attributes
* @return string
*/
public function file($field, array $attributes = array())
{
if (is_array($field))
{
$attributes = $field;
}
else
{
$attributes['name'] = (string) $field;
}
$attributes['type'] = 'file';
return $this->input($attributes);
}
/**
* Create a button
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public function button($field, $value = null, array $attributes = array())
{
if (is_array($field))
{
$attributes = $field;
$value = isset($attributes['value']) ? $attributes['value'] : $value;
}
else
{
$attributes['name'] = (string) $field;
$value = isset($value) ? $value : $attributes['name'];
}
return html_tag('button', $this->attr_to_string($attributes), $value);
}
/**
* Create a reset button
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public function reset($field = 'reset', $value = 'Reset', array $attributes = array())
{
if (is_array($field))
{
$attributes = $field;
}
else
{
$attributes['name'] = (string) $field;
$attributes['value'] = (string) $value;
}
$attributes['type'] = 'reset';
return $this->input($attributes);
}
/**
* Create a submit button
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public function submit($field = 'submit', $value = 'Submit', array $attributes = array())
{
if (is_array($field))
{
$attributes = $field;
}
else
{
$attributes['name'] = (string) $field;
$attributes['value'] = (string) $value;
}
$attributes['type'] = 'submit';
return $this->input($attributes);
}
/**
* Create a textarea field
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $value
* @param array $attributes
* @return string
*/
public function textarea($field, $value = null, array $attributes = array())
{
if (is_array($field))
{
$attributes = $field;
}
else
{
$attributes['name'] = (string) $field;
$attributes['value'] = (string) $value;
}
$value = is_scalar($attributes['value']) ? $attributes['value'] : '';
unset($attributes['value']);
if ($this->get_config('prep_value', true) && empty($attributes['dont_prep']))
{
$value = $this->prep_value($value);
}
unset($attributes['dont_prep']);
if (empty($attributes['id']) && $this->get_config('auto_id', false) == true)
{
$attributes['id'] = $this->get_config('auto_id_prefix', '').$attributes['name'];
}
return html_tag('textarea', $this->attr_to_string($attributes), $value);
}
/**
* Select
*
* Generates a html select element based on the given parameters
*
* @param string|array $field either fieldname or full attributes array (when array other params are ignored)
* @param string $values selected value(s)
* @param array $options array of options and option groups
* @param array $attributes
* @return string
*/
public function select($field, $values = null, array $options = array(), array $attributes = array())
{
if (is_array($field))
{
$attributes = $field;
if ( ! isset($attributes['selected']))
{
$attributes['selected'] = ! isset($attributes['value']) ? (isset($attributes['default']) ? $attributes['default'] : null) : $attributes['value'];
}
}
else
{
$attributes['name'] = (string) $field;
$attributes['selected'] = ($values === null or $values === array()) ? (isset($attributes['default']) ? $attributes['default'] : $values) : $values;
$attributes['options'] = $options;
}
unset($attributes['value']);
unset($attributes['default']);
if ( ! isset($attributes['options']) || ! is_array($attributes['options']))
{
throw new \InvalidArgumentException(sprintf('Select element "%s" is either missing the "options" or "options" is not array.', $attributes['name']));
}
// Get the options then unset them from the array
$options = $attributes['options'];
unset($attributes['options']);
// Get the selected options then unset it from the array
// and make sure they're all strings to avoid type conversions
$selected = ! isset($attributes['selected']) ? array() : array_map(function($a) { return (string) $a; }, array_values((array) $attributes['selected']));
unset($attributes['selected']);
// workaround to access the current object context in the closure
$current_obj =& $this;
// closure to recursively process the options array
$listoptions = function (array $options, $selected, $level = 1) use (&$listoptions, &$current_obj, &$attributes)
{
$input = PHP_EOL;
foreach ($options as $key => $val)
{
if (is_array($val))
{
$optgroup = $listoptions($val, $selected, $level + 1);
$optgroup .= str_repeat("\t", $level);
$input .= str_repeat("\t", $level).html_tag('optgroup', array('label' => $key, 'style' => 'text-indent: '.(20+10*($level-1)).'px;'), $optgroup).PHP_EOL;
}
else
{
$opt_attr = array('value' => $key);
$level > 1 and $opt_attr['style'] = 'text-indent: '.(10*($level-1)).'px;';
(in_array((string) $key, $selected, true)) && $opt_attr[] = 'selected';
$input .= str_repeat("\t", $level);
$opt_attr['value'] = ($current_obj->get_config('prep_value', true) && empty($attributes['dont_prep'])) ?
$current_obj->prep_value($opt_attr['value']) : $opt_attr['value'];
$val = ($current_obj->get_config('prep_value', true) && empty($attributes['dont_prep'])) ?
$current_obj->prep_value($val) : $val;
$input .= html_tag('option', $opt_attr, $val).PHP_EOL;
}
}
unset($attributes['dont_prep']);
return $input;
};
// generate the select options list
$input = $listoptions($options, $selected).str_repeat("\t", 0);
if (empty($attributes['id']) && $this->get_config('auto_id', false) == true)
{
$attributes['id'] = $this->get_config('auto_id_prefix', '').$attributes['name'];
}
// if it's a multiselect, make sure the name is an array
if (isset($attributes['multiple']) and substr($attributes['name'], -2) != '[]')
{
$attributes['name'] .= '[]';
}
return html_tag('select', $this->attr_to_string($attributes), $input);
}
/**
* Create a label field
*
* @param string|array $label either fieldname or full attributes array (when array other params are ignored)
* @param string $id
* @param array $attributes
* @return string
*/
public function label($label, $id = null, array $attributes = array())
{
if (is_array($label))
{
$attributes = $label;
$label = $attributes['label'];
isset($attributes['id']) and $id = $attributes['id'];
}
if (empty($attributes['for']) and ! empty($id))
{
if ($this->get_config('auto_id', false) == true)
{
$attributes['for'] = $this->get_config('auto_id_prefix', 'form_').$id;
}
else
{
$attributes['for'] = $id;
}
}
unset($attributes['label']);
return html_tag('label', $attributes, \Lang::get($label, array(), false) ?: $label);
}
/**
* Prep Value
*
* Prepares the value for display in the form
*
* @param string $value
* @return string
*/
public function prep_value($value)
{
$value = \Security::htmlentities($value, ENT_QUOTES);
return $value;
}
/**
* Attr to String
*
* Wraps the global attributes function and does some form specific work
*
* @param array $attr
* @return string
*/
protected function attr_to_string($attr)
{
unset($attr['label']);
return array_to_attr($attr);
}
// fieldset related methods
/**
* Returns the related fieldset
*
* @return Fieldset
*/
public function fieldset()
{
return $this->fieldset;
}
/**
* Build & template individual field
*
* @param string|Fieldset_Field $field field instance or name of a field in this form's fieldset
* @return string
* @deprecated until v1.2
*/
public function build_field($field)
{
! $field instanceof Fieldset_Field && $field = $this->field($field);
return $field->build();
}
/**
* Add a CSRF token and a validation rule to check it
*/
public function add_csrf()
{
$this->add(\Config::get('security.csrf_token_key', 'fuel_csrf_token'), 'CSRF Token')
->set_type('hidden')
->set_value(\Security::fetch_token())
->add_rule(array('Security', 'check_token'));
return $this;
}
/**
* Sets a config value on the fieldset
*
* @param string $config
* @param mixed $value
* @return Fieldset this, to allow chaining
*/
public function set_config($config, $value = null)
{
$this->fieldset->set_config($config, $value);
return $this;
}
/**
* Get a single or multiple config values by key
*
* @param string|array $key a single key or multiple in an array, empty to fetch all
* @param mixed $default default output when config wasn't set
* @return mixed|array a single config value or multiple in an array when $key input was an array
*/
public function get_config($key = null, $default = null)
{
if ($key === null)
{
return $this->fieldset->get_config();
}
if (is_array($key))
{
$output = array();
foreach ($key as $k)
{
$output[$k] = $this->fieldset->get_config($k, null) !== null
? $this->fieldset->get_config($k, $default)
: \Config::get('form.'.$k, $default);
}
return $output;
}
return $this->fieldset->get_config($key, null) !== null
? $this->fieldset->get_config($key, $default)
: \Config::get('form.'.$key, $default);
}
/**
* Alias for $this->fieldset->build()
*
* @param mixed $action
* @return string
*/
public function build($action = null)
{
return $this->fieldset()->build($action);
}
/**
* Alias for $this->fieldset->add()
*
* @param string
* @param string
* @param array
* @param array
* @return Fieldset_Field
*/
public function add($name, $label = '', array $attributes = array(), array $rules = array())
{
return $this->fieldset->add($name, $label, $attributes, $rules);
}
/**
* Alias for $this->fieldset->add_model()
*
* @param string|Object $class either a full classname (including full namespace) or object instance
* @param array|Object $instance array or object that has the exactly same named properties to populate the fields
* @param string $method method name to call on model for field fetching
* @return Validation this, to allow chaining
*/
public function add_model($class, $instance = null, $method = 'set_form_fields')
{
$this->fieldset->add_model($class, $instance, $method);
return $this;
}
/**
* Alias for $this->fieldset->field()
*
* @param string|null $name field name or null to fetch an array of all
* @param bool $flatten whether to get the fields array or flattened array
* @return Fieldset_Field|false
*/
public function field($name = null, $flatten = false)
{
return $this->fieldset->field($name, $flatten);
}
/**
* Alias for $this->fieldset->populate() for this fieldset
*
* @param array|object $input
* @param bool $repopulate
* @return Fieldset
*/
public function populate($input, $repopulate = false)
{
$this->fieldset->populate($input, $repopulate);
}
/**
* Alias for $this->fieldset->repopulate() for this fieldset
*
* @return Fieldset_Field
*/
public function repopulate()
{
$this->fieldset->repopulate();
}
}

@ -1,639 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Format class
*
* Help convert between various formats such as XML, JSON, CSV, etc.
*
* @package Fuel
* @category Core
* @author Fuel Development Team
* @copyright 2010 - 2012 Fuel Development Team
* @link http://docs.fuelphp.com/classes/format.html
*/
class Format
{
/**
* Returns an instance of the Format object.
*
* echo Format::forge(array('foo' => 'bar'))->to_xml();
*
* @param mixed $data general date to be converted
* @param string $from_type data format the file was provided in
* @param mixed $param additional parameter that can be passed on to a 'from' method
* @return Format
*/
public static function forge($data = null, $from_type = null, $param = null)
{
return new static($data, $from_type, $param);
}
/**
* @var array|mixed input to convert
*/
protected $_data = array();
/**
* @var bool whether to ignore namespaces when parsing xml
*/
protected $ignore_namespaces = true;
/**
* Do not use this directly, call forge()
*
* @param mixed $data general date to be converted
* @param string $from_type data format the file was provided in
* @param mixed $param additional parameter that can be passed on to a 'from' method
* @throws \FuelException
*/
public function __construct($data = null, $from_type = null, $param = null)
{
// If the provided data is already formatted we should probably convert it to an array
if ($from_type !== null)
{
if ($from_type == 'xml:ns')
{
$this->ignore_namespaces = false;
$from_type = 'xml';
}
if (method_exists($this, '_from_' . $from_type))
{
$data = call_user_func_array(array($this, '_from_' . $from_type), array($data, $param));
}
else
{
throw new \FuelException('Format class does not support conversion from "' . $from_type . '".');
}
}
$this->_data = $data;
}
// FORMATING OUTPUT ---------------------------------------------------------
/**
* To array conversion
*
* Goes through the input and makes sure everything is either a scalar value or array
*
* @param mixed $data
* @return array
*/
public function to_array($data = null)
{
if ($data === null)
{
$data = $this->_data;
}
$array = array();
if (is_object($data) and ! $data instanceof \Iterator)
{
$data = get_object_vars($data);
}
if (empty($data))
{
return array();
}
foreach ($data as $key => $value)
{
if (is_object($value) or is_array($value))
{
$array[$key] = $this->to_array($value);
}
else
{
$array[$key] = $value;
}
}
return $array;
}
/**
* To XML conversion
*
* @param mixed $data
* @param null $structure
* @param null|string $basenode
* @param null|bool $use_cdata whether to use CDATA in nodes
* @param mixed $bool_representation if true, element values are true/false. if 1, 1/0.
* @return string
*/
public function to_xml($data = null, $structure = null, $basenode = null, $use_cdata = null, $bool_representation = null)
{
if ($data == null)
{
$data = $this->_data;
}
is_null($basenode) and $basenode = \Config::get('format.xml.basenode', 'xml');
is_null($use_cdata) and $use_cdata = \Config::get('format.xml.use_cdata', false);
is_null($bool_representation) and $bool_representation = \Config::get('format.xml.bool_representation', null);
// turn off compatibility mode as simple xml throws a wobbly if you don't.
if (ini_get('zend.ze1_compatibility_mode') == 1)
{
ini_set('zend.ze1_compatibility_mode', 0);
}
if ($structure == null)
{
$structure = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><$basenode />");
}
// Force it to be something useful
if ( ! is_array($data) and ! is_object($data))
{
$data = (array) $data;
}
foreach ($data as $key => $value)
{
// replace anything not alpha numeric
$key = preg_replace('/[^a-z_\-0-9]/i', '', $key);
// no numeric keys in our xml please!
if (is_numeric($key))
{
// make string key...
$key = (\Inflector::singularize($basenode) != $basenode) ? \Inflector::singularize($basenode) : 'item';
}
// if there is another array found recrusively call this function
if (is_array($value) or is_object($value))
{
$node = $structure->addChild($key);
// recursive call if value is not empty
if( ! empty($value))
{
$this->to_xml($value, $node, $key, $use_cdata, $bool_representation);
}
}
elseif ($bool_representation and is_bool($value))
{
if ($bool_representation === true)
{
$bool = $value ? 'true' : 'false';
}
else
{
$bool = $value ? '1' : '0';
}
$structure->addChild($key, $bool);
}
else
{
// add single node.
$encoded = htmlspecialchars(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), ENT_QUOTES, "UTF-8");
if ($use_cdata and ($encoded !== (string) $value))
{
$dom = dom_import_simplexml($structure->addChild($key));
$owner = $dom->ownerDocument;
$dom->appendChild($owner->createCDATASection($value));
}
else
{
$structure->addChild($key, $encoded);
}
}
}
// pass back as string. or simple xml object if you want!
return $structure->asXML();
}
/**
* To CSV conversion
*
* @param mixed $data
* @param mixed $delimiter
* @param mixed $enclose_numbers
* @param array $headings Custom headings to use
* @return string
*/
public function to_csv($data = null, $delimiter = null, $enclose_numbers = null, array $headings = array())
{
// csv format settings
$newline = \Config::get('format.csv.newline', \Config::get('format.csv.export.newline', "\n"));
$delimiter or $delimiter = \Config::get('format.csv.delimiter', \Config::get('format.csv.export.delimiter', ','));
$enclosure = \Config::get('format.csv.enclosure', \Config::get('format.csv.export.enclosure', '"'));
$escape = \Config::get('format.csv.escape', \Config::get('format.csv.export.escape', '\\'));
is_null($enclose_numbers) and $enclose_numbers = \Config::get('format.csv.enclose_numbers', true);
// escape, delimit and enclose function
$escaper = function($items, $enclose_numbers) use($enclosure, $escape, $delimiter) {
return implode($delimiter, array_map(function($item) use($enclosure, $escape, $delimiter, $enclose_numbers) {
if ( ! is_numeric($item) or $enclose_numbers)
{
$item = $enclosure.str_replace($enclosure, $escape.$enclosure, $item).$enclosure;
}
return $item;
}, $items));
};
if ($data === null)
{
$data = $this->_data;
}
if (is_object($data) and ! $data instanceof \Iterator)
{
$data = $this->to_array($data);
}
// Multi-dimensional array
if (empty($headings))
{
if (is_array($data) and \Arr::is_multi($data))
{
$data = array_values($data);
if (\Arr::is_assoc($data[0]))
{
$headings = array_keys($data[0]);
}
else
{
$headings = array_shift($data);
}
}
// Single array
else
{
$headings = array_keys((array) $data);
$data = array($data);
}
}
$output = $escaper($headings, true).$newline;
foreach ($data as $row)
{
$output .= $escaper($row, $enclose_numbers).$newline;
}
return rtrim($output, $newline);
}
/**
* To JSON conversion
*
* @param mixed $data
* @param bool $pretty whether to make the json pretty
* @return string
*/
public function to_json($data = null, $pretty = false)
{
if ($data === null)
{
$data = $this->_data;
}
// To allow exporting ArrayAccess objects like Orm\Model instances they need to be
// converted to an array first
$data = (is_array($data) or is_object($data)) ? $this->to_array($data) : $data;
return $pretty ? static::pretty_json($data) : json_encode($data, \Config::get('format.json.encode.options', JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP));
}
/**
* To JSONP conversion
*
* @param mixed $data
* @param bool $pretty whether to make the json pretty
* @param string $callback JSONP callback
* @return string formatted JSONP
*/
public function to_jsonp($data = null, $pretty = false, $callback = null)
{
$callback or $callback = \Input::param('callback');
is_null($callback) and $callback = 'response';
return $callback.'('.$this->to_json($data, $pretty).')';
}
/**
* Serialize
*
* @param mixed $data
* @return string
*/
public function to_serialized($data = null)
{
if ($data === null)
{
$data = $this->_data;
}
return serialize($data);
}
/**
* Return as a string representing the PHP structure
*
* @param mixed $data
* @return string
*/
public function to_php($data = null)
{
if ($data === null)
{
$data = $this->_data;
}
return var_export($data, true);
}
/**
* Convert to YAML
*
* @param mixed $data
* @return string
*/
public function to_yaml($data = null)
{
if ($data == null)
{
$data = $this->_data;
}
if ( ! function_exists('spyc_load'))
{
import('spyc/spyc', 'vendor');
}
return \Spyc::YAMLDump($data);
}
/**
* Import XML data
*
* @param string $string
* @param bool $recursive
* @return array
*/
protected function _from_xml($string, $recursive = false)
{
// If it forged with 'xml:ns'
if ( ! $this->ignore_namespaces)
{
static $escape_keys = array();
$recursive or $escape_keys = array('_xmlns' => 'xmlns');
if ( ! $recursive and strpos($string, 'xmlns') !== false and preg_match_all('/(\<.+?\>)/s', $string, $matches))
{
foreach ($matches[1] as $tag)
{
$escaped_tag = $tag;
strpos($tag, 'xmlns=') !== false and $escaped_tag = str_replace('xmlns=', '_xmlns=', $tag);
if (preg_match_all('/[\s\<\/]([^\/\s\'"]*?:\S*?)[=\/\>\s]/s', $escaped_tag, $xmlns))
{
foreach ($xmlns[1] as $ns)
{
$escaped = \Arr::search($escape_keys, $ns);
$escaped or $escape_keys[$escaped = str_replace(':', '_', $ns)] = $ns;
$string = str_replace($tag, $escaped_tag = str_replace($ns, $escaped, $escaped_tag), $string);
$tag = $escaped_tag;
}
}
}
}
}
$_arr = is_string($string) ? simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA) : $string;
// Convert all objects SimpleXMLElement to array recursively
$arr = array();
foreach ((array) $_arr as $key => $val)
{
$this->ignore_namespaces or $key = \Arr::get($escape_keys, $key, $key);
if ( ! $val instanceOf \SimpleXMLElement or $val->count() or $val->attributes())
{
$arr[$key] = (is_array($val) or is_object($val)) ? $this->_from_xml($val, true) : $val;
}
else
{
$arr[$val->getName()] = null;
}
}
return $arr;
}
/**
* Import YAML data
*
* @param string $string
* @return array
*/
protected function _from_yaml($string)
{
if ( ! function_exists('spyc_load'))
{
import('spyc/spyc', 'vendor');
}
return \Spyc::YAMLLoadString($string);
}
/**
* Import CSV data
*
* @param string $string
* @param bool $no_headings
* @return array
*/
protected function _from_csv($string, $no_headings = false)
{
$data = array();
// csv config
$newline = \Config::get('format.csv.regex_newline', "\n");
$delimiter = \Config::get('format.csv.delimiter', \Config::get('format.csv.import.delimiter', ','));
$escape = \Config::get('format.csv.escape', \Config::get('format.csv.import.escape', '"'));
// have to do this in two steps, empty string is a valid value for enclosure!
$enclosure = \Config::get('format.csv.enclosure', \Config::get('format.csv.import.enclosure', null));
$enclosure === null and $enclosure = '"';
if (empty($enclosure))
{
$rows = preg_split('/(['.$newline.'])/m', trim($string), -1, PREG_SPLIT_NO_EMPTY);
}
else
{
$rows = preg_split('/(?<=[0-9'.preg_quote($enclosure).'])'.$newline.'/', trim($string));
}
// Get the headings
if ($no_headings !== false)
{
$headings = str_replace($escape.$enclosure, $enclosure, str_getcsv(array_shift($rows), $delimiter, $enclosure, $escape));
$headcount = count($headings);
}
// Process the rows
$incomplete = '';
foreach ($rows as $row)
{
// process the row
$data_fields = str_replace($escape.$enclosure, $enclosure, str_getcsv($incomplete.($incomplete ? $newline : '').$row, $delimiter, $enclosure, $escape));
// if we didn't have headers, the first row determines the number of fields
if ( ! isset($headcount))
{
$headcount = count($data_fields);
}
// finish the row if the have the correct field count, otherwise add the data to the next row
if (count($data_fields) == $headcount)
{
$data[] = $no_headings === false ? $data_fields : array_combine($headings, $data_fields);
$incomplete = '';
}
else
{
$incomplete = $row;
}
}
return $data;
}
/**
* Import JSON data
*
* @param string $string
* @return mixed
*/
private function _from_json($string)
{
return json_decode(trim($string));
}
/**
* Import Serialized data
*
* @param string $string
* @return mixed
*/
private function _from_serialize($string)
{
return unserialize(trim($string));
}
/**
* Makes json pretty the json output.
* Borrowed from http://www.php.net/manual/en/function.json-encode.php#80339
*
* @param string $data json encoded array
* @return string|false pretty json output or false when the input was not valid
*/
protected static function pretty_json($data)
{
$json = json_encode($data, \Config::get('format.json.encode.options', JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP));
if ( ! $json)
{
return false;
}
$tab = "\t";
$newline = "\n";
$new_json = "";
$indent_level = 0;
$in_string = false;
$len = strlen($json);
for ($c = 0; $c < $len; $c++)
{
$char = $json[$c];
switch($char)
{
case '{':
case '[':
if ( ! $in_string)
{
$new_json .= $char.$newline.str_repeat($tab, $indent_level+1);
$indent_level++;
}
else
{
$new_json .= $char;
}
break;
case '}':
case ']':
if ( ! $in_string)
{
$indent_level--;
$new_json .= $newline.str_repeat($tab, $indent_level).$char;
}
else
{
$new_json .= $char;
}
break;
case ',':
if ( ! $in_string)
{
$new_json .= ','.$newline.str_repeat($tab, $indent_level);
}
else
{
$new_json .= $char;
}
break;
case ':':
if ( ! $in_string)
{
$new_json .= ': ';
}
else
{
$new_json .= $char;
}
break;
case '"':
if ($c > 0 and $json[$c-1] !== '\\')
{
$in_string = ! $in_string;
}
default:
$new_json .= $char;
break;
}
}
return $new_json;
}
/**
* Loads Format config.
*/
public static function _init()
{
\Config::load('format', true);
}
}

@ -1,651 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class FtpConnectionException extends \FuelException {}
class FtpFileAccessException extends \FuelException {}
/**
* FTP Class
*
* @package Fuel
* @category Core
* @author Phil Sturgeon
* @link http://docs.fuelphp.com/classes/ftp.html
*/
class Ftp
{
public static $initialized = false;
protected $_hostname = 'localhost';
protected $_username = '';
protected $_password = '';
protected $_port = 21;
protected $_timeout = 90;
protected $_passive = true;
protected $_debug = false;
protected $_conn_id = false;
/**
* Returns a new Ftp object. If you do not define the "file" parameter,
*
* $ftp = static::forge('group');
*
* @param string|array $config The name of the config group to use, or a configuration array.
* @param bool $connect Automatically connect to this server.
* @return Ftp
*/
public static function forge($config = 'default', $connect = true)
{
$ftp = new static($config);
// Unless told not to, connect automatically
$connect === true and $ftp->connect();
return $ftp;
}
/**
* Sets the initial Ftp filename and local data.
*
* @param string|array $config The name of the config group to use, or a configuration array.
*/
public function __construct($config = 'default')
{
\Config::load('ftp', true);
// If it is a string we're looking at a predefined config group
if (is_string($config))
{
$config_arr = \Config::get('ftp.'.$config);
// Check that it exists
if ( ! is_array($config_arr) or $config_arr === array())
{
throw new \UnexpectedValueException('You have specified an invalid ftp connection group: '.$config);
}
$config = $config_arr;
}
// Prep the hostname
$this->_hostname = preg_replace('|.+?://|', '', $config['hostname']);
$this->_username = $config['username'];
$this->_password = $config['password'];
$this->_timeout = ! empty($config['timeout']) ? (int) $config['timeout'] : 90;
$this->_port = ! empty($config['port']) ? (int) $config['port'] : 21;
$this->_passive = (bool) $config['passive'];
$this->_ssl_mode = (bool) $config['ssl_mode'];
$this->_debug = (bool) $config['debug'];
static::$initialized = true;
}
// --------------------------------------------------------------------
/**
* FTP Connect
*
* @return \Ftp
* @throws \FtpConnectionException
*/
public function connect()
{
if($this->_ssl_mode === true)
{
if( ! function_exists('ftp_ssl_connect'))
{
throw new \RuntimeException('ftp_ssl_connect() function is missing.');
}
$this->_conn_id = @ftp_ssl_connect($this->_hostname, $this->_port, $this->_timeout);
}
else
{
$this->_conn_id = @ftp_connect($this->_hostname, $this->_port, $this->_timeout);
}
if ($this->_conn_id === false)
{
if ($this->_debug == true)
{
throw new \FtpConnectionException('Unable to establish a connection');
}
return false;
}
if ( ! $this->_login())
{
if ($this->_debug == true)
{
throw new \FtpConnectionException('Unable to login');
}
}
// Set passive mode if needed
if ($this->_passive == true)
{
ftp_pasv($this->_conn_id, true);
}
return $this;
}
// --------------------------------------------------------------------
/**
* FTP Login
*
* @return bool
*/
protected function _login()
{
return @ftp_login($this->_conn_id, $this->_username, $this->_password);
}
// --------------------------------------------------------------------
/**
* Validates the connection ID
*
* @return bool
*/
protected function _is_conn()
{
if ( ! is_resource($this->_conn_id))
{
if ($this->_debug == true)
{
throw new \InvalidArgumentException('Invalid connection');
}
return false;
}
return true;
}
// --------------------------------------------------------------------
/**
* Change directory
*
* The second parameter lets us momentarily turn off debugging so that
* this function can be used to test for the existence of a folder
* without throwing an error. There's no FTP equivalent to is_dir()
* so we do it by trying to change to a particular directory.
* Internally, this parameter is only used by the "mirror" function below.
*
* @param string $path
* @return bool
* @throws \FtpFileAccessException
*/
public function change_dir($path = '')
{
if ($path == '' or ! $this->_is_conn())
{
return false;
}
$result = @ftp_chdir($this->_conn_id, $path);
if ($result === false)
{
if ($this->_debug == true)
{
throw new \FtpFileAccessException('Unable to change the directory');
}
return false;
}
return true;
}
// --------------------------------------------------------------------
/**
* Create a directory
*
* @param string $path
* @param string $permissions
* @return bool
* @throws \FtpFileAccessException
*/
public function mkdir($path, $permissions = null)
{
if ( ! $this->_is_conn())
{
return false;
}
$result = ftp_mkdir($this->_conn_id, $path);
if ($result === false)
{
if ($this->_debug == true)
{
throw new \FtpFileAccessException('Unable to create directory');
}
return false;
}
// Set file permissions if needed
if ($permissions !== null)
{
$this->chmod($path, (int) $permissions);
}
return true;
}
// --------------------------------------------------------------------
/**
* Upload a file to the server
*
* @param string $local_path
* @param string $remote_path
* @param string $mode
* @param string $permissions
* @return bool
* @throws \FtpFileAccessException
*/
public function upload($local_path, $remote_path, $mode = 'auto', $permissions = null)
{
if ( ! $this->_is_conn())
{
return false;
}
if ( ! is_file($local_path))
{
throw new \FtpFileAccessException('No source file');
}
// Set the mode if not specified
if ($mode == 'auto')
{
// Get the file extension so we can set the upload type
$ext = pathinfo($local_path, PATHINFO_EXTENSION);
$mode = $this->_settype($ext);
}
$mode = ($mode == 'ascii') ? FTP_ASCII : FTP_BINARY;
$result = @ftp_put($this->_conn_id, $remote_path, $local_path, $mode);
if ($result === false)
{
if ($this->_debug == true)
{
throw new \FtpFileAccessException('Unable to upload');
}
return false;
}
// Set file permissions if needed
if ($permissions !== null)
{
$this->chmod($remote_path, (int) $permissions);
}
return true;
}
// --------------------------------------------------------------------
/**
* Download a file from a remote server to the local server
*
* @param string $remote_path
* @param string $local_path
* @param string $mode
* @return bool
* @throws \FtpFileAccessException
*/
public function download($remote_path, $local_path, $mode = 'auto')
{
if ( ! $this->_is_conn())
{
return false;
}
// Set the mode if not specified
if ($mode == 'auto')
{
// Get the file extension so we can set the upload type
$ext = pathinfo($remote_path, PATHINFO_BASENAME);
$mode = $this->_settype($ext);
}
$mode = ($mode == 'ascii') ? FTP_ASCII : FTP_BINARY;
$result = @ftp_get($this->_conn_id, $local_path, $remote_path, $mode);
if ($result === false)
{
if ($this->_debug === true)
{
throw new \FtpFileAccessException('Unable to download');
}
return false;
}
return true;
}
// --------------------------------------------------------------------
/**
* Rename (or move) a file
*
* @param $old_file string
* @param $new_file string
* @param $move bool
* @return bool
* @throws \FtpFileAccessException
*/
public function rename($old_file, $new_file, $move = false)
{
if ( ! $this->_is_conn())
{
return false;
}
$result = @ftp_rename($this->_conn_id, $old_file, $new_file);
if ($result === false)
{
if ($this->_debug == true)
{
$msg = ($move == false) ? 'Unable to rename' : 'Unable to move';
throw new \FtpFileAccessException($msg);
}
return false;
}
return true;
}
// --------------------------------------------------------------------
/**
* Move a file
*
* @param string $old_file
* @param string $new_file
* @return bool
*/
public function move($old_file, $new_file)
{
return $this->rename($old_file, $new_file, true);
}
// --------------------------------------------------------------------
/**
* Rename (or move) a file
*
* @param string $filepath
* @return bool
* @throws \FtpFileAccessException
*/
function delete_file($filepath)
{
if ( ! $this->_is_conn())
{
return false;
}
$result = @ftp_delete($this->_conn_id, $filepath);
if ($result === false)
{
if ($this->_debug == true)
{
throw new \FtpFileAccessException('Unable to delete');
}
return false;
}
return true;
}
// --------------------------------------------------------------------
/**
* Delete a folder and recursively delete everything (including sub-folders)
* contained within it.
*
* @param string $filepath
* @return bool
* @throws \FtpFileAccessException
*/
function delete_dir($filepath)
{
if ( ! $this->_is_conn())
{
return false;
}
// Add a trailing slash to the file path if needed
$filepath = preg_replace("/(.+?)\/*$/", "\\1/", $filepath);
$list = $this->list_files($filepath);
if ($list !== false and count($list) > 0)
{
foreach ($list as $item)
{
// If we can't delete the item it's probaly a folder so
// we'll recursively call delete_dir()
if ( ! @ftp_delete($this->_conn_id, $item))
{
// don't recurse into current of parent directory
if ( ! preg_match('/\/\.\.|\/\.$/', $item))
{
$this->delete_dir($item);
}
}
}
}
$result = @ftp_rmdir($this->_conn_id, $filepath);
if ($result === false)
{
if ($this->_debug == true)
{
throw new \FtpFileAccessException('Unable to delete');
}
return false;
}
return true;
}
// --------------------------------------------------------------------
/**
* Set file permissions
*
* @param string $path the file path
* @param string $permissions the permissions
* @return bool
* @throws \FtpFileAccessException
*/
public function chmod($path, $permissions)
{
if ( ! $this->_is_conn())
{
return false;
}
// Permissions can only be set when running PHP 5
if ( ! function_exists('ftp_chmod'))
{
if ($this->_debug == true)
{
throw new \FtpFileAccessException('CHMOD function does not exist');
}
return false;
}
$result = @ftp_chmod($this->_conn_id, $permissions, $path);
if ($result === false)
{
if ($this->_debug == true)
{
throw new \FtpFileAccessException('Unable to CHMOD');
}
return false;
}
return true;
}
// --------------------------------------------------------------------
/**
* FTP List files in the specified directory
*
* @param string $path
* @return array
*/
public function list_files($path = '.')
{
if ( ! $this->_is_conn())
{
return false;
}
return ftp_nlist($this->_conn_id, $path);
}
// ------------------------------------------------------------------------
/**
* Read a directory and recreate it remotely
*
* This function recursively reads a folder and everything it contains (including
* sub-folders) and creates a mirror via FTP based on it. Whatever the directory structure
* of the original file path will be recreated on the server.
*
* @param string $local_path path to source with trailing slash
* @param string $remote_path path to destination - include the base folder with trailing slash
* @return bool
*/
public function mirror($local_path, $remote_path)
{
if ( ! $this->_is_conn())
{
return false;
}
// Open the local file path
if ($fp = @opendir($local_path))
{
// Attempt to open the remote file path.
if ( ! $this->change_dir($remote_path, true))
{
// If it doesn't exist we'll attempt to create the directory
if ( ! $this->mkdir($remote_path) or ! $this->change_dir($remote_path))
{
return false;
}
}
// Recursively read the local directory
while (false !== ($file = readdir($fp)))
{
if (@is_dir($local_path.$file) and substr($file, 0, 1) != '.')
{
$this->mirror($local_path.$file."/", $remote_path.$file."/");
}
elseif (substr($file, 0, 1) != ".")
{
// Get the file extension so we can se the upload type
$ext = pathinfo($file, PATHINFO_EXTENSION);
$mode = $this->_settype($ext);
$this->upload($local_path.$file, $remote_path.$file, $mode);
}
}
return true;
}
return false;
}
// --------------------------------------------------------------------
/**
* Set the upload type
*
* @param string $ext
* @return string
*/
protected function _settype($ext)
{
$text_types = array(
'txt',
'text',
'php',
'phps',
'php4',
'js',
'css',
'htm',
'html',
'phtml',
'shtml',
'log',
'xml',
);
return in_array($ext, $text_types) ? 'ascii' : 'binary';
}
// ------------------------------------------------------------------------
/**
* Close the connection
*
* @return void
*/
public function close()
{
if ( ! $this->_is_conn())
{
return false;
}
@ftp_close($this->_conn_id);
}
// ------------------------------------------------------------------------
/**
* Close the connection when the class is unset
*
* @return void
*/
public function __destruct()
{
$this->close();
}
}

@ -1,391 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* General Fuel Exception class
*/
class FuelException extends \Exception {}
/**
* The core of the framework.
*
* @package Fuel
* @subpackage Core
*/
class Fuel
{
/**
* @var string The version of Fuel
*/
const VERSION = '1.8';
/**
* @var string constant used for when in testing mode
*/
const TEST = 'test';
/**
* @var string constant used for when in development
*/
const DEVELOPMENT = 'development';
/**
* @var string constant used for when in production
*/
const PRODUCTION = 'production';
/**
* @var string constant used for when testing the app in a staging env.
*/
const STAGING = 'staging';
/**
* @var int No logging
*/
const L_NONE = 0;
/**
* @var int Log everything
*/
const L_ALL = 99;
/**
* @var int Log debug massages and below
*/
const L_DEBUG = 100;
/**
* @var int Log info massages and below
*/
const L_INFO = 200;
/**
* @var int Log warning massages and below
*/
const L_WARNING = 300;
/**
* @var int Log errors only
*/
const L_ERROR = 400;
/**
* @var bool Whether Fuel has been initialized
*/
public static $initialized = false;
/**
* @var string The Fuel environment
*/
public static $env = \Fuel::DEVELOPMENT;
/**
* @var bool Whether to display the profiling information
*/
public static $profiling = false;
public static $locale = 'en_US';
public static $timezone = 'UTC';
public static $encoding = 'UTF-8';
public static $is_cli = false;
public static $is_test = false;
public static $volatile_paths = array();
protected static $_paths = array();
protected static $packages = array();
final private function __construct() { }
/**
* Initializes the framework. This can only be called once.
*
* @access public
* @return void
*/
public static function init($config)
{
if (static::$initialized)
{
throw new \FuelException("You can't initialize Fuel more than once.");
}
static::$_paths = array(APPPATH, COREPATH);
// Is Fuel running on the command line?
static::$is_cli = (bool) defined('STDIN');
\Config::load($config);
// Disable output compression if the client doesn't support it
if (static::$is_cli or ! in_array('gzip', explode(', ', \Input::headers('Accept-Encoding', ''))))
{
\Config::set('ob_callback', null);
}
// Start up output buffering
static::$is_cli or ob_start(\Config::get('ob_callback'));
if (\Config::get('caching', false))
{
\Finder::instance()->read_cache('FuelFileFinder');
}
static::$profiling = \Config::get('profiling', false);
static::$profiling and \Profiler::init();
// set a default timezone if one is defined
try
{
static::$timezone = \Config::get('default_timezone') ?: date_default_timezone_get();
date_default_timezone_set(static::$timezone);
}
catch (\Exception $e)
{
date_default_timezone_set('UTC');
throw new \PHPErrorException($e->getMessage());
}
static::$encoding = \Config::get('encoding', static::$encoding);
MBSTRING and mb_internal_encoding(static::$encoding);
static::$locale = \Config::get('locale', static::$locale);
// Set locale, log warning when it fails
if (static::$locale)
{
setlocale(LC_ALL, static::$locale) or
logger(\Fuel::L_WARNING, 'The configured locale '.static::$locale.' is not installed on your system.', __METHOD__);
}
if ( ! static::$is_cli)
{
if (\Config::get('base_url') === null)
{
\Config::set('base_url', static::generate_base_url());
}
}
// Run Input Filtering
\Security::clean_input();
\Event::register('fuel-shutdown', 'Fuel::finish');
// Always load classes, config & language set in always_load.php config
static::always_load();
// Load in the routes
\Config::load('routes', true);
\Router::add(\Config::get('routes'));
// BC FIX FOR APPLICATIONS <= 1.6.1, makes Redis_Db available as Redis,
// like it was in versions before 1.7
class_exists('Redis', false) or class_alias('Redis_Db', 'Redis');
// BC FIX FOR PHP < 7.0 to make the error class available
if (PHP_VERSION_ID < 70000)
{
// alias the error class to the new errorhandler
class_alias('\Fuel\Core\Errorhandler', '\Fuel\Core\Error');
// does the app have an overloaded Error class?
if (class_exists('Error'))
{
// then alias that too
class_alias('Error', 'Errorhandler');
}
}
static::$initialized = true;
// fire any app created events
\Event::instance()->has_events('app_created') and \Event::instance()->trigger('app_created', '', 'none');
if (static::$profiling)
{
\Profiler::mark(__METHOD__.' End');
}
}
/**
* Cleans up Fuel execution, ends the output buffering, and outputs the
* buffer contents.
*
* @access public
* @return void
*/
public static function finish()
{
if (\Config::get('caching', false))
{
\Finder::instance()->write_cache('FuelFileFinder');
}
if (static::$profiling and ! static::$is_cli and ! \Input::is_ajax())
{
// Grab the output buffer and flush it, we will rebuffer later
$output = ob_get_clean();
$headers = headers_list();
$show = true;
foreach ($headers as $header)
{
if (stripos($header, 'content-type') === 0 and stripos($header, 'text/html') === false)
{
$show = false;
}
}
if ($show)
{
\Profiler::mark('End of Fuel Execution');
if (preg_match("|</body>.*?</html>|is", $output))
{
$output = preg_replace("|</body>.*?</html>|is", '', $output);
$output .= \Profiler::output();
$output .= '</body></html>';
}
else
{
$output .= \Profiler::output();
}
}
// Restart the output buffer and send the new output
ob_start(\Config::get('ob_callback'));
echo $output;
}
}
/**
* Generates a base url.
*
* @return string the base url
*/
protected static function generate_base_url()
{
$base_url = '';
if(\Input::server('http_host'))
{
$base_url .= \Input::protocol().'://'.\Input::server('http_host');
}
if (\Input::server('script_name'))
{
$common = get_common_path(array(\Input::server('request_uri'), \Input::server('script_name')));
$base_url .= $common;
}
// Add a slash if it is missing and return it
return rtrim($base_url, '/').'/';
}
/**
* Includes the given file and returns the results.
*
* @param string the path to the file
* @return mixed the results of the include
*/
public static function load($file)
{
return include $file;
}
/**
* Always load packages, modules, classes, config & language files set in always_load.php config
*
* @param array what to autoload
*/
public static function always_load($array = null)
{
is_null($array) and $array = \Config::get('always_load', array());
isset($array['packages']) and \Package::load($array['packages']);
isset($array['modules']) and \Module::load($array['modules']);
if (isset($array['classes']))
{
foreach ($array['classes'] as $class)
{
if ( ! class_exists($class = \Str::ucwords($class)))
{
throw new \FuelException('Class '.$class.' defined in your "always_load" config could not be loaded.');
}
}
}
/**
* Config and Lang must be either just the filename, example: array(filename)
* or the filename as key and the group as value, example: array(filename => some_group)
*/
if (isset($array['config']))
{
foreach ($array['config'] as $config => $config_group)
{
\Config::load((is_int($config) ? $config_group : $config), (is_int($config) ? true : $config_group));
}
}
if (isset($array['language']))
{
foreach ($array['language'] as $lang => $lang_group)
{
\Lang::load((is_int($lang) ? $lang_group : $lang), (is_int($lang) ? true : $lang_group));
}
}
}
/**
* Takes a value and checks if it is a Closure or not, if it is it
* will return the result of the closure, if not, it will simply return the
* value.
*
* @param mixed $var The value to get
* @return mixed
*/
public static function value($var)
{
return ($var instanceof \Closure) ? $var() : $var;
}
/**
* Cleans a file path so that it does not contain absolute file paths.
*
* @param string the filepath
* @return string the clean path
*/
public static function clean_path($path)
{
// framework default paths
static $search = array('\\', APPPATH, COREPATH, PKGPATH, DOCROOT);
static $replace = array('/', 'APPPATH/', 'COREPATH/', 'PKGPATH/', 'DOCROOT/');
// additional paths configured than need cleaning
$extra = \Config::get('security.clean_paths', array());
foreach ($extra as $r => $s)
{
$search[] = $s;
$replace[] = $r.'/';
}
// clean up and return it
return str_ireplace($search, $replace, $path);
}
}

@ -1,289 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
// ------------------------------------------------------------------------
/**
* Html Class
*
* @package Fuel
* @subpackage Core
* @category Core
* @author Alfredo Rivera
* @link http://docs.fuelphp.com/classes/html.html
*/
class Html
{
public static $doctypes = null;
public static $html5 = true;
/**
* Creates an html link
*
* @param string $href the url
* @param string $text the text value
* @param array $attr the attributes array
* @param bool $secure true to force https, false to force http
* @return string the html link
*/
public static function anchor($href, $text = null, $attr = array(), $secure = null)
{
if ( ! preg_match('#^(\w+://|javascript:|\#)# i', $href))
{
$urlparts = explode('?', $href, 2);
$href = \Uri::create($urlparts[0], array(), isset($urlparts[1]) ? $urlparts[1] : array(), $secure);
}
elseif ( ! preg_match('#^(javascript:|\#)# i', $href) and is_bool($secure))
{
$href = http_build_url($href, array('scheme' => $secure ? 'https' : 'http'));
// Trim the trailing slash
$href = rtrim($href, '/');
}
// Create and display a URL hyperlink
is_null($text) and $text = $href;
$attr['href'] = $href;
return html_tag('a', $attr, $text);
}
/**
* Creates an html image tag
*
* Sets the alt attribute to filename of it is not supplied.
*
* @param string $src the source
* @param array $attr the attributes array
* @return string the image tag
*/
public static function img($src, $attr = array())
{
if ( ! preg_match('#^(\w+://)# i', $src))
{
$src = \Uri::base(false).$src;
}
$attr['src'] = $src;
$attr['alt'] = (isset($attr['alt'])) ? $attr['alt'] : pathinfo($src, PATHINFO_FILENAME);
return html_tag('img', $attr);
}
/**
* Adds the given schema to the given URL if it is not already there.
*
* @param string $url the url
* @param string $schema the schema
* @return string url with schema
*/
public static function prep_url($url, $schema = 'http')
{
if ( ! preg_match('#^(\w+://|javascript:)# i', $url))
{
$url = $schema.'://'.$url;
}
return $url;
}
/**
* Creates a mailto link.
*
* @param string $email The email address
* @param string $text The text value
* @param string $subject The subject
* @param array $attr attributes for the tag
* @return string The mailto link
*/
public static function mail_to($email, $text = null, $subject = null, $attr = array())
{
$text or $text = $email;
$subject and $subject = '?subject='.$subject;
return html_tag('a', array(
'href' => 'mailto:'.$email.$subject,
) + $attr, $text);
}
/**
* Creates a mailto link with Javascript to prevent bots from picking up the
* email address.
*
* @param string $email the email address
* @param string $text the text value
* @param string $subject the subject
* @param array $attr attributes for the tag
* @return string the javascript code containing email
*/
public static function mail_to_safe($email, $text = null, $subject = null, $attr = array())
{
$text or $text = str_replace('@', '[at]', $email);
$email = explode("@", $email);
$subject and $subject = '?subject='.$subject;
$attr = array_to_attr($attr);
$attr = ($attr == '' ? '' : ' ').$attr;
$output = '<script type="text/javascript">';
$output .= '(function() {';
$output .= 'var user = "'.$email[0].'";';
$output .= 'var at = "@";';
$output .= 'var server = "'.$email[1].'";';
$output .= "document.write('<a href=\"' + 'mail' + 'to:' + user + at + server + '$subject\"$attr>$text</a>');";
$output .= '})();';
$output .= '</script>';
return $output;
}
/**
* Generates a html meta tag
*
* @param string|array $name multiple inputs or name/http-equiv value
* @param string $content content value
* @param string $type name or http-equiv
* @return string
*/
public static function meta($name = '', $content = '', $type = 'name')
{
if( ! is_array($name))
{
$result = html_tag('meta', array($type => $name, 'content' => $content));
}
elseif(is_array($name))
{
$result = "";
foreach($name as $array)
{
$meta = $array;
$result .= "\n" . html_tag('meta', $meta);
}
}
return $result;
}
/**
* Generates a html doctype tag
*
* @param string $type doctype declaration key from doctypes config
* @return string
*/
public static function doctype($type = 'xhtml1-trans')
{
if(static::$doctypes === null)
{
\Config::load('doctypes', true);
static::$doctypes = \Config::get('doctypes', array());
}
if(is_array(static::$doctypes) and isset(static::$doctypes[$type]))
{
if($type == "html5")
{
static::$html5 = true;
}
return static::$doctypes[$type];
}
else
{
return false;
}
}
/**
* Generates a html5 audio tag
* It is required that you set html5 as the doctype to use this method
*
* @param string|array $src one or multiple audio sources
* @param array $attr tag attributes
* @return string
*/
public static function audio($src = '', $attr = false)
{
if(static::$html5)
{
if(is_array($src))
{
$source = '';
foreach($src as $item)
{
$source .= html_tag('source', array('src' => $item));
}
}
else
{
$source = html_tag('source', array('src' => $src));
}
return html_tag('audio', $attr, $source);
}
}
/**
* Generates a html un-ordered list tag
*
* @param array $list list items, may be nested
* @param array|string $attr outer list attributes
* @return string
*/
public static function ul(array $list = array(), $attr = false)
{
return static::build_list('ul', $list, $attr);
}
/**
* Generates a html ordered list tag
*
* @param array $list list items, may be nested
* @param array|string $attr outer list attributes
* @return string
*/
public static function ol(array $list = array(), $attr = false)
{
return static::build_list('ol', $list, $attr);
}
/**
* Generates the html for the list methods
*
* @param string $type list type (ol or ul)
* @param array $list list items, may be nested
* @param array $attr tag attributes
* @param string $indent indentation
* @return string
*/
protected static function build_list($type = 'ul', array $list = array(), $attr = false, $indent = '')
{
if ( ! is_array($list))
{
$result = false;
}
$out = '';
foreach ($list as $key => $val)
{
if ( ! is_array($val))
{
$out .= $indent."\t".html_tag('li', array(), $val).PHP_EOL;
}
else
{
$out .= $indent."\t".html_tag('li', array(), $key.PHP_EOL.static::build_list($type, $val, '', $indent."\t\t").$indent."\t").PHP_EOL;
}
}
$result = $indent.html_tag($type, $attr, PHP_EOL.$out.$indent).PHP_EOL;
return $result;
}
}

@ -1,42 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
abstract class HttpException extends \FuelException
{
/**
* Must return a response object for the handle method
*
* @return Response
*/
abstract protected function response();
/**
* When this type of exception isn't caught this method is called by
* Errorhandler::exception_handler() to deal with the problem.
*/
public function handle()
{
// get the exception response
$response = $this->response();
// fire any app shutdown events
\Event::instance()->trigger('shutdown', '', 'none', true);
// fire any framework shutdown events
\Event::instance()->trigger('fuel-shutdown', '', 'none', true);
// send the response out
$response->send(true);
}
}

@ -1,45 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class HttpBadRequestException extends HttpException
{
public function response()
{
return new \Response(\View::forge('400'), 400);
}
}
class HttpNoAccessException extends HttpException
{
public function response()
{
return new \Response(\View::forge('403'), 403);
}
}
class HttpNotFoundException extends HttpException
{
public function response()
{
return new \Response(\View::forge('404'), 404);
}
}
class HttpServerErrorException extends HttpException
{
public function response()
{
return new \Response(\View::forge('500'), 500);
}
}

@ -1,301 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Image
{
protected static $_instance = null;
/**
* Holds the config until an instance is initiated.
*
* @var array Config options to be passed when the instance is created.
*/
protected static $_config = array();
/**
* Initialize by loading config
*
* @return void
*/
public static function _init()
{
\Config::load('image', true);
}
/**
* Creates a new instance for static use of the class.
*
* @return Image_Driver
*/
protected static function instance()
{
if (static::$_instance == null)
{
static::$_instance = static::forge(static::$_config);
}
return static::$_instance;
}
/**
* Creates a new instance of the image driver
*
* @param array $config
* @param string $filename The file to load
* @return Image_Driver
* @throws \FuelException
*/
public static function forge($config = array(), $filename = null)
{
!is_array($config) and $config = array();
$config = array_merge(\Config::get('image', array()), $config);
$protocol = ucfirst( ! empty($config['driver']) ? $config['driver'] : 'gd');
$class = 'Image_'.$protocol;
if ($protocol == 'Driver' || ! class_exists($class))
{
throw new \FuelException('Driver '.$protocol.' is not a valid driver for image manipulation.');
}
$return = new $class($config);
if ($filename !== null)
{
$return->load($filename);
}
return $return;
}
/**
* Used to set configuration options.
*
* Sending the config options through the static reference initializes the
* instance. If you need to send a driver config through the static reference,
* make sure its the first one sent! If errors arise, create a new instance using
* forge().
*
* @param array $index An array of configuration settings.
* @param mixed $value
* @return Image_Driver
*/
public static function config($index = array(), $value = null)
{
if (static::$_instance === null)
{
if ($value !== null)
{
$index = array($index => $value);
}
if (is_array($index))
{
static::$_config = array_merge(static::$_config, $index);
}
static::instance();
return static::instance();
} else {
return static::instance()->config($index, $value);
}
}
/**
* Loads the image and checks if its compatible.
*
* @param string $filename The file to load
* @param string $return_data Decides if it should return the images data, or just "$this".
* @param mixed $force_extension Whether or not to force the image extension
* @return Image_Driver
*/
public static function load($filename, $return_data = false, $force_extension = false)
{
return static::instance()->load($filename, $return_data, $force_extension);
}
/**
* Crops the image using coordinates or percentages.
*
* Absolute integer or percentages accepted for all 4.
*
* @param integer $x1 X-Coordinate based from the top-left corner.
* @param integer $y1 Y-Coordinate based from the top-left corner.
* @param integer $x2 X-Coordinate based from the bottom-right corner.
* @param integer $y2 Y-Coordinate based from the bottom-right corner.
* @return Image_Driver
*/
public static function crop($x1, $y1, $x2, $y2)
{
return static::instance()->crop($x1, $y1, $x2, $y2);
}
/**
* Resize the image. If the width or height is null, it will resize retaining the original aspect ratio.
*
* @param integer $width The new width of the image.
* @param integer $height The new height of the image.
* @param boolean $keepar Defaults to true. If false, allows resizing without keeping AR.
* @param boolean $pad If set to true and $keepar is true, it will pad the image with the configured bgcolor
* @return Image_Driver
*/
public static function resize($width, $height, $keepar = true, $pad = false)
{
return static::instance()->resize($width, $height, $keepar, $pad);
}
/**
* Resize the image. If the width or height is null, it will resize retaining the original aspect ratio.
*
* @param integer $width The new width of the image.
* @param integer $height The new height of the image.
* @return Image_Driver
*/
public static function crop_resize($width, $height)
{
return static::instance()->crop_resize($width, $height);
}
/**
* Rotates the image
*
* @param integer $degrees The degrees to rotate, negatives integers allowed.
* @return Image_Driver
*/
public static function rotate($degrees)
{
return static::instance()->rotate($degrees);
}
/**
* Creates a vertical / horizontal or both mirror image.
*
* @param string $direction 'vertical', 'horizontal', 'both'
* @return Image_Driver
*/
public static function flip($direction)
{
return static::instance()->flip($direction);
}
/**
* Adds a watermark to the image.
*
* @param string $filename The filename of the watermark file to use.
* @param string $position The position of the watermark, ex: "bottom right", "center center", "top left"
* @param integer $padding The spacing between the edge of the image.
* @return Image_Driver
*/
public static function watermark($filename, $position, $padding = 5)
{
return static::instance()->watermark($filename, $position, $padding);
}
/**
* Adds a border to the image.
*
* @param integer $size The side of the border, in pixels.
* @param string $color A hexadecimal color.
* @return Image_Driver
*/
public static function border($size, $color = null)
{
return static::instance()->border($size, $color);
}
/**
* Masks the image using the alpha channel of the image input.
*
* @param string $maskimage The location of the image to use as the mask
* @return Image_Driver
*/
public static function mask($maskimage)
{
return static::instance()->mask($maskimage);
}
/**
* Adds rounded corners to the image.
*
* @param integer $radius
* @param integer $sides Accepts any combination of "tl tr bl br" separated by spaces, or null for all sides
* @param integer $antialias Sets the anti-alias range.
* @return Image_Driver
*/
public static function rounded($radius, $sides = null, $antialias = null)
{
return static::instance()->rounded($radius, $sides, $antialias);
}
/**
* Turns the image into a grayscale version
*
* @return Image_Driver
*/
public static function grayscale()
{
return static::instance()->grayscale();
}
/**
* Saves the image, and optionally attempts to set permissions
*
* @param string $filename The location where to save the image.
* @param string $permissions Allows unix style permissions
* @return Image_Driver
*/
public static function save($filename = null, $permissions = null)
{
return static::instance()->save($filename, $permissions);
}
/**
* Saves the image, and optionally attempts to set permissions
*
* @param string $prepend The text to add to the beginning of the filename.
* @param string $append The text to add to the end of the filename.
* @param string $permissions Allows unix style permissions
* @return Image_Driver
*/
public static function save_pa($prepend, $append = null, $permissions = null)
{
return static::instance()->save_pa($prepend, $append, $permissions);
}
/**
* Outputs the file directly to the user.
*
* @param string $filetype The extension type to use. Ex: png, jpg, bmp, gif
* @return Image_Driver
*/
public static function output($filetype = null)
{
return static::instance()->output($filetype);
}
/**
* Returns sizes for the currently loaded image, or the image given in the $filename.
*
* @param string $filename The location of the file to get sizes for.
* @return object An object containing width and height variables.
*/
public static function sizes($filename = null)
{
return static::instance()->sizes($filename);
}
/**
* Reloads the image.
*
* @return Image_Driver
*/
public static function reload()
{
return static::instance()->reload();
}
}

@ -1,912 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
abstract class Image_Driver
{
protected $image_fullpath = null;
protected $image_directory = null;
protected $image_filename = null;
protected $image_extension = null;
protected $new_extension = null;
protected $config = array();
protected $queued_actions = array();
protected $accepted_extensions;
/**
* Initialize by loading config
*
* @return void
*/
public static function _init()
{
\Config::load('image', true);
}
public function __construct($config)
{
if (is_array($config))
{
$this->config = array_merge(\Config::get('image', array()), $config);
}
else
{
$this->config = \Config::get('image', array());
}
$this->debug("Image Class was initialized using the " . $this->config['driver'] . " driver.");
}
/**
* Accepts configuration in either an array (as $index) or a pairing using $index and $value
*
* @param string $index The index to be set, or an array of configuration options.
* @param mixed $value The value to be set if $index is not an array.
* @return Image_Driver
*/
public function config($index = null, $value = null)
{
if (is_array($index))
{
if (isset($index['driver']))
{
throw new \RuntimeException("The driver cannot be changed after initialization!");
}
$this->config = array_merge($this->config, $index);
}
elseif ($index != null)
{
if ($index == 'driver')
{
throw new \RuntimeException("The driver cannot be changed after initialization!");
}
$this->config[$index] = $value;
}
return $this;
}
/**
* Executes the presets set in the config. Additional parameters replace the $1, $2, ect.
*
* @param string $name The name of the preset.
* @return Image_Driver
*/
public function preset($name)
{
$vars = func_get_args();
if (isset($this->config['presets'][$name]))
{
$old_config = $this->config;
$this->config = array_merge($this->config, $this->config['presets'][$name]);
foreach ($this->config['actions'] AS $action)
{
$func = $action[0];
array_shift($action);
for ($i = 0; $i < count($action); $i++)
{
for ($x = count($vars) - 1; $x >= 0; $x--)
{
$action[$i] = preg_replace('#\$' . $x . '#', $vars[$x], $action[$i]);
}
}
call_fuel_func_array(array($this, $func), $action);
}
$this->config = $old_config;
}
else
{
throw new \InvalidArgumentException("Could not load preset $name, you sure it exists?");
}
return $this;
}
/**
* Loads the image and checks if its compatible.
*
* @param string $filename The file to load
* @param string $return_data Decides if it should return the images data, or just "$this".
* @param mixed $force_extension Decides if it should force the extension with this (or false)
* @return Image_Driver
*/
public function load($filename, $return_data = false, $force_extension = false)
{
// First check if the filename exists
$filename = realpath($filename);
$return = array(
'filename' => $filename,
'return_data' => $return_data,
);
if (is_file($filename))
{
// Check the extension
$ext = $this->check_extension($filename, false, $force_extension);
if ($ext !== false)
{
$return = array_merge($return, array(
'image_fullpath' => $filename,
'image_directory' => dirname($filename),
'image_filename' => basename($filename),
'image_extension' => $ext,
));
if ( ! $return_data)
{
$this->image_fullpath = $filename;
$this->image_directory = dirname($filename);
$this->image_filename = basename($filename);
$this->image_extension = $ext;
}
}
else
{
throw new \RuntimeException("The library does not support this filetype for $filename.");
}
}
else
{
throw new \OutOfBoundsException("Image file $filename does not exist.");
}
return $return;
}
/**
* Crops the image using coordinates or percentages.
*
* Positive whole numbers or percentages are coordinates from the top left.
*
* Negative whole numbers or percentages are coordinates from the bottom right.
*
* @param integer $x1 X-Coordinate for first set.
* @param integer $y1 Y-Coordinate for first set.
* @param integer $x2 X-Coordinate for second set.
* @param integer $y2 Y-Coordinate for second set.
* @return Image_Driver
*/
public function crop($x1, $y1, $x2, $y2)
{
$this->queue('crop', $x1, $y1, $x2, $y2);
return $this;
}
/**
* Executes the crop event when the queue is ran.
*
* Formats the crop method input for use with driver specific methods
*
* @param integer $x1 X-Coordinate for first set.
* @param integer $y1 Y-Coordinate for first set.
* @param integer $x2 X-Coordinate for second set.
* @param integer $y2 Y-Coordinate for second set.
* @return array An array of variables for the specific driver.
*/
protected function _crop($x1, $y1, $x2, $y2)
{
$y1 === null and $y1 = $x1;
$x2 === null and $x2 = "-" . $x1;
$y2 === null and $y2 = "-" . $y1;
$x1 = $this->convert_number($x1, true);
$y1 = $this->convert_number($y1, false);
$x2 = $this->convert_number($x2, true);
$y2 = $this->convert_number($y2, false);
return array(
'x1' => $x1,
'y1' => $y1,
'x2' => $x2,
'y2' => $y2,
);
}
/**
* Resize the image. If the width or height is null, it will resize retaining the original aspect ratio.
*
* @param integer $width The new width of the image.
* @param integer $height The new height of the image.
* @param boolean $keepar If false, allows stretching of the image.
* @param boolean $pad Adds padding to the image when resizing.
* @return Image_Driver
*/
public function resize($width, $height = null, $keepar = true, $pad = false)
{
$this->queue('resize', $width, $height, $keepar, $pad);
return $this;
}
/**
* Creates a vertical / horizontal or both mirror image.
*
* @param mixed $direction 'vertical', 'horizontal', 'both'
* @return Image_Driver
*/
public function flip($direction)
{
$this->queue('flip', $direction);
return $this;
}
/**
* Executes the resize event when the queue is ran.
*
* Formats the resize method input for use with driver specific methods.
*
* @param integer $width The new width of the image.
* @param integer $height The new height of the image.
* @param boolean $keepar If false, allows stretching of the image.
* @param boolean $pad Adds padding to the image when resizing.
* @return array An array of variables for the specific driver.
*/
protected function _resize($width, $height = null, $keepar = true, $pad = true)
{
if ($height == null or $width == null)
{
if ($height == null and substr($width, -1) == '%')
{
$height = $width;
}
elseif (substr($height, -1) == '%' and $width == null)
{
$width = $height;
}
else
{
$sizes = $this->sizes();
if ($height == null and $width != null)
{
$height = $width * ($sizes->height / $sizes->width);
}
elseif ($height != null and $width == null)
{
$width = $height * ($sizes->width / $sizes->height);
}
else
{
throw new \InvalidArgumentException("Width and height cannot be null.");
}
}
}
$origwidth = $this->convert_number($width, true);
$origheight = $this->convert_number($height, false);
$width = $origwidth;
$height = $origheight;
$sizes = $this->sizes();
$x = 0;
$y = 0;
if ($keepar)
{
// See which is the biggest ratio
if (function_exists('bcdiv'))
{
$width_ratio = bcdiv($width, $sizes->width, 10);
$height_ratio = bcdiv($height, $sizes->height, 10);
$compare = bccomp($width_ratio, $height_ratio, 10);
if ($compare > -1)
{
$height = ceil((float) bcmul($sizes->height, $height_ratio, 10));
$width = ceil((float) bcmul($sizes->width, $height_ratio, 10));
}
else
{
$height = ceil((float) bcmul($sizes->height, $width_ratio, 10));
$width = ceil((float) bcmul($sizes->width, $width_ratio, 10));
}
}
else
{
$width_ratio = $width / $sizes->width;
$height_ratio = $height / $sizes->height;
if ($width_ratio >= $height_ratio)
{
$height = ceil($sizes->height * $height_ratio);
$width = ceil($sizes->width * $height_ratio);
}
else
{
$height = ceil($sizes->height * $width_ratio);
$width = ceil($sizes->width * $width_ratio);
}
}
}
if ($pad)
{
$x = floor(($origwidth - $width) / 2);
$y = floor(($origheight - $height) / 2);
}
else
{
$origwidth = $width;
$origheight = $height;
}
return array(
'width' => $width,
'height' => $height,
'cwidth' => $origwidth,
'cheight' => $origheight,
'x' => $x,
'y' => $y,
);
}
public function crop_resize($width, $height = null)
{
is_null($height) and $height = $width;
$this->queue('crop_resize', $width, $height);
return $this;
}
protected function _crop_resize($width, $height)
{
// Determine the crop size
$sizes = $this->sizes();
$width = $this->convert_number($width, true);
$height = $this->convert_number($height, false);
if (function_exists('bcdiv'))
{
if (bccomp(bcdiv($sizes->width, $width, 10), bcdiv($sizes->height, $height, 10), 10) < 1)
{
$this->_resize($width, 0, true, false);
}
else
{
$this->_resize(0, $height, true, false);
}
}
else
{
if ($sizes->width / $width < $sizes->height / $height)
{
$this->_resize($width, 0, true, false);
}
else
{
$this->_resize(0, $height, true, false);
}
}
$sizes = $this->sizes();
$y = floor(max(0, $sizes->height - $height) / 2);
$x = floor(max(0, $sizes->width - $width) / 2);
$this->_crop($x, $y, $x + $width, $y + $height);
}
/**
* Rotates the image
*
* @param integer $degrees The degrees to rotate, negatives integers allowed.
* @return Image_Driver
*/
public function rotate($degrees)
{
$this->queue('rotate', $degrees);
return $this;
}
/**
* Executes the rotate event when the queue is ran.
*
* Formats the rotate method input for use with driver specific methods
*
* @param integer $degrees The degrees to rotate, negatives integers allowed.
* @return array An array of variables for the specific driver.
*/
protected function _rotate($degrees)
{
$degrees %= 360;
if ($degrees < 0)
{
$degrees = 360 + $degrees;
}
return array(
'degrees' => $degrees,
);
}
/**
* Adds a watermark to the image.
*
* @param string $filename The filename of the watermark file to use.
* @param string $position The position of the watermark, ex: "bottom right", "center center", "top left"
* @param integer $padding The amount of padding (in pixels) from the position.
* @return Image_Driver
*/
public function watermark($filename, $position, $padding = 5)
{
$this->queue('watermark', $filename, $position, $padding);
return $this;
}
/**
* Executes the watermark event when the queue is ran.
*
* Formats the watermark method input for use with driver specific methods
*
* @param string $filename The filename of the watermark file to use.
* @param string $position The position of the watermark, ex: "bottom right", "center center", "top left"
* @param integer $padding The amount of padding (in pixels) from the position.
* @return array An array of variables for the specific driver.
*/
protected function _watermark($filename, $position, $padding = 5)
{
$filename = realpath($filename);
$return = false;
if (is_file($filename) and $this->check_extension($filename, false))
{
$x = 0;
$y = 0;
$wsizes = $this->sizes($filename);
$sizes = $this->sizes();
// Get the x and y positions.
list($ypos, $xpos) = explode(' ', $position);
switch ($xpos)
{
case 'left':
$x = $padding;
break;
case 'middle':
case 'center':
$x = ($sizes->width / 2) - ($wsizes->width / 2);
break;
case 'right':
$x = $sizes->width - $wsizes->width - $padding;
break;
}
switch ($ypos)
{
case 'top':
$y = $padding;
break;
case 'middle':
case 'center':
$y = ($sizes->height / 2) - ($wsizes->height / 2);
break;
case 'bottom':
$y = $sizes->height - $wsizes->height - $padding;
break;
}
$this->debug("Watermark being placed at $x,$y");
$return = array(
'filename' => $filename,
'x' => $x,
'y' => $y,
'padding' => $padding,
);
}
return $return;
}
/**
* Adds a border to the image.
*
* @param integer $size The side of the border, in pixels.
* @param string $color A hexadecimal color.
* @return Image_Driver
*/
public function border($size, $color = null)
{
$this->queue('border', $size, $color);
return $this;
}
/**
* Executes the border event when the queue is ran.
*
* Formats the border method input for use with driver specific methods
*
* @param integer $size The side of the border, in pixels.
* @param string $color A hexadecimal color.
* @return array An array of variables for the specific driver.
*/
protected function _border($size, $color = null)
{
empty($color) and $color = $this->config['bgcolor'];
return array(
'size' => $size,
'color' => $color,
);
}
/**
* Masks the image using the alpha channel of the image input.
*
* @param string $maskimage The location of the image to use as the mask
* @return Image_Driver
*/
public function mask($maskimage)
{
$this->queue('mask', $maskimage);
return $this;
}
/**
* Executes the mask event when the queue is ran.
*
* Formats the mask method input for use with driver specific methods
*
* @param string $maskimage The location of the image to use as the mask
* @return array An array of variables for the specific driver.
*/
protected function _mask($maskimage)
{
return array(
'maskimage' => $maskimage,
);
}
/**
* Adds rounded corners to the image.
*
* @param integer $radius
* @param integer $sides Accepts any combination of "tl tr bl br" separated by spaces, or null for all sides
* @param integer $antialias Sets the anti-alias range.
* @return Image_Driver
*/
public function rounded($radius, $sides = null, $antialias = null)
{
$this->queue('rounded', $radius, $sides, $antialias);
return $this;
}
/**
* Executes the rounded event when the queue is ran.
*
* Formats the rounded method input for use with driver specific methods
*
* @param integer $radius
* @param integer $sides Accepts any combination of "tl tr bl br" separated by spaces, or null for all sides
* @param integer $antialias Sets the anti-alias range.
* @return array An array of variables for the specific driver.
*/
protected function _rounded($radius, $sides, $antialias)
{
$radius < 0 and $radius = 0;
$tl = $tr = $bl = $br = $sides == null;
if ($sides != null)
{
$sides = explode(' ', $sides);
foreach ($sides as $side)
{
if ($side == 'tl' or $side == 'tr' or $side == 'bl' or $side == 'br')
{
$$side = true;
}
}
}
$antialias == null and $antialias = 1;
return array(
'radius' => $radius,
'tl' => $tl,
'tr' => $tr,
'bl' => $bl,
'br' => $br,
'antialias' => $antialias,
);
}
/**
* Turns the image into a grayscale version
*
* @return Image_Driver
*/
public function grayscale()
{
$this->queue('grayscale');
return $this;
}
/**
* Executes the grayscale event when the queue is ran.
*/
abstract protected function _grayscale();
/**
* Saves the image, and optionally attempts to set permissions
*
* @param string $filename The location where to save the image.
* @param string $permissions Allows unix style permissions
* @return array
*/
public function save($filename = null, $permissions = null)
{
if (empty($filename))
{
$filename = $this->image_filename;
}
$directory = dirname($filename);
if ( ! is_dir($directory))
{
throw new \OutOfBoundsException("Could not find directory \"$directory\"");
}
if ( ! $this->check_extension($filename, true))
{
$filename .= "." . $this->image_extension;
}
// Touch the file
if ( ! touch($filename))
{
throw new \RuntimeException("Do not have permission to write to \"$filename\"");
}
// Set the new permissions
if ($permissions != null and ! chmod($filename, $permissions))
{
throw new \RuntimeException("Could not set permissions on the file.");
}
$this->debug("", "Saving image as <code>$filename</code>");
return array(
'filename' => $filename,
);
}
/**
* Saves the file in the original location, adding the append and prepend to the filename.
*
* @param string $append The string to append to the filename
* @param string $prepend The string to prepend to the filename
* @param string $extension The extension to save the image as, null defaults to the loaded images extension.
* @param integer $permissions The permissions to attempt to set on the file.
* @return Image_Driver
*/
public function save_pa($append, $prepend = null, $extension = null, $permissions = null)
{
$filename = substr($this->image_filename, 0, -(strlen($this->image_extension) + 1));
$fullpath = $this->image_directory.'/'.$append.$filename.$prepend.'.'.
($extension !== null ? $extension : $this->image_extension);
$this->save($fullpath, $permissions);
return $this;
}
/**
* Outputs the file directly to the user.
*
* @param string $filetype The extension type to use. Ex: png, jpg, gif
* @return array
* @throws \FuelException
*/
public function output($filetype = null)
{
if ($filetype == null)
{
$filetype = $this->config['filetype'] == null ? $this->image_extension : $this->config['filetype'];
}
if ($this->check_extension($filetype, false))
{
if ( ! $this->config['debug'])
{
$mimetype = $filetype === 'jpg' ? 'jpeg' : $filetype;
header('Content-Type: image/' . $mimetype);
}
$this->new_extension = $filetype;
}
else
{
throw new \FuelException("Image extension $filetype is unsupported.");
}
$this->debug('', "Outputting image as $filetype");
return array(
'filetype' => $filetype,
);
}
/**
* Returns sizes for the currently loaded image, or the image given in the $filename.
*
* @param string $filename The location of the file to get sizes for.
* @return object An object containing width and height variables.
*/
abstract public function sizes($filename = null);
/**
* Adds a background to the image using the 'bgcolor' config option.
*/
abstract protected function add_background();
/**
* Creates a new color usable by all drivers.
*
* @param string $hex The hex code of the color
* @return array rgba representation of the hex and alpha values.
*/
protected function create_hex_color($hex)
{
if ($hex == null)
{
$red = 0;
$green = 0;
$blue = 0;
$alpha = 0;
}
else
{
// Check if theres a # in front
if (substr($hex, 0, 1) == '#')
{
$hex = substr($hex, 1);
}
// Break apart the hex
if (strlen($hex) == 6 or strlen($hex) == 8)
{
$red = hexdec(substr($hex, 0, 2));
$green = hexdec(substr($hex, 2, 2));
$blue = hexdec(substr($hex, 4, 2));
$alpha = (strlen($hex) == 8) ? hexdec(substr($hex, 6, 2)) : 255;
}
else
{
$red = hexdec(substr($hex, 0, 1).substr($hex, 0, 1));
$green = hexdec(substr($hex, 1, 1).substr($hex, 1, 1));
$blue = hexdec(substr($hex, 2, 1).substr($hex, 2, 1));
$alpha = (strlen($hex) > 3) ? hexdec(substr($hex, 3, 1).substr($hex, 3, 1)) : 255;
}
}
$alpha = floor($alpha / 2.55);
return array(
'red' => $red,
'green' => $green,
'blue' => $blue,
'alpha' => $alpha,
);
}
/**
* Checks if the extension is accepted by this library, and if its valid sets the $this->image_extension variable.
*
* @param string $filename
* @param boolean $writevar Decides if the extension should be written to $this->image_extension
* @param mixed $force_extension Decides if the extension should be overridden with this (or false)
* @return boolean
*/
protected function check_extension($filename, $writevar = true, $force_extension = false)
{
$return = false;
if ($force_extension !== false and in_array($force_extension, $this->accepted_extensions))
{
return $force_extension;
}
foreach ($this->accepted_extensions as $ext)
{
if (strtolower(substr($filename, strlen($ext) * -1)) == strtolower($ext))
{
$writevar and $this->image_extension = $ext;
$return = $ext;
}
}
return $return;
}
/**
* Converts percentages, negatives, and other values to absolute integers.
*
* @param string $input
* @param boolean $x Determines if the number relates to the x-axis or y-axis.
* @return integer The converted number, usable with the image being edited.
*/
protected function convert_number($input, $x = null)
{
// Sanitize double negatives
$input = str_replace('--', '', $input);
// Depending on php configuration, float are sometimes converted to strings
// using commas instead of points. This notation can create issues since the
// conversion from string to float will return an integer.
// For instance: "1.2" / 10 == 0.12 but "1,2" / 10 == 0.1...
$input = str_replace(',', '.', $input);
$orig = $input;
$sizes = $this->sizes();
$size = $x ? $sizes->width : $sizes->height;
// Convert percentages to absolutes
if (substr($input, -1) == '%')
{
$input = floor((substr($input, 0, -1) / 100) * $size);
}
// Negatives are based off the bottom right
if ($x !== null and $input < 0)
{
$input = $size + $input;
}
return $input;
}
/**
* Queues a function to run at a later time.
*
* @param string $function The name of the function to be ran, without the leading _
*/
protected function queue($function)
{
$func = func_get_args();
$tmpfunc = array();
for ($i = 0; $i < count($func); $i++)
{
$tmpfunc[$i] = var_export($func[$i], true);
}
$this->debug("Queued <code>" . implode(", ", $tmpfunc) . "</code>");
$this->queued_actions[] = $func;
}
/**
* Runs all queued actions on the loaded image.
*
* @param boolean $clear Decides if the queue should be cleared once completed.
*/
public function run_queue($clear = null)
{
foreach ($this->queued_actions as $action)
{
$tmpfunc = array();
for ($i = 0; $i < count($action); $i++)
{
$tmpfunc[$i] = var_export($action[$i], true);
}
$this->debug('', "<b>Executing <code>" . implode(", ", $tmpfunc) . "</code></b>");
call_user_func_array(array(&$this, '_' . $action[0]), array_slice($action, 1));
}
if (($clear === null and $this->config['clear_queue']) or $clear === true)
{
$this->queued_actions = array();
}
}
/**
* Reloads the image.
*
* @return Image_Driver
*/
public function reload()
{
$this->debug("Reloading was called!");
$this->load($this->image_fullpath);
return $this;
}
/**
* Get the file extension (type) worked out on construct
*
* @return string File extension
*/
public function extension()
{
return $this->image_extension;
}
/**
* Used for debugging image output.
*/
protected function debug()
{
if ($this->config['debug'])
{
$messages = func_get_args();
foreach ($messages as $message)
{
echo '<div>' . $message . '&nbsp;</div>';
}
}
}
}

@ -1,551 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Image_Gd extends \Image_Driver
{
protected $image_data = null;
protected $accepted_extensions = array('png', 'gif', 'jpg', 'jpeg');
protected $gdresizefunc = "imagecopyresampled";
public function load($filename, $return_data = false, $force_extension = false)
{
extract(parent::load($filename, $return_data, $force_extension));
$return = false;
$image_extension == 'jpg' and $image_extension = 'jpeg';
if ( ! $return_data)
{
$this->image_data !== null and imagedestroy($this->image_data);
$this->image_data = null;
}
// Check if the function exists
if (function_exists('imagecreatefrom'.$image_extension))
{
// Create a new transparent image.
$sizes = $this->sizes($image_fullpath);
$tmpImage = call_user_func('imagecreatefrom'.$image_extension, $image_fullpath);
$image = $this->create_transparent_image($sizes->width, $sizes->height, $tmpImage);
if ( ! $return_data)
{
$this->image_data = $image;
$return = true;
}
else
{
$return = $image;
}
$this->debug('', "<strong>Loaded</strong> <code>".$image_fullpath."</code> with size of ".$sizes->width."x".$sizes->height);
}
else
{
throw new \RuntimeException("Function imagecreatefrom".$image_extension."() does not exist (Missing GD?)");
}
return $return_data ? $return : $this;
}
protected function _crop($x1, $y1, $x2, $y2)
{
extract(parent::_crop($x1, $y1, $x2, $y2));
$width = $x2 - $x1;
$height = $y2 - $y1;
$this->debug("Cropping image ".$width."x".$height."+$x1+$y1 based on coords ($x1, $y1), ($x2, $y2)");
$image = $this->create_transparent_image($width, $height);
imagecopy($image, $this->image_data, 0, 0, $x1, $y1, $width, $height);
$this->image_data = $image;
}
protected function _resize($width, $height = null, $keepar = true, $pad = true)
{
extract(parent::_resize($width, $height, $keepar, $pad));
$sizes = $this->sizes();
$this->debug("Resizing image to $width, $height with" . ($keepar ? '' : 'out') . " keeping AR and with" . ($pad ? '' : 'out') . " padding.");
// Add the original image.
$image = $this->create_transparent_image($cwidth, $cheight);
call_user_func($this->gdresizefunc, $image, $this->image_data, $x, $y, 0, 0, $width, $height, $sizes->width, $sizes->height);
$this->image_data = $image;
}
protected function _rotate($degrees)
{
extract(parent::_rotate($degrees));
$degrees = 360 - $degrees;
$bgcolor = $this->config['bgcolor'] !== null ? $this->config['bgcolor'] : '#000';
$color = $this->create_color($this->image_data, $bgcolor, 100);
$this->image_data = imagerotate($this->image_data, $degrees, $color, false);
}
protected function _watermark($filename, $position, $padding = 5)
{
$values = parent::_watermark($filename, $position, $padding);
if ($values == false)
{
throw new \InvalidArgumentException("Watermark image not found or invalid filetype.");
}
else
{
extract($values);
$wsizes = $this->sizes($filename);
$sizes = $this->sizes();
// Load the watermark preserving transparency
$watermark = $this->load($filename, true);
// Below is to prevent glitch in GD with negative $x coords
if ($x < 0 || $y < 0)
{
$this->debug("Modifying watermark to remove negative coords.");
// Generate a new width and height for the watermark.
$newwidth = ($x < 0 ? $wsizes->width + $x : $wsizes->width);
$newheight = ($y < 0 ? $wsizes->height + $y : $wsizes->height);
// Create a transparent image the size of the new watermark.
$tmpwatermark = $this->create_transparent_image($newwidth, $newheight);
$this->debug("New size is $newwidth x $newheight and coords are $x , $y");
// Call the resize function based on image format
imagecopy(
$tmpwatermark, $watermark, // Copy the new image into the tmp watermark
0, 0,
$x < 0 ? abs($x) : 0,
$y < 0 ? abs($y) : 0,
$newwidth, $newheight
);
// Set the variables for the image_merge
$watermark = $tmpwatermark;
$x = $x < 0 ? 0 : $x;
$y = $y < 0 ? 0 : $y;
}
// Used as a workaround for lack of alpha support in imagecopymerge.
$this->debug("Coords for watermark are $x , $y");
$this->image_merge($this->image_data, $watermark, $x, $y, $this->config['watermark_alpha']);
}
}
protected function _flip($mode)
{
$sizes = (array) $this->sizes();
$source = array_merge($sizes, array('x' => 0, 'y' => 0));
switch ($mode)
{
case 'vertical':
$source['y'] = $sizes['height'] - 1;
$source['height'] = -$sizes['height'];
break;
case 'horizontal':
$source['x'] = $sizes['width'] - 1;
$source['width'] = -$sizes['width'];
break;
case 'both':
$source['y'] = $sizes['height'] - 1;
$source['x'] = $sizes['width'] - 1;
$source['height'] = -$sizes['height'];
$source['width'] = -$sizes['width'];
break;
default: return false;
}
$image = imagecreatetruecolor($sizes['width'], $sizes['height']);
imagecopyresampled(
$image,
$this->image_data,
0,
0,
$source['x'],
$source['y'],
$sizes['width'],
$sizes['height'],
$source['width'],
$source['height']
);
$this->image_data = $image;
}
protected function _border($size, $color = null)
{
extract(parent::_border($size, $color));
$sizes = $this->sizes();
$image = $this->create_transparent_image($sizes->width + ($size * 2), $sizes->height + ($size * 2));
$color = $this->create_color($image, $color, 100);
$this->image_merge($image, $this->image_data, $size, $size, 100);
for ($s = 0; $s < $size; $s++)
{
imagerectangle($image, $s, $s, $sizes->width + ($size * 2) - $s - 1, $sizes->height + ($size * 2) - $s - 1, $color);
}
$this->image_data = $image;
}
protected function _mask($maskimage)
{
extract(parent::_mask($maskimage));
// Get size and width of image
$sizes = $this->sizes();
$masksizes = $this->sizes($maskimage);
// Create new blank image
$image = $this->create_transparent_image($sizes->width, $sizes->height);
if (is_resource($maskimage))
{
$maskim = $maskimage;
}
else
{
$maskim = $this->load($maskimage, true);
}
$masksizes->width > $sizes->width and $masksizes->width = $sizes->width;
$masksizes->height > $sizes->width and $masksizes->height = $sizes->height;
// Loop through all the pixels
for ($x = 0; $x < $masksizes->width; $x++)
{
for ($y = 0; $y < $masksizes->height; $y++)
{
$maskcolor = imagecolorat($maskim, $x, $y);
$maskcolor = imagecolorsforindex($maskim, $maskcolor);
$maskalpha = 127 - floor(($maskcolor['red'] + $maskcolor['green'] + $maskcolor['blue']) / 6);
if ($maskalpha == 127)
{
continue;
}
if ($maskalpha == 0)
{
$ourcolor = array(
'red' => 0,
'green' => 0,
'blue' => 0,
'alpha' => 0,
);
}
else
{
$ourcolor = imagecolorat($this->image_data, $x, $y);
$ourcolor = imagecolorsforindex($this->image_data, $ourcolor);
}
$ouralpha = 127 - $ourcolor['alpha'];
if ($ouralpha == 0)
{
continue;
}
$newalpha = floor($ouralpha - (($maskalpha / 127) * $ouralpha));
$newcolor = imagecolorallocatealpha($image, $ourcolor['red'], $ourcolor['green'], $ourcolor['blue'], 127 - $newalpha);
imagesetpixel($image, $x, $y, $newcolor);
}
}
$this->image_data = $image;
}
protected function _rounded($radius, $sides, $antialias)
{
extract(parent::_rounded($radius, $sides, $antialias));
$tl and $this->round_corner($this->image_data, $radius, $antialias, true, true);
$tr and $this->round_corner($this->image_data, $radius, $antialias, true, false);
$bl and $this->round_corner($this->image_data, $radius, $antialias, false, true);
$br and $this->round_corner($this->image_data, $radius, $antialias, false, false);
}
protected function _grayscale()
{
$sizes = $this->sizes();
// Create the 256 color palette
$bwpalette = array();
for ($i = 0; $i < 256; $i++)
{
$bwpalette[$i] = imagecolorallocate($this->image_data, $i, $i, $i);
}
for ($x = 0; $x < $sizes->width; $x++)
{
for ($y = 0; $y < $sizes->height; $y++)
{
$color = imagecolorat($this->image_data, $x, $y);
$red = ($color >> 16) & 0xFF;
$green = ($color >> 8) & 0xFF;
$blue = $color & 0xFF;
// If its black or white, theres no use in setting the pixel
if (($red == 0 && $green == 0 && $blue == 0) || ($red == 255 && $green == 255 && $blue == 255))
{
continue;
}
// Now set the color
$shade = (($red*0.299)+($green*0.587)+($blue*0.114));
imagesetpixel($this->image_data, $x, $y, $bwpalette[$shade]);
}
}
}
public function sizes($filename = null)
{
if (empty($filename) && !empty($this->image_fullpath))
{
$filename = $this->image_fullpath;
}
if ($filename == $this->image_fullpath && is_resource($this->image_data))
{
$width = imagesx($this->image_data);
$height = imagesy($this->image_data);
}
elseif (is_resource($filename))
{
$width = imagesx($filename);
$height = imagesy($filename);
}
else
{
list($width, $height) = getimagesize($filename);
}
return (object) array('width' => $width, 'height' => $height);
}
public function save($filename = null, $permissions = null)
{
extract(parent::save($filename, $permissions));
$this->run_queue();
$this->add_background();
$vars = array(&$this->image_data, $filename);
$filetype = $this->image_extension;
if ($filetype == 'jpg' || $filetype == 'jpeg')
{
$vars[] = $this->config['quality'];
$filetype = 'jpeg';
}
elseif ($filetype == 'png')
{
$vars[] = floor(($this->config['quality'] / 100) * 9);
}
call_fuel_func_array('image'.$filetype, $vars);
if ($this->config['persistence'] === false)
{
$this->reload();
}
return $this;
}
public function output($filetype = null)
{
$this->gdresizefunc = ($filetype == 'gif') ? 'imagecopyresized' : $this->gdresizefunc = 'imagecopyresampled';
extract(parent::output($filetype));
$this->run_queue();
$this->add_background();
$vars = array($this->image_data, null);
if ($filetype == 'jpg' || $filetype == 'jpeg')
{
$vars[] = $this->config['quality'];
$filetype = 'jpeg';
}
elseif ($filetype == 'png')
{
$vars[] = floor(($this->config['quality'] / 100) * 9);
}
call_fuel_func_array('image'.$filetype, $vars);
if ($this->config['persistence'] === false)
{
$this->reload();
}
return $this;
}
/**
* Creates a new color usable by GD.
*
* @param resource $image The image to create the color from
* @param string $hex The hex code of the color
* @param integer $alpha The alpha of the color, 0 (trans) to 100 (opaque)
* @return integer The color
*/
protected function create_color(&$image, $hex, $alpha)
{
extract($this->create_hex_color($hex));
// Handling alpha is different among drivers
if ($hex == null)
{
$alpha = 127;
}
else
{
$alpha = 127 - floor($alpha * 1.27);
}
// Check if the transparency is allowed
return imagecolorallocatealpha($image, $red, $green, $blue, $alpha);
}
protected function add_background()
{
if ($this->config['bgcolor'] != null || ($this->new_extension == 'jpg' || $this->new_extension == 'jpeg'))
{
$bgcolor = $this->config['bgcolor'] == null ? '#000' : $this->config['bgcolor'];
$this->debug("Adding background color $bgcolor");
$sizes = $this->sizes();
$bgimg = $this->create_transparent_image($sizes->width, $sizes->height);
$color = $this->create_color($bgimg, $bgcolor, 100);
imagefill($bgimg, 0, 0, $color);
$this->image_merge($bgimg, $this->image_data, 0, 0, 100);
$this->image_data = $bgimg;
}
}
/**
* Creates a new transparent image.
*
* @param integer $width The width of the image.
* @param integer $height The height of the image.
* @param resource $resource Optionally add an image to the new transparent image.
* @return resource Returns the image in resource form.
*/
protected function create_transparent_image($width, $height, $resource = null)
{
$image = imagecreatetruecolor($width, $height);
$bgcolor = $this->config['bgcolor'] == null ? '#000' : $this->config['bgcolor'];
$color = $this->create_color($image, $bgcolor, 0);
imagesavealpha($image, true);
if ($this->image_extension == 'gif' || $this->image_extension == 'png')
{
// Get the current transparent color if possible...
$transcolor = imagecolortransparent($image);
if ($transcolor > 0)
{
$color = $transcolor;
}
imagecolortransparent($image, $color);
}
// Set the blending mode to false, add the bgcolor, then switch it back.
imagealphablending($image, false);
imagefilledrectangle($image, 0, 0, $width, $height, $color);
imagealphablending($image, true);
if (is_resource($resource))
{
imagecopy($image, $resource, 0, 0, 0, 0, $width, $height);
}
return $image;
}
/**
* Creates a rounded corner on the image.
*
* @param resource $image
* @param integer $radius
* @param integer $antialias
* @param boolean $top
* @param boolean $left
*/
protected function round_corner(&$image, $radius, $antialias, $top, $left)
{
$this->debug("Rounding ".($top ? 'top' : 'bottom')." ".($left ? 'left' : 'right')." corner with a radius of ".$radius."px.");
$sX = $left ? -$radius : 0;
$sY = $top ? -$radius : 0;
$eX = $left ? 0 : $radius;
$eY = $top ? 0 : $radius;
// Get this images size
$sizes = $this->sizes();
$offsetX = ($left ? $radius : $sizes->width - $radius - 1);
$offsetY = ($top ? $radius : $sizes->height - $radius - 1);
// Set the images alpha blend to false
imagealphablending($image, false);
// Make this color ahead time
$transparent = $this->create_color($image, null, 0);
for ($x = $sX; $x <= $eX; $x++)
{
for ($y = $sY; $y <= $eY; $y++)
{
$dist = sqrt(($x * $x) + ($y * $y));
if ($dist <= $radius + $antialias)
{
// Decide if anything needs to be changed
// We subtract from antialias so the transparency makes sense.
$fromCirc = $dist - $radius;
if ($fromCirc > 0)
{
if ($fromCirc == 0)
{
imagesetpixel($image, $x + $offsetX, $y + $offsetY, $transparent);
}
else
{
// Get color information from this spot on the image
$rgba = imagecolorat($image, $x + $offsetX, $y + $offsetY);
$tmpColor = imagecolorallocatealpha(
$image,
($rgba >> 16) & 0xFF, // Red
($rgba >> 8) & 0xFF, // Green
$rgba & 0xFF, // Blue
(127 - (($rgba >> 24) & 0xFF)) * ($fromCirc / $antialias) // Alpha
);
imagesetpixel($image, $x + $offsetX, $y + $offsetY, $tmpColor);
}
}
}
else
{
// Clear this area out...
imagesetpixel($image, $x + $offsetX, $y + $offsetY, $transparent);
}
}
}
// Reset alpha blending
imagealphablending($image, true);
}
/**
* Merges to images together, using a fix for transparency
*
* @param resource $image The bottom image
* @param resource $watermark The image to be placed on top
* @param integer $x The position of the watermark on the X-axis
* @param integer $y The position of the watermark on the Y-axis
* @param integer $alpha The transparency of the watermark, 0 (trans) to 100 (opaque)
*/
protected function image_merge(&$image, $watermark, $x, $y, $alpha)
{
$wsizes = $this->sizes($watermark);
$tmpimage = $this->create_transparent_image($wsizes->width, $wsizes->height);
imagecopy($tmpimage, $image, 0, 0, $x, $y, $wsizes->width, $wsizes->height);
imagecopy($tmpimage, $watermark, 0, 0, 0, 0, $wsizes->width, $wsizes->height);
imagealphablending($image, false);
imagecopymerge($image, $tmpimage, $x, $y, 0, 0, $wsizes->width, $wsizes->height, $alpha);
imagealphablending($image, true);
}
}

@ -1,356 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Image_Imagemagick extends \Image_Driver
{
protected $image_temp = null;
protected $accepted_extensions = array('png', 'gif', 'jpg', 'jpeg');
protected $sizes_cache = null;
protected $im_path = null;
public function load($filename, $return_data = false, $force_extension = false)
{
extract(parent::load($filename, $return_data, $force_extension));
$this->clear_sizes();
if (empty($this->image_temp))
{
do
{
$this->image_temp = $this->config['temp_dir'].substr($this->config['temp_append'].md5(time() * microtime()), 0, 32).'.png';
}
while (is_file($this->image_temp));
}
elseif (is_file($this->image_temp))
{
$this->debug('Removing previous temporary image.');
unlink($this->image_temp);
}
$this->debug('Temp file: '.$this->image_temp);
if ( ! is_dir($this->config['temp_dir']))
{
throw new \RuntimeException("The temp directory that was given does not exist.");
}
elseif (!touch($this->config['temp_dir'] . $this->config['temp_append'] . '_touch'))
{
throw new \RuntimeException("Could not write in the temp directory.");
}
$this->exec('convert', '"'.$image_fullpath.'"[0] "'.$this->image_temp.'"');
return $this;
}
protected function _crop($x1, $y1, $x2, $y2)
{
extract(parent::_crop($x1, $y1, $x2, $y2));
$image = '"'.$this->image_temp.'"';
$this->exec('convert', $image.' -crop '.($x2 - $x1).'x'.($y2 - $y1).'+'.$x1.'+'.$y1.' +repage '.$image);
$this->clear_sizes();
}
protected function _resize($width, $height = null, $keepar = true, $pad = true)
{
extract(parent::_resize($width, $height, $keepar, $pad));
$image = '"'.$this->image_temp.'"';
$this->exec('convert', "-define png:size=".$cwidth."x".$cheight." ".$image." ".
"-background none ".
"-resize \"".($pad ? $width : $cwidth)."x".($pad ? $height : $cheight)."!\" ".
"-gravity center ".
"-extent ".$cwidth."x".$cheight." ".$image);
$this->clear_sizes();
}
protected function _rotate($degrees)
{
extract(parent::_rotate($degrees));
$image = '"'.$this->image_temp.'"';
$this->exec('convert', $image." -background none -virtual-pixel background +distort ScaleRotateTranslate ".$degrees." +repage ".$image);
$this->clear_sizes();
}
protected function _flip($direction)
{
switch ($direction)
{
case 'vertical':
$arg = '-flip';
break;
case 'horizontal':
$arg = '-flop';
break;
case 'both':
$arg = '-flip -flop';
break;
default: return false;
}
$image = '"'.$this->image_temp.'"';
$this->exec('convert', $image.' '.$arg.' '.$image);
}
protected function _watermark($filename, $position, $padding = 5)
{
$values = parent::_watermark($filename, $position, $padding);
if ($values == false)
{
throw new \InvalidArgumentException("Watermark image not found or invalid filetype.");
}
extract($values);
$x >= 0 and $x = '+'.$x;
$y >= 0 and $y = '+'.$y;
$image = '"'.$this->image_temp.'"';
$this->exec(
'composite',
'-compose atop -geometry '.$x.$y.' '.
'-dissolve '.$this->config['watermark_alpha'].'% '.
'"'.$filename.'" "'.$this->image_temp.'" '.$image
);
}
protected function _border($size, $color = null)
{
extract(parent::_border($size, $color));
$image = '"'.$this->image_temp.'"';
$color = $this->create_color($color, 100);
$command = $image.' -compose copy -bordercolor '.$color.' -border '.$size.'x'.$size.' '.$image;
$this->exec('convert', $command);
$this->clear_sizes();
}
protected function _mask($maskimage)
{
extract(parent::_mask($maskimage));
$mimage = '"'.$maskimage.'"';
$image = '"'.$this->image_temp.'"';
$command = $image.' '.$mimage.' +matte -compose copy-opacity -composite '.$image;
$this->exec('convert', $command);
}
/**
* Credit to Leif Åstrand <leif@sitelogic.fi> for the base of the round corners.
*
* Note there is a defect with this, as non-transparent corners get opaque circles of color. Maybe mask it with auto-generated corners?
*
* @link http://www.imagemagick.org/Usage/thumbnails/#rounded
*/
protected function _rounded($radius, $sides, $antialias = 0)
{
extract(parent::_rounded($radius, $sides, null));
$image = '"'.$this->image_temp.'"';
$r = $radius;
$command = $image." \\( +clone -alpha extract ".
( ! $tr ? '' : "-draw \"fill black polygon 0,0 0,$r $r,0 fill white circle $r,$r $r,0\" ")."-flip ".
( ! $br ? '' : "-draw \"fill black polygon 0,0 0,$r $r,0 fill white circle $r,$r $r,0\" ")."-flop ".
( ! $bl ? '' : "-draw \"fill black polygon 0,0 0,$r $r,0 fill white circle $r,$r $r,0\" ")."-flip ".
( ! $tl ? '' : "-draw \"fill black polygon 0,0 0,$r $r,0 fill white circle $r,$r $r,0\" ").
'\\) -alpha off -compose CopyOpacity -composite '.$image;
$this->exec('convert', $command);
}
protected function _grayscale()
{
$image = '"'.$this->image_temp.'"';
$this->exec('convert', $image." -colorspace Gray ".$image);
}
public function sizes($filename = null, $usecache = true)
{
$is_loaded_file = $filename == null;
if ( ! $is_loaded_file or $this->sizes_cache == null or !$usecache)
{
$reason = ($filename != null ? "filename" : ($this->sizes_cache == null ? 'cache' : 'option'));
$this->debug("Generating size of image... (triggered by $reason)");
if ($is_loaded_file and ! empty($this->image_temp))
{
$filename = $this->image_temp;
}
$output = $this->exec('identify', '-format "%w %h" "'.$filename.'"[0]');
list($width, $height) = explode(" ", $output[0]);
$return = (object) array(
'width' => $width,
'height' => $height,
);
if ($is_loaded_file)
{
$this->sizes_cache = $return;
}
$this->debug("Sizes ".( !$is_loaded_file ? "for <code>$filename</code> " : "")."are now $width and $height");
}
else
{
$return = $this->sizes_cache;
}
return $return;
}
public function save($filename = null, $permissions = null)
{
extract(parent::save($filename, $permissions));
$this->run_queue();
$this->add_background();
$filetype = $this->image_extension;
$old = '"'.$this->image_temp.'"';
$new = '"'.$filename.'"';
if(($filetype == 'jpeg' or $filetype == 'jpg') and $this->config['quality'] != 100)
{
$quality = '"'.$this->config['quality'].'%"';
$this->exec('convert', $old.' -quality '.$quality.' '.$new);
}
else
{
$this->exec('convert', $old.' '.$new);
}
if ($this->config['persistence'] === false)
{
$this->reload();
}
return $this;
}
public function output($filetype = null)
{
extract(parent::output($filetype));
$this->run_queue();
$this->add_background();
$image = '"'.$this->image_temp.'"';
if(($filetype == 'jpeg' or $filetype == 'jpg') and $this->config['quality'] != 100)
{
$quality = '"'.$this->config['quality'].'%"';
$this->exec('convert', $image.' -quality '.$quality.' '.strtolower($filetype).':-', true);
}
elseif (substr($this->image_temp, -1 * strlen($filetype)) != $filetype)
{
if ( ! $this->config['debug'])
{
$this->exec('convert', $image.' '.strtolower($filetype).':-', true);
}
}
else
{
if ( ! $this->config['debug'])
{
echo file_get_contents($this->image_temp);
}
}
if ($this->config['persistence'] === false)
{
$this->reload();
}
return $this;
}
/**
* Cleared the currently loaded sizes, used to removed cached sizes.
*/
protected function clear_sizes()
{
$this->sizes_cache = null;
}
protected function add_background()
{
if ($this->config['bgcolor'] != null)
{
$bgcolor = $this->config['bgcolor'] == null ? '#000' : $this->config['bgcolor'];
$image = '"'.$this->image_temp.'"';
$color = $this->create_color($bgcolor, 100);
$sizes = $this->sizes();
$command = '-size '.$sizes->width.'x'.$sizes->height.' '.'canvas:'.$color.' '.
$image.' -composite '.$image;
$this->exec('convert', $command);
}
}
/**
* Executes the specified imagemagick executable and returns the output.
*
* @param string $program The name of the executable.
* @param string $params The parameters of the executable.
* @param boolean $passthru Returns the output if false or pass it to browser.
* @return mixed Either returns the output or returns nothing.
*/
protected function exec($program, $params, $passthru = false)
{
// Determine the path
$this->im_path = realpath($this->config['imagemagick_dir'].$program);
if ( ! $this->im_path)
{
$this->im_path = realpath($this->config['imagemagick_dir'].$program.'.exe');
}
if ( ! $this->im_path)
{
throw new \RuntimeException("imagemagick executables not found in ".$this->config['imagemagick_dir']);
}
$command = $this->im_path." ".$params;
$this->debug("Running command: <code>$command</code>");
$code = 0;
$output = null;
$passthru ? passthru($command) : exec($command, $output, $code);
if ($code != 0)
{
throw new \FuelException("imagemagick failed to edit the image. Returned with $code.<br /><br />Command:\n <code>$command</code>");
}
return $output;
}
/**
* Creates a new color usable by ImageMagick.
*
* @param string $hex The hex code of the color
* @param integer $alpha The alpha of the color, 0 (trans) to 100 (opaque)
* @return string rgba representation of the hex and alpha values.
*/
protected function create_color($hex, $alpha)
{
extract($this->create_hex_color($hex));
return "\"rgba(".$red.", ".$green.", ".$blue.", ".round($alpha / 100, 2).")\"";
}
public function __destruct()
{
if (is_file($this->image_temp))
{
unlink($this->image_temp);
}
}
}

@ -1,265 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class Image_Imagick extends \Image_Driver
{
protected $accepted_extensions = array('png', 'gif', 'jpg', 'jpeg');
protected $imagick = null;
public function load($filename, $return_data = false, $force_extension = false)
{
extract(parent::load($filename, $return_data, $force_extension));
if ($this->imagick == null)
{
$this->imagick = new \Imagick();
}
$this->imagick->readImage($filename);
return $this;
}
protected function _crop($x1, $y1, $x2, $y2)
{
extract(parent::_crop($x1, $y1, $x2, $y2));
$width = $x2 - $x1;
$height = $y2 - $y1;
$this->debug("Cropping image ".$width."x".$height."+$x1+$y1 based on coords ($x1, $y1), ($x2, $y2)");
$this->imagick->cropImage($width, $height, $x1, $y1);
$this->imagick->setImagePage(0, 0, 0, 0);
}
protected function _resize($width, $height = null, $keepar = true, $pad = true)
{
extract(parent::_resize($width, $height, $keepar, $pad));
$this->imagick->scaleImage($width, $height, $keepar);
if ($pad)
{
$tmpimage = new \Imagick();
$tmpimage->newImage($cwidth, $cheight, $this->create_color('#000', 0), 'png');
$tmpimage->compositeImage($this->imagick, \Imagick::COMPOSITE_DEFAULT, ($cwidth-$width) / 2, ($cheight-$height) / 2);
$this->imagick = $tmpimage;
}
}
protected function _rotate($degrees)
{
extract(parent::_rotate($degrees));
$this->imagick->rotateImage($this->create_color('#000', 0), $degrees);
}
protected function _watermark($filename, $position, $padding = 5)
{
extract(parent::_watermark($filename, $position, $padding));
$wmimage = new \Imagick();
$wmimage->readImage($filename);
$wmimage->evaluateImage(\Imagick::EVALUATE_MULTIPLY, $this->config['watermark_alpha'] / 100, \Imagick::CHANNEL_ALPHA);
$this->imagick->compositeImage($wmimage, \Imagick::COMPOSITE_DEFAULT, $x, $y);
}
protected function _flip($direction)
{
switch ($direction)
{
case 'vertical':
$this->imagick->flipImage();
break;
case 'horizontal':
$this->imagick->flopImage();
break;
case 'both':
$this->imagick->flipImage();
$this->imagick->flopImage();
break;
default: return false;
}
}
protected function _border($size, $color = null)
{
extract(parent::_border($size, $color));
$this->imagick->borderImage($this->create_color($color, 100), $size, $size);
}
protected function _mask($maskimage)
{
extract(parent::_mask($maskimage));
$wmimage = new \Imagick();
$wmimage->readImage($maskimage);
$wmimage->setImageMatte(false);
$this->imagick->compositeImage($wmimage, \Imagick::COMPOSITE_COPYOPACITY, 0, 0);
}
protected function _rounded($radius, $sides, $antialias = 0)
{
extract(parent::_rounded($radius, $sides, null));
$sizes = $this->sizes();
$sizes->width_half = $sizes->width / 2;
$sizes->height_half = $sizes->height / 2;
$list = array();
if (!$tl) {
$list = array('x' => 0, 'y' => 0);
}
if (!$tr) {
$list = array('x' => $sizes->width_half, 'y' => 0);
}
if (!$bl) {
$list = array('x' => 0, 'y' => $sizes->height_half);
}
if (!$br) {
$list = array('x' => $sizes->width_half, 'y' => $sizes->height_half);
}
foreach($list as $index => $element) {
$image = $this->imagick->clone();
$image->cropImage($sizes->width_half, $sizes->height_half, $element['x'], $element['y']);
$list[$index]['image'] = $image;
}
$this->imagick->roundCorners($radius, $radius);
foreach($list as $element) {
$this->imagick->compositeImage($element['image'], \Imagick::COMPOSITE_DEFAULT, $element['x'], $element['y']);
}
}
protected function _grayscale()
{
$this->imagick->setImageType(\Imagick::IMGTYPE_GRAYSCALEMATTE);
}
public function sizes($filename = null, $usecache = true)
{
if ($filename === null)
{
return (object) array(
'width' => $this->imagick->getImageWidth(),
'height' => $this->imagick->getImageHeight(),
);
}
$tmpimage = new \Imagick();
$tmpimage->readImage($filename);
return (object) array(
'width' => $tmpimage->getImageWidth(),
'height' => $tmpimage->getImageHeight(),
);
}
public function save($filename = null, $permissions = null)
{
extract(parent::save($filename, $permissions));
$this->run_queue();
$this->add_background();
$filetype = $this->image_extension;
if ($filetype == 'jpg' or $filetype == 'jpeg')
{
$filetype = 'jpeg';
}
if ($this->imagick->getImageFormat() != $filetype)
{
$this->imagick->setImageFormat($filetype);
}
if($this->imagick->getImageFormat() == 'jpeg' and $this->config['quality'] != 100)
{
$this->imagick->setImageCompression(\Imagick::COMPRESSION_JPEG);
$this->imagick->setImageCompressionQuality($this->config['quality']);
$this->imagick->stripImage();
}
file_put_contents($filename, $this->imagick->getImageBlob());
if ($this->config['persistence'] === false)
{
$this->reload();
}
return $this;
}
public function output($filetype = null)
{
extract(parent::output($filetype));
$this->run_queue();
$this->add_background();
if ($filetype == 'jpg' or $filetype == 'jpeg')
{
$filetype = 'jpeg';
}
if ($this->imagick->getImageFormat() != $filetype)
{
$this->imagick->setImageFormat($filetype);
}
if($this->imagick->getImageFormat() == 'jpeg' and $this->config['quality'] != 100)
{
$this->imagick->setImageCompression(\Imagick::COMPRESSION_JPEG);
$this->imagick->setImageCompressionQuality($this->config['quality']);
$this->imagick->stripImage();
}
if ( ! $this->config['debug'])
{
echo $this->imagick->getImageBlob();
}
return $this;
}
protected function add_background()
{
if($this->config['bgcolor'] != null)
{
$tmpimage = new \Imagick();
$sizes = $this->sizes();
$tmpimage->newImage($sizes->width, $sizes->height, $this->create_color($this->config['bgcolor'], $this->config['bgcolor'] == null ? 0 : 100), 'png');
$tmpimage->compositeImage($this->imagick, \Imagick::COMPOSITE_DEFAULT, 0, 0);
$this->imagick = $tmpimage;
}
}
/**
* Creates a new color usable by Imagick.
*
* @param string $hex The hex code of the color
* @param integer $alpha The alpha of the color, 0 (trans) to 100 (opaque)
* @return string rgba representation of the hex and alpha values.
*/
protected function create_color($hex, $alpha)
{
extract($this->create_hex_color($hex));
return new \ImagickPixel('rgba('.$red.', '.$green.', '.$blue.', '.round($alpha / 100, 2).')');
}
}

@ -1,461 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Some of this code was written by Flinn Mueller.
*
* @package Fuel
* @category Core
* @copyright Flinn Mueller
* @link http://docs.fuelphp.com/classes/inlector.html
*/
class Inflector
{
/**
* @var array default list of uncountable words, in English
*/
protected static $uncountable_words = array(
'equipment', 'information', 'rice', 'money',
'species', 'series', 'fish', 'meta',
);
/**
* @var array default list of iregular plural words, in English
*/
protected static $plural_rules = array(
'/^(ox)$/i' => '\1\2en', // ox
'/([m|l])ouse$/i' => '\1ice', // mouse, louse
'/(matr|vert|ind)ix|ex$/i' => '\1ices', // matrix, vertex, index
'/(x|ch|ss|sh)$/i' => '\1es', // search, switch, fix, box, process, address
'/([^aeiouy]|qu)y$/i' => '\1ies', // query, ability, agency
'/(hive)$/i' => '\1s', // archive, hive
'/(?:([^f])fe|([lr])f)$/i' => '\1\2ves', // half, safe, wife
'/sis$/i' => 'ses', // basis, diagnosis
'/([ti])um$/i' => '\1a', // datum, medium
'/(p)erson$/i' => '\1eople', // person, salesperson
'/(m)an$/i' => '\1en', // man, woman, spokesman
'/(c)hild$/i' => '\1hildren', // child
'/(buffal|tomat)o$/i' => '\1\2oes', // buffalo, tomato
'/(bu|campu)s$/i' => '\1\2ses', // bus, campus
'/(alias|status|virus)$/i' => '\1es', // alias
'/(octop)us$/i' => '\1i', // octopus
'/(ax|cris|test)is$/i' => '\1es', // axis, crisis
'/s$/' => 's', // no change (compatibility)
'/$/' => 's',
);
/**
* @var array default list of iregular singular words, in English
*/
protected static $singular_rules = array(
'/(matr)ices$/i' => '\1ix',
'/(vert|ind)ices$/i' => '\1ex',
'/^(ox)en/i' => '\1',
'/(alias)es$/i' => '\1',
'/([octop|vir])i$/i' => '\1us',
'/(cris|ax|test)es$/i' => '\1is',
'/(shoe)s$/i' => '\1',
'/(o)es$/i' => '\1',
'/(bus|campus)es$/i' => '\1',
'/([m|l])ice$/i' => '\1ouse',
'/(x|ch|ss|sh)es$/i' => '\1',
'/(m)ovies$/i' => '\1\2ovie',
'/(s)eries$/i' => '\1\2eries',
'/([^aeiouy]|qu)ies$/i' => '\1y',
'/([lr])ves$/i' => '\1f',
'/(tive)s$/i' => '\1',
'/(hive)s$/i' => '\1',
'/([^f])ves$/i' => '\1fe',
'/(^analy)ses$/i' => '\1sis',
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
'/([ti])a$/i' => '\1um',
'/(p)eople$/i' => '\1\2erson',
'/(m)en$/i' => '\1an',
'/(s)tatuses$/i' => '\1\2tatus',
'/(c)hildren$/i' => '\1\2hild',
'/(n)ews$/i' => '\1\2ews',
'/([^us])s$/i' => '\1',
);
/**
* Load any localized rules on first load
*/
public static function _init()
{
static::load_rules();
}
/**
* Load any localized rulesets based on the current language configuration
* If not exists, the current rules remain active
*/
public static function load_rules()
{
\Lang::load('inflector', true, false, true);
if ($rules = \Lang::get('inflector.uncountable_words', array()))
{
static::$uncountable_words = $rules;
}
if ($rules = \Lang::get('inflector.singular_rules', array()))
{
static::$singular_rules = $rules;
}
if ($rules = \Lang::get('inflector.plural_rules', array()))
{
static::$plural_rules = $rules;
}
}
/**
* Add order suffix to numbers ex. 1st 2nd 3rd 4th 5th
*
* @param int $number the number to ordinalize
* @return string the ordinalized version of $number
* @link http://snipplr.com/view/4627/a-function-to-add-a-prefix-to-numbers-ex-1st-2nd-3rd-4th-5th/
*/
public static function ordinalize($number)
{
if ( ! is_numeric($number))
{
return $number;
}
if (in_array(($number % 100), range(11, 13)))
{
return $number . 'th';
}
else
{
switch ($number % 10)
{
case 1:
return $number . 'st';
break;
case 2:
return $number . 'nd';
break;
case 3:
return $number . 'rd';
break;
default:
return $number . 'th';
break;
}
}
}
/**
* Gets the plural version of the given word
*
* @param string $word the word to pluralize
* @param int $count number of instances
* @return string the plural version of $word
*/
public static function pluralize($word, $count = 0)
{
$result = strval($word);
// If a counter is provided, and that equals 1
// return as singular.
if ($count === 1)
{
return $result;
}
if ( ! static::is_countable($result))
{
return $result;
}
foreach (static::$plural_rules as $rule => $replacement)
{
if (preg_match($rule, $result))
{
$result = preg_replace($rule, $replacement, $result);
break;
}
}
return $result;
}
/**
* Gets the singular version of the given word
*
* @param string $word the word to singularize
* @return string the singular version of $word
*/
public static function singularize($word)
{
$result = strval($word);
if ( ! static::is_countable($result))
{
return $result;
}
foreach (static::$singular_rules as $rule => $replacement)
{
if (preg_match($rule, $result))
{
$result = preg_replace($rule, $replacement, $result);
break;
}
}
return $result;
}
/**
* Takes a string that has words separated by underscores and turns it into
* a CamelCased string.
*
* @param string $underscored_word the underscored word
* @return string the CamelCased version of $underscored_word
*/
public static function camelize($underscored_word)
{
return preg_replace_callback(
'/(^|_)(.)/',
function ($parm)
{
return strtoupper($parm[2]);
},
strval($underscored_word)
);
}
/**
* Takes a CamelCased string and returns an underscore separated version.
*
* @param string $camel_cased_word the CamelCased word
* @return string an underscore separated version of $camel_cased_word
*/
public static function underscore($camel_cased_word)
{
return \Str::lower(preg_replace('/([A-Z]+)([A-Z])/', '\1_\2', preg_replace('/([a-z\d])([A-Z])/', '\1_\2', strval($camel_cased_word))));
}
/**
* Translate string to 7-bit ASCII
* Only works with UTF-8.
*
* @param string $str string to translate
* @param bool $allow_non_ascii whether to remove non ascii
* @return string translated string
*/
public static function ascii($str, $allow_non_ascii = false)
{
// Translate unicode characters to their simpler counterparts
\Config::load('ascii', true);
$foreign_characters = \Config::get('ascii');
$str = preg_replace(array_keys($foreign_characters), array_values($foreign_characters), $str);
if ( ! $allow_non_ascii)
{
return preg_replace('/[^\x09\x0A\x0D\x20-\x7E]/', '', $str);
}
return $str;
}
/**
* Converts your text to a URL-friendly title so it can be used in the URL.
* Only works with UTF8 input and and only outputs 7 bit ASCII characters.
*
* @param string $str the text
* @param string $sep the separator
* @param bool $lowercase whether to convert to lowercase
* @param bool $allow_non_ascii whether to allow non ascii
* @return string the new title
*/
public static function friendly_title($str, $sep = '-', $lowercase = false, $allow_non_ascii = false)
{
// Remove tags
$str = \Security::strip_tags($str);
// Decode all entities to their simpler forms
$str = html_entity_decode($str, ENT_QUOTES, 'UTF-8');
// Only allow 7bit characters
$str = static::ascii($str, $allow_non_ascii);
if ($allow_non_ascii)
{
// Strip regular special chars
$str = preg_replace("#[\.;:\]\}\[\{\+\)\(\*&\^\$\#@\!±`%~']#iu", '', $str);
}
else
{
// Strip unwanted characters
$str = preg_replace("#[^a-z0-9]#i", $sep, $str);
}
// Remove all quotes
$str = preg_replace("#[\"\']#", '', $str);
// Replace apostrophes by separators
$str = preg_replace("#[\]#", '-', $str);
// Replace repeating characters
$str = preg_replace("#[/_|+ -]+#u", $sep, $str);
// Remove separators from both ends
$str = trim($str, $sep);
// And convert to lowercase if needed
if ($lowercase === true)
{
$str = \Str::lower($str);
}
return $str;
}
/**
* Turns an underscore or dash separated word and turns it into a human looking string.
*
* @param string $str the word
* @param string $sep the separator (either _ or -)
* @param bool $lowercase lowercase string and upper case first
* @return string the human version of given string
*/
public static function humanize($str, $sep = '_', $lowercase = true)
{
// Allow dash, otherwise default to underscore
$sep = $sep != '-' ? '_' : $sep;
if ($lowercase === true)
{
$str = \Str::ucfirst($str);
}
return str_replace($sep, " ", strval($str));
}
/**
* Takes the class name out of a modulized string.
*
* @param string $class_name_in_module the modulized class
* @return string the string without the class name
*/
public static function demodulize($class_name_in_module)
{
return preg_replace('/^.*::/', '', strval($class_name_in_module));
}
/**
* Takes the namespace off the given class name.
*
* @param string $class_name the class name
* @return string the string without the namespace
*/
public static function denamespace($class_name)
{
$class_name = trim($class_name, '\\');
if ($last_separator = strrpos($class_name, '\\'))
{
$class_name = substr($class_name, $last_separator + 1);
}
return $class_name;
}
/**
* Returns the namespace of the given class name.
*
* @param string $class_name the class name
* @return string the string without the namespace
*/
public static function get_namespace($class_name)
{
$class_name = trim($class_name, '\\');
if ($last_separator = strrpos($class_name, '\\'))
{
return substr($class_name, 0, $last_separator + 1);
}
return '';
}
/**
* Takes a class name and determines the table name. The table name is a
* pluralized version of the class name.
*
* @param string $class_name the table name
* @return string the table name
*/
public static function tableize($class_name)
{
$class_name = static::denamespace($class_name);
if (strncasecmp($class_name, 'Model_', 6) === 0)
{
$class_name = substr($class_name, 6);
}
return \Str::lower(static::pluralize(static::underscore($class_name)));
}
/**
* Takes an underscored classname and uppercases all letters after the underscores.
*
* @param string $class classname
* @param string $sep separator
* @return string
*/
public static function words_to_upper($class, $sep = '_')
{
return str_replace(' ', $sep, ucwords(str_replace($sep, ' ', $class)));
}
/**
* Takes a table name and creates the class name.
*
* @param string $name the table name
* @param bool $force_singular whether to singularize the table name or not
* @return string the class name
*/
public static function classify($name, $force_singular = true)
{
$class = ($force_singular) ? static::singularize($name) : $name;
return static::words_to_upper($class);
}
/**
* Gets the foreign key for a given class.
*
* @param string $class_name the class name
* @param bool $use_underscore whether to use an underscore or not
* @return string the foreign key
*/
public static function foreign_key($class_name, $use_underscore = true)
{
$class_name = static::denamespace(\Str::lower($class_name));
if (strncasecmp($class_name, 'Model_', 6) === 0)
{
$class_name = substr($class_name, 6);
}
return static::underscore(static::demodulize($class_name)).($use_underscore ? "_id" : "id");
}
/**
* Checks if the given word has a plural version.
*
* @param string $word the word to check
* @return bool if the word is countable
*/
public static function is_countable($word)
{
return ! (\in_array(\Str::lower(\strval($word)), static::$uncountable_words));
}
}

@ -1,565 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
/**
* Input class
*
* The input class allows you to access HTTP parameters, load server variables
* and user agent details.
*
* @package Fuel
* @category Core
* @link http://docs.fuelphp.com/classes/input.html
*/
class Input
{
/**
* @var $detected_uri The URI that was detected automatically
*/
protected static $detected_uri = null;
/**
* @var $detected_ext The URI extension that was detected automatically
*/
protected static $detected_ext = null;
/**
* @var array $input All of the input (GET, POST, PUT, DELETE, PATCH)
*/
protected static $input = null;
/**
* @var array $put_patch_delete All of the put or delete vars
*/
protected static $put_patch_delete = null;
/**
* @var $php_input Cache for the php://input stream
*/
protected static $php_input = null;
/**
* @var $json parsed request body as json
*/
protected static $json = null;
/**
* @var $xml parsed request body as xml
*/
protected static $xml = null;
/**
* Get the request body interpreted as JSON.
*
* @param mixed $index
* @param mixed $default
* @return array parsed request body content.
*/
public static function json($index = null, $default = null)
{
static::$json === null and static::hydrate_raw_input('json');
return (func_num_args() === 0) ? static::$json : \Arr::get(static::$json, $index, $default);
}
/**
* Get the request body interpreted as XML.
*
* @param mixed $index
* @param mixed $default
* @return array parsed request body content.
*/
public static function xml($index = null, $default = null)
{
static::$xml === null and static::hydrate_raw_input('xml');
return (func_num_args() === 0) ? static::$xml : \Arr::get(static::$xml, $index, $default);
}
/**
* Hydration from raw request (xml/json requests)
*
* @param string $type input type
*/
protected static function hydrate_raw_input($type)
{
static::$php_input === null and static::$php_input = file_get_contents('php://input');
static::$$type = \Security::clean(\Format::forge(static::$php_input, $type)->to_array());
}
/**
* Detects and returns the current URI based on a number of different server
* variables.
*
* @throws \FuelException
* @return string
*/
public static function uri()
{
if (static::$detected_uri !== null)
{
return static::$detected_uri;
}
if (\Fuel::$is_cli)
{
if (($uri = \Cli::option('uri')) !== null)
{
static::$detected_uri = $uri;
}
else
{
static::$detected_uri = \Cli::option(1);
}
return static::$detected_uri;
}
// We want to use PATH_INFO if we can.
if ( ! empty($_SERVER['PATH_INFO']))
{
$uri = $_SERVER['PATH_INFO'];
}
// Only use ORIG_PATH_INFO if it contains the path
elseif ( ! empty($_SERVER['ORIG_PATH_INFO']) and ($path = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['ORIG_PATH_INFO'])) != '')
{
$uri = $path;
}
else
{
// Fall back to parsing the REQUEST URI
if (isset($_SERVER['REQUEST_URI']))
{
$uri = strpos($_SERVER['SCRIPT_NAME'], $_SERVER['REQUEST_URI']) !== 0 ? $_SERVER['REQUEST_URI'] : '';
}
else
{
throw new \FuelException('Unable to detect the URI.');
}
// Remove the base URL from the URI
$base_url = parse_url(\Config::get('base_url'), PHP_URL_PATH);
if ($uri != '' and strncmp($uri, $base_url, strlen($base_url)) === 0)
{
$uri = substr($uri, strlen($base_url) - 1);
}
// If we are using an index file (not mod_rewrite) then remove it
$index_file = \Config::get('index_file');
if ($index_file and strncmp($uri, $index_file, strlen($index_file)) === 0)
{
$uri = substr($uri, strlen($index_file));
}
// When index.php? is used and the config is set wrong, lets just
// be nice and help them out.
if ($index_file and strncmp($uri, '?/', 2) === 0)
{
$uri = substr($uri, 1);
}
// decode the uri, and put any + back (does not mean a space in the url path)
$uri = str_replace("\r", '+', urldecode(str_replace('+', "\r", $uri)));
// Lets split the URI up in case it contains a ?. This would
// indicate the server requires 'index.php?' and that mod_rewrite
// is not being used.
preg_match('#(.*?)\?(.*)#i', $uri, $matches);
// If there are matches then lets set set everything correctly
if ( ! empty($matches))
{
$uri = $matches[1];
// only reconstruct $_GET if we didn't have a query string
if (empty($_SERVER['QUERY_STRING']))
{
$_SERVER['QUERY_STRING'] = $matches[2];
parse_str($matches[2], $_GET);
$_GET = \Security::clean($_GET);
}
}
}
// Deal with any trailing dots
$uri = rtrim($uri, '.');
// Do we have a URI and does it not end on a slash?
if ($uri and substr($uri, -1) !== '/')
{
// Strip the defined url suffix from the uri if needed
$ext = strrchr($uri, '.');
$path = $ext === false ? $uri : substr($uri, 0, -strlen($ext));
// Did we detect something that looks like an extension?
if ( ! empty($ext))
{
// if it has a slash in it, it's a URI segment with a dot in it
if (strpos($ext, '/') === false)
{
static::$detected_ext = ltrim($ext, '.');
if (\Config::get('routing.strip_extension', true))
{
$uri = $path;
}
}
}
}
// Do some final clean up of the uri
static::$detected_uri = \Security::clean_uri($uri, true);
return static::$detected_uri;
}
/**
* Detects and returns the current URI extension
*
* @return string
*/
public static function extension()
{
static::$detected_ext === null and static::uri();
return static::$detected_ext;
}
/**
* Get the public ip address of the user.
*
* @param string $default
* @return array|string
*/
public static function ip($default = '0.0.0.0')
{
return static::server('REMOTE_ADDR', $default);
}
/**
* Get the real ip address of the user. Even if they are using a proxy.
*
* @param string $default the default to return on failure
* @param bool $exclude_reserved exclude private and reserved IPs
* @return string the real ip address of the user
*/
public static function real_ip($default = '0.0.0.0', $exclude_reserved = false)
{
static $server_keys = null;
if (empty($server_keys))
{
$server_keys = array('HTTP_CLIENT_IP', 'REMOTE_ADDR');
if (\Config::get('security.allow_x_headers', false))
{
$server_keys = array_merge(array('HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_X_FORWARDED_FOR'), $server_keys);
}
}
foreach ($server_keys as $key)
{
if ( ! static::server($key))
{
continue;
}
$ips = explode(',', static::server($key));
array_walk($ips, function (&$ip) {
$ip = trim($ip);
});
$ips = array_filter($ips, function($ip) use($exclude_reserved) {
return filter_var($ip, FILTER_VALIDATE_IP, $exclude_reserved ? FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE : null);
});
if ($ips)
{
return reset($ips);
}
}
return \Fuel::value($default);
}
/**
* Return's the protocol that the request was made with
*
* @return string
*/
public static function protocol()
{
if (static::server('HTTPS') == 'on' or
static::server('HTTPS') == 1 or
static::server('SERVER_PORT') == 443 or
(\Config::get('security.allow_x_headers', false) and static::server('HTTP_X_FORWARDED_PROTO') == 'https') or
(\Config::get('security.allow_x_headers', false) and static::server('HTTP_X_FORWARDED_PORT') == 443))
{
return 'https';
}
return 'http';
}
/**
* Return's whether this is an AJAX request or not
*
* @return bool
*/
public static function is_ajax()
{
return (static::server('HTTP_X_REQUESTED_WITH') !== null) and strtolower(static::server('HTTP_X_REQUESTED_WITH')) === 'xmlhttprequest';
}
/**
* Return's the referrer
*
* @param string $default
* @return string
*/
public static function referrer($default = '')
{
return static::server('HTTP_REFERER', $default);
}
/**
* Return's the input method used (GET, POST, DELETE, etc.)
*
* @param string $default
* @return string
*/
public static function method($default = 'GET')
{
// get the method from the current active request
if ($request = \Request::active() and $method = $request->get_method())
{
return $method;
}
// if called before a request is active, fall back to the global server setting
if (\Config::get('security.allow_x_headers', false))
{
return static::server('HTTP_X_HTTP_METHOD_OVERRIDE', static::server('REQUEST_METHOD', $default));
}
else
{
return static::server('REQUEST_METHOD', $default);
}
}
/**
* Return's the user agent
*
* @param $default
* @return string
*/
public static function user_agent($default = '')
{
return static::server('HTTP_USER_AGENT', $default);
}
/**
* Returns all of the GET, POST, PUT and DELETE variables.
*
* @return array
*/
public static function all()
{
static::$input === null and static::hydrate();
return static::$input;
}
/**
* Gets the specified GET variable.
*
* @param string $index The index to get
* @param string $default The default value
* @return string|array
*/
public static function get($index = null, $default = null)
{
return (func_num_args() === 0) ? $_GET : \Arr::get($_GET, $index, $default);
}
/**
* Fetch an item from the POST array
*
* @param string $index The index key
* @param mixed $default The default value
* @return string|array
*/
public static function post($index = null, $default = null)
{
return (func_num_args() === 0) ? $_POST : \Arr::get($_POST, $index, $default);
}
/**
* Fetch an item from the php://input for put arguments
*
* @param string $index The index key
* @param mixed $default The default value
* @return string|array
*/
public static function put($index = null, $default = null)
{
static::$put_patch_delete === null and static::hydrate();
return (func_num_args() === 0) ? static::$put_patch_delete : \Arr::get(static::$put_patch_delete, $index, $default);
}
/**
* Fetch an item from the php://input for patch arguments
*
* @param string $index The index key
* @param mixed $default The default value
* @return string|array
*/
public static function patch($index = null, $default = null)
{
static::$put_patch_delete === null and static::hydrate();
return (func_num_args() === 0) ? static::$put_patch_delete : \Arr::get(static::$put_patch_delete, $index, $default);
}
/**
* Fetch an item from the php://input for delete arguments
*
* @param string $index The index key
* @param mixed $default The default value
* @return string|array
*/
public static function delete($index = null, $default = null)
{
static::$put_patch_delete === null and static::hydrate();
return (is_null($index) and func_num_args() === 0) ? static::$put_patch_delete : \Arr::get(static::$put_patch_delete, $index, $default);
}
/**
* Fetch an item from the FILE array
*
* @param string $index The index key
* @param mixed $default The default value
* @return string|array
*/
public static function file($index = null, $default = null)
{
return (func_num_args() === 0) ? $_FILES : \Arr::get($_FILES, $index, $default);
}
/**
* Fetch an item from either the GET, POST, PUT, PATCH or DELETE array
*
* @param string $index The index key
* @param mixed $default The default value
* @return string|array
*/
public static function param($index = null, $default = null)
{
static::$input === null and static::hydrate();
return \Arr::get(static::$input, $index, $default);
}
/**
* Fetch an item from the COOKIE array
*
* @param string $index The index key
* @param mixed $default The default value
* @return string|array
*/
public static function cookie($index = null, $default = null)
{
return (func_num_args() === 0) ? $_COOKIE : \Arr::get($_COOKIE, $index, $default);
}
/**
* Fetch an item from the SERVER array
*
* @param string $index The index key
* @param mixed $default The default value
* @return string|array
*/
public static function server($index = null, $default = null)
{
return (func_num_args() === 0) ? $_SERVER : \Arr::get($_SERVER, strtoupper($index), $default);
}
/**
* Fetch a item from the HTTP request headers
*
* @param mixed $index
* @param mixed $default
* @return array
*/
public static function headers($index = null, $default = null)
{
static $headers = null;
// do we need to fetch the headers?
if ($headers === null)
{
// deal with fcgi or nginx installs
if ( ! function_exists('getallheaders'))
{
$server = \Arr::filter_prefixed(static::server(), 'HTTP_', true);
foreach ($server as $key => $value)
{
$key = join('-', array_map('ucfirst', explode('_', strtolower($key))));
$headers[$key] = $value;
}
$value = static::server('Content_Type', static::server('Content-Type')) and $headers['Content-Type'] = $value;
$value = static::server('Content_Length', static::server('Content-Length')) and $headers['Content-Length'] = $value;
}
else
{
$headers = getallheaders();
}
}
return empty($headers) ? $default : ((func_num_args() === 0) ? $headers : \Arr::get(array_change_key_case($headers), strtolower($index), $default));
}
/**
* Hydrates the input array
*
* @return void
*/
protected static function hydrate()
{
static::$input = array_merge($_GET, $_POST);
if (static::method() == 'PUT' or static::method() == 'PATCH' or static::method() == 'DELETE')
{
static::$php_input === null and static::$php_input = file_get_contents('php://input');
if (strpos(static::headers('Content-Type'), 'www-form-urlencoded') > 0 and \Config::get('security.form-double-urlencoded', false))
{
static::$php_input = urldecode(static::$php_input);
}
parse_str(static::$php_input, static::$put_patch_delete);
static::$input = array_merge(static::$input, static::$put_patch_delete);
}
else
{
static::$put_patch_delete = array();
}
}
/**
* Return's the query string
*
* @param string $default
* @return string
*/
public static function query_string($default = '')
{
return static::server('QUERY_STRING', $default);
}
}

@ -1,292 +0,0 @@
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class LangException extends \FuelException { }
class Lang
{
/**
* @var array $loaded_files array of loaded files
*/
public static $loaded_files = array();
/**
* @var array language lines
*/
public static $lines = array();
/**
* @var array language(s) to fall back on when loading a file from the current lang fails
*/
public static $fallback;
public static function _init()
{
static::$fallback = (array) \Config::get('language_fallback', 'en');
}
/**
* Returns currently active language.
*
* @return string currently active language
*/
public static function get_lang()
{
$language = \Config::get('language');
empty($language) and $language = static::$fallback[0];
return $language;
}
/**
* Loads a language file.
*
* @param mixed $file string file | language array | Lang_Interface instance
* @param mixed $group null for no group, true for group is filename, false for not storing in the master lang
* @param string|null $language name of the language to load, null for the configured language
* @param bool $overwrite true for array_merge, false for \Arr::merge
* @param bool $reload true to force a reload even if the file is already loaded
* @return array the (loaded) language array
* @throws \FuelException
*/
public static function load($file, $group = null, $language = null, $overwrite = false, $reload = false)
{
// get the active language and all fallback languages
$language or $language = static::get_lang();
$languages = static::$fallback;
// make sure we don't have the active language in the fallback array
if (in_array($language, $languages))
{
unset($languages[array_search($language, $languages)]);
}
// stick the active language to the front of the list
array_unshift($languages, $language);
if ( ! $reload and
! is_array($file) and
! is_object($file) and
array_key_exists($language.'/'.$file, static::$loaded_files))
{
$group === true and $group = $file;
if ($group === null or $group === false or ! isset(static::$lines[$language][$group]))
{
return false;
}
return static::$lines[$language][$group];
}
$lang = array();
if (is_array($file))
{
$lang = $file;
}
elseif (is_string($file))
{
$info = pathinfo($file);
$type = 'php';
if (isset($info['extension']))
{
$type = $info['extension'];
// Keep extension when it's an absolute path, because the finder won't add it
if ($file[0] !== '/' and $file[1] !== ':')
{
$file = substr($file, 0, -(strlen($type) + 1));
}
}
$class = '\\Lang_'.ucfirst($type);
if (class_exists($class))
{
static::$loaded_files[$language.'/'.$file] = func_get_args();
$file = new $class($file, $languages);
}
else
{
throw new \FuelException(sprintf('Invalid lang type "%s".', $type));
}
}
if ($file instanceof Lang_Interface)
{
try
{
$lang = $file->load($overwrite);
}
catch (\LangException $e)
{
$lang = array();
}
$group = $group === true ? $file->group() : $group;
}
isset(static::$lines[$language]) or static::$lines[$language] = array();
if ($group === null)
{
static::$lines[$language] = $overwrite ? array_merge(static::$lines[$language], $lang) : \Arr::merge(static::$lines[$language], $lang);
}
else
{
$group = ($group === true) ? $file : $group;
if ($overwrite)
{
\Arr::set(static::$lines[$language], $group, array_merge(\Arr::get(static::$lines[$language], $group, array()), $lang));
}
else
{
\Arr::set(static::$lines[$language], $group, \Arr::merge(\Arr::get(static::$lines[$language], $group, array()), $lang));
}
}
return $lang;
}
/**
* Save a language array to disk.
*
* @param string $file desired file name
* @param string|array $lang master language array key or language array
* @param string|null $language name of the language to load, null for the configured language
* @return bool false when language is empty or invalid else \File::update result
* @throws \LangException
*/
public static function save($file, $lang, $language = null)
{
($language === null) and $language = static::get_lang();
// prefix the file with the language
if ( ! is_null($language))
{
$file = explode('::', $file);
end($file);
$file[key($file)] = $language.DS.end($file);
$file = implode('::', $file);
}
if ( ! is_array($lang))
{
if ( ! isset(static::$lines[$language][$lang]))
{
return false;
}
$lang = static::$lines[$language][$lang];
}
$type = pathinfo($file, PATHINFO_EXTENSION);
if( ! $type)
{
$type = 'php';
$file .= '.'.$type;
}
$class = '\\Lang_'.ucfirst($type);
if( ! class_exists($class, true))
{
throw new \LangException('Cannot save a language file of type: '.$type);
}
$driver = new $class;
return $driver->save($file, $lang);
}
/**
* Returns a (dot notated) language string
*
* @param string $line key for the line
* @param array $params array of params to str_replace
* @param mixed $default default value to return
* @param string|null $language name of the language to get, null for the configured language
* @return mixed either the line or default when not found
*/
public static function get($line, array $params = array(), $default = null, $language = null)
{
($language === null) and $language = static::get_lang();
return isset(static::$lines[$language]) ? \Str::tr(\Fuel::value(\Arr::get(static::$lines[$language], $line, $default)), $params) : $default;
}
/**
* Sets a (dot notated) language string
*
* @param string $line a (dot notated) language key
* @param mixed $value the language string
* @param string $group group
* @param string|null $language name of the language to set, null for the configured language
* @return void the \Arr::set result
*/
public static function set($line, $value, $group = null, $language = null)
{
$group === null or $line = $group.'.'.$line;
($language === null) and $language = static::get_lang();
isset(static::$lines[$language]) or static::$lines[$language] = array();
\Arr::set(static::$lines[$language], $line, \Fuel::value($value));
}
/**
* Deletes a (dot notated) language string
*
* @param string $item a (dot notated) language key
* @param string $group group
* @param string|null $language name of the language to set, null for the configured language
* @return array|bool the \Arr::delete result, success boolean or array of success booleans
*/
public static function delete($item, $group = null, $language = null)
{
$group === null or $item = $group.'.'.$item;
($language === null) and $language = static::get_lang();
return isset(static::$lines[$language]) ? \Arr::delete(static::$lines[$language], $item) : false;
}
/**
* Sets the current language, and optionally reloads all language files loaded in another language
*
* @param string $language name of the language to activate
* @param bool $reload true to force a reload of already loaded language files
* @return bool success boolean, false if no language or the current was passed, true otherwise
*/
public static function set_lang($language, $reload = false)
{
// check if a language was passedd
if ( ! empty($language) and $language != static::get_lang())
{
// set it
\Config::set('language', $language);
// do we need to reload?
if ($reload)
{
foreach (static::$loaded_files as $file => $args)
{
// reload with exactly the same arguments
if (strpos($file, $language.'/') !== 0)
{
call_user_func_array('Lang::load', $args);
}
}
}
// return success
return true;
}
// no language or the current language was passed
return false;
}
}

@ -1,173 +0,0 @@
<?php
namespace Fuel\Core;
/**
* DB lang data parser
*/
class Lang_Db implements Lang_Interface
{
protected $identifier;
protected $ext = '.db';
protected $languages = array();
protected $vars = array();
protected $table;
/**
* Sets up the file to be parsed and variables
*
* @param string $identifier Lang identifier name
* @param array $languages Languages to scan for the lang file
* @param array $vars Variables to parse in the data retrieved
*/
public function __construct($identifier = null, $languages = array(), $vars = array())
{
$this->identifier = $identifier;
// we need the highest priority language last in the list
$this->languages = array_reverse($languages);
$this->vars = array(
'APPPATH' => APPPATH,
'COREPATH' => COREPATH,
'PKGPATH' => PKGPATH,
'DOCROOT' => DOCROOT,
) + $vars;
$this->table = \Config::get('lang.table_name', 'lang');
}
/**
* Loads the language file(s).
*
* @param bool $overwrite Whether to overwrite existing values
* @return array the language array
* @throws \Database_Exception
*/
public function load($overwrite = false)
{
$lang = array();
foreach ($this->languages as $language)
{
// try to retrieve the config from the database
try
{
$result = \DB::select('lang')->from($this->table)->where('identifier', '=', $this->identifier)->where('language', '=', $language)->execute();
}
catch (Database_Exception $e)
{
// strip the actual query from the message
$msg = $e->getMessage();
$msg = substr($msg, 0, strlen($msg) - strlen(strrchr($msg, ':')));
// and rethrow it
throw new \Database_Exception($msg);
}
// did we succeed?
if ($result->count())
{
if ( ! empty($result[0]['lang']))
{
$lang = $overwrite ?
array_merge($lang, unserialize($this->parse_vars($result[0]['lang']))) :
\Arr::merge($lang, unserialize($this->parse_vars($result[0]['lang'])));
}
}
}
return $lang;
}
/**
* Gets the default group name.
*
* @return string
*/
public function group()
{
return $this->identifier;
}
/**
* Parses a string using all of the previously set variables. Allows you to
* use something like %APPPATH% in non-PHP files.
*
* @param string $string String to parse
* @return string
*/
protected function parse_vars($string)
{
foreach ($this->vars as $var => $val)
{
$string = str_replace("%$var%", $val, $string);
}
return $string;
}
/**
* Replaces FuelPHP's path constants to their string counterparts.
*
* @param array $array array to be prepped
* @return array prepped array
*/
protected function prep_vars(&$array)
{
static $replacements = false;
if ($replacements === false)
{
foreach ($this->vars as $i => $v)
{
$replacements['#^('.preg_quote($v).'){1}(.*)?#'] = "%".$i."%$2";
}
}
foreach ($array as $i => $value)
{
if (is_string($value))
{
$array[$i] = preg_replace(array_keys($replacements), array_values($replacements), $value);
}
elseif(is_array($value))
{
$this->prep_vars($array[$i]);
}
}
}
/**
* Formats the output and saved it to the database.
*
* @param string $identifier filename
* @param $contents $contents language array to save
* @return bool DB result
*/
public function save($identifier, $contents)
{
// get the language and the identifier
list($language, $identifier) = explode(DS, $identifier, 2);
$identifier = basename($identifier, '.db');
// prep the contents
$this->prep_vars($contents);
$contents = serialize($contents);
// update the config in the database
$result = \DB::update($this->table)->set(array('lang' => $contents, 'hash' => uniqid()))->where('identifier', '=', $identifier)->where('language', '=', $language)->execute();
// if there wasn't an update, do an insert
if ($result === 0)
{
list($notused, $result) = \DB::insert($this->table)->set(array('identifier' => $identifier, 'language' => $language, 'lang' => $contents, 'hash' => uniqid()))->execute();
}
return $result === 1;
}
}

@ -1,210 +0,0 @@
<?php
namespace Fuel\Core;
/**
* A base Lang File class for File based configs.
*/
abstract class Lang_File implements Lang_Interface
{
protected $file;
protected $languages = array();
protected $vars = array();
/**
* Sets up the file to be parsed and variables
*
* @param string $file Lang file name
* @param array $languages Languages to scan for the lang file
* @param array $vars Variables to parse in the file
*/
public function __construct($file = null, $languages = array(), $vars = array())
{
$this->file = $file;
$this->languages = $languages;
$this->vars = array(
'APPPATH' => APPPATH,
'COREPATH' => COREPATH,
'PKGPATH' => PKGPATH,
'DOCROOT' => DOCROOT,
) + $vars;
}
/**
* Loads the language file(s).
*
* @param bool $overwrite Whether to overwrite existing values
* @return array the language array
*/
public function load($overwrite = false)
{
$paths = $this->find_file();
$lang = array();
foreach ($paths as $path)
{
$lang = $overwrite ?
array_merge($lang, $this->load_file($path)) :
\Arr::merge($lang, $this->load_file($path));
}
return $lang;
}
/**
* Gets the default group name.
*
* @return string
*/
public function group()
{
return $this->file;
}
/**
* Parses a string using all of the previously set variables. Allows you to
* use something like %APPPATH% in non-PHP files.
*
* @param string $string String to parse
* @return string
*/
protected function parse_vars($string)
{
foreach ($this->vars as $var => $val)
{
$string = str_replace("%$var%", $val, $string);
}
return $string;
}
/**
* Replaces FuelPHP's path constants to their string counterparts.
*
* @param array $array array to be prepped
* @return array prepped array
*/
protected function prep_vars(&$array)
{
static $replacements = false;
if ($replacements === false)
{
foreach ($this->vars as $i => $v)
{
$replacements['#^('.preg_quote($v).'){1}(.*)?#'] = "%".$i."%$2";
}
}
foreach ($array as $i => $value)
{
if (is_string($value))
{
$array[$i] = preg_replace(array_keys($replacements), array_values($replacements), $value);
}
elseif(is_array($value))
{
$this->prep_vars($array[$i]);
}
}
}
/**
* Finds the given language files
*
* @return array
* @throws \LangException
*/
protected function find_file()
{
$paths = array();
foreach ($this->languages as $lang)
{
$paths = array_merge($paths, \Finder::search('lang'.DS.$lang, $this->file, $this->ext, true));
}
if (empty($paths))
{
throw new \LangException(sprintf('File "%s" does not exist.', $this->file));
}
return array_reverse($paths);
}
/**
* Formats the output and saved it to disc.
*
* @param string $identifier filename
* @param $contents $contents language array to save
* @return bool \File::update result
*/
public function save($identifier, $contents)
{
// get the formatted output
$output = $this->export_format($contents);
if ( ! $output)
{
return false;
}
if ( ! $path = \Finder::search('lang', $identifier))
{
if ($pos = strripos($identifier, '::'))
{
// get the namespace path
if ($path = \Autoloader::namespace_path('\\'.ucfirst(substr($identifier, 0, $pos))))
{
// strip the namespace from the filename
$identifier = substr($identifier, $pos+2);
// strip the classes directory as we need the module root
$path = substr($path, 0, -8).'lang'.DS.$identifier;
}
else
{
// invalid namespace requested
return false;
}
}
}
// absolute path requested?
if ($identifier[0] === '/' or (isset($identifier[1]) and $identifier[1] === ':'))
{
$path = $identifier;
}
// make sure we have a fallback
$path or $path = APPPATH.'lang'.DS.$identifier;
$path = pathinfo($path);
if ( ! is_dir($path['dirname']))
{
mkdir($path['dirname'], 0777, true);
}
return \File::update($path['dirname'], $path['basename'], $output);
}
/**
* Must be implemented by child class. Gets called for each file to load.
*
* @param string $file File to load
* @return array
*/
abstract protected function load_file($file);
/**
* Must be impletmented by child class. Gets called when saving a language file.
*
* @param array $contents language array to save
* @return string formatted output
*/
abstract protected function export_format($contents);
}

@ -1,35 +0,0 @@
<?php
namespace Fuel\Core;
/**
* INI Lang file parser
*/
class Lang_Ini extends \Lang_File
{
protected $ext = '.ini';
/**
* Loads in the given file and parses it.
*
* @param string $file File to load
* @return array
*/
protected function load_file($file)
{
$contents = $this->parse_vars(file_get_contents($file));
return parse_ini_string($contents, true);
}
/**
* Returns the formatted language file contents.
*
* @param array $contents language array
* @return string formatted language file contents
* @throws \LangException
*/
protected function export_format($contents)
{
throw new \LangException('Saving lang to ini is not supported at this time');
}
}

@ -1,10 +0,0 @@
<?php
namespace Fuel\Core;
interface Lang_Interface
{
public function load($overwrite = false);
public function group();
public function save($identifier, $contents);
}

@ -1,35 +0,0 @@
<?php
namespace Fuel\Core;
/**
* JSON Lang file parser
*/
class Lang_Json extends \Lang_File
{
protected $ext = '.json';
/**
* Loads in the given file and parses it.
*
* @param string $file File to load
* @return array
*/
protected function load_file($file)
{
$contents = $this->parse_vars(file_get_contents($file));
return json_decode($contents, true);
}
/**
* Returns the formatted language file contents.
*
* @param array $contents config array
* @return string formatted config file contents
*/
protected function export_format($contents)
{
$this->prep_vars($contents);
return \Format::forge()->to_json($contents, true);
}
}

@ -1,126 +0,0 @@
<?php
namespace Fuel\Core;
/**
* PHP Lang file parser
*/
class Lang_Php extends \Lang_File
{
/**
* @var bool whether or not opcache is in use
*/
protected static $uses_opcache = false;
/**
* @var bool whether or not APC is in use
*/
protected static $uses_apc = false;
/**
* @var bool whether or not we need to flush the opcode cache after a save
*/
protected static $flush_needed = false;
/**
* check the status of any opcache mechanism in use
*/
public static function _init()
{
// do we have Opcache active?
static::$uses_opcache = (PHP_VERSION_ID >= 50500 and function_exists('opcache_invalidate'));
// do we have APC active?
static::$uses_apc = function_exists('apc_compile_file');
// determine if we have an opcode cache active
static::$flush_needed = static::$uses_opcache or static::$uses_apc;
}
/**
* @var string the extension used by this config file parser
*/
protected $ext = '.php';
/**
* Formats the output and saved it to disc.
*
* @param string $identifier filename
* @param $contents $contents language array to save
* @return bool \File::update result
*/
public function save($identifier, $contents)
{
// store the current filename
$file = $this->file;
// save it
$return = parent::save($identifier, $contents);
// existing file? saved? and do we need to flush the opcode cache?
if ($file == $this->file and $return and static::$flush_needed)
{
if ($this->file[0] !== '/' and ( ! isset($this->file[1]) or $this->file[1] !== ':'))
{
// locate the file
if ($pos = strripos($identifier, '::'))
{
// get the namespace path
if ($file = \Autoloader::namespace_path('\\'.ucfirst(substr($identifier, 0, $pos))))
{
// strip the namespace from the filename
$identifier = substr($identifier, $pos+2);
// strip the classes directory as we need the module root
$file = substr($file, 0, -8).'lang'.DS.$identifier;
}
else
{
// invalid namespace requested
return false;
}
}
else
{
$file = \Finder::search('lang', $identifier);
}
}
// make sure we have a fallback
$file or $file = APPPATH.'lang'.DS.$identifier;
// flush the opcode caches that are active
static::$uses_opcache and opcache_invalidate($file, true);
static::$uses_apc and apc_compile_file($file);
}
return $return;
}
/**
* Loads in the given file and parses it.
*
* @param string $file File to load
* @return array
*/
protected function load_file($file)
{
return \Fuel::load($file);
}
/**
* Returns the formatted language file contents.
*
* @param array $contents config array
* @return string formatted config file contents
*/
protected function export_format($contents)
{
$output = <<<CONF
<?php
CONF;
$output .= 'return '.str_replace(array(' ', 'array (', '\''.APPPATH, '\''.DOCROOT, '\''.COREPATH, '\''.PKGPATH), array("\t", 'array(', 'APPPATH.\'', 'DOCROOT.\'', 'COREPATH.\'', 'PKGPATH.\''), var_export($contents, true)).";\n";
return $output;
}
}

@ -1,40 +0,0 @@
<?php
namespace Fuel\Core;
/**
* Yaml Lang file parser
*/
class Lang_Yml extends \Lang_File
{
protected $ext = '.yml';
/**
* Loads in the given file and parses it.
*
* @param string $file File to load
* @return array
*/
protected function load_file($file)
{
$contents = $this->parse_vars(file_get_contents($file));
return \Format::forge($contents, 'yaml')->to_array();
}
/**
* Returns the formatted language file contents.
*
* @param array $contents config array
* @return string formatted config file contents
*/
protected function export_format($contents)
{
if ( ! function_exists('spyc_load'))
{
import('spyc/spyc', 'vendor');
}
$this->prep_vars($contents);
return \Spyc::YAMLDump($contents);
}
}

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

Loading…
Cancel
Save