diff --git a/OpenVBX/config/autoload.php b/OpenVBX/config/autoload.php index f38b7359..997b55a2 100644 --- a/OpenVBX/config/autoload.php +++ b/OpenVBX/config/autoload.php @@ -8,7 +8,7 @@ | In order to keep the framework as light-weight as possible only the | absolute minimal resources are loaded by default. For example, | the database is not connected to automatically since no assumption -| is made regarding whether you intend to use it. This file lets +| is made regarding whether you intend to use it. This file lets | you globally define which systems you would like loaded with every | request. | @@ -18,15 +18,28 @@ | | These are the things you can load automatically: | -| 1. Libraries -| 2. Helper files -| 3. Plugins -| 4. Custom config files -| 5. Language files -| 6. Models +| 1. Packages +| 2. Libraries +| 3. Drivers +| 4. Helper files +| 5. Custom config files +| 6. Language files +| 7. Models | */ +/* +| ------------------------------------------------------------------- +| Auto-load Packages +| ------------------------------------------------------------------- +| Prototype: +| +| $autoload['packages'] = array(APPPATH.'third_party', '/usr/local/shared'); +| +*/ + +$autoload['packages'] = array(); + /* | ------------------------------------------------------------------- | Auto-load Libraries @@ -43,26 +56,29 @@ /* | ------------------------------------------------------------------- -| Auto-load Helper Files +| Auto-load Drivers | ------------------------------------------------------------------- +| These classes are located in the system/libraries folder or in your +| application/libraries folder within their own subdirectory. They +| offer multiple interchangeable driver options. +| | Prototype: | -| $autoload['helper'] = array('url', 'file'); +| $autoload['drivers'] = array('session', 'cache'); */ -$autoload['helper'] = array('applet', 'url', 'format', 'form', 'mail', 'json', 'model', 'banner'); - +$autoload['drivers'] = array(); /* | ------------------------------------------------------------------- -| Auto-load Plugins +| Auto-load Helper Files | ------------------------------------------------------------------- | Prototype: | -| $autoload['plugin'] = array('captcha', 'js_calendar'); +| $autoload['helper'] = array('url', 'file'); */ -$autoload['plugin'] = array(); +$autoload['helper'] = array('applet', 'url', 'format', 'form', 'mail', 'json', 'model', 'banner'); /* diff --git a/OpenVBX/config/cache.php b/OpenVBX/config/cache.php index 2b1b4815..473964ff 100644 --- a/OpenVBX/config/cache.php +++ b/OpenVBX/config/cache.php @@ -53,4 +53,4 @@ */ if (is_file(APPPATH.'config/cache-local.php')) { include_once(APPPATH.'config/cache-local.php'); -} \ No newline at end of file +} diff --git a/OpenVBX/config/config.php b/OpenVBX/config/config.php index 958c0c70..d0c93db5 100755 --- a/OpenVBX/config/config.php +++ b/OpenVBX/config/config.php @@ -317,7 +317,7 @@ | enabled you MUST set an encryption key. See the user guide for info. | */ -$config['encryption_key'] = ""; +$config['encryption_key'] = ''; /* |-------------------------------------------------------------------------- @@ -337,6 +337,7 @@ $config['sess_use_database'] = FALSE; $config['sess_table_name'] = 'sessions'; $config['sess_match_ip'] = FALSE; +$config['sess_match_useragent'] = FALSE; $config['sess_time_to_update'] = 300; /* diff --git a/OpenVBX/config/foreign_chars.php b/OpenVBX/config/foreign_chars.php new file mode 100644 index 00000000..14b0d737 --- /dev/null +++ b/OpenVBX/config/foreign_chars.php @@ -0,0 +1,64 @@ + 'ae', + '/ö|œ/' => 'oe', + '/ü/' => 'ue', + '/Ä/' => 'Ae', + '/Ü/' => 'Ue', + '/Ö/' => 'Oe', + '/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ/' => 'A', + '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª/' => 'a', + '/Ç|Ć|Ĉ|Ċ|Č/' => 'C', + '/ç|ć|ĉ|ċ|č/' => 'c', + '/Ð|Ď|Đ/' => 'D', + '/ð|ď|đ/' => 'd', + '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě/' => 'E', + '/è|é|ê|ë|ē|ĕ|ė|ę|ě/' => 'e', + '/Ĝ|Ğ|Ġ|Ģ/' => 'G', + '/ĝ|ğ|ġ|ģ/' => 'g', + '/Ĥ|Ħ/' => 'H', + '/ĥ|ħ/' => 'h', + '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ/' => 'I', + '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı/' => 'i', + '/Ĵ/' => 'J', + '/ĵ/' => 'j', + '/Ķ/' => 'K', + '/ķ/' => 'k', + '/Ĺ|Ļ|Ľ|Ŀ|Ł/' => 'L', + '/ĺ|ļ|ľ|ŀ|ł/' => 'l', + '/Ñ|Ń|Ņ|Ň/' => 'N', + '/ñ|ń|ņ|ň|ʼn/' => 'n', + '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ/' => 'O', + '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º/' => 'o', + '/Ŕ|Ŗ|Ř/' => 'R', + '/ŕ|ŗ|ř/' => 'r', + '/Ś|Ŝ|Ş|Š/' => 'S', + '/ś|ŝ|ş|š|ſ/' => 's', + '/Ţ|Ť|Ŧ/' => 'T', + '/ţ|ť|ŧ/' => 't', + '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ/' => 'U', + '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ/' => 'u', + '/Ý|Ÿ|Ŷ/' => 'Y', + '/ý|ÿ|ŷ/' => 'y', + '/Ŵ/' => 'W', + '/ŵ/' => 'w', + '/Ź|Ż|Ž/' => 'Z', + '/ź|ż|ž/' => 'z', + '/Æ|Ǽ/' => 'AE', + '/ß/'=> 'ss', + '/IJ/' => 'IJ', + '/ij/' => 'ij', + '/Œ/' => 'OE', + '/ƒ/' => 'f' +); + +/* End of file foreign_chars.php */ +/* Location: ./application/config/foreign_chars.php */ \ No newline at end of file diff --git a/OpenVBX/config/mimes.php b/OpenVBX/config/mimes.php index 438f610c..100f7d44 100644 --- a/OpenVBX/config/mimes.php +++ b/OpenVBX/config/mimes.php @@ -10,12 +10,12 @@ $mimes = array( 'hqx' => 'application/mac-binhex40', 'cpt' => 'application/mac-compactpro', - 'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel'), + 'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel'), 'bin' => 'application/macbinary', 'dms' => 'application/octet-stream', 'lha' => 'application/octet-stream', 'lzh' => 'application/octet-stream', - 'exe' => 'application/octet-stream', + 'exe' => array('application/octet-stream', 'application/x-msdownload'), 'class' => 'application/octet-stream', 'psd' => 'application/x-photoshop', 'so' => 'application/octet-stream', @@ -48,7 +48,7 @@ 'swf' => 'application/x-shockwave-flash', 'sit' => 'application/x-stuffit', 'tar' => 'application/x-tar', - 'tgz' => 'application/x-tar', + 'tgz' => array('application/x-tar', 'application/x-gzip-compressed'), 'xhtml' => 'application/xhtml+xml', 'xht' => 'application/xhtml+xml', 'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed'), @@ -56,7 +56,7 @@ 'midi' => 'audio/midi', 'mpga' => 'audio/mpeg', 'mp2' => 'audio/mpeg', - 'mp3' => array('audio/mpeg', 'audio/mpg'), + 'mp3' => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'), 'aif' => 'audio/x-aiff', 'aiff' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff', @@ -65,8 +65,8 @@ 'rpm' => 'audio/x-pn-realaudio-plugin', 'ra' => 'audio/x-realaudio', 'rv' => 'video/vnd.rn-realvideo', - 'wav' => 'audio/x-wav', - 'bmp' => 'image/bmp', + 'wav' => array('audio/x-wav', 'audio/wave', 'audio/wav'), + 'bmp' => array('image/bmp', 'image/x-windows-bmp'), 'gif' => 'image/gif', 'jpeg' => array('image/jpeg', 'image/pjpeg'), 'jpg' => array('image/jpeg', 'image/pjpeg'), @@ -93,13 +93,14 @@ 'avi' => 'video/x-msvideo', 'movie' => 'video/x-sgi-movie', 'doc' => 'application/msword', - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'docx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip'), + 'xlsx' => array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip'), 'word' => array('application/msword', 'application/octet-stream'), 'xl' => 'application/excel', - 'eml' => 'message/rfc822' + 'eml' => 'message/rfc822', + 'json' => array('application/json', 'text/json') ); /* End of file mimes.php */ -/* Location: ./system/application/config/mimes.php */ \ No newline at end of file +/* Location: ./application/config/mimes.php */ diff --git a/OpenVBX/config/profiler.php b/OpenVBX/config/profiler.php new file mode 100644 index 00000000..f8a5b1a1 --- /dev/null +++ b/OpenVBX/config/profiler.php @@ -0,0 +1,17 @@ + 'Flock', + 'Chrome' => 'Chrome', 'Opera' => 'Opera', 'MSIE' => 'Internet Explorer', 'Internet Explorer' => 'Internet Explorer', @@ -59,8 +61,8 @@ 'Camino' => 'Camino', 'Netscape' => 'Netscape', 'OmniWeb' => 'OmniWeb', - 'Mozilla' => 'Mozilla', 'Safari' => 'Safari', + 'Mozilla' => 'Mozilla', 'Konqueror' => 'Konqueror', 'icab' => 'iCab', 'Lynx' => 'Lynx', @@ -92,6 +94,7 @@ 'nokia' => "Nokia", 'palm' => "Palm", 'iphone' => "Apple iPhone", + 'ipad' => "iPad", 'ipod' => "Apple iPod Touch", 'sony' => "Sony Ericsson", 'ericsson' => "Sony Ericsson", @@ -111,7 +114,7 @@ 'benq' => "BenQ", 'ipaq' => "HP iPaq", 'mot-' => "Motorola", - 'playstation portable' => "PlayStation Portable", + 'playstation portable' => "PlayStation Portable", 'hiptop' => "Danger Hiptop", 'nec-' => "NEC", 'panasonic' => "Panasonic", @@ -124,7 +127,7 @@ // Operating Systems 'symbian' => "Symbian", - 'SymbianOS' => "SymbianOS", + 'SymbianOS' => "SymbianOS", 'elaine' => "Palm", 'palm' => "Palm", 'series60' => "Symbian S60", @@ -149,7 +152,7 @@ // Fallback 'mobile' => "Generic Mobile", - 'wireless' => "Generic Mobile", + 'wireless' => "Generic Mobile", 'j2me' => "Generic Mobile", 'midp' => "Generic Mobile", 'cldc' => "Generic Mobile", @@ -172,4 +175,4 @@ ); /* End of file user_agents.php */ -/* Location: ./system/application/config/user_agents.php */ \ No newline at end of file +/* Location: ./application/config/user_agents.php */ \ No newline at end of file diff --git a/OpenVBX/core/MY_Config.php b/OpenVBX/core/MY_Config.php new file mode 100644 index 00000000..d70c01fe --- /dev/null +++ b/OpenVBX/core/MY_Config.php @@ -0,0 +1,117 @@ +router->tenant)) + { + $url = $ci->router->tenant . '/' . $url; + } + + return self::url_trim(parent::site_url($url)); + } + + public function real_site_url($uri) + { + return self::url_trim(parent::site_url($uri)); + } +} + +function real_site_url($uri) +{ + $CI =& get_instance(); + return $CI->config->real_site_url($uri); +} + +function asset_url($uri) +{ + $CI = &get_instance(); + $url = $CI->config->real_site_url($uri); + $index_page = $CI->config->item('index_page'); + if(strlen($index_page)) + { + $url = str_replace('/'.$index_page, '', $url); + } + + return $url; +} + +function iphone_handler_url($uri) +{ + $CI =& get_instance(); + return 'openvbx://'.$CI->config->item('server_name').'/'.$uri; +} + +function tenant_url($uri, $tenant_id = NULL) +{ + $CI = & get_instance(); + if(!$tenant_id) + $tenant_id = $CI->tenant->id; + $tenant = $CI->settings->get_tenant_by_id($tenant_id); + return $CI->config->real_site_url($tenant->url_prefix . '/' . $uri); +} + +function current_url() +{ + $CI =& get_instance(); + return $CI->config->site_url($CI->uri->uri_string()); +} + +function redirect($uri = '', $method = 'location', $http_response_code = 302) +{ + if(!headers_sent()) + { + $ci = &get_instance(); + if(is_object($ci) + && isset($ci->session) + && is_object($ci->session)) + $ci->session->persist(); + } + else + { + error_log('Unable to write session, headers already sent'); + } + + if ( ! preg_match('#^https?://#i', $uri)) + { + $uri = site_url($uri); + } + + switch($method) + { + case 'refresh' : header("Refresh:0;url=".$uri); + break; + default : header("Location: ".$uri, TRUE, $http_response_code); + break; + } + exit; +} + diff --git a/OpenVBX/libraries/MY_Controller.php b/OpenVBX/core/MY_Controller.php similarity index 99% rename from OpenVBX/libraries/MY_Controller.php rename to OpenVBX/core/MY_Controller.php index 42c637bf..a591f317 100644 --- a/OpenVBX/libraries/MY_Controller.php +++ b/OpenVBX/core/MY_Controller.php @@ -33,7 +33,7 @@ require_once BASEPATH . '../OpenVBX/libraries/AppletInstance.php'; require_once BASEPATH . '../OpenVBX/libraries/Caches/Abstract.php'; -class MY_Controller extends Controller +class MY_Controller extends CI_Controller { protected $user_id; protected $section; diff --git a/OpenVBX/libraries/MY_Model.php b/OpenVBX/core/MY_Model.php similarity index 99% rename from OpenVBX/libraries/MY_Model.php rename to OpenVBX/core/MY_Model.php index d4699991..44904e4a 100644 --- a/OpenVBX/libraries/MY_Model.php +++ b/OpenVBX/core/MY_Model.php @@ -36,7 +36,7 @@ public function __toString() } } -class MY_Model extends Model +class MY_Model extends CI_Model { public static $caching = true; protected static $__CLASS__ = __CLASS__; diff --git a/OpenVBX/core/MY_Pagination.php b/OpenVBX/core/MY_Pagination.php new file mode 100644 index 00000000..7dface0a --- /dev/null +++ b/OpenVBX/core/MY_Pagination.php @@ -0,0 +1,164 @@ +total_rows == 0 OR $this->per_page == 0) + { + return ''; + } + + // Calculate the total number of pages + $num_pages = ceil($this->total_rows / $this->per_page); + + // Is there only one page? Hm... nothing more to do here then. + if ($num_pages == 1) + { + return ''; + } + + // Determine the current page number. + $CI =& get_instance(); + + if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE) + { + if ($CI->input->get($this->query_string_segment) != 0) + { + $this->cur_page = $CI->input->get($this->query_string_segment); + + // Prep the current page - no funny business! + $this->cur_page = (int) $this->cur_page; + } + } + else + { + if ($CI->uri->segment($this->uri_segment) != 0) + { + $this->cur_page = $CI->uri->segment($this->uri_segment); + + // Prep the current page - no funny business! + $this->cur_page = (int) $this->cur_page; + } + } + + $this->num_links = (int)$this->num_links; + + if ($this->num_links < 1) + { + show_error('Your number of links must be a positive number.'); + } + + if ( ! is_numeric($this->cur_page)) + { + $this->cur_page = 0; + } + + // Is the page number beyond the result range? + // If so we show the last page + if ($this->cur_page > $this->total_rows) + { + $this->cur_page = ($num_pages - 1) * $this->per_page; + } + + $uri_page_number = $this->cur_page; + $this->cur_page = floor(($this->cur_page/$this->per_page) + 1); + + // Calculate the start and end numbers. These determine + // which number to start and end the digit links with + $start = (($this->cur_page - $this->num_links) > 0) ? $this->cur_page - ($this->num_links - 1) : 1; + $end = (($this->cur_page + $this->num_links) < $num_pages) ? $this->cur_page + $this->num_links : $num_pages; + + $this->base_url = rtrim($this->base_url).'?'; + + // And here we go... + $output = ''; + + $page_args = array('offset' => '', + 'max' => $this->per_page); + + + // Render the "First" link + if ($this->cur_page > ($this->num_links + 1)) + { + $output .= $this->first_tag_open.''.$this->first_link.''.$this->first_tag_close; + } + + // Render the "previous" link + if ($this->cur_page != 1) + { + $i = $uri_page_number - $this->per_page; + if ($i == 0) $i = ''; + $page_args['offset'] = $i; + $output .= $this->prev_tag_open.''.$this->prev_link.''.$this->prev_tag_close; + } + + // Write the digit links + for ($loop = $start -1; $loop <= $end; $loop++) + { + $i = ($loop * $this->per_page) - $this->per_page; + + if ($i >= 0) + { + if ($this->cur_page == $loop) + { + $output .= $this->cur_tag_open.$loop.$this->cur_tag_close; // Current page + } + else + { + $n = ($i == 0) ? '' : $i; + $page_args['offset'] = $n; + $output .= $this->num_tag_open.''.$loop.''.$this->num_tag_close; + } + } + } + + // Render the "next" link + if ($this->cur_page < $num_pages) + { + $page_args['offset'] = $this->cur_page * $this->per_page; + $output .= $this->next_tag_open.''.$this->next_link.''.$this->next_tag_close; + } + + // Render the "Last" link + if (($this->cur_page + $this->num_links) < $num_pages) + { + $i = (($num_pages * $this->per_page) - $this->per_page); + $page_args['offset'] = $i; + $output .= $this->last_tag_open.''.$this->last_link.''.$this->last_tag_close; + } + + // Kill double slashes. Note: Sometimes we can end up with a double slash + // in the penultimate link so we'll kill all double slashes. + $output = preg_replace("#([^:])//+#", "\\1/", $output); + + // Add the wrapper HTML if exists + $output = $this->full_tag_open.$output.$this->full_tag_close; + + return $output; + } +} \ No newline at end of file diff --git a/OpenVBX/core/MY_Router.php b/OpenVBX/core/MY_Router.php new file mode 100644 index 00000000..4a1aa9df --- /dev/null +++ b/OpenVBX/core/MY_Router.php @@ -0,0 +1,339 @@ +routes))) + { + return false; + } + + if($controller && + !in_array($controller, array_keys($this->routes))) + { + return false; + } + + if(is_null($controller) + && !empty($tenant)) + { + return $segments; + } + + + return $segments; + } + + function _validate_api($segments) + { + $api_prefix = isset($segments[0])? $segments[0] : null; + $api_version = isset($segments[1])? $segments[1] : null; + + if(!$api_prefix) + { + return false; + } + + if($api_prefix != 'api') + { + return false; + } + + switch($api_version) + { + case '2009-12-01': + break; + default: + return false; + } + return true; + } + + function _validate_tenant_api($segments) + { + $tenant = isset($segments[0])? $segments[0] : null; + $api_prefix = isset($segments[1])? $segments[1] : null; + $api_version = isset($segments[2])? $segments[2] : null; + $controller = isset($segments[3])? $segments[3] : null; + + if(!$api_prefix) + { + return false; + } + + if($api_prefix != 'api') + { + return false; + } + + switch($api_version) + { + case '2009-12-01': + break; + default: + return false; + } + + if(is_string($tenant) + && in_array($tenant, array_keys($this->routes))) + { + return false; + } + + if($controller && + !in_array($controller, array_keys($this->routes))) + { + return false; + } + + return true; + } + + function set_tenant($tenant) + { + $this->tenant = $tenant; + } + + function set_api_version($api_version) + { + $this->api_version = $api_version; + } + + function _get_relative_segments($segments) + { + if (file_exists(APPPATH.'controllers/'.$segments[0].EXT)) + { + return $segments; + } + + // Is the controller in a sub-folder? + if (is_dir(APPPATH.'controllers/'.$segments[0])) + { + // Set the directory and remove it from the segment array + $this->set_directory($segments[0]); + + $segments = array_slice($segments, 1); + + if (count($segments) > 0 && + file_exists(APPPATH.'controllers/'.$this->directory + .'/'.$segments[0].EXT)) + { + return $segments; + } + else + { + $this->set_class($this->default_controller); + $this->set_method($this->default_method); + + // Does the default controller exist in the sub-folder? + if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT)) + { + $this->directory = ''; + return array(); + } + + } + + return $segments; + } + + return false; + } + + function _validate_request($segments) + { + // Does the requested controller exist in the root folder? + if (!empty($segments[0]) && file_exists(APPPATH.'controllers/'.$segments[0].EXT)) + { + return $segments; + } + + // Is the controller in a sub-folder? + $segment = (!empty($segments[0])) ? $segments[0] : null; + if (is_dir(APPPATH.'controllers/'.$segment)) + { + // Set the directory and remove it from the segment array + $this->set_directory($segment); + $segments = array_slice($segments, 1); + + if (count($segments) > 0) + { + // Does the requested controller exist in the sub-folder? + if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT)) + { + show_404($this->fetch_directory().$segments[0]); + } + } + else + { + $this->set_class($this->default_controller); + $this->set_method('index'); + + // Does the default controller exist in the sub-folder? + if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT)) + { + $this->directory = ''; + return array(); + } + + } + + return $segments; + } + + // Can't find the requested controller... + show_404($segment); + } + + private function _parse_segments($rel_segments, $segments) + { + $new_segments = array( + $rel_segments[0] + ); + + if(isset($rel_segments[1]) + && ($rel_segments[1] > 0 + || $rel_segments[1] == '0') + ) + { + $new_segments[] = $this->default_method; + $new_segments[] = $rel_segments[1]; + + if(count($rel_segments) > 2) + { + foreach(array_slice($segments, 3) as $seg) + { + $new_segments[] = $seg; + } + } + $this->set_method($this->default_method); + } + else + { + if(isset($rel_segments[1])) + { + $new_segments[] = $rel_segments[1]; + } + + foreach(array_slice($rel_segments, 2) as $seg) + { + $new_segments[] = $seg; + } + } + + $rel_segments = $new_segments; + + return $rel_segments; + } + + function _parse_routes() + { + // Do we even have any custom routing to deal with? + // There is a default scaffolding trigger, so we'll look just for 1 + if (count($this->routes) == 1) + { + $this->_set_request($this->uri->segments); + return; + } + + $segments = $this->uri->segments; + if($this->_validate_api($segments)) + { + $api = $segments[0]; + $api_version = $segments[1]; + $segments = array_slice($segments, 2); + $this->set_api_version($api_version); + $this->uri->segments = $segments; + } + + if(($tenant_segments = $this->_validate_tenant($segments))) + { + $tenant = $segments[0]; + $segments = array_slice($segments, 1); + $this->set_tenant($tenant); + if(empty($segments)) + { + $this->set_directory('iframe'); + $this->uri->segments = array(); + } + else + { + $this->uri->segments = $segments; + } + } + + if($this->_validate_tenant_api($segments)) + { + $tenant = $segments[0]; + $api = $segments[1]; + $api_version = $segments[2]; + $this->set_tenant($tenant); + $this->set_api_version($api_version); + + $segments = array_slice($segments, 3); + + $this->uri->segments = $segments; + } + + // Turn the segment array into a URI string + $uri = implode('/', $this->uri->segments); + + // Is there a literal match? If so we're done + if (isset($this->routes[$uri])) + { + $this->_set_request(explode('/', $this->routes[$uri])); + return; + } + + // Loop through the route array looking for wild-cards + foreach ($this->routes as $key => $val) + { + // Convert wild-cards to RegEx + $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key)); + + // Does the RegEx match? + if (preg_match('#^'.$key.'$#', $uri)) + { + // Do we have a back-reference? + if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE) + { + $val = preg_replace('#^'.$key.'$#', $val, $uri); + } + $this->_set_request(explode('/', $val)); + return; + } + } + + // If we got this far it means we didn't encounter a + // matching route so we'll set the site default route + $this->_set_request($this->uri->segments); + } +} \ No newline at end of file diff --git a/OpenVBX/core/MY_Session.lazy.php b/OpenVBX/core/MY_Session.lazy.php new file mode 100644 index 00000000..a2d91acf --- /dev/null +++ b/OpenVBX/core/MY_Session.lazy.php @@ -0,0 +1,64 @@ + $newval); + } + + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + $this->userdata[$key] = $val; + } + } + + } + + function unset_userdata($newdata = array()) + { + if (is_string($newdata)) + { + $newdata = array($newdata => ''); + } + + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + unset($this->userdata[$key]); + } + } + + } + + public function persist() + { + $this->sess_write(); + } +} \ No newline at end of file diff --git a/OpenVBX/core/MY_Session.php b/OpenVBX/core/MY_Session.php new file mode 100644 index 00000000..56e871c4 --- /dev/null +++ b/OpenVBX/core/MY_Session.php @@ -0,0 +1,26 @@ +id = empty($id) ? 'table_' . uniqid() : $id; + } + + + // -------------------------------------------------------------------- + + /** + * Add a table row + * + * The first parameter will be the {ID} value that is replaced on each row template. + * Data can be passed as an array or discreet params + * + * @access public + * @param mixed + * @return void + */ + function add_id_row($id, $data) + { + $args = func_get_args(); + array_shift($args); + $this->rows[] = (is_array($data)) ? $data : $args; + + $index = count($this->rows) - 1; + $this->row_ids[$index] = $id; + } + + // -------------------------------------------------------------------- + + /** + * Generate the table + * + * @access public + * @param mixed + * @return string + */ + function generate($table_data = NULL) + { + // The table data can optionally be passed to this function + // either as a database result object or an array + if ( ! is_null($table_data)) + { + if (is_object($table_data)) + { + $this->_set_from_object($table_data); + } + elseif (is_array($table_data)) + { + $set_heading = (count($this->heading) == 0 AND $this->auto_heading == FALSE) ? FALSE : TRUE; + $this->_set_from_array($table_data, $set_heading); + } + } + + // Is there anything to display? No? Smite them! + if (count($this->heading) == 0 AND count($this->rows) == 0) + { + return 'Undefined table data'; + } + + // Compile and validate the template date + $this->_compile_template(); + + + // Build the table! + + $out = str_replace('{ID}', $this->id, $this->template['table_open']); + $out .= $this->newline; + + // Add any caption here + if ($this->caption) + { + $out .= $this->newline; + $out .= '' . $this->caption . ''; + $out .= $this->newline; + } + + // Is there a table heading to display? + if (count($this->heading) > 0) + { + $out .= $this->template['heading_row_start']; + $out .= $this->newline; + + for($col = 0; $col < count($this->heading); $col++) + { + $out .= str_replace('{COL}', $col, $this->template['heading_cell_start']); + $out .= $this->heading[$col]; + $out .= $this->template['heading_cell_end']; + } + + $out .= $this->template['heading_row_end']; + $out .= $this->newline; + } + + // Build the table rows + if (count($this->rows) > 0) + { + $i = 1; + $row_find = array('{ROW}', '{ID}'); + for($r = 0; $r < count($this->rows); $r++) + { + $row = $this->rows[$r]; + if ( ! is_array($row)) break; + $row_id = isset($this->row_ids[$r]) ? $this->row_ids[$r] : ''; + + // We use modulus to alternate the row colors + $name = (fmod($i++, 2)) ? '' : 'alt_'; + + $out .= str_replace($row_find, array($r, $row_id), $this->template['row_'.$name.'start']); + $out .= $this->newline; + + for($col = 0; $col < count($row); $col++) + { + $out .= str_replace('{COL}', $col, $this->template['cell_'.$name.'start']); + + $cell = $row[$col]; + if ($cell === "") + { + $out .= $this->empty_cells; + } + else + { + $out .= $cell; + } + + $out .= $this->template['cell_'.$name.'end']; + } + + $out .= $this->template['row_'.$name.'end']; + $out .= $this->newline; + } + } + + $out .= $this->template['table_close']; + + return $out; + } + + function clear() + { + parent::clear(); + $this->row_ids = array(); + } + + // -------------------------------------------------------------------- + + /** + * Default Template + * + * @access private + * @return void + */ + function _default_template() + { + return array ( + 'table_open' => '', + + 'heading_row_start' => '', + 'heading_row_end' => '', + 'heading_cell_start' => '', + + 'row_start' => '', + 'row_end' => '', + 'cell_start' => '', + + 'row_alt_start' => '', + 'row_alt_end' => '', + 'cell_alt_start' => '', + + 'table_close' => '
', + 'heading_cell_end' => '
', + 'cell_end' => '
', + 'cell_alt_end' => '
' + ); + } + +} diff --git a/OpenVBX/core/MY_URI.php b/OpenVBX/core/MY_URI.php new file mode 100644 index 00000000..d8988c11 --- /dev/null +++ b/OpenVBX/core/MY_URI.php @@ -0,0 +1,48 @@ +tenant && $ci->tenant->id > 1) + { + $uri = preg_replace('/^\/'.$ci->tenant->url_prefix.'/i', '', $uri); + } + return $uri; + } + + function _explode_segments() + { + foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val) + { + // Filter segments for security + $val = trim($this->_filter_uri($val)); + $val = preg_replace('/\?.*$/','', $val); + if ($val != '') + { + $this->segments[] = $val; + } + } + } +} diff --git a/OpenVBX/core/User_Controller.php b/OpenVBX/core/User_Controller.php new file mode 100644 index 00000000..d09cbe69 --- /dev/null +++ b/OpenVBX/core/User_Controller.php @@ -0,0 +1,394 @@ +config_check(); + + $this->config->load('openvbx'); + + // check for required configuration values + $this->load->database(); + $this->load->library('ErrorMessages'); // deprecated in 1.2 + $this->load->model('vbx_rest_access'); + $this->load->model('vbx_message'); + + // When we're in testing mode, allow access to set Hiccup configuration + $this->testing_mode = !empty($_REQUEST['vbx_testing_key'])? $_REQUEST['vbx_testing_key'] == $this->config->item('testing-key') : false; + $this->config->set_item('sess_cookie_name', $this->tenant->id . '-' . $this->config->item('sess_cookie_name')); + $this->load->library('session'); + + $keys = array('base_url', 'salt'); + foreach($keys as $key) + { + $item[$key] = $this->config->item($key); + if(empty($item[$key])) + { + redirect('install'); + } + } + + /* Rest API Authentication - one time pass only */ + $singlepass = $this->input->cookie('singlepass'); + if(!empty($singlepass)) + { + $ra = new VBX_Rest_Access(); + $user_id = $ra->auth_key($singlepass); + unset($_COOKIE['singlepass']); + if($user_id) + { + $this->session->set_userdata('user_id', $user_id); + $this->session->set_userdata('loggedin', true); + $this->session->set_userdata('signature', VBX_User::signature($user_id)); + } + } + + $user_id = $this->session->userdata('user_id'); + + // Signature check + if (!empty($user_id)) + { + $signature = $this->session->userdata('signature'); + if (!VBX_User::check_signature($user_id, $signature)) + { + $this->session->set_flashdata('error', 'Your session has expired'); + $this->session->set_userdata('loggedin', false); + } + } + + if($this->response_type == 'json') + { + $this->attempt_digest_auth(); + } + + if (!$this->session->userdata('loggedin') && $this->response_type != 'json') + { + $redirect = site_url($this->uri->uri_string()); + if (!empty($_COOKIE['last_known_url'])) + { + $redirect = $_COOKIE['last_known_url']; + set_last_known_url('', time() - 3600); + } + return redirect('auth/login?redirect='.urlencode($redirect)); + } + + $this->user_id = $this->session->userdata('user_id'); + $this->set_request_method(); + + /* Mark the user as seen */ + if (!empty($this->user_id)) + { + try + { + $user = VBX_User::get($this->user_id); + $user->setting_set('last_seen', new MY_ModelLiteral('UTC_TIMESTAMP()')); + } + catch(VBX_UserException $e) + { + /* Handle this gracefully, but report the error. */ + error_log($e->getMessage()); + } + + $this->connect_check(); + + /* Check for first run */ + if ($this->session->userdata('is_admin') && $this->uri->segment(1) != 'welcome') + { + $this->welcome_check(); + } + + /* Check for updates if an admin */ + if($this->session->userdata('is_admin') && $this->uri->segment(1) != "upgrade") + { + $this->upgrade_check(); + } + + } + } + + protected function redirect($url) + { + redirect($url); + } + + private function config_check() + { + $vbx_config = APPPATH.'config/openvbx.php'; + $db_config = APPPATH.'config/database.php'; + if(!file_exists($vbx_config) || !file_exists($db_config)) + { + redirect('install'); + } + } + + private function upgrade_check() + { + $currentSchemaVersion = OpenVBX::schemaVersion(false); + $upgradingToSchemaVersion = OpenVBX::getLatestSchemaVersion(); + if($currentSchemaVersion != $upgradingToSchemaVersion) + { + redirect('upgrade'); + } + } + + private function welcome_check() + { + if ($this->router->class == 'iframe' || $this->router->class == 'welcome') + { + return false; + } + + if ($this->settings->get('tenant_first_run', $this->tenant->id)) + { + redirect('welcome'); + } + } + + private function connect_check() { + $section = $this->uri->segment(1); + if (!in_array($section, array('welcome', 'auth', 'connect'))) + { + if ($this->twilio_sid == 'unauthorized_client') + { + $redirect_path = 'welcome'; + } + + if ($this->twilio_sid == 'deauthorized_client') { + if ($this->session->userdata('is_admin')) { + $redirect_path = 'welcome'; + } + else { + $redirect_path = 'auth/connect/account_deauthorized'; + } + } + + if (!empty($redirect_path)) { + redirect($redirect_path); + } + } + } + + function digest_parse($digest) + { + // protect against missing data + $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1); + $data = array(); + + preg_match_all('@(\w+)=(?:(?:\'([^\']+)\'|"([^"]+)")|([^\s,]+))@', $digest, $matches, PREG_SET_ORDER); + + foreach ($matches as $m) { + $data[$m[1]] = $m[2] ? $m[2] : ($m[3] ? $m[3] : $m[4]); + unset($needed_parts[$m[1]]); + } + + return $needed_parts ? false : $data; + } + + + function attempt_digest_auth() + { + $message = ''; + + if(isset($_SERVER['Authorization'])) { + // Just in case they ever fix Apache to send the Authorization header on, the following code is included + $headers['Authorization'] = $_SERVER['Authorization']; + } + + if(function_exists('apache_request_headers')) { + // We are running PHP as an Apache module, so we can get the Authorization header this way + $headers = apache_request_headers(); + } + + // Support cgi based auth via rewrite hack: + // --------------------- + // RewriteEngine on + // RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] + // $_SERVER['PHP_AUTH_USER'] = ''; + // $_SERVER['PHP_AUTH_PW'] = ''; + if(isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { + $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; + } + + if (isset($_SERVER['HTTP_AUTHORIZATION'])) { + if(preg_match('/Basic (.*)$/', $_SERVER['HTTP_AUTHORIZATION'], $matches)) + list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = + explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6))); + + } + + // Support standard PHP Authorization magic with apache + if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) { + // Basic authentication information can be retrieved from these server variables + $username = $_SERVER['PHP_AUTH_USER']; + $password = $_SERVER['PHP_AUTH_PW']; + } + + if(isset($headers['Authorization'])) { + $_SERVER['PHP_AUTH_DIGEST'] = $headers['Authorization']; + $data = $this->digest_parse($_SERVER['PHP_AUTH_DIGEST']); + } + + $captcha = ''; + if(isset($headers['Captcha'])) + { + $captcha = $headers['Captcha']; + } + + $captcha_token = ''; + if(isset($headers['CaptchaToken'])) + { + $captcha_token = $headers['CaptchaToken']; + } + + if (isset($username) && isset($password)) + { + log_message('info', 'Logging in user: '.var_export($username, true)); + + $u = VBX_User::login($username, $password, $captcha, $captcha_token); + if($u) + { + $next = $this->session->userdata('next'); + $this->session->unset_userdata('next'); + $userdata = array( + 'email' => $u->email, + 'user_id' => $u->id, + 'is_admin' => $u->is_admin, + 'loggedin' => TRUE, + 'signature' => VBX_User::signature($u->id), + ); + + $this->session->set_userdata($userdata); + } + } + + if(!$this->session->userdata('loggedin')) + { + header("WWW-Authenticate: Basic realm=\"OpenVBX\""); + header("HTTP/1.0 401 Unauthorized"); + exit; + } + + return $message; + } + + // make sure this page or function can only be accessed by admins + function admin_only($page_name = 'this page') + { + if (!$this->session->userdata('is_admin')) { + $this->session->set_userdata('next', uri_string()); + $this->session->set_flashdata('error', "You must be an administrator to access $page_name."); + redirect('auth/login'); + } + } + + protected function init_view_data($full_view = true) + { + $data = array(); + + if($full_view) + { + $data['counts'] = $counts = $this->message_counts(); + } + + try + { + $data['callerid_numbers'] = $this->get_twilio_numbers(); + } + catch(User_ControllerException $e) + { + // @todo - set a "same page view" error message + // $this->session->set_flashdata('error', $e->getMessage()); + error_log($e->getMessage()); + } + + $data['user_numbers'] = $this->get_user_numbers(); + $data['error'] = $this->session->flashdata('error'); + if(!empty($data['error'])) + { + log_message('error', $data['error']); + } + $data['section'] = $this->section; + + return $data; + } + + protected function get_user_numbers() + { + $this->load->model('vbx_device'); + $numbers = $this->vbx_device->get_by_user($this->user_id); + + return $numbers; + } + + protected function message_counts() + { + $groups = VBX_User::get_group_ids($this->user_id); + $counts = $this->vbx_message->get_folders($this->user_id, $groups); + return $counts; + } + + protected function get_twilio_numbers() + { + $this->load->model('vbx_incoming_numbers'); + $numbers = array(); + try + { + /* Retrieve twilio numbers w/o sandbox */ + $numbers = $this->vbx_incoming_numbers->get_numbers(); + } + catch(VBX_IncomingNumberException $e) + { + error_log($e->getMessage()); + throw new User_ControllerException($e->getMessage()); + /* Silent fail */ + } + + return $numbers; + } + + /* Used to give access to internals via rest-based calls */ + protected function make_rest_access() + { + /* Set a cookie for Rest Access */ + $this->load->model('vbx_rest_access'); + return $this->vbx_rest_access->make_key($this->session->userdata('user_id')); + } + + public function get_tenant() + { + return $this->tenant; + } +} diff --git a/OpenVBX/helpers/mail_helper.php b/OpenVBX/helpers/mail_helper.php index 9453556f..c25c6e98 100644 --- a/OpenVBX/helpers/mail_helper.php +++ b/OpenVBX/helpers/mail_helper.php @@ -18,25 +18,30 @@ * Contributor(s): **/ - + function openvbx_mail($recipient, $subject, $template, $maildata = array()) -{ +{ $ci = &get_instance(); - + $from_email = $ci->settings->get('from_email', $ci->tenant->id); if(empty($from_email)) { $domain = $ci->config->item('server_name'); - $from_email = "$from "; + $from_email = "do-not-reply@$domain"; } - - $headers = 'From: '.$from_email."\r\n"; - $headers .= 'Reply-To: '.$from_email."\r\n"; - $headers .= 'Return-Path: '.$from_email."\r\n"; - $headers .= 'User-Agent: OpenVBX-'.OpenVBX::version(); - + $message = $ci->load->view('emails/'.$template, $maildata, true); - + + $ci->load->library('email'); + $ci->email->useragent = 'OpenVBX-' . OpenVBX::version(); + $ci->email->clear() + ->from($from_email) + ->reply_to($from_email) + ->to($recipient) + ->subject($subject) + ->message($message); + log_message('debug', 'MAILING -- to: '.$recipient.' -- body: '.$message); - return mail($recipient, '[OpenVBX] '.$subject, $message, $headers); -} \ No newline at end of file + + return $ci->email->send(); +} diff --git a/OpenVBX/libraries/OpenVBX.php b/OpenVBX/libraries/OpenVBX.php index f0409943..71719d20 100644 --- a/OpenVBX/libraries/OpenVBX.php +++ b/OpenVBX/libraries/OpenVBX.php @@ -223,18 +223,15 @@ public static function schemaVersion() $ci =& get_instance(); if ($ci->db) { - $reenable_cache = false; - $ci->load->model('vbx_settings'); - if (isset($ci->cache) && $ci->cache->enabled()) + $reenable_cache = false; + if (!$ci->cache && $ci->cache->enabled()) { $ci->cache->enabled(false); $reenable_cache = true; } - self::$schemaVersion = $ci->vbx_settings->get('schema-version', VBX_PARENT_TENANT); - - if ($reenable_cache) + if ($reenable_cache) { $ci->cache->enabled(true); } @@ -379,7 +376,7 @@ protected static function get_http_opts() // optionally load in the included cert for api communication if ($use_certificate = $ci->config->item('twilio_use_certificate')) { - $_http_opts['opts']['curlopts'][CURLOPT_CAINFO] = APPPATH . 'libraries/Services/twilio_ssl_certificate.crt'; + $_http_opts['opts']['curlopts'][CURLOPT_CAINFO] = APPPATH . 'libraries/Services/cacert.pem'; } // internal api development override, you'll never need this @@ -474,7 +471,7 @@ public static function validateRequest($url = false, $post_vars = false) // we weren't handed post-vars, use the default $post_vars = $_POST; } - + return self::$_twilioValidator->validate(self::getRequestSignature(), $url, $post_vars); } diff --git a/OpenVBX/libraries/Services/Twilio.php b/OpenVBX/libraries/Services/Twilio.php index 5aa957fc..26e68bc9 100755 --- a/OpenVBX/libraries/Services/Twilio.php +++ b/OpenVBX/libraries/Services/Twilio.php @@ -1,5 +1,11 @@ `_ + * :param string $version: API version to use + * :param $_http: A HTTP client for making requests. + * :type $_http: :php:class:`Services_Twilio_TinyHttp` + * :param int $retryAttempts: + * Number of times to retry failed requests. Currently only idempotent + * requests (GET's and DELETE's) are retried. + * + * Here's an example: * - * @category Services - * @package Services_Twilio - * @author Neuman Vong - * @license http://creativecommons.org/licenses/MIT/ MIT - * @link http://pear.php.net/package/Services_Twilio + * .. code-block:: php + * + * require('Services/Twilio.php'); + * $client = new Services_Twilio('AC123', '456bef', null, null, 3); + * // Take some action with the client, etc. */ class Services_Twilio extends Services_Twilio_Resource { - const USER_AGENT = 'twilio-php/3.9.0'; + const USER_AGENT = 'twilio-php/3.12.1'; protected $http; protected $retryAttempts; + protected $last_response; protected $version; protected $versions = array('2008-08-01', '2010-04-01'); - /** - * Constructor. - * - * @param string $sid Account SID - * @param string $token Account auth token - * @param string $version API version - * @param Services_Twilio_Http $_http A HTTP client - * @param int $retryAttempts Number of times to retry failed requests - */ public function __construct( $sid, $token, @@ -49,22 +60,36 @@ public function __construct( $version : end($this->versions); if (null === $_http) { - if (!in_array('curl', get_loaded_extensions())) { - trigger_error("It looks like you do not have curl installed.\n". - "Curl is required to make HTTP requests using the twilio-php\n" . - "library. For install instructions, visit the following page:\n" . - "http://php.net/manual/en/curl.installation.php", - E_USER_WARNING + if (!in_array('openssl', get_loaded_extensions())) { + throw new Services_Twilio_HttpException("The OpenSSL extension is required but not currently enabled. For more information, see http://php.net/manual/en/book.openssl.php"); + } + if (in_array('curl', get_loaded_extensions())) { + $_http = new Services_Twilio_TinyHttp( + "https://api.twilio.com", + array("curlopts" => array( + CURLOPT_USERAGENT => self::USER_AGENT, + CURLOPT_HTTPHEADER => array('Accept-Charset: utf-8'), + CURLOPT_CAINFO => dirname(__FILE__) . '/cacert.pem', + )) + ); + } else { + $_http = new Services_Twilio_HttpStream( + "https://api.twilio.com", + array( + "http_options" => array( + "http" => array( + "user_agent" => self::USER_AGENT, + "header" => "Accept-Charset: utf-8\r\n", + ), + "ssl" => array( + 'verify_peer' => true, + 'cafile' => dirname(__FILE__) . '/cacert.pem', + 'verify_depth' => 5, + ), + ), + ) ); } - $_http = new Services_Twilio_TinyHttp( - "https://api.twilio.com", - array("curlopts" => array( - CURLOPT_USERAGENT => self::USER_AGENT, - CURLOPT_HTTPHEADER => array('Accept-Charset: utf-8'), - CURLOPT_CAINFO => dirname(__FILE__) . '/cacert.pem', - )) - ); } $_http->authenticate($sid, $token); $this->http = $_http; @@ -76,7 +101,8 @@ public function __construct( /** * Get the api version used by the rest client * - * @return string the API version in use + * :return: the API version in use + * :returntype: string */ public function getVersion() { return $this->version; @@ -85,25 +111,27 @@ public function getVersion() { /** * Get the retry attempt limit used by the rest client * - * @return int the number of retry attempts + * :return: the number of retry attempts + * :rtype: int */ public function getRetryAttempts() { return $this->retryAttempts; } /** - * Construct a URI based on initial path, query params, and paging + * Construct a URI based on initial path, query params, and paging * information * - * We want to use the query params, unless we have a next_page_uri from the + * We want to use the query params, unless we have a next_page_uri from the * API. * - * @param string $path The request path (may contain query params if it's + * :param string $path: The request path (may contain query params if it's * a next_page_uri) - * @param array $params Query parameters to use with the request - * @param boolean $full_uri Whether the $path contains the full uri + * :param array $params: Query parameters to use with the request + * :param boolean $full_uri: Whether the $path contains the full uri * - * @return string the URI that should be requested by the library + * :return: the URI that should be requested by the library + * :returntype: string */ public static function getRequestUri($path, $params, $full_uri = false) { $json_path = $full_uri ? $path : "$path.json"; @@ -118,11 +146,12 @@ public static function getRequestUri($path, $params, $full_uri = false) { /** * Helper method for implementing request retry logic * - * @param array $callable The function that makes an HTTP request - * @param string $uri The URI to request - * @param int $retriesLeft Number of times to retry + * :param array $callable: The function that makes an HTTP request + * :param string $uri: The URI to request + * :param int $retriesLeft: Number of times to retry * - * @return object The object representation of the resource + * :return: The object representation of the resource + * :rtype: object */ protected function _makeIdempotentRequest($callable, $uri, $retriesLeft) { $response = call_user_func_array($callable, array($uri)); @@ -137,61 +166,111 @@ protected function _makeIdempotentRequest($callable, $uri, $retriesLeft) { /** * GET the resource at the specified path. * - * @param string $path Path to the resource - * @param array $params Query string parameters - * @param boolean $full_uri Whether the full URI has been passed as an + * :param string $path: Path to the resource + * :param array $params: Query string parameters + * :param boolean $full_uri: Whether the full URI has been passed as an * argument * - * @return object The object representation of the resource + * :return: The object representation of the resource + * :rtype: object */ - public function retrieveData($path, array $params = array(), + public function retrieveData($path, $params = array(), $full_uri = false ) { $uri = self::getRequestUri($path, $params, $full_uri); - return $this->_makeIdempotentRequest(array($this->http, 'get'), + return $this->_makeIdempotentRequest(array($this->http, 'get'), $uri, $this->retryAttempts); } /** * DELETE the resource at the specified path. * - * @param string $path Path to the resource - * @param array $params Query string parameters + * :param string $path: Path to the resource + * :param array $params: Query string parameters * - * @return object The object representation of the resource + * :return: The object representation of the resource + * :rtype: object */ - public function deleteData($path, array $params = array()) + public function deleteData($path, $params = array()) { $uri = self::getRequestUri($path, $params); - return $this->_makeIdempotentRequest(array($this->http, 'delete'), + return $this->_makeIdempotentRequest(array($this->http, 'delete'), $uri, $this->retryAttempts); } /** * POST to the resource at the specified path. * - * @param string $path Path to the resource - * @param array $params Query string parameters + * :param string $path: Path to the resource + * :param array $params: Query string parameters * - * @return object The object representation of the resource + * :return: The object representation of the resource + * :rtype: object */ - public function createData($path, array $params = array()) + public function createData($path, $params = array()) { $path = "$path.json"; $headers = array('Content-Type' => 'application/x-www-form-urlencoded'); $response = $this->http->post( - $path, $headers, http_build_query($params, '', '&') + $path, $headers, self::buildQuery($params, '') ); return $this->_processResponse($response); } + /** + * Build a query string from query data + * + * :param array $queryData: An associative array of keys and values. The + * values can be a simple type or a list, in which case the list is + * converted to multiple query parameters with the same key. + * :param string $numericPrefix: + * :param string $queryStringStyle: Determine how to build the url + * - strict: Build a standards compliant query string without braces (can be hacked by using braces in key) + * - php: Build a PHP compatible query string with nested array syntax + * :return: The encoded query string + * :rtype: string + */ + public static function buildQuery($queryData, $numericPrefix = '') { + $query = ''; + // Loop through all of the $query_data + foreach ($queryData as $key => $value) { + // If the key is an int, add the numeric_prefix to the beginning + if (is_int($key)) { + $key = $numericPrefix . $key; + } + + // If the value is an array, we will end up recursing + if (is_array($value)) { + // Loop through the values + foreach ($value as $value2) { + // Add an arg_separator if needed + if ($query !== '') { + $query .= '&'; + } + // Recurse + $query .= self::buildQuery(array($key => $value2), $numericPrefix); + } + } else { + // Add an arg_separator if needed + if ($query !== '') { + $query .= '&'; + } + // Add the key and the urlencoded value (as a string) + $query .= $key . '=' . urlencode((string)$value); + } + } + return $query; + } + /** * Convert the JSON encoded resource into a PHP object. * - * @param array $response 3-tuple containing status, headers, and body + * :param array $response: 3-tuple containing status, headers, and body * - * @return object PHP object decoded from JSON - * @throws Services_Twilio_RestException (Response in 300-500 class) + * :return: PHP object decoded from JSON + * :rtype: object + * :throws: A :php:class:`Services_Twilio_RestException` if the Response is + * in the 300-500 range of status codes. */ private function _processResponse($response) { @@ -203,18 +282,20 @@ private function _processResponse($response) if ($decoded === null) { throw new Services_Twilio_RestException( $status, - 'Could not decode response body as JSON. ' . + 'Could not decode response body as JSON. ' . 'This likely indicates a 500 server error' ); } if (200 <= $status && $status < 300) { + $this->last_response = $decoded; return $decoded; } throw new Services_Twilio_RestException( - (int)$decoded->status, - $decoded->message, + $status, + isset($decoded->message) ? $decoded->message : '', isset($decoded->code) ? $decoded->code : null, isset($decoded->more_info) ? $decoded->more_info : null ); } } + diff --git a/OpenVBX/libraries/Services/Twilio/Capability.php b/OpenVBX/libraries/Services/Twilio/Capability.php index 554e2a32..9f02e452 100755 --- a/OpenVBX/libraries/Services/Twilio/Capability.php +++ b/OpenVBX/libraries/Services/Twilio/Capability.php @@ -68,7 +68,7 @@ public function allowClientOutgoing($appSid, array $appParams=array()) { $this->allow('client', 'outgoing', array( 'appSid' => $appSid, - 'appParams' => http_build_query($appParams))); + 'appParams' => http_build_query($appParams, '', '&'))); } /** @@ -80,7 +80,7 @@ public function allowEventStream(array $filters=array()) { $this->allow('stream', 'subscribe', array( 'path' => '/2010-04-01/Events', - 'params' => http_build_query($filters), + 'params' => http_build_query($filters, '', '&'), )); } @@ -146,7 +146,7 @@ public function toString() { $uri = "scope:{$this->service}:{$this->privilege}"; if (count($this->params)) { - $uri .= "?".http_build_query($this->params); + $uri .= "?".http_build_query($this->params, '', '&'); } return $uri; } @@ -343,4 +343,4 @@ private static function handleJsonError($errno) : 'Unknown JSON error: ' . $errno ); } -} \ No newline at end of file +} diff --git a/OpenVBX/libraries/Services/Twilio/HttpException.php b/OpenVBX/libraries/Services/Twilio/HttpException.php new file mode 100644 index 00000000..b79a357d --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/HttpException.php @@ -0,0 +1,3 @@ + array( + "headers" => "", + "timeout" => 60, + "follow_location" => true, + "ignore_errors" => true, + ), + "ssl" => array(), + ); + private $options = array(); + + public function __construct($uri = '', $kwargs = array()) { + $this->uri = $uri; + if (isset($kwargs['debug'])) { + $this->debug = true; + } + if (isset($kwargs['http_options'])) { + $this->options = $kwargs['http_options'] + self::$default_options; + } else { + $this->options = self::$default_options; + } + } + + public function __call($name, $args) { + list($res, $req_headers, $req_body) = $args + array(0, array(), ''); + + $request_options = $this->options; + $url = $this->uri . $res; + + if (isset($req_body) && strlen($req_body) > 0) { + $request_options['http']['content'] = $req_body; + } + + foreach($req_headers as $key => $value) { + $request_options['http']['header'] .= sprintf("%s: %s\r\n", $key, $value); + } + + if (isset($this->auth_header)) { + $request_options['http']['header'] .= $this->auth_header; + } + + $request_options['http']['method'] = strtoupper($name); + $request_options['http']['ignore_errors'] = true; + + if ($this->debug) { + error_log(var_export($request_options, true)); + } + $ctx = stream_context_create($request_options); + $result = file_get_contents($url, false, $ctx); + + if (false === $result) { + throw new Services_Twilio_HttpStreamException( + "Unable to connect to service"); + } + + $status_header = array_shift($http_response_header); + if (1 !== preg_match('#HTTP/\d+\.\d+ (\d+)#', $status_header, $matches)) { + throw new Services_Twilio_HttpStreamException( + "Unable to detect the status code in the HTTP result."); + } + + $status_code = intval($matches[1]); + $response_headers = array(); + + foreach($http_response_header as $header) { + list($key, $val) = explode(":", $header); + $response_headers[trim($key)] = trim($val); + } + + return array($status_code, $response_headers, $result); + } + + public function authenticate($user, $pass) { + if (isset($user) && isset($pass)) { + $this->auth_header = sprintf("Authorization: Basic %s", + base64_encode(sprintf("%s:%s", $user, $pass))); + } else { + $this->auth_header = null; + } + } +} diff --git a/OpenVBX/libraries/Services/Twilio/InstanceResource.php b/OpenVBX/libraries/Services/Twilio/InstanceResource.php index 6c1e9a1a..011d8f99 100755 --- a/OpenVBX/libraries/Services/Twilio/InstanceResource.php +++ b/OpenVBX/libraries/Services/Twilio/InstanceResource.php @@ -1,22 +1,27 @@ * @license http://creativecommons.org/licenses/MIT/ MIT * @link http://pear.php.net/package/Services_Twilio - */ -abstract class Services_Twilio_InstanceResource - extends Services_Twilio_Resource -{ + */ + +/** + * Abstraction of an instance resource from the Twilio API. + */ +abstract class Services_Twilio_InstanceResource extends Services_Twilio_Resource { + /** - * @param mixed $params An array of updates, or a property name - * @param mixed $value A value with which to update the resource + * Make a request to the API to update an instance resource * - * @return null + * :param mixed $params: An array of updates, or a property name + * :param mixed $value: A value with which to update the resource + * + * :rtype: null + * :throws: a :php:class:`RestException ` if + * the update fails. */ public function update($params, $value = null) { @@ -27,13 +32,14 @@ public function update($params, $value = null) $this->updateAttributes($decamelizedParams); } - /* - * Add all properties from an associative array (the JSON response body) as + /* + * Add all properties from an associative array (the JSON response body) as * properties on this instance resource, except the URI * - * @param stdClass $params An object containing all of the parameters of + * :param stdClass $params: An object containing all of the parameters of * this instance - * @return null Purely side effecting + * :return: Nothing, this is purely side effecting + * :rtype: null */ public function updateAttributes($params) { unset($params->uri); @@ -44,15 +50,25 @@ public function updateAttributes($params) { /** * Get the value of a property on this resource. - * - * To help with lazy HTTP requests, we don't actually retrieve an object - * from the API unless you really need it. Hence, this function may make - * API requests if the property you're requesting isn't available on the + * + * Instead of defining all of the properties of an object directly, we rely + * on the API to tell us which properties an object has. This method will + * query the API to retrieve a property for an object, if it is not already + * set on the object. + * + * If the call is to a subresource, eg ``$client->account->messages``, no + * request is made. + * + * To help with lazy HTTP requests, we don't actually retrieve an object + * from the API unless you really need it. Hence, this function may make API + * requests even if the property you're requesting isn't available on the * resource. * - * @param string $key The property name + * :param string $key: The property name * - * @return mixed Could be anything. + * :return mixed: Could be anything. + * :throws: a :php:class:`RestException ` if + * the update fails. */ public function __get($key) { diff --git a/OpenVBX/libraries/Services/Twilio/ListResource.php b/OpenVBX/libraries/Services/Twilio/ListResource.php index e628b42d..4d7bc3c3 100755 --- a/OpenVBX/libraries/Services/Twilio/ListResource.php +++ b/OpenVBX/libraries/Services/Twilio/ListResource.php @@ -1,22 +1,26 @@ + * @author Neuman Vong neuman@twilio.com * @license http://creativecommons.org/licenses/MIT/ MIT * @link http://pear.php.net/package/Services_Twilio */ -abstract class Services_Twilio_ListResource - extends Services_Twilio_Resource + +/** + * Abstraction of a list resource from the Twilio API. + * + * The list resource implements the `IteratorAggregate + * `_ and the `Countable + * `_ interfaces. + * + */ +abstract class Services_Twilio_ListResource extends Services_Twilio_Resource implements IteratorAggregate, Countable { public function __construct($client, $uri) { $name = $this->getResourceName(true); - /* + /* * By default trim the 's' from the end of the list name to get the * instance name (ex Accounts -> Account). This behavior can be * overridden by child classes if the rule doesn't work. @@ -24,17 +28,18 @@ public function __construct($client, $uri) { if (!isset($this->instance_name)) { $this->instance_name = "Services_Twilio_Rest_" . rtrim($name, 's'); } + parent::__construct($client, $uri); } /** * Gets a resource from this list. * - * @param string $sid The resource SID - * @return Services_Twilio_InstanceResource The resource + * :param string $sid: The resource SID + * :return: The resource + * :rtype: :php:class:`InstanceResource ` */ - public function get($sid) - { + public function get($sid) { $instance = new $this->instance_name( $this->client, $this->uri . "/$sid" ); @@ -43,12 +48,14 @@ public function get($sid) return $instance; } - /* - * Construct an InstanceResource with the specified params. + /** + * Construct an :php:class:`InstanceResource + * ` with the specified params. * - * @param array params usually a JSON HTTP response from the API - * @return Services_Twilio_InstanceResource An instance with properties + * :param array $params: usually a JSON HTTP response from the API + * :return: An instance with properties * initialized to the values in the params array. + * :rtype: :php:class:`InstanceResource ` */ public function getObjectFromJson($params, $idParam = "sid") { @@ -63,10 +70,10 @@ public function getObjectFromJson($params, $idParam = "sid") /** * Deletes a resource from this list. * - * @param string $sid The resource SID - * @return null + * :param string $sid: The resource SID + * :rtype: null */ - public function delete($sid, array $params = array()) + public function delete($sid, $params = array()) { $this->client->deleteData($this->uri . '/' . $sid, $params); } @@ -75,11 +82,12 @@ public function delete($sid, array $params = array()) * Create a resource on the list and then return its representation as an * InstanceResource. * - * @param array $params The parameters with which to create the resource + * :param array $params: The parameters with which to create the resource * - * @return Services_Twilio_InstanceResource The created resource + * :return: The created resource + * :rtype: :php:class:`InstanceResource ` */ - protected function _create(array $params) + protected function _create($params) { $params = $this->client->createData($this->uri, $params); /* Some methods like verified caller ID don't return sids. */ @@ -92,19 +100,20 @@ protected function _create(array $params) } /** - * Returns a page of InstanceResources from this list. + * Returns a page of :php:class:`InstanceResources + * ` from this list. * - * @param int $page The start page - * @param int $size Number of items per page - * @param array $filters Optional filters - * @param string $deep_paging_uri if provided, the $page and $size + * :param int $page: The start page + * :param int $size: Number of items per page + * :param array $filters: Optional filters + * :param string $deep_paging_uri: if provided, the $page and $size * parameters will be ignored and this URI will be requested directly. * - * @return Services_Twilio_Page A page + * :return: A page of resources + * :rtype: :php:class:`Services_Twilio_Page` */ public function getPage( - $page = 0, $size = 50, array $filters = array(), - $deep_paging_uri = null + $page = 0, $size = 50, $filters = array(), $deep_paging_uri = null ) { $list_name = $this->getResourceName(); if ($deep_paging_uri !== null) { @@ -130,13 +139,15 @@ public function getPage( } /** - * Get the total number of instance members. Note this will make one small - * HTTP request to retrieve the total, every time this method is called. + * Get the total number of instances for this list. * - * If the total is not set or an Exception was thrown, returns 0 + * This will make one HTTP request to retrieve the total, every time this + * method is called. * - * @return integer + * If the total is not set, or an Exception was thrown, returns 0 * + * :return: The total number of instance members + * :rtype: integer */ public function count() { try { @@ -149,37 +160,44 @@ public function count() { /** - * Returns an iterable list of InstanceResources + * Returns an iterable list of + * :php:class:`instance resources `. + * + * :param int $page: The start page + * :param int $size: Number of items per page + * :param array $filters: Optional filters. + * The filter array can accept full datetimes when StartTime or DateCreated + * are used. Inequalities should be within the key portion of the array and + * multiple filter parameters can be combined for more specific searches. * - * @param int $page The start page - * @param int $size Number of items per page - * @param array $size Optional filters + * .. code-block:: php * - * The filter array can accept full datetimes when StartTime or DateCreated - * are used. Inequalities should be within the key portion of the array and - * multiple filter parameters can be combined for more specific searches. + * array('DateCreated>' => '2011-07-05 08:00:00', 'DateCreated<' => '2011-08-01') * - * eg. - * array('DateCreated>' => '2011-07-05 08:00:00', 'DateCreated<' => '2011-08-01') - * or - * array('StartTime<' => '2011-07-05 08:00:00') + * .. code-block:: php * - * @return Services_Twilio_AutoPagingIterator An iterator + * array('StartTime<' => '2011-07-05 08:00:00') + * + * :return: An iterator + * :rtype: :php:class:`Services_Twilio_AutoPagingIterator` */ public function getIterator( - $page = 0, $size = 50, array $filters = array() + $page = 0, $size = 50, $filters = array() ) { return new Services_Twilio_AutoPagingIterator( array($this, 'getPageGenerator'), $page, $size, $filters ); } - /* - * Retrieve a new page of API results, and update iterator parameters. + /** + * Retrieve a new page of API results, and update iterator parameters. This + * function is called by the paging iterator to retrieve a new page and + * shouldn't be called directly. */ public function getPageGenerator( - $page, $size, array $filters = array(), $deep_paging_uri = null + $page, $size, $filters = array(), $deep_paging_uri = null ) { return $this->getPage($page, $size, $filters, $deep_paging_uri); } } + diff --git a/OpenVBX/libraries/Services/Twilio/NumberType.php b/OpenVBX/libraries/Services/Twilio/NumberType.php new file mode 100644 index 00000000..0683d996 --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/NumberType.php @@ -0,0 +1,35 @@ +instance_name = 'Services_Twilio_Rest_IncomingPhoneNumber'; + return $camelized ? 'IncomingPhoneNumbers' : 'incoming_phone_numbers'; + } + + /** + * Purchase a new phone number. + * + * Example usage: + * + * .. code-block:: php + * + * $marlosBurner = '+14105551234'; + * $client->account->incoming_phone_numbers->local->purchase($marlosBurner); + * + * :param string $phone_number: The phone number to purchase + * :param array $params: An optional array of parameters to pass along with + * the request (to configure the phone number) + */ + public function purchase($phone_number, array $params = array()) { + $postParams = array( + 'PhoneNumber' => $phone_number + ); + return $this->create($postParams + $params); + } + + public function create(array $params = array()) { + return parent::_create($params); + } + +} diff --git a/OpenVBX/libraries/Services/Twilio/RequestValidator.php b/OpenVBX/libraries/Services/Twilio/RequestValidator.php index 4bf3f0cb..52a40d91 100755 --- a/OpenVBX/libraries/Services/Twilio/RequestValidator.php +++ b/OpenVBX/libraries/Services/Twilio/RequestValidator.php @@ -33,4 +33,4 @@ public function validate($expectedSignature, $url, $data = array()) == $expectedSignature; } -} \ No newline at end of file +} diff --git a/OpenVBX/libraries/Services/Twilio/Resource.php b/OpenVBX/libraries/Services/Twilio/Resource.php index 5d80f479..5320e537 100755 --- a/OpenVBX/libraries/Services/Twilio/Resource.php +++ b/OpenVBX/libraries/Services/Twilio/Resource.php @@ -8,7 +8,7 @@ * @author Neuman Vong * @license http://creativecommons.org/licenses/MIT/ MIT * @link http://pear.php.net/package/Services_Twilio - */ + */ abstract class Services_Twilio_Resource { protected $subresources; @@ -50,14 +50,14 @@ protected function setupSubresources() } } - /* + /* * Get the resource name from the classname - * + * * Ex: Services_Twilio_Rest_Accounts -> Accounts * * @param boolean $camelized Whether to return camel case or not */ - public function getResourceName($camelized = false) + public function getResourceName($camelized = false) { $name = get_class($this); $parts = explode('_', $name); @@ -71,28 +71,35 @@ public function getResourceName($camelized = false) public static function decamelize($word) { - return preg_replace( - '/(^|[a-z])([A-Z])/e', - 'strtolower(strlen("\\1") ? "\\1_\\2" : "\\2")', + $callback = create_function('$matches', + 'return strtolower(strlen("$matches[1]") ? "$matches[1]_$matches[2]" : "$matches[2]");'); + + return preg_replace_callback( + '/(^|[a-z])([A-Z])/', + $callback, $word ); } /** * Return camelized version of a word - * Examples: sms_messages => SMSMessages, calls => Calls, + * Examples: sms_messages => SMSMessages, calls => Calls, * incoming_phone_numbers => IncomingPhoneNumbers * * @param string $word The word to camelize * @return string */ public static function camelize($word) { - return preg_replace('/(^|_)([a-z])/e', 'strtoupper("\\2")', $word); + $callback = create_function('$matches', 'return strtoupper("$matches[2]");'); + + return preg_replace_callback('/(^|_)([a-z])/', + $callback, + $word); } /** * Get the value of a property on this resource. - * + * * @param string $key The property name * @return mixed Could be anything. */ @@ -104,19 +111,19 @@ public function __get($key) { } /** - * Print a JSON representation of this object. Strips the HTTP client + * Print a JSON representation of this object. Strips the HTTP client * before returning. * - * Note, this should mainly be used for debugging, and is not guaranteed + * Note, this should mainly be used for debugging, and is not guaranteed * to correspond 1:1 with the JSON API output. * - * Note that echoing an object before an HTTP request has been made to + * Note that echoing an object before an HTTP request has been made to * "fill in" its properties may return an empty object */ public function __toString() { $out = array(); foreach ($this as $key => $value) { - if ($key !== "client") { + if ($key !== "client" && $key !== "subresources") { $out[$key] = (string)$value; } } diff --git a/OpenVBX/libraries/Services/Twilio/Rest/Account.php b/OpenVBX/libraries/Services/Twilio/Rest/Account.php index fec0e21c..e1181b7d 100755 --- a/OpenVBX/libraries/Services/Twilio/Rest/Account.php +++ b/OpenVBX/libraries/Services/Twilio/Rest/Account.php @@ -10,6 +10,8 @@ protected function init($client, $uri) { 'calls', 'conferences', 'incoming_phone_numbers', + 'media', + 'messages', 'notifications', 'outgoing_callerids', 'recordings', @@ -20,7 +22,8 @@ protected function init($client, $uri) { 'authorized_connect_apps', 'usage_records', 'usage_triggers', - 'queues' + 'queues', + 'sip' ); $this->sandbox = new Services_Twilio_Rest_Sandbox( diff --git a/OpenVBX/libraries/Services/Twilio/Rest/Accounts.php b/OpenVBX/libraries/Services/Twilio/Rest/Accounts.php index d85db9e1..0e7ea0a5 100755 --- a/OpenVBX/libraries/Services/Twilio/Rest/Accounts.php +++ b/OpenVBX/libraries/Services/Twilio/Rest/Accounts.php @@ -1,10 +1,25 @@ `_ documentation. + */ +class Services_Twilio_Rest_Accounts extends Services_Twilio_ListResource { + + /** + * Create a new subaccount. + * + * :param array $params: An array of parameters describing the new + * subaccount. The ``$params`` array can contain the following keys: + * + * *FriendlyName* + * A description of this account, up to 64 characters long + * + * :returns: The new subaccount + * :rtype: :php:class:`Services_Twilio_Rest_Account` + * + */ + public function create($params = array()) { return parent::_create($params); } } diff --git a/OpenVBX/libraries/Services/Twilio/Rest/AvailablePhoneNumbers.php b/OpenVBX/libraries/Services/Twilio/Rest/AvailablePhoneNumbers.php index e774b94c..9d371411 100755 --- a/OpenVBX/libraries/Services/Twilio/Rest/AvailablePhoneNumbers.php +++ b/OpenVBX/libraries/Services/Twilio/Rest/AvailablePhoneNumbers.php @@ -3,8 +3,7 @@ class Services_Twilio_Rest_AvailablePhoneNumbers extends Services_Twilio_ListResource { - public function getLocal($country) - { + public function getLocal($country) { $curried = new Services_Twilio_PartialApplicationHelper(); $curried->set( 'getList', @@ -13,8 +12,7 @@ public function getLocal($country) ); return $curried; } - public function getTollFree($country) - { + public function getTollFree($country) { $curried = new Services_Twilio_PartialApplicationHelper(); $curried->set( 'getList', @@ -24,12 +22,23 @@ public function getTollFree($country) return $curried; } + public function getMobile($country) + { + $curried = new Services_Twilio_PartialApplicationHelper(); + $curried->set( + 'getList', + array($this, 'getList'), + array($country, 'Mobile') + ); + return $curried; + } + /** - * Get a list of available phone numbers. + * Get a list of available phone numbers. * * @param string $country The 2-digit country code you'd like to search for * numbers e.g. ('US', 'CA', 'GB') - * @param string $type The type of number ('Local' or 'TollFree') + * @param string $type The type of number ('Local', 'TollFree', or 'Mobile') * @return object The object representation of the resource */ public function getList($country, $type, array $params = array()) @@ -37,8 +46,7 @@ public function getList($country, $type, array $params = array()) return $this->client->retrieveData($this->uri . "/$country/$type", $params); } - public function getResourceName($camelized = false) - { + public function getResourceName($camelized = false) { // You can't page through the list of available phone numbers. $this->instance_name = 'Services_Twilio_Rest_AvailablePhoneNumber'; return $camelized ? 'Countries' : 'countries'; diff --git a/OpenVBX/libraries/Services/Twilio/Rest/Call.php b/OpenVBX/libraries/Services/Twilio/Rest/Call.php index f862c79b..75565684 100755 --- a/OpenVBX/libraries/Services/Twilio/Rest/Call.php +++ b/OpenVBX/libraries/Services/Twilio/Rest/Call.php @@ -1,19 +1,102 @@ `_ documentation. + * + * .. php:attr:: sid + * + * A 34 character string that uniquely identifies this resource. + * + * .. php:attr:: parent_call_sid + * + * A 34 character string that uniquely identifies the call that created this leg. + * + * .. php:attr:: date_created + * + * The date that this resource was created, given as GMT in RFC 2822 format. + * + * .. php:attr:: date_updated + * + * The date that this resource was last updated, given as GMT in RFC 2822 format. + * + * .. php:attr:: account_sid + * + * The unique id of the Account responsible for creating this call. + * + * .. php:attr:: to + * + * The phone number that received this call. e.g., +16175551212 (E.164 format) + * + * .. php:attr:: from + * + * The phone number that made this call. e.g., +16175551212 (E.164 format) + * + * .. php:attr:: phone_number_sid + * + * If the call was inbound, this is the Sid of the IncomingPhoneNumber that + * received the call. If the call was outbound, it is the Sid of the + * OutgoingCallerId from which the call was placed. + * + * .. php:attr:: status + * + * A string representing the status of the call. May be `QUEUED`, `RINGING`, + * `IN-PROGRESS`, `COMPLETED`, `FAILED`, `BUSY` or `NO_ANSWER`. + * + * .. php:attr:: stat_time + * + * The start time of the call, given as GMT in RFC 2822 format. Empty if the call has not yet been dialed. + * + * .. php:attr:: end_time + * + * The end time of the call, given as GMT in RFC 2822 format. Empty if the call did not complete successfully. + * + * .. php:attr:: duration + * + * The length of the call in seconds. This value is empty for busy, failed, unanswered or ongoing calls. + * + * .. php:attr:: price + * + * The charge for this call in USD. Populated after the call is completed. May not be immediately available. + * + * .. php:attr:: direction + * + * A string describing the direction of the call. inbound for inbound + * calls, outbound-api for calls initiated via the REST API or + * outbound-dial for calls initiated by a verb. + * + * .. php:attr:: answered_by + * + * If this call was initiated with answering machine detection, either human or machine. Empty otherwise. + * + * .. php:attr:: forwarded_from + * + * If this call was an incoming call forwarded from another number, the + * forwarding phone number (depends on carrier supporting forwarding). + * Empty otherwise. + * + * .. php:attr:: caller_name + * + * If this call was an incoming call from a phone number with Caller ID Lookup enabled, the caller's name. Empty otherwise. + */ +class Services_Twilio_Rest_Call extends Services_Twilio_InstanceResource { + + /** + * Hang up the call + */ + public function hangup() { $this->update('Status', 'completed'); } + /** + * Redirect the call to a new URL + * + * :param string $url: the new URL to retrieve call flow from. + */ public function route($url) { $this->update('Url', $url); } - protected function init($client, $uri) - { + protected function init($client, $uri) { $this->setupSubresources( 'notifications', 'recordings' diff --git a/OpenVBX/libraries/Services/Twilio/Rest/Credential.php b/OpenVBX/libraries/Services/Twilio/Rest/Credential.php new file mode 100644 index 00000000..03d82652 --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/Credential.php @@ -0,0 +1,30 @@ +setupSubresources( + 'credentials' + ); + } +} + diff --git a/OpenVBX/libraries/Services/Twilio/Rest/CredentialListMapping.php b/OpenVBX/libraries/Services/Twilio/Rest/CredentialListMapping.php new file mode 100644 index 00000000..3f9c3054 --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/CredentialListMapping.php @@ -0,0 +1,37 @@ +setupSubresources( + 'credentials' + ); + } +} diff --git a/OpenVBX/libraries/Services/Twilio/Rest/CredentialListMappings.php b/OpenVBX/libraries/Services/Twilio/Rest/CredentialListMappings.php new file mode 100644 index 00000000..ab34f60c --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/CredentialListMappings.php @@ -0,0 +1,24 @@ +account->sip->domains->get('SDXXX')->credential_list_mappings->create("CLXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + * + * :param string $credential_list_sid: the sid of the CredentialList you're adding to this domain. + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($credential_list_sid, $params = array()) { + return parent::_create(array( + 'CredentialListSid' => $credential_list_sid, + ) + $params); + } +} + diff --git a/OpenVBX/libraries/Services/Twilio/Rest/CredentialLists.php b/OpenVBX/libraries/Services/Twilio/Rest/CredentialLists.php new file mode 100644 index 00000000..e8eb1a69 --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/CredentialLists.php @@ -0,0 +1,24 @@ +account->sip->credential_lists->create("MyFriendlyName"); + * + * :param string $friendly_name: the friendly name of this credential list + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($friendly_name, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + ) + $params); + } + +} diff --git a/OpenVBX/libraries/Services/Twilio/Rest/Credentials.php b/OpenVBX/libraries/Services/Twilio/Rest/Credentials.php new file mode 100644 index 00000000..129a44db --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/Credentials.php @@ -0,0 +1,28 @@ +account->sip->credential_lists->get('CLXXX')->credentials->create( + * "AwesomeUsername", "SuperSecretPassword", + * ); + * + * :param string $username: the username for the new Credential object + * :param string $password: the password for the new Credential object + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($username, $password, $params = array()) { + return parent::_create(array( + 'Username' => $username, + 'Password' => $password, + ) + $params); + } + +} diff --git a/OpenVBX/libraries/Services/Twilio/Rest/Domain.php b/OpenVBX/libraries/Services/Twilio/Rest/Domain.php new file mode 100644 index 00000000..7d5a5c26 --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/Domain.php @@ -0,0 +1,70 @@ +setupSubresources( + 'ip_access_control_list_mappings', + 'credential_list_mappings' + ); + } +} diff --git a/OpenVBX/libraries/Services/Twilio/Rest/Domains.php b/OpenVBX/libraries/Services/Twilio/Rest/Domains.php new file mode 100644 index 00000000..041c080c --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/Domains.php @@ -0,0 +1,28 @@ +account->sip->domains->create( + * "MyFriendlyName", "MyDomainName" + * ); + * + * :param string $friendly_name: the friendly name of this domain + * :param string $domain_name: the domain name for this domain + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($friendly_name, $domain_name, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + 'DomainName' => $domain_name, + ) + $params); + } +} + diff --git a/OpenVBX/libraries/Services/Twilio/Rest/IncomingPhoneNumber.php b/OpenVBX/libraries/Services/Twilio/Rest/IncomingPhoneNumber.php index 9cc65526..ab72eafe 100755 --- a/OpenVBX/libraries/Services/Twilio/Rest/IncomingPhoneNumber.php +++ b/OpenVBX/libraries/Services/Twilio/Rest/IncomingPhoneNumber.php @@ -1,5 +1,90 @@ `_ + * documentation. + * + * .. php:attr:: sid + * + * A 34 character string that uniquely idetifies this resource. + * + * .. php:attr:: date_created + * + * The date that this resource was created, given as GMT RFC 2822 format. + * + * .. php:attr:: date_updated + * + * The date that this resource was last updated, given as GMT RFC 2822 format. + * + * .. php:attr:: friendly_name + * + * A human readable descriptive text for this resource, up to 64 + * characters long. By default, the FriendlyName is a nicely formatted + * version of the phone number. + * + * .. php:attr:: account_sid + * + * The unique id of the Account responsible for this phone number. + * + * .. php:attr:: phone_number + * + * The incoming phone number. e.g., +16175551212 (E.164 format) + * + * .. php:attr:: api_version + * + * Calls to this phone number will start a new TwiML session with this + * API version. + * + * .. php:attr:: voice_caller_id_lookup + * + * Look up the caller's caller-ID name from the CNAM database (additional charges apply). Either true or false. + * + * .. php:attr:: voice_url + * + * The URL Twilio will request when this phone number receives a call. + * + * .. php:attr:: voice_method + * + * The HTTP method Twilio will use when requesting the above Url. Either GET or POST. + * + * .. php:attr:: voice_fallback_url + * + * The URL that Twilio will request if an error occurs retrieving or executing the TwiML requested by Url. + * + * .. php:attr:: voice_fallback_method + * + * The HTTP method Twilio will use when requesting the VoiceFallbackUrl. Either GET or POST. + * + * .. php:attr:: status_callback + * + * The URL that Twilio will request to pass status parameters (such as call ended) to your application. + * + * .. php:attr:: status_callback_method + * + * The HTTP method Twilio will use to make requests to the StatusCallback URL. Either GET or POST. + * + * .. php:attr:: sms_url + * + * The URL Twilio will request when receiving an incoming SMS message to this number. + * + * .. php:attr:: sms_method + * + * The HTTP method Twilio will use when making requests to the SmsUrl. Either GET or POST. + * + * .. php:attr:: sms_fallback_url + * + * The URL that Twilio will request if an error occurs retrieving or executing the TwiML from SmsUrl. + * + * .. php:attr:: sms_fallback_method + * + * The HTTP method Twilio will use when requesting the above URL. Either GET or POST. + * + * .. php:attr:: uri + * + * The URI for this resource, relative to https://api.twilio.com. + */ class Services_Twilio_Rest_IncomingPhoneNumber extends Services_Twilio_InstanceResource { diff --git a/OpenVBX/libraries/Services/Twilio/Rest/IncomingPhoneNumbers.php b/OpenVBX/libraries/Services/Twilio/Rest/IncomingPhoneNumbers.php index 15cafa22..48ce4cab 100755 --- a/OpenVBX/libraries/Services/Twilio/Rest/IncomingPhoneNumbers.php +++ b/OpenVBX/libraries/Services/Twilio/Rest/IncomingPhoneNumbers.php @@ -1,22 +1,44 @@ `_ + * documentation at twilio.com. + */ +class Services_Twilio_Rest_IncomingPhoneNumbers extends Services_Twilio_ListResource { + function init($client, $uri) { + $this->setupSubresources( + 'local', + 'toll_free', + 'mobile' + ); + } + function create(array $params = array()) { return parent::_create($params); } + function getList($type, array $params = array()) + { + return $this->client->retrieveData($this->uri . "/$type", $params); + } + /** * Return a phone number instance from its E.164 representation. If more * than one number matches the search string, returns the first one. * - * @param string $number The number in E.164 format, eg "+684105551234" - * @return Services_Twilio_Rest_IncomingPhoneNumber|null The number object, - * or null - * - * @throws Services_Twilio_RestException if the number is invalid, not - * provided in E.164 format or for any other API exception. + * Example usage: + * + * .. code-block:: php + * + * $number = $client->account->incoming_phone_numbers->getNumber('+14105551234'); + * echo $number->sid; + * + * :param string $number: The number in E.164 format, eg "+684105551234" + * :return: A :php:class:`Services_Twilio_Rest_IncomingPhoneNumber` object, or null + * :raises: a A :php:class:`Services_Twilio_RestException` if the number is + * invalid, not provided in E.164 format or for any other API exception. */ public function getNumber($number) { $page = $this->getPage(0, 1, array( @@ -29,3 +51,9 @@ public function getNumber($number) { return $items[0]; } } + +class Services_Twilio_Rest_Local extends Services_Twilio_NumberType { } + +class Services_Twilio_Rest_Mobile extends Services_Twilio_NumberType { } + +class Services_Twilio_Rest_TollFree extends Services_Twilio_NumberType { } diff --git a/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlList.php b/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlList.php new file mode 100644 index 00000000..5ba83f3e --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlList.php @@ -0,0 +1,40 @@ +setupSubresources( + 'ip_addresses' + ); + } +} diff --git a/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlListMapping.php b/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlListMapping.php new file mode 100644 index 00000000..ce5bc5a9 --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlListMapping.php @@ -0,0 +1,37 @@ +setupSubresources( + 'ip_addresses' + ); + } +} + diff --git a/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlListMappings.php b/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlListMappings.php new file mode 100644 index 00000000..f58e1b95 --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlListMappings.php @@ -0,0 +1,25 @@ +account->sip->domains->get('SDXXX')->ip_access_control_list_mappings->create("ALXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + * + * :param string $ip_access_control_list_sid: the sid of the IpAccessControList + * you're adding to this domain. + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($ip_access_control_list_sid, $params = array()) { + return parent::_create(array( + 'IpAccessControlListSid' => $ip_access_control_list_sid, + ) + $params); + } +} + diff --git a/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlLists.php b/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlLists.php new file mode 100644 index 00000000..88b9d14f --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/IpAccessControlLists.php @@ -0,0 +1,27 @@ +account->sip->ip_access_control_lists->create("MyFriendlyName"); + * + * :param string $friendly_name: the friendly name of this ip access control list + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + * :return: the created list + * :rtype: :class:`Services_Twilio_Rest_IpAccessControlList` + * + */ + public function create($friendly_name, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + ) + $params); + } + +} diff --git a/OpenVBX/libraries/Services/Twilio/Rest/IpAddress.php b/OpenVBX/libraries/Services/Twilio/Rest/IpAddress.php new file mode 100644 index 00000000..38b716e6 --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/IpAddress.php @@ -0,0 +1,34 @@ +instance_name = "Services_Twilio_Rest_IpAddress"; + parent::__construct($client, $uri); + } + + /** + * Creates a new IpAddress instance + * + * Example usage: + * + * .. code-block:: php + * + * $client->account->sip->ip_access_control_lists->get('ALXXX')->ip_addresses->create( + * "FriendlyName", "127.0.0.1" + * ); + * + * :param string $friendly_name: the friendly name for the new IpAddress object + * :param string $ip_address: the ip address for the new IpAddress object + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. + */ + public function create($friendly_name, $ip_address, $params = array()) { + return parent::_create(array( + 'FriendlyName' => $friendly_name, + 'IpAddress' => $ip_address, + ) + $params); + } +} + diff --git a/OpenVBX/libraries/Services/Twilio/Rest/Media.php b/OpenVBX/libraries/Services/Twilio/Rest/Media.php new file mode 100644 index 00000000..0d8a19f3 --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/Media.php @@ -0,0 +1,31 @@ +` objects. + * For the definitive reference, see the `Twilio Media List Documentation + * `_. + */ +class Services_Twilio_Rest_Media extends Services_Twilio_ListResource { + + + // This is overridden because the list key in the Twilio response + // is "media_list", not "media". + public function getResourceName($camelized = false) + { + if ($camelized) { + return "MediaList"; + } else { + return "media_list"; + } + } + + // We manually set the instance name here so that the parent + // constructor doesn't attempt to figure out it. It would do it + // incorrectly because we override getResourceName above. + public function __construct($client, $uri) { + $this->instance_name = "Services_Twilio_Rest_MediaInstance"; + parent::__construct($client, $uri); + } + +} + diff --git a/OpenVBX/libraries/Services/Twilio/Rest/MediaInstance.php b/OpenVBX/libraries/Services/Twilio/Rest/MediaInstance.php new file mode 100644 index 00000000..1a152b2e --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/MediaInstance.php @@ -0,0 +1,37 @@ +`_. + * + * .. php:attr:: sid + * + * A 34 character string that identifies this object + * + * .. php:attr:: account_sid + * + * A 34 character string representing the account that sent the message + * + * .. php:attr:: parent_sid + * + * The sid of the message that created this media. + * + * .. php:attr:: date_created + * + * The date the message was created + * + * .. php:attr:: date_updated + * + * The date the message was updated + * + * .. php:attr:: content_type + * + * The content-type of the media. + */ +class Services_Twilio_Rest_MediaInstance extends Services_Twilio_InstanceResource { + public function __construct($client, $uri) { + $uri = str_replace('MediaInstance', 'Media', $uri); + parent::__construct($client, $uri); + } +} + diff --git a/OpenVBX/libraries/Services/Twilio/Rest/Message.php b/OpenVBX/libraries/Services/Twilio/Rest/Message.php new file mode 100644 index 00000000..afc6cf5b --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/Message.php @@ -0,0 +1,53 @@ +setupSubresources( + 'media' + ); + } +} + diff --git a/OpenVBX/libraries/Services/Twilio/Rest/Messages.php b/OpenVBX/libraries/Services/Twilio/Rest/Messages.php new file mode 100644 index 00000000..355fce03 --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/Messages.php @@ -0,0 +1,73 @@ +account->messages->create(array( + * "Body" => "foo", + * "From" => "+14105551234", + * "To" => "+14105556789", + * )); + * + * :param array $params: a single array of parameters which is serialized and + * sent directly to the Twilio API. You may find it easier to use the + * sendMessage helper instead of this function. + * + */ + public function create($params = array()) { + return parent::_create($params); + } + + /** + * Send a message + * + * .. code-block:: php + * + * $client = new Services_Twilio('AC123', '123'); + * $message = $client->account->messages->sendMessage( + * '+14105551234', // From a Twilio number in your account + * '+14105556789', // Text any number + * 'Come at the king, you best not miss.' // Message body (if any) + * array('https://demo.twilio.com/owl.png'), // An array of MediaUrls + * ); + * + * :param string $from: the from number for the message, this must be a + * number you purchased from Twilio + * :param string $to: the message recipient's phone number + * :param $mediaUrls: the URLs of images to send in this MMS + * :type $mediaUrls: null (don't include media), a single URL, or an array + * of URLs to send as media with this message + * :param string $body: the text to include along with this MMS + * :param array $params: Any additional params (callback, etc) you'd like to + * send with this request, these are serialized and sent as POST + * parameters + * + * :return: The created :class:`Services_Twilio_Rest_Message` + * :raises: :class:`Services_Twilio_RestException` + * An exception if the parameters are invalid (for example, the from + * number is not a Twilio number registered to your account, or is + * unable to send MMS) + */ + public function sendMessage($from, $to, $body = null, $mediaUrls = null, + $params = array() + ) { + $postParams = array( + 'From' => $from, + 'To' => $to, + ); + // When the request is made, this will get serialized into MediaUrl=a&MediaUrl=b + if (!is_null($mediaUrls)) { + $postParams['MediaUrl'] = $mediaUrls; + } + if (!is_null($body)) { + $postParams['Body'] = $body; + } + return self::create($postParams + $params); + } +} diff --git a/OpenVBX/libraries/Services/Twilio/Rest/Sip.php b/OpenVBX/libraries/Services/Twilio/Rest/Sip.php new file mode 100644 index 00000000..8c4bdb5d --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/Rest/Sip.php @@ -0,0 +1,19 @@ +setupSubresources( + 'domains', + 'ip_access_control_lists', + 'credential_lists' + ); + } + + public function getResourceName($camelized = false) { + return "SIP"; + } +} diff --git a/OpenVBX/libraries/Services/Twilio/RestException.php b/OpenVBX/libraries/Services/Twilio/RestException.php index c7e77a3c..c7de16ce 100755 --- a/OpenVBX/libraries/Services/Twilio/RestException.php +++ b/OpenVBX/libraries/Services/Twilio/RestException.php @@ -1,25 +1,44 @@ status = $status; $this->info = $info; parent::__construct($message, $code); } - public function getStatus() - { + /** + * Get the HTTP status code + */ + public function getStatus() { return $this->status; } - public function getInfo() - { + /** + * Get a link to more information + */ + public function getInfo() { return $this->info; } } diff --git a/OpenVBX/libraries/Services/Twilio/SIPListResource.php b/OpenVBX/libraries/Services/Twilio/SIPListResource.php new file mode 100644 index 00000000..1e63b67f --- /dev/null +++ b/OpenVBX/libraries/Services/Twilio/SIPListResource.php @@ -0,0 +1,14 @@ + array( + * CURLOPT_USERAGENT => self::USER_AGENT, + * CURLOPT_HTTPHEADER => array('Accept-Charset: utf-8'), + * CURLOPT_CAINFO => dirname(__FILE__) . '/cacert.pem', + * )) + * ); + */ class Services_Twilio_TinyHttp { var $user, $pass, $scheme, $host, $port, $debug, $curlopts; @@ -83,7 +107,7 @@ public function __call($name, $args) { fclose($buf); } return array($status, $headers, $body); - } else { + } else { throw new Services_Twilio_TinyHttpException(curl_error($curl)); } } else throw new Services_Twilio_TinyHttpException(curl_error($curl)); diff --git a/OpenVBX/libraries/Services/Twilio/Twiml.php b/OpenVBX/libraries/Services/Twilio/Twiml.php index 41e73053..93c30eb7 100755 --- a/OpenVBX/libraries/Services/Twilio/Twiml.php +++ b/OpenVBX/libraries/Services/Twilio/Twiml.php @@ -115,7 +115,7 @@ public function __call($verb, array $args) } $child->addAttribute($name, $value); } - return new self($child); + return new static($child); } /** diff --git a/OpenVBX/models/vbx_accounts.php b/OpenVBX/models/vbx_accounts.php index 167256dc..b9d937fa 100644 --- a/OpenVBX/models/vbx_accounts.php +++ b/OpenVBX/models/vbx_accounts.php @@ -23,7 +23,7 @@ class VBX_AccountsException extends Exception {} -class VBX_Accounts extends Model +class VBX_Accounts extends CI_Model { public function __construct() { @@ -50,4 +50,4 @@ function getAccountType() return $account_type; } -} \ No newline at end of file +} diff --git a/OpenVBX/models/vbx_call.php b/OpenVBX/models/vbx_call.php index 4fca18c5..00998193 100644 --- a/OpenVBX/models/vbx_call.php +++ b/OpenVBX/models/vbx_call.php @@ -26,14 +26,14 @@ class VBX_CallException extends Exception {} /* * Call Class */ -class VBX_Call extends Model { +class VBX_Call extends CI_Model { public $total = 0; const CACHE_TIME_SEC = 180; public function __construct() { - parent::Model(); + parent::__construct(); } /** diff --git a/OpenVBX/models/vbx_incoming_numbers.php b/OpenVBX/models/vbx_incoming_numbers.php index 14de41da..fce9922a 100644 --- a/OpenVBX/models/vbx_incoming_numbers.php +++ b/OpenVBX/models/vbx_incoming_numbers.php @@ -23,7 +23,7 @@ class VBX_IncomingNumberException extends Exception {} -class VBX_Incoming_numbers extends Model +class VBX_Incoming_numbers extends CI_Model { public function __construct() { diff --git a/OpenVBX/models/vbx_message.php b/OpenVBX/models/vbx_message.php index cbf0c545..9639e379 100644 --- a/OpenVBX/models/vbx_message.php +++ b/OpenVBX/models/vbx_message.php @@ -24,7 +24,7 @@ class VBX_MessageException extends Exception {} /* * Message Class */ -class VBX_Message extends Model { +class VBX_Message extends CI_Model { public $auto_populate_has_one = TRUE; public $has_one = array('group', 'user'); diff --git a/OpenVBX/models/vbx_settings.php b/OpenVBX/models/vbx_settings.php index 8be12eb4..4dec2036 100644 --- a/OpenVBX/models/vbx_settings.php +++ b/OpenVBX/models/vbx_settings.php @@ -21,7 +21,7 @@ class VBX_SettingsException extends Exception {} -class VBX_Settings extends Model +class VBX_Settings extends CI_Model { protected $settings_table = 'settings'; protected $tenants_table = 'tenants'; diff --git a/OpenVBX/models/vbx_sms_message.php b/OpenVBX/models/vbx_sms_message.php index e7742ece..3bf88e2d 100644 --- a/OpenVBX/models/vbx_sms_message.php +++ b/OpenVBX/models/vbx_sms_message.php @@ -25,7 +25,7 @@ class VBX_Sms_messageException extends Exception {} /* * SMS Message Class */ -class VBX_Sms_message extends Model { +class VBX_Sms_message extends CI_Model { public $total = 0; @@ -35,7 +35,7 @@ class VBX_Sms_message extends Model { function __construct() { - parent::Model(); + parent::__construct(); $ci = &get_instance(); $this->cache_key = $ci->twilio_sid . '_sms'; } diff --git a/OpenVBX/models/vbx_theme.php b/OpenVBX/models/vbx_theme.php index 4c63b26a..eb478d40 100644 --- a/OpenVBX/models/vbx_theme.php +++ b/OpenVBX/models/vbx_theme.php @@ -21,7 +21,7 @@ class VBX_ThemeException extends Exception {} -class VBX_Theme extends Model +class VBX_Theme extends CI_Model { public function __construct() { @@ -54,4 +54,4 @@ public function get_iphone_json($name) $name = preg_replace('/[^0-9a-zA-Z-_]/', '', $name); return read_file('assets/themes/'.$name.'/iphone.json'); } -} \ No newline at end of file +} diff --git a/index.php b/index.php index 5cf6fdbc..87cd043e 100644 --- a/index.php +++ b/index.php @@ -90,7 +90,7 @@ function shutdown() | NO TRAILING SLASH! | */ -$application_folder = dirname(__FILE__) . '/OpenVBX'; +$application_folder = 'OpenVBX'; /* |=============================================================== @@ -136,9 +136,11 @@ function shutdown() | */ define('EXT', '.'.pathinfo(__FILE__, PATHINFO_EXTENSION)); -define('FCPATH', __FILE__); +define('FCPATH', str_replace(SELF, '', __FILE__)); define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME)); define('BASEPATH', $system_folder.'/'); +// Name of the "system folder" +define('SYSDIR', trim(strrchr(trim(BASEPATH, '/'), '/'), '/')); if (is_dir($application_folder)) { @@ -162,7 +164,7 @@ function shutdown() | And away we go... | */ -require_once BASEPATH.'codeigniter/CodeIgniter'.EXT; +require_once BASEPATH.'core/CodeIgniter.php'; /* End of file index.php */ /* Location: ./index.php */ diff --git a/system/codeigniter/Base4.php b/system/codeigniter/Base4.php deleted file mode 100644 index 91a43502..00000000 --- a/system/codeigniter/Base4.php +++ /dev/null @@ -1,69 +0,0 @@ -load->library('email') to instantiate - * classes that can then be used within controllers as $this->email->send() - * - * PHP 4 also has trouble referencing the CI super object within application - * constructors since objects do not exist until the class is fully - * instantiated. Basically PHP 4 sucks... - * - * Since PHP 5 doesn't suffer from this problem so we load one of - * two files based on the version of PHP being run. - * - * @package CodeIgniter - * @subpackage codeigniter - * @category front-controller - * @author ExpressionEngine Dev Team - * @link http://codeigniter.com/user_guide/ - */ - class CI_Base extends CI_Loader { - - function CI_Base() - { - // This allows syntax like $this->load->foo() to work - parent::CI_Loader(); - $this->load =& $this; - - // This allows resources used within controller constructors to work - global $OBJ; - $OBJ = $this->load; // Do NOT use a reference. - } -} - -function &get_instance() -{ - global $CI, $OBJ; - - if (is_object($CI)) - { - return $CI; - } - - return $OBJ->load; -} - - -/* End of file Base4.php */ -/* Location: ./system/codeigniter/Base4.php */ \ No newline at end of file diff --git a/system/codeigniter/Base5.php b/system/codeigniter/Base5.php deleted file mode 100644 index a2cca72c..00000000 --- a/system/codeigniter/Base5.php +++ /dev/null @@ -1,56 +0,0 @@ -mark('total_execution_time_start'); -$BM->mark('loading_time_base_classes_start'); - -/* - * ------------------------------------------------------ - * Instantiate the hooks class - * ------------------------------------------------------ - */ - -$EXT =& load_class('Hooks'); - -/* - * ------------------------------------------------------ - * Is there a "pre_system" hook? - * ------------------------------------------------------ - */ -$EXT->_call_hook('pre_system'); - -/* - * ------------------------------------------------------ - * Instantiate the base classes - * ------------------------------------------------------ - */ - -$CFG =& load_class('Config'); -$URI =& load_class('URI'); -$RTR =& load_class('Router'); -$OUT =& load_class('Output'); - -/* - * ------------------------------------------------------ - * Is there a valid cache file? If so, we're done... - * ------------------------------------------------------ - */ - -if ($EXT->_call_hook('cache_override') === FALSE) -{ - if ($OUT->_display_cache($CFG, $URI) == TRUE) - { - exit; - } -} - -/* - * ------------------------------------------------------ - * Load the remaining base classes - * ------------------------------------------------------ - */ - -$IN =& load_class('Input'); -$LANG =& load_class('Language'); - -/* - * ------------------------------------------------------ - * Load the app controller and local controller - * ------------------------------------------------------ - * - * Note: Due to the poor object handling in PHP 4 we'll - * conditionally load different versions of the base - * class. Retaining PHP 4 compatibility requires a bit of a hack. - * - * Note: The Loader class needs to be included first - * - */ -if ( ! is_php('5.0.0')) -{ - load_class('Loader', FALSE); - require(BASEPATH.'codeigniter/Base4'.EXT); -} -else -{ - require(BASEPATH.'codeigniter/Base5'.EXT); -} - -// Load the base controller class -load_class('Controller', FALSE); - -// Load the local application controller -// Note: The Router class automatically validates the controller path. If this include fails it -// means that the default controller in the Routes.php file is not resolving to something valid. -if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().EXT)) -{ - show_error('Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.'); -} - -include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().EXT); - -// Set a mark point for benchmarking -$BM->mark('loading_time_base_classes_end'); - - -/* - * ------------------------------------------------------ - * Security check - * ------------------------------------------------------ - * - * None of the functions in the app controller or the - * loader class can be called via the URI, nor can - * controller functions that begin with an underscore - */ -$class = $RTR->fetch_class(); -$method = $RTR->fetch_method(); - -if ( ! class_exists($class) - OR $method == 'controller' - OR strncmp($method, '_', 1) == 0 - OR in_array(strtolower($method), array_map('strtolower', get_class_methods('Controller'))) - ) -{ - show_404("{$class}/{$method}"); -} - -/* - * ------------------------------------------------------ - * Is there a "pre_controller" hook? - * ------------------------------------------------------ - */ -$EXT->_call_hook('pre_controller'); - -/* - * ------------------------------------------------------ - * Instantiate the controller and call requested method - * ------------------------------------------------------ - */ - -// Mark a start point so we can benchmark the controller -$BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start'); - -$CI = new $class(); - -// Is this a scaffolding request? -if ($RTR->scaffolding_request === TRUE) -{ - if ($EXT->_call_hook('scaffolding_override') === FALSE) - { - $CI->_ci_scaffolding(); - } -} -else -{ - /* - * ------------------------------------------------------ - * Is there a "post_controller_constructor" hook? - * ------------------------------------------------------ - */ - $EXT->_call_hook('post_controller_constructor'); - - // Is there a "remap" function? - if (method_exists($CI, '_remap')) - { - $CI->_remap($method); - } - else - { - // is_callable() returns TRUE on some versions of PHP 5 for private and protected - // methods, so we'll use this workaround for consistent behavior - if ( ! in_array(strtolower($method), array_map('strtolower', get_class_methods($CI)))) - { - show_404("{$class}/{$method}"); - } - - // Call the requested method. - // Any URI segments present (besides the class/function) will be passed to the method for convenience - call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2)); - } -} - -// Mark a benchmark end point -$BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end'); - -/* - * ------------------------------------------------------ - * Is there a "post_controller" hook? - * ------------------------------------------------------ - */ -$EXT->_call_hook('post_controller'); - -/* - * ------------------------------------------------------ - * Send the final rendered output to the browser - * ------------------------------------------------------ - */ - -if ($EXT->_call_hook('display_override') === FALSE) -{ - $OUT->_display(); -} - -/* - * ------------------------------------------------------ - * Is there a "post_system" hook? - * ------------------------------------------------------ - */ -$EXT->_call_hook('post_system'); - -/* - * ------------------------------------------------------ - * Close the DB connection if one exists - * ------------------------------------------------------ - */ -if (class_exists('CI_DB') AND isset($CI->db)) -{ - $CI->db->close(); -} - - -/* End of file CodeIgniter.php */ -/* Location: ./system/codeigniter/CodeIgniter.php */ \ No newline at end of file diff --git a/system/codeigniter/Common.php b/system/codeigniter/Common.php deleted file mode 100644 index eb9dce64..00000000 --- a/system/codeigniter/Common.php +++ /dev/null @@ -1,421 +0,0 @@ - 5 -* we'll set a static variable. -* -* @access public -* @param string -* @return bool -*/ -function is_php($version = '5.0.0') -{ - static $_is_php; - $version = (string)$version; - - if ( ! isset($_is_php[$version])) - { - $_is_php[$version] = (version_compare(PHP_VERSION, $version) < 0) ? FALSE : TRUE; - } - - return $_is_php[$version]; -} - -// ------------------------------------------------------------------------ - -/** - * Tests for file writability - * - * is_writable() returns TRUE on Windows servers when you really can't write to - * the file, based on the read-only attribute. is_writable() is also unreliable - * on Unix servers if safe_mode is on. - * - * @access private - * @return void - */ -function is_really_writable($file) -{ - // If we're on a Unix server with safe_mode off we call is_writable - if (DIRECTORY_SEPARATOR == '/' AND @ini_get("safe_mode") == FALSE) - { - return is_writable($file); - } - - // For windows servers and safe_mode "on" installations we'll actually - // write a file then read it. Bah... - if (is_dir($file)) - { - $file = rtrim($file, '/').'/'.md5(rand(1,100)); - - if (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) - { - return FALSE; - } - - fclose($fp); - @chmod($file, DIR_WRITE_MODE); - @unlink($file); - return TRUE; - } - elseif (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) - { - return FALSE; - } - - fclose($fp); - return TRUE; -} - -// ------------------------------------------------------------------------ - -/** -* Class registry -* -* This function acts as a singleton. If the requested class does not -* exist it is instantiated and set to a static variable. If it has -* previously been instantiated the variable is returned. -* -* @access public -* @param string the class name being requested -* @param bool optional flag that lets classes get loaded but not instantiated -* @return object -*/ -function &load_class($class, $instantiate = TRUE) -{ - static $objects = array(); - - // Does the class exist? If so, we're done... - if (isset($objects[$class])) - { - return $objects[$class]; - } - - // If the requested class does not exist in the application/libraries - // folder we'll load the native class from the system/libraries folder. - if (file_exists(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT)) - { - require(BASEPATH.'libraries/'.$class.EXT); - require(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT); - $is_subclass = TRUE; - } - else - { - if (file_exists(APPPATH.'libraries/'.$class.EXT)) - { - require(APPPATH.'libraries/'.$class.EXT); - $is_subclass = FALSE; - } - else - { - require(BASEPATH.'libraries/'.$class.EXT); - $is_subclass = FALSE; - } - } - - if ($instantiate == FALSE) - { - $objects[$class] = TRUE; - return $objects[$class]; - } - - if ($is_subclass == TRUE) - { - $name = config_item('subclass_prefix').$class; - - $objects[$class] =& instantiate_class(new $name()); - return $objects[$class]; - } - - $name = ($class != 'Controller') ? 'CI_'.$class : $class; - - $objects[$class] =& instantiate_class(new $name()); - return $objects[$class]; -} - -/** - * Instantiate Class - * - * Returns a new class object by reference, used by load_class() and the DB class. - * Required to retain PHP 4 compatibility and also not make PHP 5.3 cry. - * - * Use: $obj =& instantiate_class(new Foo()); - * - * @access public - * @param object - * @return object - */ -function &instantiate_class(&$class_object) -{ - return $class_object; -} - -/** -* Loads the main config.php file -* -* @access private -* @return array -*/ -function &get_config() -{ - static $main_conf; - - if ( ! isset($main_conf)) - { - if ( ! file_exists(APPPATH.'config/config'.EXT)) - { - exit('The configuration file config'.EXT.' does not exist.'); - } - - require(APPPATH.'config/config'.EXT); - - if ( ! isset($config) OR ! is_array($config)) - { - exit('Your config file does not appear to be formatted correctly.'); - } - - $main_conf[0] =& $config; - } - return $main_conf[0]; -} - -/** -* Gets a config item -* -* @access public -* @return mixed -*/ -function config_item($item) -{ - static $config_item = array(); - - if ( ! isset($config_item[$item])) - { - $config =& get_config(); - - if ( ! isset($config[$item])) - { - return FALSE; - } - $config_item[$item] = $config[$item]; - } - - return $config_item[$item]; -} - - -/** -* Error Handler -* -* This function lets us invoke the exception class and -* display errors using the standard error template located -* in application/errors/errors.php -* This function will send the error page directly to the -* browser and exit. -* -* @access public -* @return void -*/ -function show_error($message, $status_code = 500) -{ - $error =& load_class('Exceptions'); - echo $error->show_error('An Error Was Encountered', $message, 'error_general', $status_code); - exit; -} - - -/** -* 404 Page Handler -* -* This function is similar to the show_error() function above -* However, instead of the standard error template it displays -* 404 errors. -* -* @access public -* @return void -*/ -function show_404($page = '') -{ - $error =& load_class('Exceptions'); - $error->show_404($page); - exit; -} - - -/** -* Error Logging Interface -* -* We use this as a simple mechanism to access the logging -* class and send messages to be logged. -* -* @access public -* @return void -*/ -function log_message($level = 'error', $message, $php_error = FALSE) -{ - static $LOG; - - $config =& get_config(); - if ($config['log_threshold'] == 0) - { - return; - } - - $LOG =& load_class('Log'); - $LOG->write_log($level, $message, $php_error); -} - - -/** - * Set HTTP Status Header - * - * @access public - * @param int the status code - * @param string - * @return void - */ -function set_status_header($code = 200, $text = '') -{ - $stati = array( - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - - 400 => 'Bad Request', - 401 => 'Unauthorized', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported' - ); - - if ($code == '' OR ! is_numeric($code)) - { - show_error('Status codes must be numeric', 500); - } - - if (isset($stati[$code]) AND $text == '') - { - $text = $stati[$code]; - } - - if ($text == '') - { - show_error('No status text available. Please check your status code number or supply your own message text.', 500); - } - - $server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : FALSE; - - if (substr(php_sapi_name(), 0, 3) == 'cgi') - { - header("Status: {$code} {$text}", TRUE); - } - elseif ($server_protocol == 'HTTP/1.1' OR $server_protocol == 'HTTP/1.0') - { - header($server_protocol." {$code} {$text}", TRUE, $code); - } - else - { - header("HTTP/1.1 {$code} {$text}", TRUE, $code); - } -} - - -/** -* Exception Handler -* -* This is the custom exception handler that is declaired at the top -* of Codeigniter.php. The main reason we use this is permit -* PHP errors to be logged in our own log files since we may -* not have access to server logs. Since this function -* effectively intercepts PHP errors, however, we also need -* to display errors based on the current error_reporting level. -* We do that with the use of a PHP error template. -* -* @access private -* @return void -*/ -function _exception_handler($severity, $message, $filepath, $line) -{ - // We don't bother with "strict" notices since they will fill up - // the log file with information that isn't normally very - // helpful. For example, if you are running PHP 5 and you - // use version 4 style class functions (without prefixes - // like "public", "private", etc.) you'll get notices telling - // you that these have been deprecated. - - if ($severity == E_STRICT) - { - return; - } - - $error =& load_class('Exceptions'); - - // Should we display the error? - // We'll get the current error_reporting level and add its bits - // with the severity bits to find out. - - if (($severity & error_reporting()) == $severity) - { - $error->show_php_error($severity, $message, $filepath, $line); - } - - // Should we log the error? No? We're done... - $config =& get_config(); - if ($config['log_threshold'] == 0) - { - return; - } - - $error->log_exception($severity, $message, $filepath, $line); -} - - - -/* End of file Common.php */ -/* Location: ./system/codeigniter/Common.php */ \ No newline at end of file diff --git a/system/codeigniter/Compat.php b/system/codeigniter/Compat.php deleted file mode 100644 index 958ab4c0..00000000 --- a/system/codeigniter/Compat.php +++ /dev/null @@ -1,93 +0,0 @@ -marker[$point2] = microtime(); } - + list($sm, $ss) = explode(' ', $this->marker[$point1]); list($em, $es) = explode(' ', $this->marker[$point2]); return number_format(($em + $es) - ($sm + $ss), $decimals); } - + // -------------------------------------------------------------------- /** @@ -110,4 +115,4 @@ function memory_usage() // END CI_Benchmark class /* End of file Benchmark.php */ -/* Location: ./system/libraries/Benchmark.php */ \ No newline at end of file +/* Location: ./system/core/Benchmark.php */ \ No newline at end of file diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php new file mode 100755 index 00000000..e0819c80 --- /dev/null +++ b/system/core/CodeIgniter.php @@ -0,0 +1,402 @@ + $assign_to_config['subclass_prefix'])); + } + +/* + * ------------------------------------------------------ + * Set a liberal script execution time limit + * ------------------------------------------------------ + */ + if (function_exists("set_time_limit") == TRUE AND @ini_get("safe_mode") == 0) + { + @set_time_limit(300); + } + +/* + * ------------------------------------------------------ + * Start the timer... tick tock tick tock... + * ------------------------------------------------------ + */ + $BM =& load_class('Benchmark', 'core'); + $BM->mark('total_execution_time_start'); + $BM->mark('loading_time:_base_classes_start'); + +/* + * ------------------------------------------------------ + * Instantiate the hooks class + * ------------------------------------------------------ + */ + $EXT =& load_class('Hooks', 'core'); + +/* + * ------------------------------------------------------ + * Is there a "pre_system" hook? + * ------------------------------------------------------ + */ + $EXT->_call_hook('pre_system'); + +/* + * ------------------------------------------------------ + * Instantiate the config class + * ------------------------------------------------------ + */ + $CFG =& load_class('Config', 'core'); + + // Do we have any manually set config items in the index.php file? + if (isset($assign_to_config)) + { + $CFG->_assign_to_config($assign_to_config); + } + +/* + * ------------------------------------------------------ + * Instantiate the UTF-8 class + * ------------------------------------------------------ + * + * Note: Order here is rather important as the UTF-8 + * class needs to be used very early on, but it cannot + * properly determine if UTf-8 can be supported until + * after the Config class is instantiated. + * + */ + + $UNI =& load_class('Utf8', 'core'); + +/* + * ------------------------------------------------------ + * Instantiate the URI class + * ------------------------------------------------------ + */ + $URI =& load_class('URI', 'core'); + +/* + * ------------------------------------------------------ + * Instantiate the routing class and set the routing + * ------------------------------------------------------ + */ + $RTR =& load_class('Router', 'core'); + $RTR->_set_routing(); + + // Set any routing overrides that may exist in the main index file + if (isset($routing)) + { + $RTR->_set_overrides($routing); + } + +/* + * ------------------------------------------------------ + * Instantiate the output class + * ------------------------------------------------------ + */ + $OUT =& load_class('Output', 'core'); + +/* + * ------------------------------------------------------ + * Is there a valid cache file? If so, we're done... + * ------------------------------------------------------ + */ + if ($EXT->_call_hook('cache_override') === FALSE) + { + if ($OUT->_display_cache($CFG, $URI) == TRUE) + { + exit; + } + } + +/* + * ----------------------------------------------------- + * Load the security class for xss and csrf support + * ----------------------------------------------------- + */ + $SEC =& load_class('Security', 'core'); + +/* + * ------------------------------------------------------ + * Load the Input class and sanitize globals + * ------------------------------------------------------ + */ + $IN =& load_class('Input', 'core'); + +/* + * ------------------------------------------------------ + * Load the Language class + * ------------------------------------------------------ + */ + $LANG =& load_class('Lang', 'core'); + +/* + * ------------------------------------------------------ + * Load the app controller and local controller + * ------------------------------------------------------ + * + */ + // Load the base controller class + require BASEPATH.'core/Controller.php'; + + function &get_instance() + { + return CI_Controller::get_instance(); + } + + + if (file_exists(APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php')) + { + require APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'; + } + + // Load the local application controller + // Note: The Router class automatically validates the controller path using the router->_validate_request(). + // If this include fails it means that the default controller in the Routes.php file is not resolving to something valid. + if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php')) + { + show_error('Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.'); + } + + include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().'.php'); + + // Set a mark point for benchmarking + $BM->mark('loading_time:_base_classes_end'); + +/* + * ------------------------------------------------------ + * Security check + * ------------------------------------------------------ + * + * None of the functions in the app controller or the + * loader class can be called via the URI, nor can + * controller functions that begin with an underscore + */ + $class = $RTR->fetch_class(); + $method = $RTR->fetch_method(); + + if ( ! class_exists($class) + OR strncmp($method, '_', 1) == 0 + OR in_array(strtolower($method), array_map('strtolower', get_class_methods('CI_Controller'))) + ) + { + if ( ! empty($RTR->routes['404_override'])) + { + $x = explode('/', $RTR->routes['404_override']); + $class = $x[0]; + $method = (isset($x[1]) ? $x[1] : 'index'); + if ( ! class_exists($class)) + { + if ( ! file_exists(APPPATH.'controllers/'.$class.'.php')) + { + show_404("{$class}/{$method}"); + } + + include_once(APPPATH.'controllers/'.$class.'.php'); + } + } + else + { + show_404("{$class}/{$method}"); + } + } + +/* + * ------------------------------------------------------ + * Is there a "pre_controller" hook? + * ------------------------------------------------------ + */ + $EXT->_call_hook('pre_controller'); + +/* + * ------------------------------------------------------ + * Instantiate the requested controller + * ------------------------------------------------------ + */ + // Mark a start point so we can benchmark the controller + $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start'); + + $CI = new $class(); + +/* + * ------------------------------------------------------ + * Is there a "post_controller_constructor" hook? + * ------------------------------------------------------ + */ + $EXT->_call_hook('post_controller_constructor'); + +/* + * ------------------------------------------------------ + * Call the requested method + * ------------------------------------------------------ + */ + // Is there a "remap" function? If so, we call it instead + if (method_exists($CI, '_remap')) + { + $CI->_remap($method, array_slice($URI->rsegments, 2)); + } + else + { + // is_callable() returns TRUE on some versions of PHP 5 for private and protected + // methods, so we'll use this workaround for consistent behavior + if ( ! in_array(strtolower($method), array_map('strtolower', get_class_methods($CI)))) + { + // Check and see if we are using a 404 override and use it. + if ( ! empty($RTR->routes['404_override'])) + { + $x = explode('/', $RTR->routes['404_override']); + $class = $x[0]; + $method = (isset($x[1]) ? $x[1] : 'index'); + if ( ! class_exists($class)) + { + if ( ! file_exists(APPPATH.'controllers/'.$class.'.php')) + { + show_404("{$class}/{$method}"); + } + + include_once(APPPATH.'controllers/'.$class.'.php'); + unset($CI); + $CI = new $class(); + } + } + else + { + show_404("{$class}/{$method}"); + } + } + + // Call the requested method. + // Any URI segments present (besides the class/function) will be passed to the method for convenience + call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2)); + } + + + // Mark a benchmark end point + $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end'); + +/* + * ------------------------------------------------------ + * Is there a "post_controller" hook? + * ------------------------------------------------------ + */ + $EXT->_call_hook('post_controller'); + +/* + * ------------------------------------------------------ + * Send the final rendered output to the browser + * ------------------------------------------------------ + */ + if ($EXT->_call_hook('display_override') === FALSE) + { + $OUT->_display(); + } + +/* + * ------------------------------------------------------ + * Is there a "post_system" hook? + * ------------------------------------------------------ + */ + $EXT->_call_hook('post_system'); + +/* + * ------------------------------------------------------ + * Close the DB connection if one exists + * ------------------------------------------------------ + */ + if (class_exists('CI_DB') AND isset($CI->db)) + { + $CI->db->close(); + } + + +/* End of file CodeIgniter.php */ +/* Location: ./system/core/CodeIgniter.php */ \ No newline at end of file diff --git a/system/core/Common.php b/system/core/Common.php new file mode 100644 index 00000000..07534c51 --- /dev/null +++ b/system/core/Common.php @@ -0,0 +1,564 @@ + 5 +* we'll set a static variable. +* +* @access public +* @param string +* @return bool TRUE if the current version is $version or higher +*/ +if ( ! function_exists('is_php')) +{ + function is_php($version = '5.0.0') + { + static $_is_php; + $version = (string)$version; + + if ( ! isset($_is_php[$version])) + { + $_is_php[$version] = (version_compare(PHP_VERSION, $version) < 0) ? FALSE : TRUE; + } + + return $_is_php[$version]; + } +} + +// ------------------------------------------------------------------------ + +/** + * Tests for file writability + * + * is_writable() returns TRUE on Windows servers when you really can't write to + * the file, based on the read-only attribute. is_writable() is also unreliable + * on Unix servers if safe_mode is on. + * + * @access private + * @return void + */ +if ( ! function_exists('is_really_writable')) +{ + function is_really_writable($file) + { + // If we're on a Unix server with safe_mode off we call is_writable + if (DIRECTORY_SEPARATOR == '/' AND @ini_get("safe_mode") == FALSE) + { + return is_writable($file); + } + + // For windows servers and safe_mode "on" installations we'll actually + // write a file then read it. Bah... + if (is_dir($file)) + { + $file = rtrim($file, '/').'/'.md5(mt_rand(1,100).mt_rand(1,100)); + + if (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) + { + return FALSE; + } + + fclose($fp); + @chmod($file, DIR_WRITE_MODE); + @unlink($file); + return TRUE; + } + elseif ( ! is_file($file) OR ($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) + { + return FALSE; + } + + fclose($fp); + return TRUE; + } +} + +// ------------------------------------------------------------------------ + +/** +* Class registry +* +* This function acts as a singleton. If the requested class does not +* exist it is instantiated and set to a static variable. If it has +* previously been instantiated the variable is returned. +* +* @access public +* @param string the class name being requested +* @param string the directory where the class should be found +* @param string the class name prefix +* @return object +*/ +if ( ! function_exists('load_class')) +{ + function &load_class($class, $directory = 'libraries', $prefix = 'CI_') + { + static $_classes = array(); + + // Does the class exist? If so, we're done... + if (isset($_classes[$class])) + { + return $_classes[$class]; + } + + $name = FALSE; + + // Look for the class first in the local application/libraries folder + // then in the native system/libraries folder + foreach (array(APPPATH, BASEPATH) as $path) + { + if (file_exists($path.$directory.'/'.$class.'.php')) + { + $name = $prefix.$class; + + if (class_exists($name) === FALSE) + { + require($path.$directory.'/'.$class.'.php'); + } + + break; + } + } + + // Is the request a class extension? If so we load it too + if (file_exists(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php')) + { + $name = config_item('subclass_prefix').$class; + + if (class_exists($name) === FALSE) + { + require(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php'); + } + } + + // Did we find the class? + if ($name === FALSE) + { + // Note: We use exit() rather then show_error() in order to avoid a + // self-referencing loop with the Excptions class + exit('Unable to locate the specified class: '.$class.'.php'); + } + + // Keep track of what we just loaded + is_loaded($class); + + $_classes[$class] = new $name(); + return $_classes[$class]; + } +} + +// -------------------------------------------------------------------- + +/** +* Keeps track of which libraries have been loaded. This function is +* called by the load_class() function above +* +* @access public +* @return array +*/ +if ( ! function_exists('is_loaded')) +{ + function &is_loaded($class = '') + { + static $_is_loaded = array(); + + if ($class != '') + { + $_is_loaded[strtolower($class)] = $class; + } + + return $_is_loaded; + } +} + +// ------------------------------------------------------------------------ + +/** +* Loads the main config.php file +* +* This function lets us grab the config file even if the Config class +* hasn't been instantiated yet +* +* @access private +* @return array +*/ +if ( ! function_exists('get_config')) +{ + function &get_config($replace = array()) + { + static $_config; + + if (isset($_config)) + { + return $_config[0]; + } + + // Is the config file in the environment folder? + if ( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php')) + { + $file_path = APPPATH.'config/config.php'; + } + + // Fetch the config file + if ( ! file_exists($file_path)) + { + exit('The configuration file does not exist.'); + } + + require($file_path); + + // Does the $config array exist in the file? + if ( ! isset($config) OR ! is_array($config)) + { + exit('Your config file does not appear to be formatted correctly.'); + } + + // Are any values being dynamically replaced? + if (count($replace) > 0) + { + foreach ($replace as $key => $val) + { + if (isset($config[$key])) + { + $config[$key] = $val; + } + } + } + + return $_config[0] =& $config; + } +} + +// ------------------------------------------------------------------------ + +/** +* Returns the specified config item +* +* @access public +* @return mixed +*/ +if ( ! function_exists('config_item')) +{ + function config_item($item) + { + static $_config_item = array(); + + if ( ! isset($_config_item[$item])) + { + $config =& get_config(); + + if ( ! isset($config[$item])) + { + return FALSE; + } + $_config_item[$item] = $config[$item]; + } + + return $_config_item[$item]; + } +} + +// ------------------------------------------------------------------------ + +/** +* Error Handler +* +* This function lets us invoke the exception class and +* display errors using the standard error template located +* in application/errors/errors.php +* This function will send the error page directly to the +* browser and exit. +* +* @access public +* @return void +*/ +if ( ! function_exists('show_error')) +{ + function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered') + { + $_error =& load_class('Exceptions', 'core'); + echo $_error->show_error($heading, $message, 'error_general', $status_code); + exit; + } +} + +// ------------------------------------------------------------------------ + +/** +* 404 Page Handler +* +* This function is similar to the show_error() function above +* However, instead of the standard error template it displays +* 404 errors. +* +* @access public +* @return void +*/ +if ( ! function_exists('show_404')) +{ + function show_404($page = '', $log_error = TRUE) + { + $_error =& load_class('Exceptions', 'core'); + $_error->show_404($page, $log_error); + exit; + } +} + +// ------------------------------------------------------------------------ + +/** +* Error Logging Interface +* +* We use this as a simple mechanism to access the logging +* class and send messages to be logged. +* +* @access public +* @return void +*/ +if ( ! function_exists('log_message')) +{ + function log_message($level = 'error', $message, $php_error = FALSE) + { + static $_log; + + if (config_item('log_threshold') == 0) + { + return; + } + + $_log =& load_class('Log'); + $_log->write_log($level, $message, $php_error); + } +} + +// ------------------------------------------------------------------------ + +/** + * Set HTTP Status Header + * + * @access public + * @param int the status code + * @param string + * @return void + */ +if ( ! function_exists('set_status_header')) +{ + function set_status_header($code = 200, $text = '') + { + $stati = array( + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + + 400 => 'Bad Request', + 401 => 'Unauthorized', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported' + ); + + if ($code == '' OR ! is_numeric($code)) + { + show_error('Status codes must be numeric', 500); + } + + if (isset($stati[$code]) AND $text == '') + { + $text = $stati[$code]; + } + + if ($text == '') + { + show_error('No status text available. Please check your status code number or supply your own message text.', 500); + } + + $server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : FALSE; + + if (substr(php_sapi_name(), 0, 3) == 'cgi') + { + header("Status: {$code} {$text}", TRUE); + } + elseif ($server_protocol == 'HTTP/1.1' OR $server_protocol == 'HTTP/1.0') + { + header($server_protocol." {$code} {$text}", TRUE, $code); + } + else + { + header("HTTP/1.1 {$code} {$text}", TRUE, $code); + } + } +} + +// -------------------------------------------------------------------- + +/** +* Exception Handler +* +* This is the custom exception handler that is declaired at the top +* of Codeigniter.php. The main reason we use this is to permit +* PHP errors to be logged in our own log files since the user may +* not have access to server logs. Since this function +* effectively intercepts PHP errors, however, we also need +* to display errors based on the current error_reporting level. +* We do that with the use of a PHP error template. +* +* @access private +* @return void +*/ +if ( ! function_exists('_exception_handler')) +{ + function _exception_handler($severity, $message, $filepath, $line) + { + // We don't bother with "strict" notices since they tend to fill up + // the log file with excess information that isn't normally very helpful. + // For example, if you are running PHP 5 and you use version 4 style + // class functions (without prefixes like "public", "private", etc.) + // you'll get notices telling you that these have been deprecated. + if ($severity == E_STRICT) + { + return; + } + + $_error =& load_class('Exceptions', 'core'); + + // Should we display the error? We'll get the current error_reporting + // level and add its bits with the severity bits to find out. + if (($severity & error_reporting()) == $severity) + { + $_error->show_php_error($severity, $message, $filepath, $line); + } + + // Should we log the error? No? We're done... + if (config_item('log_threshold') == 0) + { + return; + } + + $_error->log_exception($severity, $message, $filepath, $line); + } +} + +// -------------------------------------------------------------------- + +/** + * Remove Invisible Characters + * + * This prevents sandwiching null characters + * between ascii characters, like Java\0script. + * + * @access public + * @param string + * @return string + */ +if ( ! function_exists('remove_invisible_characters')) +{ + function remove_invisible_characters($str, $url_encoded = TRUE) + { + $non_displayables = array(); + + // every control character except newline (dec 10) + // carriage return (dec 13), and horizontal tab (dec 09) + + if ($url_encoded) + { + $non_displayables[] = '/%0[0-8bcef]/'; // url encoded 00-08, 11, 12, 14, 15 + $non_displayables[] = '/%1[0-9a-f]/'; // url encoded 16-31 + } + + $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127 + + do + { + $str = preg_replace($non_displayables, '', $str, -1, $count); + } + while ($count); + + return $str; + } +} + +// ------------------------------------------------------------------------ + +/** +* Returns HTML escaped variable +* +* @access public +* @param mixed +* @return mixed +*/ +if ( ! function_exists('html_escape')) +{ + function html_escape($var) + { + if (is_array($var)) + { + return array_map('html_escape', $var); + } + else + { + return htmlspecialchars($var, ENT_QUOTES, config_item('charset')); + } + } +} + +/* End of file Common.php */ +/* Location: ./system/core/Common.php */ \ No newline at end of file diff --git a/system/core/Config.php b/system/core/Config.php new file mode 100755 index 00000000..5dffbf3f --- /dev/null +++ b/system/core/Config.php @@ -0,0 +1,379 @@ +config =& get_config(); + log_message('debug', "Config Class Initialized"); + + // Set the base_url automatically if none was provided + if ($this->config['base_url'] == '') + { + if (isset($_SERVER['HTTP_HOST'])) + { + $base_url = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http'; + $base_url .= '://'. $_SERVER['HTTP_HOST']; + $base_url .= str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']); + } + + else + { + $base_url = 'http://localhost/'; + } + + $this->set_item('base_url', $base_url); + } + } + + // -------------------------------------------------------------------- + + /** + * Load Config File + * + * @access public + * @param string the config file name + * @param boolean if configuration values should be loaded into their own section + * @param boolean true if errors should just return false, false if an error message should be displayed + * @return boolean if the file was loaded correctly + */ + function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) + { + $file = ($file == '') ? 'config' : str_replace('.php', '', $file); + $found = FALSE; + $loaded = FALSE; + + $check_locations = defined('ENVIRONMENT') + ? array(ENVIRONMENT.'/'.$file, $file) + : array($file); + + foreach ($this->_config_paths as $path) + { + foreach ($check_locations as $location) + { + $file_path = $path.'config/'.$location.'.php'; + + if (in_array($file_path, $this->is_loaded, TRUE)) + { + $loaded = TRUE; + continue 2; + } + + if (file_exists($file_path)) + { + $found = TRUE; + break; + } + } + + if ($found === FALSE) + { + continue; + } + + include($file_path); + + if ( ! isset($config) OR ! is_array($config)) + { + if ($fail_gracefully === TRUE) + { + return FALSE; + } + show_error('Your '.$file_path.' file does not appear to contain a valid configuration array.'); + } + + if ($use_sections === TRUE) + { + if (isset($this->config[$file])) + { + $this->config[$file] = array_merge($this->config[$file], $config); + } + else + { + $this->config[$file] = $config; + } + } + else + { + $this->config = array_merge($this->config, $config); + } + + $this->is_loaded[] = $file_path; + unset($config); + + $loaded = TRUE; + log_message('debug', 'Config file loaded: '.$file_path); + break; + } + + if ($loaded === FALSE) + { + if ($fail_gracefully === TRUE) + { + return FALSE; + } + show_error('The configuration file '.$file.'.php does not exist.'); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Fetch a config file item + * + * + * @access public + * @param string the config item name + * @param string the index name + * @param bool + * @return string + */ + function item($item, $index = '') + { + if ($index == '') + { + if ( ! isset($this->config[$item])) + { + return FALSE; + } + + $pref = $this->config[$item]; + } + else + { + if ( ! isset($this->config[$index])) + { + return FALSE; + } + + if ( ! isset($this->config[$index][$item])) + { + return FALSE; + } + + $pref = $this->config[$index][$item]; + } + + return $pref; + } + + // -------------------------------------------------------------------- + + /** + * Fetch a config file item - adds slash after item (if item is not empty) + * + * @access public + * @param string the config item name + * @param bool + * @return string + */ + function slash_item($item) + { + if ( ! isset($this->config[$item])) + { + return FALSE; + } + if( trim($this->config[$item]) == '') + { + return ''; + } + + return rtrim($this->config[$item], '/').'/'; + } + + // -------------------------------------------------------------------- + + /** + * Site URL + * Returns base_url . index_page [. uri_string] + * + * @access public + * @param string the URI string + * @return string + */ + function site_url($uri = '') + { + if ($uri == '') + { + return $this->slash_item('base_url').$this->item('index_page'); + } + + if ($this->item('enable_query_strings') == FALSE) + { + $suffix = ($this->item('url_suffix') == FALSE) ? '' : $this->item('url_suffix'); + return $this->slash_item('base_url').$this->slash_item('index_page').$this->_uri_string($uri).$suffix; + } + else + { + return $this->slash_item('base_url').$this->item('index_page').'?'.$this->_uri_string($uri); + } + } + + // ------------------------------------------------------------- + + /** + * Base URL + * Returns base_url [. uri_string] + * + * @access public + * @param string $uri + * @return string + */ + function base_url($uri = '') + { + return $this->slash_item('base_url').ltrim($this->_uri_string($uri), '/'); + } + + // ------------------------------------------------------------- + + /** + * Build URI string for use in Config::site_url() and Config::base_url() + * + * @access protected + * @param $uri + * @return string + */ + protected function _uri_string($uri) + { + if ($this->item('enable_query_strings') == FALSE) + { + if (is_array($uri)) + { + $uri = implode('/', $uri); + } + $uri = trim($uri, '/'); + } + else + { + if (is_array($uri)) + { + $i = 0; + $str = ''; + foreach ($uri as $key => $val) + { + $prefix = ($i == 0) ? '' : '&'; + $str .= $prefix.$key.'='.$val; + $i++; + } + $uri = $str; + } + } + return $uri; + } + + // -------------------------------------------------------------------- + + /** + * System URL + * + * @access public + * @return string + */ + function system_url() + { + $x = explode("/", preg_replace("|/*(.+?)/*$|", "\\1", BASEPATH)); + return $this->slash_item('base_url').end($x).'/'; + } + + // -------------------------------------------------------------------- + + /** + * Set a config file item + * + * @access public + * @param string the config item key + * @param string the config item value + * @return void + */ + function set_item($item, $value) + { + $this->config[$item] = $value; + } + + // -------------------------------------------------------------------- + + /** + * Assign to Config + * + * This function is called by the front controller (CodeIgniter.php) + * after the Config class is instantiated. It permits config items + * to be assigned or overriden by variables contained in the index.php file + * + * @access private + * @param array + * @return void + */ + function _assign_to_config($items = array()) + { + if (is_array($items)) + { + foreach ($items as $key => $val) + { + $this->set_item($key, $val); + } + } + } +} + +// END CI_Config class + +/* End of file Config.php */ +/* Location: ./system/core/Config.php */ diff --git a/system/core/Controller.php b/system/core/Controller.php new file mode 100644 index 00000000..fddb81e1 --- /dev/null +++ b/system/core/Controller.php @@ -0,0 +1,64 @@ + $class) + { + $this->$var =& load_class($class); + } + + $this->load =& load_class('Loader', 'core'); + + $this->load->initialize(); + + log_message('debug', "Controller Class Initialized"); + } + + public static function &get_instance() + { + return self::$instance; + } +} +// END Controller class + +/* End of file Controller.php */ +/* Location: ./system/core/Controller.php */ \ No newline at end of file diff --git a/system/libraries/Exceptions.php b/system/core/Exceptions.php old mode 100644 new mode 100755 similarity index 82% rename from system/libraries/Exceptions.php rename to system/core/Exceptions.php index 9c655a17..869739a5 --- a/system/libraries/Exceptions.php +++ b/system/core/Exceptions.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -30,8 +30,21 @@ class CI_Exceptions { var $message; var $filename; var $line; + + /** + * Nesting level of the output buffering mechanism + * + * @var int + * @access public + */ var $ob_level; + /** + * List if available error levels + * + * @var array + * @access public + */ var $levels = array( E_ERROR => 'Error', E_WARNING => 'Warning', @@ -50,14 +63,13 @@ class CI_Exceptions { /** * Constructor - * - */ - function CI_Exceptions() + */ + public function __construct() { $this->ob_level = ob_get_level(); // Note: Do not log messages from this constructor. } - + // -------------------------------------------------------------------- /** @@ -73,9 +85,9 @@ function CI_Exceptions() * @return string */ function log_exception($severity, $message, $filepath, $line) - { + { $severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity]; - + log_message('error', 'Severity: '.$severity.' --> '.$message. ' '.$filepath.' '.$line, TRUE); } @@ -85,19 +97,25 @@ function log_exception($severity, $message, $filepath, $line) * 404 Page Not Found Handler * * @access private - * @param string + * @param string the page + * @param bool log error yes/no * @return string */ - function show_404($page = '') - { + function show_404($page = '', $log_error = TRUE) + { $heading = "404 Page Not Found"; $message = "The page you requested was not found."; - log_message('error', '404 Page Not Found --> '.$page); + // By default we log this, but allow a dev to skip it + if ($log_error) + { + log_message('error', '404 Page Not Found --> '.$page); + } + echo $this->show_error($heading, $message, 'error_404', 404); exit; } - + // -------------------------------------------------------------------- /** @@ -111,20 +129,21 @@ function show_404($page = '') * @param string the heading * @param string the message * @param string the template name + * @param int the status code * @return string */ function show_error($heading, $message, $template = 'error_general', $status_code = 500) { set_status_header($status_code); - + $message = '

'.implode('

', ( ! is_array($message)) ? array($message) : $message).'

'; if (ob_get_level() > $this->ob_level + 1) { - ob_end_flush(); + ob_end_flush(); } ob_start(); - include(APPPATH.'errors/'.$template.EXT); + include(APPPATH.'errors/'.$template.'.php'); $buffer = ob_get_contents(); ob_end_clean(); return $buffer; @@ -143,24 +162,24 @@ function show_error($heading, $message, $template = 'error_general', $status_cod * @return string */ function show_php_error($severity, $message, $filepath, $line) - { + { $severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity]; - + $filepath = str_replace("\\", "/", $filepath); - + // For safety reasons we do not show the full file path if (FALSE !== strpos($filepath, '/')) { $x = explode('/', $filepath); $filepath = $x[count($x)-2].'/'.end($x); } - + if (ob_get_level() > $this->ob_level + 1) { - ob_end_flush(); + ob_end_flush(); } ob_start(); - include(APPPATH.'errors/error_php'.EXT); + include(APPPATH.'errors/error_php.php'); $buffer = ob_get_contents(); ob_end_clean(); echo $buffer; @@ -171,4 +190,4 @@ function show_php_error($severity, $message, $filepath, $line) // END Exceptions Class /* End of file Exceptions.php */ -/* Location: ./system/libraries/Exceptions.php */ \ No newline at end of file +/* Location: ./system/core/Exceptions.php */ \ No newline at end of file diff --git a/system/libraries/Hooks.php b/system/core/Hooks.php old mode 100644 new mode 100755 similarity index 82% rename from system/libraries/Hooks.php rename to system/core/Hooks.php index 0b5d4680..33f1c034 --- a/system/libraries/Hooks.php +++ b/system/core/Hooks.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -18,8 +18,7 @@ /** * CodeIgniter Hooks Class * - * Provides a mechanism to extend the base system without hacking. Most of - * this class is borrowed from Paul's Extension class in ExpressionEngine. + * Provides a mechanism to extend the base system without hacking. * * @package CodeIgniter * @subpackage Libraries @@ -29,20 +28,35 @@ */ class CI_Hooks { - var $enabled = FALSE; - var $hooks = array(); + /** + * Determines wether hooks are enabled + * + * @var bool + */ + var $enabled = FALSE; + /** + * List of all hooks set in config/hooks.php + * + * @var array + */ + var $hooks = array(); + /** + * Determines wether hook is in progress, used to prevent infinte loops + * + * @var bool + */ var $in_progress = FALSE; /** * Constructor * */ - function CI_Hooks() + function __construct() { $this->_initialize(); log_message('debug', "Hooks Class Initialized"); } - + // -------------------------------------------------------------------- /** @@ -50,10 +64,10 @@ function CI_Hooks() * * @access private * @return void - */ - function _initialize() - { - $CFG =& load_class('Config'); + */ + function _initialize() + { + $CFG =& load_class('Config', 'core'); // If hooks are not enabled in the config file // there is nothing else to do @@ -66,7 +80,15 @@ function _initialize() // Grab the "hooks" definition file. // If there are no hooks, we're done. - @include(APPPATH.'config/hooks'.EXT); + if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/hooks.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'); + } + elseif (is_file(APPPATH.'config/hooks.php')) + { + include(APPPATH.'config/hooks.php'); + } + if ( ! isset($hook) OR ! is_array($hook)) { @@ -75,8 +97,8 @@ function _initialize() $this->hooks =& $hook; $this->enabled = TRUE; - } - + } + // -------------------------------------------------------------------- /** @@ -223,4 +245,4 @@ function _run_hook($data) // END CI_Hooks class /* End of file Hooks.php */ -/* Location: ./system/libraries/Hooks.php */ \ No newline at end of file +/* Location: ./system/core/Hooks.php */ \ No newline at end of file diff --git a/system/core/Input.php b/system/core/Input.php new file mode 100755 index 00000000..0c1f2b08 --- /dev/null +++ b/system/core/Input.php @@ -0,0 +1,849 @@ +_allow_get_array = (config_item('allow_get_array') === TRUE); + $this->_enable_xss = (config_item('global_xss_filtering') === TRUE); + $this->_enable_csrf = (config_item('csrf_protection') === TRUE); + + global $SEC; + $this->security =& $SEC; + + // Do we need the UTF-8 class? + if (UTF8_ENABLED === TRUE) + { + global $UNI; + $this->uni =& $UNI; + } + + // Sanitize global arrays + $this->_sanitize_globals(); + } + + // -------------------------------------------------------------------- + + /** + * Fetch from array + * + * This is a helper function to retrieve values from global arrays + * + * @access private + * @param array + * @param string + * @param bool + * @return string + */ + function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE) + { + if ( ! isset($array[$index])) + { + return FALSE; + } + + if ($xss_clean === TRUE) + { + return $this->security->xss_clean($array[$index]); + } + + return $array[$index]; + } + + // -------------------------------------------------------------------- + + /** + * Fetch an item from the GET array + * + * @access public + * @param string + * @param bool + * @return string + */ + function get($index = NULL, $xss_clean = FALSE) + { + // Check if a field has been provided + if ($index === NULL AND ! empty($_GET)) + { + $get = array(); + + // loop through the full _GET array + foreach (array_keys($_GET) as $key) + { + $get[$key] = $this->_fetch_from_array($_GET, $key, $xss_clean); + } + return $get; + } + + return $this->_fetch_from_array($_GET, $index, $xss_clean); + } + + // -------------------------------------------------------------------- + + /** + * Fetch an item from the POST array + * + * @access public + * @param string + * @param bool + * @return string + */ + function post($index = NULL, $xss_clean = FALSE) + { + // Check if a field has been provided + if ($index === NULL AND ! empty($_POST)) + { + $post = array(); + + // Loop through the full _POST array and return it + foreach (array_keys($_POST) as $key) + { + $post[$key] = $this->_fetch_from_array($_POST, $key, $xss_clean); + } + return $post; + } + + return $this->_fetch_from_array($_POST, $index, $xss_clean); + } + + + // -------------------------------------------------------------------- + + /** + * Fetch an item from either the GET array or the POST + * + * @access public + * @param string The index key + * @param bool XSS cleaning + * @return string + */ + function get_post($index = '', $xss_clean = FALSE) + { + if ( ! isset($_POST[$index]) ) + { + return $this->get($index, $xss_clean); + } + else + { + return $this->post($index, $xss_clean); + } + } + + // -------------------------------------------------------------------- + + /** + * Fetch an item from the COOKIE array + * + * @access public + * @param string + * @param bool + * @return string + */ + function cookie($index = '', $xss_clean = FALSE) + { + return $this->_fetch_from_array($_COOKIE, $index, $xss_clean); + } + + // ------------------------------------------------------------------------ + + /** + * Set cookie + * + * Accepts six parameter, or you can submit an associative + * array in the first parameter containing all the values. + * + * @access public + * @param mixed + * @param string the value of the cookie + * @param string the number of seconds until expiration + * @param string the cookie domain. Usually: .yourdomain.com + * @param string the cookie path + * @param string the cookie prefix + * @param bool true makes the cookie secure + * @return void + */ + function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE) + { + if (is_array($name)) + { + // always leave 'name' in last place, as the loop will break otherwise, due to $$item + foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'name') as $item) + { + if (isset($name[$item])) + { + $$item = $name[$item]; + } + } + } + + if ($prefix == '' AND config_item('cookie_prefix') != '') + { + $prefix = config_item('cookie_prefix'); + } + if ($domain == '' AND config_item('cookie_domain') != '') + { + $domain = config_item('cookie_domain'); + } + if ($path == '/' AND config_item('cookie_path') != '/') + { + $path = config_item('cookie_path'); + } + if ($secure == FALSE AND config_item('cookie_secure') != FALSE) + { + $secure = config_item('cookie_secure'); + } + + if ( ! is_numeric($expire)) + { + $expire = time() - 86500; + } + else + { + $expire = ($expire > 0) ? time() + $expire : 0; + } + + setcookie($prefix.$name, $value, $expire, $path, $domain, $secure); + } + + // -------------------------------------------------------------------- + + /** + * Fetch an item from the SERVER array + * + * @access public + * @param string + * @param bool + * @return string + */ + function server($index = '', $xss_clean = FALSE) + { + return $this->_fetch_from_array($_SERVER, $index, $xss_clean); + } + + // -------------------------------------------------------------------- + + /** + * Fetch the IP Address + * + * @return string + */ + public function ip_address() + { + if ($this->ip_address !== FALSE) + { + return $this->ip_address; + } + + $proxy_ips = config_item('proxy_ips'); + if ( ! empty($proxy_ips)) + { + $proxy_ips = explode(',', str_replace(' ', '', $proxy_ips)); + foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header) + { + if (($spoof = $this->server($header)) !== FALSE) + { + // Some proxies typically list the whole chain of IP + // addresses through which the client has reached us. + // e.g. client_ip, proxy_ip1, proxy_ip2, etc. + if (strpos($spoof, ',') !== FALSE) + { + $spoof = explode(',', $spoof, 2); + $spoof = $spoof[0]; + } + + if ( ! $this->valid_ip($spoof)) + { + $spoof = FALSE; + } + else + { + break; + } + } + } + + $this->ip_address = ($spoof !== FALSE && in_array($_SERVER['REMOTE_ADDR'], $proxy_ips, TRUE)) + ? $spoof : $_SERVER['REMOTE_ADDR']; + } + else + { + $this->ip_address = $_SERVER['REMOTE_ADDR']; + } + + if ( ! $this->valid_ip($this->ip_address)) + { + $this->ip_address = '0.0.0.0'; + } + + return $this->ip_address; + } + + // -------------------------------------------------------------------- + + /** + * Validate IP Address + * + * @access public + * @param string + * @param string ipv4 or ipv6 + * @return bool + */ + public function valid_ip($ip, $which = '') + { + $which = strtolower($which); + + // First check if filter_var is available + if (is_callable('filter_var')) + { + switch ($which) { + case 'ipv4': + $flag = FILTER_FLAG_IPV4; + break; + case 'ipv6': + $flag = FILTER_FLAG_IPV6; + break; + default: + $flag = ''; + break; + } + + return (bool) filter_var($ip, FILTER_VALIDATE_IP, $flag); + } + + if ($which !== 'ipv6' && $which !== 'ipv4') + { + if (strpos($ip, ':') !== FALSE) + { + $which = 'ipv6'; + } + elseif (strpos($ip, '.') !== FALSE) + { + $which = 'ipv4'; + } + else + { + return FALSE; + } + } + + $func = '_valid_'.$which; + return $this->$func($ip); + } + + // -------------------------------------------------------------------- + + /** + * Validate IPv4 Address + * + * Updated version suggested by Geert De Deckere + * + * @access protected + * @param string + * @return bool + */ + protected function _valid_ipv4($ip) + { + $ip_segments = explode('.', $ip); + + // Always 4 segments needed + if (count($ip_segments) !== 4) + { + return FALSE; + } + // IP can not start with 0 + if ($ip_segments[0][0] == '0') + { + return FALSE; + } + + // Check each segment + foreach ($ip_segments as $segment) + { + // IP segments must be digits and can not be + // longer than 3 digits or greater then 255 + if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3) + { + return FALSE; + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Validate IPv6 Address + * + * @access protected + * @param string + * @return bool + */ + protected function _valid_ipv6($str) + { + // 8 groups, separated by : + // 0-ffff per group + // one set of consecutive 0 groups can be collapsed to :: + + $groups = 8; + $collapsed = FALSE; + + $chunks = array_filter( + preg_split('/(:{1,2})/', $str, NULL, PREG_SPLIT_DELIM_CAPTURE) + ); + + // Rule out easy nonsense + if (current($chunks) == ':' OR end($chunks) == ':') + { + return FALSE; + } + + // PHP supports IPv4-mapped IPv6 addresses, so we'll expect those as well + if (strpos(end($chunks), '.') !== FALSE) + { + $ipv4 = array_pop($chunks); + + if ( ! $this->_valid_ipv4($ipv4)) + { + return FALSE; + } + + $groups--; + } + + while ($seg = array_pop($chunks)) + { + if ($seg[0] == ':') + { + if (--$groups == 0) + { + return FALSE; // too many groups + } + + if (strlen($seg) > 2) + { + return FALSE; // long separator + } + + if ($seg == '::') + { + if ($collapsed) + { + return FALSE; // multiple collapsed + } + + $collapsed = TRUE; + } + } + elseif (preg_match("/[^0-9a-f]/i", $seg) OR strlen($seg) > 4) + { + return FALSE; // invalid segment + } + } + + return $collapsed OR $groups == 1; + } + + // -------------------------------------------------------------------- + + /** + * User Agent + * + * @access public + * @return string + */ + function user_agent() + { + if ($this->user_agent !== FALSE) + { + return $this->user_agent; + } + + $this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT']; + + return $this->user_agent; + } + + // -------------------------------------------------------------------- + + /** + * Sanitize Globals + * + * This function does the following: + * + * Unsets $_GET data (if query strings are not enabled) + * + * Unsets all globals if register_globals is enabled + * + * Standardizes newline characters to \n + * + * @access private + * @return void + */ + function _sanitize_globals() + { + // It would be "wrong" to unset any of these GLOBALS. + $protected = array('_SERVER', '_GET', '_POST', '_FILES', '_REQUEST', + '_SESSION', '_ENV', 'GLOBALS', 'HTTP_RAW_POST_DATA', + 'system_folder', 'application_folder', 'BM', 'EXT', + 'CFG', 'URI', 'RTR', 'OUT', 'IN'); + + // Unset globals for securiy. + // This is effectively the same as register_globals = off + foreach (array($_GET, $_POST, $_COOKIE) as $global) + { + if ( ! is_array($global)) + { + if ( ! in_array($global, $protected)) + { + global $$global; + $$global = NULL; + } + } + else + { + foreach ($global as $key => $val) + { + if ( ! in_array($key, $protected)) + { + global $$key; + $$key = NULL; + } + } + } + } + + // Is $_GET data allowed? If not we'll set the $_GET to an empty array + if ($this->_allow_get_array == FALSE) + { + $_GET = array(); + } + else + { + if (is_array($_GET) AND count($_GET) > 0) + { + foreach ($_GET as $key => $val) + { + $_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); + } + } + } + + // Clean $_POST Data + if (is_array($_POST) AND count($_POST) > 0) + { + foreach ($_POST as $key => $val) + { + $_POST[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); + } + } + + // Clean $_COOKIE Data + if (is_array($_COOKIE) AND count($_COOKIE) > 0) + { + // Also get rid of specially treated cookies that might be set by a server + // or silly application, that are of no use to a CI application anyway + // but that when present will trip our 'Disallowed Key Characters' alarm + // http://www.ietf.org/rfc/rfc2109.txt + // note that the key names below are single quoted strings, and are not PHP variables + unset($_COOKIE['$Version']); + unset($_COOKIE['$Path']); + unset($_COOKIE['$Domain']); + + foreach ($_COOKIE as $key => $val) + { + $_COOKIE[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); + } + } + + // Sanitize PHP_SELF + $_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']); + + + // CSRF Protection check on HTTP requests + if ($this->_enable_csrf == TRUE && ! $this->is_cli_request()) + { + $this->security->csrf_verify(); + } + + log_message('debug', "Global POST and COOKIE data sanitized"); + } + + // -------------------------------------------------------------------- + + /** + * Clean Input Data + * + * This is a helper function. It escapes data and + * standardizes newline characters to \n + * + * @access private + * @param string + * @return string + */ + function _clean_input_data($str) + { + if (is_array($str)) + { + $new_array = array(); + foreach ($str as $key => $val) + { + $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); + } + return $new_array; + } + + /* We strip slashes if magic quotes is on to keep things consistent + + NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and + it will probably not exist in future versions at all. + */ + if ( ! is_php('5.4') && get_magic_quotes_gpc()) + { + $str = stripslashes($str); + } + + // Clean UTF-8 if supported + if (UTF8_ENABLED === TRUE) + { + $str = $this->uni->clean_string($str); + } + + // Remove control characters + $str = remove_invisible_characters($str); + + // Should we filter the input data? + if ($this->_enable_xss === TRUE) + { + $str = $this->security->xss_clean($str); + } + + // Standardize newlines if needed + if ($this->_standardize_newlines == TRUE) + { + if (strpos($str, "\r") !== FALSE) + { + $str = str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str); + } + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Clean Keys + * + * This is a helper function. To prevent malicious users + * from trying to exploit keys we make sure that keys are + * only named with alpha-numeric text and a few other items. + * + * @access private + * @param string + * @return string + */ + function _clean_input_keys($str) + { + if ( ! preg_match("/^[a-z0-9:_\/-]+$/i", $str)) + { + exit('Disallowed Key Characters.'); + } + + // Clean UTF-8 if supported + if (UTF8_ENABLED === TRUE) + { + $str = $this->uni->clean_string($str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Request Headers + * + * In Apache, you can simply call apache_request_headers(), however for + * people running other webservers the function is undefined. + * + * @param bool XSS cleaning + * + * @return array + */ + public function request_headers($xss_clean = FALSE) + { + // Look at Apache go! + if (function_exists('apache_request_headers')) + { + $headers = apache_request_headers(); + } + else + { + $headers['Content-Type'] = (isset($_SERVER['CONTENT_TYPE'])) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE'); + + foreach ($_SERVER as $key => $val) + { + if (strncmp($key, 'HTTP_', 5) === 0) + { + $headers[substr($key, 5)] = $this->_fetch_from_array($_SERVER, $key, $xss_clean); + } + } + } + + // take SOME_HEADER and turn it into Some-Header + foreach ($headers as $key => $val) + { + $key = str_replace('_', ' ', strtolower($key)); + $key = str_replace(' ', '-', ucwords($key)); + + $this->headers[$key] = $val; + } + + return $this->headers; + } + + // -------------------------------------------------------------------- + + /** + * Get Request Header + * + * Returns the value of a single member of the headers class member + * + * @param string array key for $this->headers + * @param boolean XSS Clean or not + * @return mixed FALSE on failure, string on success + */ + public function get_request_header($index, $xss_clean = FALSE) + { + if (empty($this->headers)) + { + $this->request_headers(); + } + + if ( ! isset($this->headers[$index])) + { + return FALSE; + } + + if ($xss_clean === TRUE) + { + return $this->security->xss_clean($this->headers[$index]); + } + + return $this->headers[$index]; + } + + // -------------------------------------------------------------------- + + /** + * Is ajax Request? + * + * Test to see if a request contains the HTTP_X_REQUESTED_WITH header + * + * @return boolean + */ + public function is_ajax_request() + { + return ($this->server('HTTP_X_REQUESTED_WITH') === 'XMLHttpRequest'); + } + + // -------------------------------------------------------------------- + + /** + * Is cli Request? + * + * Test to see if a request was made from the command line + * + * @return bool + */ + public function is_cli_request() + { + return (php_sapi_name() === 'cli' OR defined('STDIN')); + } + +} + +/* End of file Input.php */ +/* Location: ./system/core/Input.php */ \ No newline at end of file diff --git a/system/libraries/Language.php b/system/core/Lang.php old mode 100644 new mode 100755 similarity index 55% rename from system/libraries/Language.php rename to system/core/Lang.php index b679c891..5ac67183 --- a/system/libraries/Language.php +++ b/system/core/Lang.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -24,9 +24,19 @@ * @author ExpressionEngine Dev Team * @link http://codeigniter.com/user_guide/libraries/language.html */ -class CI_Language { +class CI_Lang { + /** + * List of translations + * + * @var array + */ var $language = array(); + /** + * List of loaded language files + * + * @var array + */ var $is_loaded = array(); /** @@ -34,7 +44,7 @@ class CI_Language { * * @access public */ - function CI_Language() + function __construct() { log_message('debug', "Language Class Initialized"); } @@ -47,41 +57,61 @@ function CI_Language() * @access public * @param mixed the name of the language file to be loaded. Can be an array * @param string the language (english, etc.) + * @param bool return loaded array of translations + * @param bool add suffix to $langfile + * @param string alternative path to look for language file * @return mixed */ - function load($langfile = '', $idiom = '', $return = FALSE) + function load($langfile = '', $idiom = '', $return = FALSE, $add_suffix = TRUE, $alt_path = '') { - $langfile = str_replace(EXT, '', str_replace('_lang.', '', $langfile)).'_lang'.EXT; + $langfile = str_replace('.php', '', $langfile); + + if ($add_suffix == TRUE) + { + $langfile = str_replace('_lang.', '', $langfile).'_lang'; + } + + $langfile .= '.php'; if (in_array($langfile, $this->is_loaded, TRUE)) { return; } + $config =& get_config(); + if ($idiom == '') { - $CI =& get_instance(); - $deft_lang = $CI->config->item('language'); + $deft_lang = ( ! isset($config['language'])) ? 'english' : $config['language']; $idiom = ($deft_lang == '') ? 'english' : $deft_lang; } // Determine where the language file is and load it - if (file_exists(APPPATH.'language/'.$idiom.'/'.$langfile)) + if ($alt_path != '' && file_exists($alt_path.'language/'.$idiom.'/'.$langfile)) { - include(APPPATH.'language/'.$idiom.'/'.$langfile); + include($alt_path.'language/'.$idiom.'/'.$langfile); } else { - if (file_exists(BASEPATH.'language/'.$idiom.'/'.$langfile)) + $found = FALSE; + + foreach (get_instance()->load->get_package_paths(TRUE) as $package_path) { - include(BASEPATH.'language/'.$idiom.'/'.$langfile); + if (file_exists($package_path.'language/'.$idiom.'/'.$langfile)) + { + include($package_path.'language/'.$idiom.'/'.$langfile); + $found = TRUE; + break; + } } - else + + if ($found !== TRUE) { show_error('Unable to load the requested language file: language/'.$idiom.'/'.$langfile); } } + if ( ! isset($lang)) { log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile); @@ -107,17 +137,24 @@ function load($langfile = '', $idiom = '', $return = FALSE) * Fetch a single line of text from the language array * * @access public - * @param string $line the language line + * @param string $line the language line * @return string */ function line($line = '') { - $line = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line]; - return $line; + $value = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line]; + + // Because killer robots like unicorns! + if ($value === FALSE) + { + log_message('error', 'Could not find the language line "'.$line.'"'); + } + + return $value; } } // END Language Class -/* End of file Language.php */ -/* Location: ./system/libraries/Language.php */ \ No newline at end of file +/* End of file Lang.php */ +/* Location: ./system/core/Lang.php */ diff --git a/system/libraries/Loader.php b/system/core/Loader.php similarity index 53% rename from system/libraries/Loader.php rename to system/core/Loader.php index 781c83c6..6b7ee0c2 100644 --- a/system/libraries/Loader.php +++ b/system/core/Loader.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -29,96 +29,212 @@ class CI_Loader { // All these are set automatically. Don't mess with them. - var $_ci_ob_level; - var $_ci_view_path = ''; - var $_ci_is_php5 = FALSE; - var $_ci_is_instance = FALSE; // Whether we should use $this or $CI =& get_instance() - var $_ci_cached_vars = array(); - var $_ci_classes = array(); - var $_ci_loaded_files = array(); - var $_ci_models = array(); - var $_ci_helpers = array(); - var $_ci_plugins = array(); - var $_ci_varmap = array('unit_test' => 'unit', 'user_agent' => 'agent'); - + /** + * Nesting level of the output buffering mechanism + * + * @var int + * @access protected + */ + protected $_ci_ob_level; + /** + * List of paths to load views from + * + * @var array + * @access protected + */ + protected $_ci_view_paths = array(); + /** + * List of paths to load libraries from + * + * @var array + * @access protected + */ + protected $_ci_library_paths = array(); + /** + * List of paths to load models from + * + * @var array + * @access protected + */ + protected $_ci_model_paths = array(); + /** + * List of paths to load helpers from + * + * @var array + * @access protected + */ + protected $_ci_helper_paths = array(); + /** + * List of loaded base classes + * Set by the controller class + * + * @var array + * @access protected + */ + protected $_base_classes = array(); // Set by the controller class + /** + * List of cached variables + * + * @var array + * @access protected + */ + protected $_ci_cached_vars = array(); + /** + * List of loaded classes + * + * @var array + * @access protected + */ + protected $_ci_classes = array(); + /** + * List of loaded files + * + * @var array + * @access protected + */ + protected $_ci_loaded_files = array(); + /** + * List of loaded models + * + * @var array + * @access protected + */ + protected $_ci_models = array(); + /** + * List of loaded helpers + * + * @var array + * @access protected + */ + protected $_ci_helpers = array(); + /** + * List of class name mappings + * + * @var array + * @access protected + */ + protected $_ci_varmap = array('unit_test' => 'unit', + 'user_agent' => 'agent'); /** * Constructor * * Sets the path to the view files and gets the initial output buffering level - * - * @access public */ - function CI_Loader() - { - $this->_ci_is_php5 = (floor(phpversion()) >= 5) ? TRUE : FALSE; - $this->_ci_view_path = APPPATH.'views/'; + public function __construct() + { $this->_ci_ob_level = ob_get_level(); - + $this->_ci_library_paths = array(APPPATH, BASEPATH); + $this->_ci_helper_paths = array(APPPATH, BASEPATH); + $this->_ci_model_paths = array(APPPATH); + $this->_ci_view_paths = array(APPPATH.'views/' => TRUE); + log_message('debug', "Loader Class Initialized"); } - + + // -------------------------------------------------------------------- + + /** + * Initialize the Loader + * + * This method is called once in CI_Controller. + * + * @param array + * @return object + */ + public function initialize() + { + $this->_ci_classes = array(); + $this->_ci_loaded_files = array(); + $this->_ci_models = array(); + $this->_base_classes =& is_loaded(); + + $this->_ci_autoloader(); + + return $this; + } + // -------------------------------------------------------------------- - + + /** + * Is Loaded + * + * A utility function to test if a class is in the self::$_ci_classes array. + * This function returns the object name if the class tested for is loaded, + * and returns FALSE if it isn't. + * + * It is mainly used in the form_helper -> _get_validation_object() + * + * @param string class being checked for + * @return mixed class object name on the CI SuperObject or FALSE + */ + public function is_loaded($class) + { + if (isset($this->_ci_classes[$class])) + { + return $this->_ci_classes[$class]; + } + + return FALSE; + } + + // -------------------------------------------------------------------- + /** * Class Loader * * This function lets users load and instantiate classes. * It is designed to be called from a user's app controllers. * - * @access public * @param string the name of the class * @param mixed the optional parameters * @param string an optional object name * @return void - */ - function library($library = '', $params = NULL, $object_name = NULL) + */ + public function library($library = '', $params = NULL, $object_name = NULL) { - if ($library == '') - { - return FALSE; - } - - if ( ! is_null($params) AND ! is_array($params)) - { - $params = NULL; - } - if (is_array($library)) { foreach ($library as $class) { - $this->_ci_load_class($class, $params, $object_name); + $this->library($class, $params); } + + return; } - else + + if ($library == '' OR isset($this->_base_classes[$library])) { - $this->_ci_load_class($library, $params, $object_name); + return FALSE; } - - $this->_ci_assign_to_models(); + + if ( ! is_null($params) && ! is_array($params)) + { + $params = NULL; + } + + $this->_ci_load_class($library, $params, $object_name); } // -------------------------------------------------------------------- - + /** * Model Loader * * This function lets users load and instantiate models. * - * @access public * @param string the name of the class * @param string name for the model * @param bool database connection * @return void - */ - function model($model, $name = '', $db_conn = FALSE) - { + */ + public function model($model, $name = '', $db_conn = FALSE) + { if (is_array($model)) { - foreach($model as $babe) + foreach ($model as $babe) { - $this->model($babe); + $this->model($babe); } return; } @@ -127,164 +243,161 @@ function model($model, $name = '', $db_conn = FALSE) { return; } - + + $path = ''; + // Is the model in a sub-folder? If so, parse out the filename and path. - if (strpos($model, '/') === FALSE) - { - $path = ''; - } - else + if (($last_slash = strrpos($model, '/')) !== FALSE) { - $x = explode('/', $model); - $model = end($x); - unset($x[count($x)-1]); - $path = implode('/', $x).'/'; + // The path is in front of the last slash + $path = substr($model, 0, $last_slash + 1); + + // And the model name behind it + $model = substr($model, $last_slash + 1); } - + if ($name == '') { $name = $model; } - + if (in_array($name, $this->_ci_models, TRUE)) { return; } - + $CI =& get_instance(); if (isset($CI->$name)) { show_error('The model name you are loading is the name of a resource that is already being used: '.$name); } - + $model = strtolower($model); - - if ( ! file_exists(APPPATH.'models/'.$path.$model.EXT)) - { - show_error('Unable to locate the model you have specified: '.$model); - } - - if ($db_conn !== FALSE AND ! class_exists('CI_DB')) - { - if ($db_conn === TRUE) - $db_conn = ''; - - $CI->load->database($db_conn, FALSE, TRUE); - } - - if ( ! class_exists('Model')) + + foreach ($this->_ci_model_paths as $mod_path) { - load_class('Model', FALSE); - } + if ( ! file_exists($mod_path.'models/'.$path.$model.'.php')) + { + continue; + } - require_once(APPPATH.'models/'.$path.$model.EXT); + if ($db_conn !== FALSE AND ! class_exists('CI_DB')) + { + if ($db_conn === TRUE) + { + $db_conn = ''; + } - $model = ucfirst($model); - - $CI->$name = new $model(); - $CI->$name->_assign_libraries(); - - $this->_ci_models[] = $name; + $CI->load->database($db_conn, FALSE, TRUE); + } + + if ( ! class_exists('CI_Model')) + { + load_class('Model', 'core'); + } + + require_once($mod_path.'models/'.$path.$model.'.php'); + + $model = ucfirst($model); + + $CI->$name = new $model(); + + $this->_ci_models[] = $name; + return; + } + + // couldn't find the model + show_error('Unable to locate the model you have specified: '.$model); } - + // -------------------------------------------------------------------- - + /** * Database Loader * - * @access public * @param string the DB credentials * @param bool whether to return the DB object * @param bool whether to enable active record (this allows us to override the config setting) * @return object - */ - function database($params = '', $return = FALSE, $active_record = FALSE) + */ + public function database($params = '', $return = FALSE, $active_record = NULL) { // Grab the super object $CI =& get_instance(); - + // Do we even need to load the database class? - if (class_exists('CI_DB') AND $return == FALSE AND $active_record == FALSE AND isset($CI->db) AND is_object($CI->db)) + if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db)) { return FALSE; - } - - require_once(BASEPATH.'database/DB'.EXT); + } + + require_once(BASEPATH.'database/DB.php'); if ($return === TRUE) { return DB($params, $active_record); } - - // Initialize the db variable. Needed to prevent + + // Initialize the db variable. Needed to prevent // reference errors with some configurations $CI->db = ''; - + // Load the DB class - $CI->db =& DB($params, $active_record); - - // Assign the DB object to any existing models - $this->_ci_assign_to_models(); + $CI->db =& DB($params, $active_record); } - + // -------------------------------------------------------------------- /** * Load the Utilities Class * - * @access public - * @return string - */ - function dbutil() + * @return string + */ + public function dbutil() { if ( ! class_exists('CI_DB')) { $this->database(); } - + $CI =& get_instance(); // for backwards compatibility, load dbforge so we can extend dbutils off it // this use is deprecated and strongly discouraged $CI->load->dbforge(); - - require_once(BASEPATH.'database/DB_utility'.EXT); - require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_utility'.EXT); - $class = 'CI_DB_'.$CI->db->dbdriver.'_utility'; - $CI->dbutil =& instantiate_class(new $class()); + require_once(BASEPATH.'database/DB_utility.php'); + require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_utility.php'); + $class = 'CI_DB_'.$CI->db->dbdriver.'_utility'; - $CI->load->_ci_assign_to_models(); + $CI->dbutil = new $class(); } - + // -------------------------------------------------------------------- /** * Load the Database Forge Class * - * @access public - * @return string - */ - function dbforge() + * @return string + */ + public function dbforge() { if ( ! class_exists('CI_DB')) { $this->database(); } - + $CI =& get_instance(); - - require_once(BASEPATH.'database/DB_forge'.EXT); - require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_forge'.EXT); + + require_once(BASEPATH.'database/DB_forge.php'); + require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_forge.php'); $class = 'CI_DB_'.$CI->db->dbdriver.'_forge'; $CI->dbforge = new $class(); - - $CI->load->_ci_assign_to_models(); } - + // -------------------------------------------------------------------- - + /** * Load View * @@ -296,55 +409,53 @@ function dbforge() * some cases it's advantageous to be able to return data so that * a developer can process it in some way. * - * @access public * @param string * @param array * @param bool * @return void */ - function view($view, $vars = array(), $return = FALSE) + public function view($view, $vars = array(), $return = FALSE) { return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return)); } - + // -------------------------------------------------------------------- - + /** * Load File * * This is a generic file loader * - * @access public * @param string * @param bool * @return string */ - function file($path, $return = FALSE) + public function file($path, $return = FALSE) { return $this->_ci_load(array('_ci_path' => $path, '_ci_return' => $return)); } - + // -------------------------------------------------------------------- - + /** * Set Variables * * Once variables are set they become available within * the controller class and its "view" files. * - * @access public * @param array + * @param string * @return void */ - function vars($vars = array(), $val = '') + public function vars($vars = array(), $val = '') { if ($val != '' AND is_string($vars)) { $vars = array($vars => $val); } - + $vars = $this->_ci_object_to_array($vars); - + if (is_array($vars) AND count($vars) > 0) { foreach ($vars as $key => $val) @@ -353,236 +464,270 @@ function vars($vars = array(), $val = '') } } } - + // -------------------------------------------------------------------- - + + /** + * Get Variable + * + * Check if a variable is set and retrieve it. + * + * @param array + * @return void + */ + public function get_var($key) + { + return isset($this->_ci_cached_vars[$key]) ? $this->_ci_cached_vars[$key] : NULL; + } + + // -------------------------------------------------------------------- + /** * Load Helper * * This function loads the specified helper file. * - * @access public * @param mixed * @return void */ - function helper($helpers = array()) + public function helper($helpers = array()) { - if ( ! is_array($helpers)) + foreach ($this->_ci_prep_filename($helpers, '_helper') as $helper) { - $helpers = array($helpers); - } - - foreach ($helpers as $helper) - { - $helper = strtolower(str_replace(EXT, '', str_replace('_helper', '', $helper)).'_helper'); - if (isset($this->_ci_helpers[$helper])) { continue; } - - $ext_helper = APPPATH.'helpers/'.config_item('subclass_prefix').$helper.EXT; - // Is this a helper extension request? + $ext_helper = APPPATH.'helpers/'.config_item('subclass_prefix').$helper.'.php'; + + // Is this a helper extension request? if (file_exists($ext_helper)) { - $base_helper = BASEPATH.'helpers/'.$helper.EXT; - + $base_helper = BASEPATH.'helpers/'.$helper.'.php'; + if ( ! file_exists($base_helper)) { - show_error('Unable to load the requested file: helpers/'.$helper.EXT); + show_error('Unable to load the requested file: helpers/'.$helper.'.php'); } - + include_once($ext_helper); include_once($base_helper); + + $this->_ci_helpers[$helper] = TRUE; + log_message('debug', 'Helper loaded: '.$helper); + continue; } - elseif (file_exists(APPPATH.'helpers/'.$helper.EXT)) - { - include_once(APPPATH.'helpers/'.$helper.EXT); - } - else - { - if (file_exists(BASEPATH.'helpers/'.$helper.EXT)) - { - include_once(BASEPATH.'helpers/'.$helper.EXT); - } - else + + // Try to load the helper + foreach ($this->_ci_helper_paths as $path) + { + if (file_exists($path.'helpers/'.$helper.'.php')) { - show_error('Unable to load the requested file: helpers/'.$helper.EXT); + include_once($path.'helpers/'.$helper.'.php'); + + $this->_ci_helpers[$helper] = TRUE; + log_message('debug', 'Helper loaded: '.$helper); + break; } } - $this->_ci_helpers[$helper] = TRUE; - log_message('debug', 'Helper loaded: '.$helper); - } + // unable to load the helper + if ( ! isset($this->_ci_helpers[$helper])) + { + show_error('Unable to load the requested file: helpers/'.$helper.'.php'); + } + } } - + // -------------------------------------------------------------------- - + /** * Load Helpers * * This is simply an alias to the above function in case the * user has written the plural form of this function. * - * @access public * @param array * @return void */ - function helpers($helpers = array()) + public function helpers($helpers = array()) { $this->helper($helpers); } - + // -------------------------------------------------------------------- - + /** - * Load Plugin - * - * This function loads the specified plugin. + * Loads a language file * - * @access public * @param array + * @param string * @return void */ - function plugin($plugins = array()) + public function language($file = array(), $lang = '') { - if ( ! is_array($plugins)) + $CI =& get_instance(); + + if ( ! is_array($file)) { - $plugins = array($plugins); + $file = array($file); } - - foreach ($plugins as $plugin) - { - $plugin = strtolower(str_replace(EXT, '', str_replace('_pi', '', $plugin)).'_pi'); - - if (isset($this->_ci_plugins[$plugin])) - { - continue; - } - if (file_exists(APPPATH.'plugins/'.$plugin.EXT)) - { - include_once(APPPATH.'plugins/'.$plugin.EXT); - } - else - { - if (file_exists(BASEPATH.'plugins/'.$plugin.EXT)) - { - include_once(BASEPATH.'plugins/'.$plugin.EXT); - } - else - { - show_error('Unable to load the requested file: plugins/'.$plugin.EXT); - } - } - - $this->_ci_plugins[$plugin] = TRUE; - log_message('debug', 'Plugin loaded: '.$plugin); - } + foreach ($file as $langfile) + { + $CI->lang->load($langfile, $lang); + } } // -------------------------------------------------------------------- - + /** - * Load Plugins - * - * This is simply an alias to the above function in case the - * user has written the plural form of this function. + * Loads a config file * - * @access public - * @param array + * @param string + * @param bool + * @param bool * @return void */ - function plugins($plugins = array()) + public function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) { - $this->plugin($plugins); + $CI =& get_instance(); + $CI->config->load($file, $use_sections, $fail_gracefully); } - + // -------------------------------------------------------------------- - + /** - * Loads a language file + * Driver * - * @access public - * @param array - * @param string + * Loads a driver library + * + * @param string the name of the class + * @param mixed the optional parameters + * @param string an optional object name * @return void */ - function language($file = array(), $lang = '') + public function driver($library = '', $params = NULL, $object_name = NULL) { - $CI =& get_instance(); + if ( ! class_exists('CI_Driver_Library')) + { + // we aren't instantiating an object here, that'll be done by the Library itself + require BASEPATH.'libraries/Driver.php'; + } - if ( ! is_array($file)) + if ($library == '') { - $file = array($file); + return FALSE; } - foreach ($file as $langfile) - { - $CI->lang->load($langfile, $lang); + // We can save the loader some time since Drivers will *always* be in a subfolder, + // and typically identically named to the library + if ( ! strpos($library, '/')) + { + $library = ucfirst($library).'/'.$library; } + + return $this->library($library, $params, $object_name); } + // -------------------------------------------------------------------- + /** - * Loads language files for scaffolding + * Add Package Path + * + * Prepends a parent path to the library, model, helper, and config path arrays * - * @access public * @param string - * @return arra + * @param boolean + * @return void */ - function scaffold_language($file = '', $lang = '', $return = FALSE) + public function add_package_path($path, $view_cascade=TRUE) { - $CI =& get_instance(); - return $CI->lang->load($file, $lang, $return); + $path = rtrim($path, '/').'/'; + + array_unshift($this->_ci_library_paths, $path); + array_unshift($this->_ci_model_paths, $path); + array_unshift($this->_ci_helper_paths, $path); + + $this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths; + + // Add config file path + $config =& $this->_ci_get_component('config'); + array_unshift($config->_config_paths, $path); } - + // -------------------------------------------------------------------- - + /** - * Loads a config file + * Get Package Paths + * + * Return a list of all package paths, by default it will ignore BASEPATH. * - * @access public * @param string * @return void */ - function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) - { - $CI =& get_instance(); - $CI->config->load($file, $use_sections, $fail_gracefully); + public function get_package_paths($include_base = FALSE) + { + return $include_base === TRUE ? $this->_ci_library_paths : $this->_ci_model_paths; } // -------------------------------------------------------------------- - + /** - * Scaffolding Loader + * Remove Package Path * - * This initializing function works a bit different than the - * others. It doesn't load the class. Instead, it simply - * sets a flag indicating that scaffolding is allowed to be - * used. The actual scaffolding function below is - * called by the front controller based on whether the - * second segment of the URL matches the "secret" scaffolding - * word stored in the application/config/routes.php + * Remove a path from the library, model, and helper path arrays if it exists + * If no path is provided, the most recently added path is removed. * - * @access public - * @param string - * @return void - */ - function scaffolding($table = '') - { - if ($table === FALSE) + * @param type + * @param bool + * @return type + */ + public function remove_package_path($path = '', $remove_config_path = TRUE) + { + $config =& $this->_ci_get_component('config'); + + if ($path == '') { - show_error('You must include the name of the table you would like to access when you initialize scaffolding'); + $void = array_shift($this->_ci_library_paths); + $void = array_shift($this->_ci_model_paths); + $void = array_shift($this->_ci_helper_paths); + $void = array_shift($this->_ci_view_paths); + $void = array_shift($config->_config_paths); } - - $CI =& get_instance(); - $CI->_ci_scaffolding = TRUE; - $CI->_ci_scaff_table = $table; + else + { + $path = rtrim($path, '/').'/'; + foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_helper_paths') as $var) + { + if (($key = array_search($path, $this->{$var})) !== FALSE) + { + unset($this->{$var}[$key]); + } + } + + if (isset($this->_ci_view_paths[$path.'views/'])) + { + unset($this->_ci_view_paths[$path.'views/']); + } + + if (($key = array_search($path, $config->_config_paths)) !== FALSE) + { + unset($config->_config_paths[$key]); + } + } + + // make sure the application default paths are still in the array + $this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH))); + $this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH))); + $this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH))); + $this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE)); + $config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH))); } // -------------------------------------------------------------------- - + /** * Loader * @@ -590,11 +735,10 @@ function scaffolding($table = '') * Variables are prefixed with _ci_ to avoid symbol collision with * variables made available to view files * - * @access private * @param array * @return void */ - function _ci_load($_ci_data) + protected function _ci_load($_ci_data) { // Set the default data variables foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val) @@ -602,37 +746,49 @@ function _ci_load($_ci_data) $$_ci_val = ( ! isset($_ci_data[$_ci_val])) ? FALSE : $_ci_data[$_ci_val]; } + $file_exists = FALSE; + // Set the path to the requested file - if ($_ci_path == '') + if ($_ci_path != '') { - $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION); - $_ci_file = ($_ci_ext == '') ? $_ci_view.EXT : $_ci_view; - $_ci_path = $this->_ci_view_path.$_ci_file; + $_ci_x = explode('/', $_ci_path); + $_ci_file = end($_ci_x); } else { - $_ci_x = explode('/', $_ci_path); - $_ci_file = end($_ci_x); + $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION); + $_ci_file = ($_ci_ext == '') ? $_ci_view.'.php' : $_ci_view; + + foreach ($this->_ci_view_paths as $view_file => $cascade) + { + if (file_exists($view_file.$_ci_file)) + { + $_ci_path = $view_file.$_ci_file; + $file_exists = TRUE; + break; + } + + if ( ! $cascade) + { + break; + } + } } - - if ( ! file_exists($_ci_path)) + + if ( ! $file_exists && ! file_exists($_ci_path)) { show_error('Unable to load the requested file: '.$_ci_file); } - + // This allows anything loaded using $this->load (views, files, etc.) // to become accessible from within the Controller and Model functions. - // Only needed when running PHP 5 - - if ($this->_ci_is_instance()) + + $_ci_CI =& get_instance(); + foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var) { - $_ci_CI =& get_instance(); - foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var) + if ( ! isset($this->$_ci_key)) { - if ( ! isset($this->$_ci_key)) - { - $this->$_ci_key =& $_ci_CI->$_ci_key; - } + $this->$_ci_key =& $_ci_CI->$_ci_key; } } @@ -643,13 +799,13 @@ function _ci_load($_ci_data) * function or via the second parameter of this function. We'll merge * the two types and cache them so that views that are embedded within * other views can have access to these variables. - */ + */ if (is_array($_ci_vars)) { $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars); } extract($this->_ci_cached_vars); - + /* * Buffer the output * @@ -663,11 +819,11 @@ function _ci_load($_ci_data) * the browser and then stop the timer it won't be accurate. */ ob_start(); - + // If the PHP installation does not support short tags we'll // do a little string replacement, changing the short tags // to standard PHP echo statements. - + if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE) { echo eval('?>'.preg_replace("/;*\s*\?>/", "; ?>", str_replace(' $this->_ci_ob_level + 1) { ob_end_flush(); } else { - // PHP 4 requires that we use a global - global $OUT; - $OUT->append_output(ob_get_contents()); + $_ci_CI->output->append_output(ob_get_contents()); @ob_end_clean(); } } @@ -717,47 +871,40 @@ function _ci_load($_ci_data) * * This function loads the requested class. * - * @access private - * @param string the item that is being loaded + * @param string the item that is being loaded * @param mixed any additional parameters * @param string an optional object name - * @return void + * @return void */ - function _ci_load_class($class, $params = NULL, $object_name = NULL) - { - // Get the class name, and while we're at it trim any slashes. - // The directory path can be included as part of the class name, + protected function _ci_load_class($class, $params = NULL, $object_name = NULL) + { + // Get the class name, and while we're at it trim any slashes. + // The directory path can be included as part of the class name, // but we don't want a leading slash - $class = str_replace(EXT, '', trim($class, '/')); - + $class = str_replace('.php', '', trim($class, '/')); + // Was the path included with the class name? // We look for a slash to determine this $subdir = ''; - if (strpos($class, '/') !== FALSE) + if (($last_slash = strrpos($class, '/')) !== FALSE) { - // explode the path so we can separate the filename from the path - $x = explode('/', $class); - - // Reset the $class variable now that we know the actual filename - $class = end($x); - - // Kill the filename from the array - unset($x[count($x)-1]); - - // Glue the path back together, sans filename - $subdir = implode($x, '/').'/'; + // Extract the path + $subdir = substr($class, 0, $last_slash + 1); + + // Get the filename from the path + $class = substr($class, $last_slash + 1); } // We'll test for both lowercase and capitalized versions of the file name foreach (array(ucfirst($class), strtolower($class)) as $class) { - $subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.EXT; + $subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php'; - // Is this a class extension request? + // Is this a class extension request? if (file_exists($subclass)) { - $baseclass = BASEPATH.'libraries/'.ucfirst($class).EXT; - + $baseclass = BASEPATH.'libraries/'.ucfirst($class).'.php'; + if ( ! file_exists($baseclass)) { log_message('error', "Unable to load the requested class: ".$class); @@ -775,35 +922,34 @@ function _ci_load_class($class, $params = NULL, $object_name = NULL) $CI =& get_instance(); if ( ! isset($CI->$object_name)) { - return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); + return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); } } - + $is_duplicate = TRUE; log_message('debug', $class." class already loaded. Second attempt ignored."); return; } - - include_once($baseclass); + + include_once($baseclass); include_once($subclass); $this->_ci_loaded_files[] = $subclass; - - return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); + + return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); } - + // Lets search for the requested library file and load it. - $is_duplicate = FALSE; - for ($i = 1; $i < 3; $i++) + $is_duplicate = FALSE; + foreach ($this->_ci_library_paths as $path) { - $path = ($i % 2) ? APPPATH : BASEPATH; - $filepath = $path.'libraries/'.$subdir.$class.EXT; - + $filepath = $path.'libraries/'.$subdir.$class.'.php'; + // Does the file exist? No? Bummer... if ( ! file_exists($filepath)) { continue; } - + // Safety: Was the class already loaded by a previous call? if (in_array($filepath, $this->_ci_loaded_files)) { @@ -818,16 +964,17 @@ function _ci_load_class($class, $params = NULL, $object_name = NULL) return $this->_ci_init_class($class, '', $params, $object_name); } } - + $is_duplicate = TRUE; log_message('debug', $class." class already loaded. Second attempt ignored."); return; } - + include_once($filepath); $this->_ci_loaded_files[] = $filepath; return $this->_ci_init_class($class, '', $params, $object_name); } + } // END FOREACH // One last attempt. Maybe the library is in a subdirectory, but it wasn't specified? @@ -836,7 +983,7 @@ function _ci_load_class($class, $params = NULL, $object_name = NULL) $path = strtolower($class).'/'.$class; return $this->_ci_load_class($path, $params); } - + // If we got this far we were unable to find the requested class. // We do not issue errors if the load call failed due to a duplicate request if ($is_duplicate == FALSE) @@ -845,42 +992,66 @@ function _ci_load_class($class, $params = NULL, $object_name = NULL) show_error("Unable to load the requested class: ".$class); } } - + // -------------------------------------------------------------------- /** * Instantiates a class * - * @access private * @param string * @param string + * @param bool * @param string an optional object name * @return null */ - function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) - { - // Is there an associated config file for this class? + protected function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) + { + // Is there an associated config file for this class? Note: these should always be lowercase if ($config === NULL) { - // We test for both uppercase and lowercase, for servers that - // are case-sensitive with regard to file names - if (file_exists(APPPATH.'config/'.strtolower($class).EXT)) - { - include_once(APPPATH.'config/'.strtolower($class).EXT); - } - elseif (file_exists(APPPATH.'config/'.ucfirst(strtolower($class)).EXT)) + // Fetch the config paths containing any package paths + $config_component = $this->_ci_get_component('config'); + + if (is_array($config_component->_config_paths)) { - include_once(APPPATH.'config/'.ucfirst(strtolower($class)).EXT); + // Break on the first found file, thus package files + // are not overridden by default paths + foreach ($config_component->_config_paths as $path) + { + // We test for both uppercase and lowercase, for servers that + // are case-sensitive with regard to file names. Check for environment + // first, global next + if (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php')) + { + include($path .'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'); + break; + } + elseif (defined('ENVIRONMENT') AND file_exists($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php')) + { + include($path .'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'); + break; + } + elseif (file_exists($path .'config/'.strtolower($class).'.php')) + { + include($path .'config/'.strtolower($class).'.php'); + break; + } + elseif (file_exists($path .'config/'.ucfirst(strtolower($class)).'.php')) + { + include($path .'config/'.ucfirst(strtolower($class)).'.php'); + break; + } + } } } - + if ($prefix == '') - { - if (class_exists('CI_'.$class)) + { + if (class_exists('CI_'.$class)) { $name = 'CI_'.$class; } - elseif (class_exists(config_item('subclass_prefix').$class)) + elseif (class_exists(config_item('subclass_prefix').$class)) { $name = config_item('subclass_prefix').$class; } @@ -893,18 +1064,18 @@ function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NU { $name = $prefix.$class; } - + // Is the class name valid? if ( ! class_exists($name)) { log_message('error', "Non-existent class: ".$name); show_error("Non-existent class: ".$class); } - + // Set the variable name we will assign the class to // Was a custom class name supplied? If so we'll use it $class = strtolower($class); - + if (is_null($object_name)) { $classvar = ( ! isset($this->_ci_varmap[$class])) ? $class : $this->_ci_varmap[$class]; @@ -914,68 +1085,83 @@ function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NU $classvar = $object_name; } - // Save the class name and object name + // Save the class name and object name $this->_ci_classes[$class] = $classvar; - // Instantiate the class + // Instantiate the class $CI =& get_instance(); if ($config !== NULL) { $CI->$classvar = new $name($config); } else - { + { $CI->$classvar = new $name; - } - } - + } + } + // -------------------------------------------------------------------- - + /** * Autoloader * * The config/autoload.php file contains an array that permits sub-systems, - * libraries, plugins, and helpers to be loaded automatically. + * libraries, and helpers to be loaded automatically. * - * @access private * @param array * @return void */ - function _ci_autoloader() - { - include_once(APPPATH.'config/autoload'.EXT); - + private function _ci_autoloader() + { + if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'); + } + else + { + include(APPPATH.'config/autoload.php'); + } + if ( ! isset($autoload)) { return FALSE; } - + + // Autoload packages + if (isset($autoload['packages'])) + { + foreach ($autoload['packages'] as $package_path) + { + $this->add_package_path($package_path); + } + } + // Load any custom config file if (count($autoload['config']) > 0) - { + { $CI =& get_instance(); foreach ($autoload['config'] as $key => $val) { $CI->config->load($val); } - } + } - // Autoload plugins, helpers and languages - foreach (array('helper', 'plugin', 'language') as $type) - { + // Autoload helpers and languages + foreach (array('helper', 'language') as $type) + { if (isset($autoload[$type]) AND count($autoload[$type]) > 0) { $this->$type($autoload[$type]); - } + } } // A little tweak to remain backward compatible // The $autoload['core'] item was deprecated - if ( ! isset($autoload['libraries'])) + if ( ! isset($autoload['libraries']) AND isset($autoload['core'])) { $autoload['libraries'] = $autoload['core']; } - + // Load libraries if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0) { @@ -986,100 +1172,77 @@ function _ci_autoloader() $autoload['libraries'] = array_diff($autoload['libraries'], array('database')); } - // Load scaffolding - if (in_array('scaffolding', $autoload['libraries'])) - { - $this->scaffolding(); - $autoload['libraries'] = array_diff($autoload['libraries'], array('scaffolding')); - } - // Load all other libraries foreach ($autoload['libraries'] as $item) { $this->library($item); } - } + } // Autoload models if (isset($autoload['model'])) { $this->model($autoload['model']); } - } - + // -------------------------------------------------------------------- /** - * Assign to Models + * Object to Array * - * Makes sure that anything loaded by the loader class (libraries, plugins, etc.) - * will be available to models, if any exist. + * Takes an object as input and converts the class variables to array key/vals * - * @access private * @param object * @return array */ - function _ci_assign_to_models() + protected function _ci_object_to_array($object) { - if (count($this->_ci_models) == 0) - { - return; - } - - if ($this->_ci_is_instance()) - { - $CI =& get_instance(); - foreach ($this->_ci_models as $model) - { - $CI->$model->_assign_libraries(); - } - } - else - { - foreach ($this->_ci_models as $model) - { - $this->$model->_assign_libraries(); - } - } - } + return (is_object($object)) ? get_object_vars($object) : $object; + } // -------------------------------------------------------------------- /** - * Object to Array + * Get a reference to a specific library or model * - * Takes an object as input and converts the class variables to array key/vals - * - * @access private - * @param object - * @return array + * @param string + * @return bool */ - function _ci_object_to_array($object) + protected function &_ci_get_component($component) { - return (is_object($object)) ? get_object_vars($object) : $object; + $CI =& get_instance(); + return $CI->$component; } // -------------------------------------------------------------------- /** - * Determines whether we should use the CI instance or $this + * Prep filename * - * @access private - * @return bool + * This function preps the name of various items to make loading them more reliable. + * + * @param mixed + * @param string + * @return array */ - function _ci_is_instance() + protected function _ci_prep_filename($filename, $extension) { - if ($this->_ci_is_php5 == TRUE) + if ( ! is_array($filename)) { - return TRUE; + return array(strtolower(str_replace('.php', '', str_replace($extension, '', $filename)).$extension)); } - - global $CI; - return (is_object($CI)) ? TRUE : FALSE; - } + else + { + foreach ($filename as $key => $val) + { + $filename[$key] = strtolower(str_replace('.php', '', str_replace($extension, '', $val)).$extension); + } + return $filename; + } + } } /* End of file Loader.php */ -/* Location: ./system/libraries/Loader.php */ \ No newline at end of file +/* Location: ./system/core/Loader.php */ \ No newline at end of file diff --git a/system/core/Model.php b/system/core/Model.php new file mode 100755 index 00000000..e15ffbeb --- /dev/null +++ b/system/core/Model.php @@ -0,0 +1,57 @@ +$key; + } +} +// END Model Class + +/* End of file Model.php */ +/* Location: ./system/core/Model.php */ \ No newline at end of file diff --git a/system/libraries/Output.php b/system/core/Output.php old mode 100644 new mode 100755 similarity index 61% rename from system/libraries/Output.php rename to system/core/Output.php index f661a083..ccecafd2 --- a/system/libraries/Output.php +++ b/system/core/Output.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -28,19 +28,89 @@ */ class CI_Output { - var $final_output; - var $cache_expiration = 0; - var $headers = array(); - var $enable_profiler = FALSE; - + /** + * Current output string + * + * @var string + * @access protected + */ + protected $final_output; + /** + * Cache expiration time + * + * @var int + * @access protected + */ + protected $cache_expiration = 0; + /** + * List of server headers + * + * @var array + * @access protected + */ + protected $headers = array(); + /** + * List of mime types + * + * @var array + * @access protected + */ + protected $mime_types = array(); + /** + * Determines wether profiler is enabled + * + * @var book + * @access protected + */ + protected $enable_profiler = FALSE; + /** + * Determines if output compression is enabled + * + * @var bool + * @access protected + */ + protected $_zlib_oc = FALSE; + /** + * List of profiler sections + * + * @var array + * @access protected + */ + protected $_profiler_sections = array(); + /** + * Whether or not to parse variables like {elapsed_time} and {memory_usage} + * + * @var bool + * @access protected + */ + protected $parse_exec_vars = TRUE; - function CI_Output() + /** + * Constructor + * + */ + function __construct() { + $this->_zlib_oc = @ini_get('zlib.output_compression'); + + // Get mime types for later + if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php')) + { + include APPPATH.'config/'.ENVIRONMENT.'/mimes.php'; + } + else + { + include APPPATH.'config/mimes.php'; + } + + + $this->mime_types = $mimes; + log_message('debug', "Output Class Initialized"); } - + // -------------------------------------------------------------------- - + /** * Get Output * @@ -48,14 +118,14 @@ function CI_Output() * * @access public * @return string - */ + */ function get_output() { return $this->final_output; } - + // -------------------------------------------------------------------- - + /** * Set Output * @@ -64,10 +134,12 @@ function get_output() * @access public * @param string * @return void - */ + */ function set_output($output) { $this->final_output = $output; + + return $this; } // -------------------------------------------------------------------- @@ -80,7 +152,7 @@ function set_output($output) * @access public * @param string * @return void - */ + */ function append_output($output) { if ($this->final_output == '') @@ -91,6 +163,8 @@ function append_output($output) { $this->final_output .= $output; } + + return $this; } // -------------------------------------------------------------------- @@ -105,59 +179,133 @@ function append_output($output) * * @access public * @param string + * @param bool * @return void - */ + */ function set_header($header, $replace = TRUE) { + // If zlib.output_compression is enabled it will compress the output, + // but it will not modify the content-length header to compensate for + // the reduction, causing the browser to hang waiting for more data. + // We'll just skip content-length in those cases. + + if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) == 0) + { + return; + } + $this->headers[] = array($header, $replace); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Content Type Header + * + * @access public + * @param string extension of the file we're outputting + * @return void + */ + function set_content_type($mime_type) + { + if (strpos($mime_type, '/') === FALSE) + { + $extension = ltrim($mime_type, '.'); + + // Is this extension supported? + if (isset($this->mime_types[$extension])) + { + $mime_type =& $this->mime_types[$extension]; + + if (is_array($mime_type)) + { + $mime_type = current($mime_type); + } + } + } + + $header = 'Content-Type: '.$mime_type; + + $this->headers[] = array($header, TRUE); + + return $this; } // -------------------------------------------------------------------- - + /** * Set HTTP Status Header * moved to Common procedural functions in 1.7.2 - * + * * @access public - * @param int the status code - * @param string + * @param int the status code + * @param string * @return void - */ - function set_status_header($code = '200', $text = '') + */ + function set_status_header($code = 200, $text = '') { set_status_header($code, $text); + + return $this; } - + // -------------------------------------------------------------------- - + /** * Enable/disable Profiler * * @access public * @param bool * @return void - */ + */ function enable_profiler($val = TRUE) { $this->enable_profiler = (is_bool($val)) ? $val : TRUE; + + return $this; } - + // -------------------------------------------------------------------- - + + /** + * Set Profiler Sections + * + * Allows override of default / config settings for Profiler section display + * + * @access public + * @param array + * @return void + */ + function set_profiler_sections($sections) + { + foreach ($sections as $section => $enable) + { + $this->_profiler_sections[$section] = ($enable !== FALSE) ? TRUE : FALSE; + } + + return $this; + } + + // -------------------------------------------------------------------- + /** * Set Cache * * @access public * @param integer * @return void - */ + */ function cache($time) { $this->cache_expiration = ( ! is_numeric($time)) ? 0 : $time; + + return $this; } - + // -------------------------------------------------------------------- - + /** * Display Output * @@ -170,17 +318,24 @@ function cache($time) * benchmark timer so the page rendering speed and memory usage can be shown. * * @access public + * @param string * @return mixed - */ + */ function _display($output = '') - { + { // Note: We use globals because we can't use $CI =& get_instance() // since this function is sometimes called by the caching mechanism, // which happens before the CI super object is available. global $BM, $CFG; - + + // Grab the super object if we can. + if (class_exists('CI_Controller')) + { + $CI =& get_instance(); + } + // -------------------------------------------------------------------- - + // Set the output data if ($output == '') { @@ -188,28 +343,34 @@ function _display($output = '') } // -------------------------------------------------------------------- - - // Do we need to write a cache file? - if ($this->cache_expiration > 0) + + // Do we need to write a cache file? Only if the controller does not have its + // own _output() method and we are not dealing with a cache file, which we + // can determine by the existence of the $CI object above + if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output')) { $this->_write_cache($output); } - + // -------------------------------------------------------------------- // Parse out the elapsed time and memory usage, // then swap the pseudo-variables with the data - $elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end'); - $output = str_replace('{elapsed_time}', $elapsed, $output); - - $memory = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB'; - $output = str_replace('{memory_usage}', $memory, $output); + $elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end'); + + if ($this->parse_exec_vars === TRUE) + { + $memory = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB'; + + $output = str_replace('{elapsed_time}', $elapsed, $output); + $output = str_replace('{memory_usage}', $memory, $output); + } // -------------------------------------------------------------------- - + // Is compression requested? - if ($CFG->item('compress_output') === TRUE) + if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc == FALSE) { if (extension_loaded('zlib')) { @@ -221,7 +382,7 @@ function _display($output = '') } // -------------------------------------------------------------------- - + // Are there any server headers to send? if (count($this->headers) > 0) { @@ -229,32 +390,34 @@ function _display($output = '') { @header($header[0], $header[1]); } - } + } // -------------------------------------------------------------------- - - // Does the get_instance() function exist? + + // Does the $CI object exist? // If not we know we are dealing with a cache file so we'll // simply echo out the data and exit. - if ( ! function_exists('get_instance')) + if ( ! isset($CI)) { echo $output; log_message('debug', "Final output sent to browser"); log_message('debug', "Total execution time: ".$elapsed); return TRUE; } - + // -------------------------------------------------------------------- - // Grab the super object. We'll need it in a moment... - $CI =& get_instance(); - // Do we need to generate profile data? // If so, load the Profile class and run it. if ($this->enable_profiler == TRUE) { - $CI->load->library('profiler'); - + $CI->load->library('profiler'); + + if ( ! empty($this->_profiler_sections)) + { + $CI->profiler->set_sections($this->_profiler_sections); + } + // If the output data contains closing and tags // we will remove them and add them back after we insert the profile data if (preg_match("|.*?|is", $output)) @@ -268,7 +431,7 @@ function _display($output = '') $output .= $CI->profiler->run(); } } - + // -------------------------------------------------------------------- // Does the controller contain a function named _output()? @@ -281,35 +444,37 @@ function _display($output = '') { echo $output; // Send it to the browser! } - + log_message('debug', "Final output sent to browser"); - log_message('debug', "Total execution time: ".$elapsed); + log_message('debug', "Total execution time: ".$elapsed); } - + // -------------------------------------------------------------------- - + /** * Write a Cache File * * @access public + * @param string * @return void - */ + */ function _write_cache($output) { - $CI =& get_instance(); + $CI =& get_instance(); $path = $CI->config->item('cache_path'); - - $cache_path = ($path == '') ? BASEPATH.'cache/' : $path; - + + $cache_path = ($path == '') ? APPPATH.'cache/' : $path; + if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path)) { + log_message('error', "Unable to write cache file: ".$cache_path); return; } - + $uri = $CI->config->item('base_url'). $CI->config->item('index_page'). $CI->uri->uri_string(); - + $cache_path .= md5($uri); if ( ! $fp = @fopen($cache_path, FOPEN_WRITE_CREATE_DESTRUCTIVE)) @@ -317,9 +482,9 @@ function _write_cache($output) log_message('error', "Unable to write cache file: ".$cache_path); return; } - + $expire = time() + ($this->cache_expiration * 60); - + if (flock($fp, LOCK_EX)) { fwrite($fp, $expire.'TS--->'.$output); @@ -331,73 +496,73 @@ function _write_cache($output) return; } fclose($fp); - @chmod($cache_path, DIR_WRITE_MODE); + @chmod($cache_path, FILE_WRITE_MODE); log_message('debug', "Cache file written: ".$cache_path); } // -------------------------------------------------------------------- - + /** * Update/serve a cached file * * @access public + * @param object config class + * @param object uri class * @return void - */ + */ function _display_cache(&$CFG, &$URI) { - $cache_path = ($CFG->item('cache_path') == '') ? BASEPATH.'cache/' : $CFG->item('cache_path'); - - if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path)) - { - return FALSE; - } - + $cache_path = ($CFG->item('cache_path') == '') ? APPPATH.'cache/' : $CFG->item('cache_path'); + // Build the file path. The file name is an MD5 hash of the full URI $uri = $CFG->item('base_url'). $CFG->item('index_page'). $URI->uri_string; - + $filepath = $cache_path.md5($uri); - + if ( ! @file_exists($filepath)) { return FALSE; } - + if ( ! $fp = @fopen($filepath, FOPEN_READ)) { return FALSE; } - + flock($fp, LOCK_SH); - + $cache = ''; if (filesize($filepath) > 0) { $cache = fread($fp, filesize($filepath)); } - + flock($fp, LOCK_UN); fclose($fp); - - // Strip out the embedded timestamp + + // Strip out the embedded timestamp if ( ! preg_match("/(\d+TS--->)/", $cache, $match)) { return FALSE; } - + // Has the file expired? If so we'll delete it. if (time() >= trim(str_replace('TS--->', '', $match['1']))) - { - @unlink($filepath); - log_message('debug', "Cache file has expired. File deleted"); - return FALSE; + { + if (is_really_writable($cache_path)) + { + @unlink($filepath); + log_message('debug', "Cache file has expired. File deleted"); + return FALSE; + } } // Display the cache $this->_display(str_replace($match['0'], '', $cache)); - log_message('debug', "Cache file is current. Sending it to browser."); + log_message('debug', "Cache file is current. Sending it to browser."); return TRUE; } @@ -406,4 +571,4 @@ function _display_cache(&$CFG, &$URI) // END Output Class /* End of file Output.php */ -/* Location: ./system/libraries/Output.php */ \ No newline at end of file +/* Location: ./system/core/Output.php */ \ No newline at end of file diff --git a/system/libraries/Router.php b/system/core/Router.php old mode 100644 new mode 100755 similarity index 55% rename from system/libraries/Router.php rename to system/core/Router.php index 50c7dd7c..6da66747 --- a/system/libraries/Router.php +++ b/system/core/Router.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -28,31 +28,70 @@ */ class CI_Router { - var $config; - var $routes = array(); + /** + * Config class + * + * @var object + * @access public + */ + var $config; + /** + * List of routes + * + * @var array + * @access public + */ + var $routes = array(); + /** + * List of error routes + * + * @var array + * @access public + */ var $error_routes = array(); + /** + * Current class name + * + * @var string + * @access public + */ var $class = ''; + /** + * Current method name + * + * @var string + * @access public + */ var $method = 'index'; + /** + * Sub-directory that contains the requested controller class + * + * @var string + * @access public + */ var $directory = ''; - var $uri_protocol = 'auto'; + /** + * Default controller (and method if specific) + * + * @var string + * @access public + */ var $default_controller; - var $scaffolding_request = FALSE; // Must be set to FALSE - + /** * Constructor * * Runs the route mapping function. */ - function CI_Router() + function __construct() { - $this->config =& load_class('Config'); - $this->uri =& load_class('URI'); - $this->_set_routing(); + $this->config =& load_class('Config', 'core'); + $this->uri =& load_class('URI', 'core'); log_message('debug', "Router Class Initialized"); } - + // -------------------------------------------------------------------- - + /** * Set the route mapping * @@ -64,78 +103,114 @@ function CI_Router() */ function _set_routing() { - // Are query strings enabled in the config file? - // If so, we're done since segment based URIs are not used with query strings. + // Are query strings enabled in the config file? Normally CI doesn't utilize query strings + // since URI segments are more search-engine friendly, but they can optionally be used. + // If this feature is enabled, we will gather the directory/class/method a little differently + $segments = array(); if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')])) { - $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')]))); + if (isset($_GET[$this->config->item('directory_trigger')])) + { + $this->set_directory(trim($this->uri->_filter_uri($_GET[$this->config->item('directory_trigger')]))); + $segments[] = $this->fetch_directory(); + } + + if (isset($_GET[$this->config->item('controller_trigger')])) + { + $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')]))); + $segments[] = $this->fetch_class(); + } if (isset($_GET[$this->config->item('function_trigger')])) { $this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')]))); + $segments[] = $this->fetch_method(); } - - return; } - + // Load the routes.php file. - @include(APPPATH.'config/routes'.EXT); + if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/routes.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/routes.php'); + } + elseif (is_file(APPPATH.'config/routes.php')) + { + include(APPPATH.'config/routes.php'); + } + $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route; unset($route); // Set the default controller so we can display it in the event // the URI doesn't correlated to a valid controller. - $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']); - + $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']); + + // Were there any query string segments? If so, we'll validate them and bail out since we're done. + if (count($segments) > 0) + { + return $this->_validate_request($segments); + } + // Fetch the complete URI string $this->uri->_fetch_uri_string(); - + // Is there a URI string? If not, the default controller specified in the "routes" file will be shown. if ($this->uri->uri_string == '') { - if ($this->default_controller === FALSE) - { - show_error("Unable to determine what should be displayed. A default route has not been specified in the routing file."); - } - - if (strpos($this->default_controller, '/') !== FALSE) - { - $x = explode('/', $this->default_controller); - - $this->set_class(end($x)); - $this->set_method('index'); - $this->_set_request($x); - } - else - { - $this->set_class($this->default_controller); - $this->set_method('index'); - $this->_set_request(array($this->default_controller, 'index')); - } - - // re-index the routed segments array so it starts with 1 rather than 0 - $this->uri->_reindex_segments(); - - log_message('debug', "No URI present. Default controller set."); - return; + return $this->_set_default_controller(); } - unset($this->routes['default_controller']); - + // Do we need to remove the URL suffix? $this->uri->_remove_url_suffix(); - + // Compile the segments into an array $this->uri->_explode_segments(); - + // Parse any custom routing that may exist - $this->_parse_routes(); - + $this->_parse_routes(); + // Re-index the segment array so that it starts with 1 rather than 0 $this->uri->_reindex_segments(); } - + + // -------------------------------------------------------------------- + + /** + * Set the default controller + * + * @access private + * @return void + */ + function _set_default_controller() + { + if ($this->default_controller === FALSE) + { + show_error("Unable to determine what should be displayed. A default route has not been specified in the routing file."); + } + // Is the method being specified? + if (strpos($this->default_controller, '/') !== FALSE) + { + $x = explode('/', $this->default_controller); + + $this->set_class($x[0]); + $this->set_method($x[1]); + $this->_set_request($x); + } + else + { + $this->set_class($this->default_controller); + $this->set_method('index'); + $this->_set_request(array($this->default_controller, 'index')); + } + + // re-index the routed segments array so it starts with 1 rather than 0 + $this->uri->_reindex_segments(); + + log_message('debug', "No URI present. Default controller set."); + } + // -------------------------------------------------------------------- - + /** * Set the Route * @@ -150,27 +225,18 @@ function _set_routing() function _set_request($segments = array()) { $segments = $this->_validate_request($segments); - + if (count($segments) == 0) { - return; + return $this->_set_default_controller(); } - + $this->set_class($segments[0]); - + if (isset($segments[1])) { - // A scaffolding request. No funny business with the URL - if ($this->routes['scaffolding_trigger'] == $segments[1] AND $segments[1] != '_ci_scaffolding') - { - $this->scaffolding_request = TRUE; - unset($this->routes['scaffolding_trigger']); - } - else - { - // A standard method request - $this->set_method($segments[1]); - } + // A standard method request + $this->set_method($segments[1]); } else { @@ -178,15 +244,15 @@ function _set_request($segments = array()) // index method is being used. $segments[1] = 'index'; } - + // Update our "routed" segment array to contain the segments. // Note: If there is no custom routing, this array will be // identical to $this->uri->segments $this->uri->rsegments = $segments; } - + // -------------------------------------------------------------------- - + /** * Validates the supplied segments. Attempts to determine the path to * the controller. @@ -194,48 +260,91 @@ function _set_request($segments = array()) * @access private * @param array * @return array - */ + */ function _validate_request($segments) { + if (count($segments) == 0) + { + return $segments; + } + // Does the requested controller exist in the root folder? - if (file_exists(APPPATH.'controllers/'.$segments[0].EXT)) + if (file_exists(APPPATH.'controllers/'.$segments[0].'.php')) { return $segments; } // Is the controller in a sub-folder? if (is_dir(APPPATH.'controllers/'.$segments[0])) - { + { // Set the directory and remove it from the segment array $this->set_directory($segments[0]); $segments = array_slice($segments, 1); - + if (count($segments) > 0) { // Does the requested controller exist in the sub-folder? - if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT)) + if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].'.php')) { - show_404($this->fetch_directory().$segments[0]); + if ( ! empty($this->routes['404_override'])) + { + $x = explode('/', $this->routes['404_override']); + + $this->set_directory(''); + $this->set_class($x[0]); + $this->set_method(isset($x[1]) ? $x[1] : 'index'); + + return $x; + } + else + { + show_404($this->fetch_directory().$segments[0]); + } } } else { - $this->set_class($this->default_controller); - $this->set_method('index'); - + // Is the method being specified in the route? + if (strpos($this->default_controller, '/') !== FALSE) + { + $x = explode('/', $this->default_controller); + + $this->set_class($x[0]); + $this->set_method($x[1]); + } + else + { + $this->set_class($this->default_controller); + $this->set_method('index'); + } + // Does the default controller exist in the sub-folder? - if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT)) + if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php')) { $this->directory = ''; return array(); } - + } return $segments; } - // Can't find the requested controller... + + // If we've gotten this far it means that the URI does not correlate to a valid + // controller class. We will now see if there is an override + if ( ! empty($this->routes['404_override'])) + { + $x = explode('/', $this->routes['404_override']); + + $this->set_class($x[0]); + $this->set_method(isset($x[1]) ? $x[1] : 'index'); + + return $x; + } + + + // Nothing else to do at this point but show a 404 show_404($segments[0]); } @@ -253,41 +362,31 @@ function _validate_request($segments) */ function _parse_routes() { - // Do we even have any custom routing to deal with? - // There is a default scaffolding trigger, so we'll look just for 1 - if (count($this->routes) == 1) - { - $this->_set_request($this->uri->segments); - return; - } - // Turn the segment array into a URI string $uri = implode('/', $this->uri->segments); // Is there a literal match? If so we're done if (isset($this->routes[$uri])) { - $this->_set_request(explode('/', $this->routes[$uri])); - return; + return $this->_set_request(explode('/', $this->routes[$uri])); } - + // Loop through the route array looking for wild-cards foreach ($this->routes as $key => $val) - { + { // Convert wild-cards to RegEx $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key)); - + // Does the RegEx match? if (preg_match('#^'.$key.'$#', $uri)) - { + { // Do we have a back-reference? if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE) { $val = preg_replace('#^'.$key.'$#', $val, $uri); } - - $this->_set_request(explode('/', $val)); - return; + + return $this->_set_request(explode('/', $val)); } } @@ -297,54 +396,54 @@ function _parse_routes() } // -------------------------------------------------------------------- - + /** * Set the class name * * @access public * @param string * @return void - */ + */ function set_class($class) { - $this->class = $class; + $this->class = str_replace(array('/', '.'), '', $class); } - + // -------------------------------------------------------------------- - + /** * Fetch the current class * * @access public * @return string - */ + */ function fetch_class() { return $this->class; } - + // -------------------------------------------------------------------- - + /** * Set the method name * * @access public * @param string * @return void - */ + */ function set_method($method) { $this->method = $method; } // -------------------------------------------------------------------- - + /** * Fetch the current method * * @access public * @return string - */ + */ function fetch_method() { if ($this->method == $this->fetch_class()) @@ -356,34 +455,68 @@ function fetch_method() } // -------------------------------------------------------------------- - + /** * Set the directory name * * @access public * @param string * @return void - */ + */ function set_directory($dir) { - $this->directory = $dir.'/'; + $this->directory = str_replace(array('/', '.'), '', $dir).'/'; } // -------------------------------------------------------------------- - + /** * Fetch the sub-directory (if any) that contains the requested controller class * * @access public * @return string - */ + */ function fetch_directory() { return $this->directory; } + // -------------------------------------------------------------------- + + /** + * Set the controller overrides + * + * @access public + * @param array + * @return null + */ + function _set_overrides($routing) + { + if ( ! is_array($routing)) + { + return; + } + + if (isset($routing['directory'])) + { + $this->set_directory($routing['directory']); + } + + if (isset($routing['controller']) AND $routing['controller'] != '') + { + $this->set_class($routing['controller']); + } + + if (isset($routing['function'])) + { + $routing['function'] = ($routing['function'] == '') ? 'index' : $routing['function']; + $this->set_method($routing['function']); + } + } + + } // END Router Class /* End of file Router.php */ -/* Location: ./system/libraries/Router.php */ \ No newline at end of file +/* Location: ./system/core/Router.php */ \ No newline at end of file diff --git a/system/core/Security.php b/system/core/Security.php new file mode 100755 index 00000000..b0d39b98 --- /dev/null +++ b/system/core/Security.php @@ -0,0 +1,875 @@ + '[removed]', + 'document.write' => '[removed]', + '.parentNode' => '[removed]', + '.innerHTML' => '[removed]', + 'window.location' => '[removed]', + '-moz-binding' => '[removed]', + '' => '-->', + ' '<![CDATA[', + '' => '<comment>' + ); + + /* never allowed, regex replacement */ + /** + * List of never allowed regex replacement + * + * @var array + * @access protected + */ + protected $_never_allowed_regex = array( + 'javascript\s*:', + 'expression\s*(\(|&\#40;)', // CSS and IE + 'vbscript\s*:', // IE, surprise! + 'Redirect\s+302', + "([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?" + ); + + /** + * Constructor + * + * @return void + */ + public function __construct() + { + // Is CSRF protection enabled? + if (config_item('csrf_protection') === TRUE) + { + // CSRF config + foreach (array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key) + { + if (FALSE !== ($val = config_item($key))) + { + $this->{'_'.$key} = $val; + } + } + + // Append application specific cookie prefix + if (config_item('cookie_prefix')) + { + $this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name; + } + + // Set the CSRF hash + $this->_csrf_set_hash(); + } + + log_message('debug', "Security Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Verify Cross Site Request Forgery Protection + * + * @return object + */ + public function csrf_verify() + { + // If it's not a POST request we will set the CSRF cookie + if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') + { + return $this->csrf_set_cookie(); + } + + // Do the tokens exist in both the _POST and _COOKIE arrays? + if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])) + { + $this->csrf_show_error(); + } + + // Do the tokens match? + if ($_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name]) + { + $this->csrf_show_error(); + } + + // We kill this since we're done and we don't want to + // polute the _POST array + unset($_POST[$this->_csrf_token_name]); + + // Nothing should last forever + unset($_COOKIE[$this->_csrf_cookie_name]); + $this->_csrf_set_hash(); + $this->csrf_set_cookie(); + + log_message('debug', 'CSRF token verified'); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Set Cross Site Request Forgery Protection Cookie + * + * @return object + */ + public function csrf_set_cookie() + { + $expire = time() + $this->_csrf_expire; + $secure_cookie = (config_item('cookie_secure') === TRUE) ? 1 : 0; + + if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off')) + { + return FALSE; + } + + setcookie($this->_csrf_cookie_name, $this->_csrf_hash, $expire, config_item('cookie_path'), config_item('cookie_domain'), $secure_cookie); + + log_message('debug', "CRSF cookie Set"); + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Show CSRF Error + * + * @return void + */ + public function csrf_show_error() + { + show_error('The action you have requested is not allowed.'); + } + + // -------------------------------------------------------------------- + + /** + * Get CSRF Hash + * + * Getter Method + * + * @return string self::_csrf_hash + */ + public function get_csrf_hash() + { + return $this->_csrf_hash; + } + + // -------------------------------------------------------------------- + + /** + * Get CSRF Token Name + * + * Getter Method + * + * @return string self::csrf_token_name + */ + public function get_csrf_token_name() + { + return $this->_csrf_token_name; + } + + // -------------------------------------------------------------------- + + /** + * XSS Clean + * + * Sanitizes data so that Cross Site Scripting Hacks can be + * prevented. This function does a fair amount of work but + * it is extremely thorough, designed to prevent even the + * most obscure XSS attempts. Nothing is ever 100% foolproof, + * of course, but I haven't been able to get anything passed + * the filter. + * + * Note: This function should only be used to deal with data + * upon submission. It's not something that should + * be used for general runtime processing. + * + * This function was based in part on some code and ideas I + * got from Bitflux: http://channel.bitflux.ch/wiki/XSS_Prevention + * + * To help develop this script I used this great list of + * vulnerabilities along with a few other hacks I've + * harvested from examining vulnerabilities in other programs: + * http://ha.ckers.org/xss.html + * + * @param mixed string or array + * @param bool + * @return string + */ + public function xss_clean($str, $is_image = FALSE) + { + /* + * Is the string an array? + * + */ + if (is_array($str)) + { + while (list($key) = each($str)) + { + $str[$key] = $this->xss_clean($str[$key]); + } + + return $str; + } + + /* + * Remove Invisible Characters + */ + $str = remove_invisible_characters($str); + + // Validate Entities in URLs + $str = $this->_validate_entities($str); + + /* + * URL Decode + * + * Just in case stuff like this is submitted: + * + * Google + * + * Note: Use rawurldecode() so it does not remove plus signs + * + */ + $str = rawurldecode($str); + + /* + * Convert character entities to ASCII + * + * This permits our tests below to work reliably. + * We only convert entities that are within tags since + * these are the ones that will pose security problems. + * + */ + + $str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str); + + $str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si", array($this, '_decode_entity'), $str); + + /* + * Remove Invisible Characters Again! + */ + $str = remove_invisible_characters($str); + + /* + * Convert all tabs to spaces + * + * This prevents strings like this: ja vascript + * NOTE: we deal with spaces between characters later. + * NOTE: preg_replace was found to be amazingly slow here on + * large blocks of data, so we use str_replace. + */ + + if (strpos($str, "\t") !== FALSE) + { + $str = str_replace("\t", ' ', $str); + } + + /* + * Capture converted string for later comparison + */ + $converted_string = $str; + + // Remove Strings that are never allowed + $str = $this->_do_never_allowed($str); + + /* + * Makes PHP tags safe + * + * Note: XML tags are inadvertently replaced too: + * + * '), array('<?', '?>'), $str); + } + + /* + * Compact any exploded words + * + * This corrects words like: j a v a s c r i p t + * These words are compacted back to their correct state. + */ + $words = array( + 'javascript', 'expression', 'vbscript', 'script', 'base64', + 'applet', 'alert', 'document', 'write', 'cookie', 'window' + ); + + foreach ($words as $word) + { + $temp = ''; + + for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++) + { + $temp .= substr($word, $i, 1)."\s*"; + } + + // We only want to do this when it is followed by a non-word character + // That way valid stuff like "dealer to" does not become "dealerto" + $str = preg_replace_callback('#('.substr($temp, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str); + } + + /* + * Remove disallowed Javascript in links or img tags + * We used to do some version comparisons and use of stripos for PHP5, + * but it is dog slow compared to these simplified non-capturing + * preg_match(), especially if the pattern exists in the string + */ + do + { + $original = $str; + + if (preg_match("/]*?)(>|$)#si", array($this, '_js_link_removal'), $str); + } + + if (preg_match("/]*?)(\s?/?>|$)#si", array($this, '_js_img_removal'), $str); + } + + if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str)) + { + $str = preg_replace("#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str); + } + } + while($original != $str); + + unset($original); + + // Remove evil attributes such as style, onclick and xmlns + $str = $this->_remove_evil_attributes($str, $is_image); + + /* + * Sanitize naughty HTML elements + * + * If a tag containing any of the words in the list + * below is found, the tag gets converted to entities. + * + * So this: + * Becomes: <blink> + */ + $naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss'; + $str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', array($this, '_sanitize_naughty_html'), $str); + + /* + * Sanitize naughty scripting elements + * + * Similar to above, only instead of looking for + * tags it looks for PHP and JavaScript commands + * that are disallowed. Rather than removing the + * code, it simply converts the parenthesis to entities + * rendering the code un-executable. + * + * For example: eval('some code') + * Becomes: eval('some code') + */ + $str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2(\\3)", $str); + + + // Final clean up + // This adds a bit of extra precaution in case + // something got through the above filters + $str = $this->_do_never_allowed($str); + + /* + * Images are Handled in a Special Way + * - Essentially, we want to know that after all of the character + * conversion is done whether any unwanted, likely XSS, code was found. + * If not, we return TRUE, as the image is clean. + * However, if the string post-conversion does not matched the + * string post-removal of XSS, then it fails, as there was unwanted XSS + * code found and removed/changed during processing. + */ + + if ($is_image === TRUE) + { + return ($str == $converted_string) ? TRUE: FALSE; + } + + log_message('debug', "XSS Filtering completed"); + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Random Hash for protecting URLs + * + * @return string + */ + public function xss_hash() + { + if ($this->_xss_hash == '') + { + mt_srand(); + $this->_xss_hash = md5(time() + mt_rand(0, 1999999999)); + } + + return $this->_xss_hash; + } + + // -------------------------------------------------------------------- + + /** + * HTML Entities Decode + * + * This function is a replacement for html_entity_decode() + * + * The reason we are not using html_entity_decode() by itself is because + * while it is not technically correct to leave out the semicolon + * at the end of an entity most browsers will still interpret the entity + * correctly. html_entity_decode() does not convert entities without + * semicolons, so we are left with our own little solution here. Bummer. + * + * @param string + * @param string + * @return string + */ + public function entity_decode($str, $charset='UTF-8') + { + if (stristr($str, '&') === FALSE) + { + return $str; + } + + $str = html_entity_decode($str, ENT_COMPAT, $charset); + $str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str); + return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str); + } + + // -------------------------------------------------------------------- + + /** + * Filename Security + * + * @param string + * @param bool + * @return string + */ + public function sanitize_filename($str, $relative_path = FALSE) + { + $bad = array( + "../", + "", + "<", + ">", + "'", + '"', + '&', + '$', + '#', + '{', + '}', + '[', + ']', + '=', + ';', + '?', + "%20", + "%22", + "%3c", // < + "%253c", // < + "%3e", // > + "%0e", // > + "%28", // ( + "%29", // ) + "%2528", // ( + "%26", // & + "%24", // $ + "%3f", // ? + "%3b", // ; + "%3d" // = + ); + + if ( ! $relative_path) + { + $bad[] = './'; + $bad[] = '/'; + } + + $str = remove_invisible_characters($str, FALSE); + return stripslashes(str_replace($bad, '', $str)); + } + + // ---------------------------------------------------------------- + + /** + * Compact Exploded Words + * + * Callback function for xss_clean() to remove whitespace from + * things like j a v a s c r i p t + * + * @param type + * @return type + */ + protected function _compact_exploded_words($matches) + { + return preg_replace('/\s+/s', '', $matches[1]).$matches[2]; + } + + // -------------------------------------------------------------------- + + /* + * Remove Evil HTML Attributes (like evenhandlers and style) + * + * It removes the evil attribute and either: + * - Everything up until a space + * For example, everything between the pipes: + * + * - Everything inside the quotes + * For example, everything between the pipes: + * + * + * @param string $str The string to check + * @param boolean $is_image TRUE if this is an image + * @return string The string with the evil attributes removed + */ + protected function _remove_evil_attributes($str, $is_image) + { + // All javascript event handlers (e.g. onload, onclick, onmouseover), style, and xmlns + $evil_attributes = array('on\w*', 'style', 'xmlns', 'formaction'); + + if ($is_image === TRUE) + { + /* + * Adobe Photoshop puts XML metadata into JFIF images, + * including namespacing, so we have to allow this for images. + */ + unset($evil_attributes[array_search('xmlns', $evil_attributes)]); + } + + do { + $count = 0; + $attribs = array(); + + // find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes) + preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is', $str, $matches, PREG_SET_ORDER); + + foreach ($matches as $attr) + { + $attribs[] = preg_quote($attr[0], '/'); + } + + // find occurrences of illegal attribute strings without quotes + preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*([^\s>]*)/is', $str, $matches, PREG_SET_ORDER); + + foreach ($matches as $attr) + { + $attribs[] = preg_quote($attr[0], '/'); + } + + // replace illegal attribute strings that are inside an html tag + if (count($attribs) > 0) + { + $str = preg_replace('/(<]+?)([^A-Za-z<>\-])(.*?)('.implode('|', $attribs).')(.*?)([\s><]?)([><]*)/i', '$1$2 $4$6$7$8', $str, -1, $count); + } + + } while ($count); + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Sanitize Naughty HTML + * + * Callback function for xss_clean() to remove naughty HTML elements + * + * @param array + * @return string + */ + protected function _sanitize_naughty_html($matches) + { + // encode opening brace + $str = '<'.$matches[1].$matches[2].$matches[3]; + + // encode captured opening or closing brace to prevent recursive vectors + $str .= str_replace(array('>', '<'), array('>', '<'), + $matches[4]); + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * JS Link Removal + * + * Callback function for xss_clean() to sanitize links + * This limits the PCRE backtracks, making it more performance friendly + * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in + * PHP 5.2+ on link-heavy strings + * + * @param array + * @return string + */ + protected function _js_link_removal($match) + { + return str_replace( + $match[1], + preg_replace( + '#href=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])) + ), + $match[0] + ); + } + + // -------------------------------------------------------------------- + + /** + * JS Image Removal + * + * Callback function for xss_clean() to sanitize image tags + * This limits the PCRE backtracks, making it more performance friendly + * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in + * PHP 5.2+ on image tag heavy strings + * + * @param array + * @return string + */ + protected function _js_img_removal($match) + { + return str_replace( + $match[1], + preg_replace( + '#src=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])) + ), + $match[0] + ); + } + + // -------------------------------------------------------------------- + + /** + * Attribute Conversion + * + * Used as a callback for XSS Clean + * + * @param array + * @return string + */ + protected function _convert_attribute($match) + { + return str_replace(array('>', '<', '\\'), array('>', '<', '\\\\'), $match[0]); + } + + // -------------------------------------------------------------------- + + /** + * Filter Attributes + * + * Filters tag attributes for consistency and safety + * + * @param string + * @return string + */ + protected function _filter_attributes($str) + { + $out = ''; + + if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches)) + { + foreach ($matches[0] as $match) + { + $out .= preg_replace("#/\*.*?\*/#s", '', $match); + } + } + + return $out; + } + + // -------------------------------------------------------------------- + + /** + * HTML Entity Decode Callback + * + * Used as a callback for XSS Clean + * + * @param array + * @return string + */ + protected function _decode_entity($match) + { + return $this->entity_decode($match[0], strtoupper(config_item('charset'))); + } + + // -------------------------------------------------------------------- + + /** + * Validate URL entities + * + * Called by xss_clean() + * + * @param string + * @return string + */ + protected function _validate_entities($str) + { + /* + * Protect GET variables in URLs + */ + + // 901119URL5918AMP18930PROTECT8198 + + $str = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-]+)|i', $this->xss_hash()."\\1=\\2", $str); + + /* + * Validate standard character entities + * + * Add a semicolon if missing. We do this to enable + * the conversion of entities to ASCII later. + * + */ + $str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', "\\1;\\2", $str); + + /* + * Validate UTF16 two byte encoding (x00) + * + * Just as above, adds a semicolon if missing. + * + */ + $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str); + + /* + * Un-Protect GET variables in URLs + */ + $str = str_replace($this->xss_hash(), '&', $str); + + return $str; + } + + // ---------------------------------------------------------------------- + + /** + * Do Never Allowed + * + * A utility function for xss_clean() + * + * @param string + * @return string + */ + protected function _do_never_allowed($str) + { + $str = str_replace(array_keys($this->_never_allowed_str), $this->_never_allowed_str, $str); + + foreach ($this->_never_allowed_regex as $regex) + { + $str = preg_replace('#'.$regex.'#is', '[removed]', $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Set Cross Site Request Forgery Protection Cookie + * + * @return string + */ + protected function _csrf_set_hash() + { + if ($this->_csrf_hash == '') + { + // If the cookie exists we will use it's value. + // We don't necessarily want to regenerate it with + // each page load since a page could contain embedded + // sub-pages causing this feature to fail + if (isset($_COOKIE[$this->_csrf_cookie_name]) && + preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->_csrf_cookie_name]) === 1) + { + return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name]; + } + + return $this->_csrf_hash = md5(uniqid(rand(), TRUE)); + } + + return $this->_csrf_hash; + } + +} + +/* End of file Security.php */ +/* Location: ./system/libraries/Security.php */ diff --git a/system/libraries/URI.php b/system/core/URI.php old mode 100644 new mode 100755 similarity index 73% rename from system/libraries/URI.php rename to system/core/URI.php index 68b67805..a3ae20cc --- a/system/libraries/URI.php +++ b/system/core/URI.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -28,9 +28,34 @@ */ class CI_URI { - var $keyval = array(); + /** + * List of cached uri segments + * + * @var array + * @access public + */ + var $keyval = array(); + /** + * Current uri string + * + * @var string + * @access public + */ var $uri_string; + /** + * List of uri segments + * + * @var array + * @access public + */ var $segments = array(); + /** + * Re-indexed list of uri segments + * Starts at 1 instead of 0 + * + * @var array + * @access public + */ var $rsegments = array(); /** @@ -42,9 +67,9 @@ class CI_URI { * * @access public */ - function CI_URI() + function __construct() { - $this->config =& load_class('Config'); + $this->config =& load_class('Config', 'core'); log_message('debug', "URI Class Initialized"); } @@ -61,13 +86,17 @@ function _fetch_uri_string() { if (strtoupper($this->config->item('uri_protocol')) == 'AUTO') { - // If the URL has a question mark then it's simplest to just - // build the URI string from the zero index of the $_GET array. - // This avoids having to deal with $_SERVER variables, which - // can be unreliable in some environments - if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '') + // Is the request coming from the command line? + if (php_sapi_name() == 'cli' or defined('STDIN')) { - $this->uri_string = key($_GET); + $this->_set_uri_string($this->_parse_cli_args()); + return; + } + + // Let's try the REQUEST_URI first, this will work in most situations + if ($uri = $this->_detect_uri()) + { + $this->_set_uri_string($uri); return; } @@ -76,7 +105,7 @@ function _fetch_uri_string() $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO'); if (trim($path, '/') != '' && $path != "/".SELF) { - $this->uri_string = $path; + $this->_set_uri_string($path); return; } @@ -84,93 +113,130 @@ function _fetch_uri_string() $path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING'); if (trim($path, '/') != '') { - $this->uri_string = $path; + $this->_set_uri_string($path); return; } - // No QUERY_STRING?... Maybe the ORIG_PATH_INFO variable exists? - $path = str_replace($_SERVER['SCRIPT_NAME'], '', (isset($_SERVER['ORIG_PATH_INFO'])) ? $_SERVER['ORIG_PATH_INFO'] : @getenv('ORIG_PATH_INFO')); - if (trim($path, '/') != '' && $path != "/".SELF) + // As a last ditch effort lets try using the $_GET array + if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '') { - // remove path and script information so we have good URI data - $this->uri_string = $path; + $this->_set_uri_string(key($_GET)); return; } // We've exhausted all our options... $this->uri_string = ''; + return; } - else - { - $uri = strtoupper($this->config->item('uri_protocol')); - if ($uri == 'REQUEST_URI') - { - $this->uri_string = $this->_parse_request_uri(); - return; - } + $uri = strtoupper($this->config->item('uri_protocol')); - $this->uri_string = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri); + if ($uri == 'REQUEST_URI') + { + $this->_set_uri_string($this->_detect_uri()); + return; } - - // If the URI contains only a slash we'll kill it - if ($this->uri_string == '/') + elseif ($uri == 'CLI') { - $this->uri_string = ''; + $this->_set_uri_string($this->_parse_cli_args()); + return; } + + $path = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri); + $this->_set_uri_string($path); } // -------------------------------------------------------------------- /** - * Parse the REQUEST_URI + * Set the URI String * - * Due to the way REQUEST_URI works it usually contains path info - * that makes it unusable as URI data. We'll trim off the unnecessary - * data, hopefully arriving at a valid URI that we can use. + * @access public + * @param string + * @return string + */ + function _set_uri_string($str) + { + // Filter out control characters + $str = remove_invisible_characters($str, FALSE); + + // If the URI contains only a slash we'll kill it + $this->uri_string = ($str == '/') ? '' : $str; + } + + // -------------------------------------------------------------------- + + /** + * Detects the URI + * + * This function will detect the URI automatically and fix the query string + * if necessary. * * @access private * @return string */ - function _parse_request_uri() + private function _detect_uri() { - if ( ! isset($_SERVER['REQUEST_URI']) OR $_SERVER['REQUEST_URI'] == '') + if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME'])) { return ''; } - $request_uri = preg_replace("|/(.*)|", "\\1", str_replace("\\", "/", $_SERVER['REQUEST_URI'])); - - if ($request_uri == '' OR $request_uri == SELF) + $uri = $_SERVER['REQUEST_URI']; + if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) { - return ''; + $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME'])); } - - $fc_path = FCPATH.SELF; - if (strpos($request_uri, '?') !== FALSE) + elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0) { - $fc_path .= '?'; + $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME']))); } - $parsed_uri = explode("/", $request_uri); - - $i = 0; - foreach(explode("/", $fc_path) as $segment) + // This section ensures that even on servers that require the URI to be in the query string (Nginx) a correct + // URI is found, and also fixes the QUERY_STRING server var and $_GET array. + if (strncmp($uri, '?/', 2) === 0) { - if (isset($parsed_uri[$i]) && $segment == $parsed_uri[$i]) - { - $i++; - } + $uri = substr($uri, 2); + } + $parts = preg_split('#\?#i', $uri, 2); + $uri = $parts[0]; + if (isset($parts[1])) + { + $_SERVER['QUERY_STRING'] = $parts[1]; + parse_str($_SERVER['QUERY_STRING'], $_GET); + } + else + { + $_SERVER['QUERY_STRING'] = ''; + $_GET = array(); } - $parsed_uri = implode("/", array_slice($parsed_uri, $i)); - - if ($parsed_uri != '') + if ($uri == '/' || empty($uri)) { - $parsed_uri = '/'.$parsed_uri; + return '/'; } - return $parsed_uri; + $uri = parse_url($uri, PHP_URL_PATH); + + // Do some final cleaning of the URI and return it + return str_replace(array('//', '../'), '/', trim($uri, '/')); + } + + // -------------------------------------------------------------------- + + /** + * Parse cli arguments + * + * Take each command line argument and assume it is a URI segment. + * + * @access private + * @return string + */ + private function _parse_cli_args() + { + $args = array_slice($_SERVER['argv'], 1); + + return $args ? '/' . implode('/', $args) : ''; } // -------------------------------------------------------------------- @@ -195,7 +261,7 @@ function _filter_uri($str) } // Convert programatic characters to entities - $bad = array('$', '(', ')', '%28', '%29'); + $bad = array('$', '(', ')', '%28', '%29'); $good = array('$', '(', ')', '(', ')'); return str_replace($bad, $good, $str); @@ -228,7 +294,7 @@ function _remove_url_suffix() */ function _explode_segments() { - foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val) + foreach (explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val) { // Filter segments for security $val = trim($this->_filter_uri($val)); @@ -321,15 +387,20 @@ function rsegment($n, $no_result = FALSE) */ function uri_to_assoc($n = 3, $default = array()) { - return $this->_uri_to_assoc($n, $default, 'segment'); + return $this->_uri_to_assoc($n, $default, 'segment'); } /** * Identical to above only it uses the re-routed segment array * + * @access public + * @param integer the starting segment number + * @param array an array of default values + * @return array + * */ function ruri_to_assoc($n = 3, $default = array()) { - return $this->_uri_to_assoc($n, $default, 'rsegment'); + return $this->_uri_to_assoc($n, $default, 'rsegment'); } // -------------------------------------------------------------------- @@ -482,21 +553,18 @@ function slash_rsegment($n, $where = 'trailing') */ function _slash_segment($n, $where = 'trailing', $which = 'segment') { + $leading = '/'; + $trailing = '/'; + if ($where == 'trailing') { - $trailing = '/'; $leading = ''; } elseif ($where == 'leading') { - $leading = '/'; $trailing = ''; } - else - { - $leading = '/'; - $trailing = '/'; - } + return $leading.$this->$which($n).$trailing; } @@ -576,11 +644,11 @@ function uri_string() */ function ruri_string() { - return '/'.implode('/', $this->rsegment_array()).'/'; + return '/'.implode('/', $this->rsegment_array()); } } // END URI Class /* End of file URI.php */ -/* Location: ./system/libraries/URI.php */ \ No newline at end of file +/* Location: ./system/core/URI.php */ \ No newline at end of file diff --git a/system/core/Utf8.php b/system/core/Utf8.php new file mode 100644 index 00000000..2a27d1f3 --- /dev/null +++ b/system/core/Utf8.php @@ -0,0 +1,165 @@ +item('charset') == 'UTF-8' // Application charset must be UTF-8 + ) + { + log_message('debug', "UTF-8 Support Enabled"); + + define('UTF8_ENABLED', TRUE); + + // set internal encoding for multibyte string functions if necessary + // and set a flag so we don't have to repeatedly use extension_loaded() + // or function_exists() + if (extension_loaded('mbstring')) + { + define('MB_ENABLED', TRUE); + mb_internal_encoding('UTF-8'); + } + else + { + define('MB_ENABLED', FALSE); + } + } + else + { + log_message('debug', "UTF-8 Support Disabled"); + define('UTF8_ENABLED', FALSE); + } + } + + // -------------------------------------------------------------------- + + /** + * Clean UTF-8 strings + * + * Ensures strings are UTF-8 + * + * @access public + * @param string + * @return string + */ + function clean_string($str) + { + if ($this->_is_ascii($str) === FALSE) + { + $str = @iconv('UTF-8', 'UTF-8//IGNORE', $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Remove ASCII control characters + * + * Removes all ASCII control characters except horizontal tabs, + * line feeds, and carriage returns, as all others can cause + * problems in XML + * + * @access public + * @param string + * @return string + */ + function safe_ascii_for_xml($str) + { + return remove_invisible_characters($str, FALSE); + } + + // -------------------------------------------------------------------- + + /** + * Convert to UTF-8 + * + * Attempts to convert a string to UTF-8 + * + * @access public + * @param string + * @param string - input encoding + * @return string + */ + function convert_to_utf8($str, $encoding) + { + if (function_exists('iconv')) + { + $str = @iconv($encoding, 'UTF-8', $str); + } + elseif (function_exists('mb_convert_encoding')) + { + $str = @mb_convert_encoding($str, 'UTF-8', $encoding); + } + else + { + return FALSE; + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Is ASCII? + * + * Tests if a string is standard 7-bit ASCII or not + * + * @access public + * @param string + * @return bool + */ + function _is_ascii($str) + { + return (preg_match('/[^\x00-\x7F]/S', $str) == 0); + } + + // -------------------------------------------------------------------- + +} +// End Utf8 Class + +/* End of file Utf8.php */ +/* Location: ./system/core/Utf8.php */ \ No newline at end of file diff --git a/system/cache/index.html b/system/core/index.html similarity index 100% rename from system/cache/index.html rename to system/core/index.html diff --git a/system/database/DB.php b/system/database/DB.php old mode 100644 new mode 100755 index 0f734d74..8314d3b9 --- a/system/database/DB.php +++ b/system/database/DB.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -21,46 +21,57 @@ * @category Database * @author ExpressionEngine Dev Team * @link http://codeigniter.com/user_guide/database/ + * @param string + * @param bool Determines if active record should be used or not */ -function &DB($params = '', $active_record_override = FALSE) +function &DB($params = '', $active_record_override = NULL) { // Load the DB config file if a DSN string wasn't passed if (is_string($params) AND strpos($params, '://') === FALSE) { - include(APPPATH.'config/database'.EXT); - + // Is the config file in the environment folder? + if ( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/database.php')) + { + if ( ! file_exists($file_path = APPPATH.'config/database.php')) + { + show_error('The configuration file database.php does not exist.'); + } + } + + include($file_path); + if ( ! isset($db) OR count($db) == 0) { show_error('No database connection settings were found in the database config file.'); } - + if ($params != '') { $active_group = $params; } - + if ( ! isset($active_group) OR ! isset($db[$active_group])) { show_error('You have specified an invalid database connection group.'); } - + $params = $db[$active_group]; } elseif (is_string($params)) { - + /* parse the URL from the DSN string - * Database settings can be passed as discreet - * parameters or as a data source name in the first - * parameter. DSNs must have this prototype: - * $dsn = 'driver://username:password@hostname/database'; - */ - + * Database settings can be passed as discreet + * parameters or as a data source name in the first + * parameter. DSNs must have this prototype: + * $dsn = 'driver://username:password@hostname/database'; + */ + if (($dns = @parse_url($params)) === FALSE) { show_error('Invalid DB Connection String'); } - + $params = array( 'dbdriver' => $dns['scheme'], 'hostname' => (isset($dns['host'])) ? rawurldecode($dns['host']) : '', @@ -68,13 +79,13 @@ function &DB($params = '', $active_record_override = FALSE) 'password' => (isset($dns['pass'])) ? rawurldecode($dns['pass']) : '', 'database' => (isset($dns['path'])) ? rawurldecode(substr($dns['path'], 1)) : '' ); - + // were additional config items set? if (isset($dns['query'])) { parse_str($dns['query'], $extra); - foreach($extra as $key => $val) + foreach ($extra as $key => $val) { // booleans please if (strtoupper($val) == "TRUE") @@ -90,7 +101,7 @@ function &DB($params = '', $active_record_override = FALSE) } } } - + // No DB specified yet? Beat them senseless... if ( ! isset($params['dbdriver']) OR $params['dbdriver'] == '') { @@ -101,18 +112,18 @@ function &DB($params = '', $active_record_override = FALSE) // we need to dynamically create a class that extends proper parent class // based on whether we're using the active record class or not. // Kudos to Paul for discovering this clever use of eval() - - if ($active_record_override == TRUE) + + if ($active_record_override !== NULL) { - $active_record = TRUE; + $active_record = $active_record_override; } - - require_once(BASEPATH.'database/DB_driver'.EXT); + + require_once(BASEPATH.'database/DB_driver.php'); if ( ! isset($active_record) OR $active_record == TRUE) { - require_once(BASEPATH.'database/DB_active_rec'.EXT); - + require_once(BASEPATH.'database/DB_active_rec.php'); + if ( ! class_exists('CI_DB')) { eval('class CI_DB extends CI_DB_active_record { }'); @@ -125,20 +136,25 @@ function &DB($params = '', $active_record_override = FALSE) eval('class CI_DB extends CI_DB_driver { }'); } } - - require_once(BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver'.EXT); + + require_once(BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php'); // Instantiate the DB adapter $driver = 'CI_DB_'.$params['dbdriver'].'_driver'; - $DB =& instantiate_class(new $driver($params)); - + $DB = new $driver($params); + if ($DB->autoinit == TRUE) { $DB->initialize(); } - + + if (isset($params['stricton']) && $params['stricton'] == TRUE) + { + $DB->query('SET SESSION sql_mode="STRICT_ALL_TABLES"'); + } + return $DB; -} +} diff --git a/system/database/DB_active_rec.php b/system/database/DB_active_rec.php index 07021999..129eaa7b 100644 --- a/system/database/DB_active_rec.php +++ b/system/database/DB_active_rec.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -36,17 +36,18 @@ class CI_DB_active_record extends CI_DB_driver { var $ar_like = array(); var $ar_groupby = array(); var $ar_having = array(); + var $ar_keys = array(); var $ar_limit = FALSE; var $ar_offset = FALSE; var $ar_order = FALSE; var $ar_orderby = array(); - var $ar_set = array(); + var $ar_set = array(); var $ar_wherein = array(); var $ar_aliased_tables = array(); var $ar_store_array = array(); - + // Active Record Caching variables - var $ar_caching = FALSE; + var $ar_caching = FALSE; var $ar_cache_exists = array(); var $ar_cache_select = array(); var $ar_cache_from = array(); @@ -56,8 +57,10 @@ class CI_DB_active_record extends CI_DB_driver { var $ar_cache_groupby = array(); var $ar_cache_having = array(); var $ar_cache_orderby = array(); - var $ar_cache_set = array(); - + var $ar_cache_set = array(); + + var $ar_no_escape = array(); + var $ar_cache_no_escape = array(); // -------------------------------------------------------------------- @@ -66,18 +69,11 @@ class CI_DB_active_record extends CI_DB_driver { * * Generates the SELECT portion of the query * - * @access public * @param string * @return object */ - function select($select = '*', $escape = NULL) + public function select($select = '*', $escape = NULL) { - // Set the global value if this was sepecified - if (is_bool($escape)) - { - $this->_protect_identifiers = $escape; - } - if (is_string($select)) { $select = explode(',', $select); @@ -90,11 +86,13 @@ function select($select = '*', $escape = NULL) if ($val != '') { $this->ar_select[] = $val; + $this->ar_no_escape[] = $escape; if ($this->ar_caching === TRUE) { $this->ar_cache_select[] = $val; $this->ar_cache_exists[] = 'select'; + $this->ar_cache_no_escape[] = $escape; } } } @@ -108,16 +106,15 @@ function select($select = '*', $escape = NULL) * * Generates a SELECT MAX(field) portion of a query * - * @access public * @param string the field * @param string an alias * @return object */ - function select_max($select = '', $alias = '') + public function select_max($select = '', $alias = '') { return $this->_max_min_avg_sum($select, $alias, 'MAX'); } - + // -------------------------------------------------------------------- /** @@ -125,12 +122,11 @@ function select_max($select = '', $alias = '') * * Generates a SELECT MIN(field) portion of a query * - * @access public * @param string the field * @param string an alias * @return object */ - function select_min($select = '', $alias = '') + public function select_min($select = '', $alias = '') { return $this->_max_min_avg_sum($select, $alias, 'MIN'); } @@ -142,12 +138,11 @@ function select_min($select = '', $alias = '') * * Generates a SELECT AVG(field) portion of a query * - * @access public * @param string the field * @param string an alias * @return object */ - function select_avg($select = '', $alias = '') + public function select_avg($select = '', $alias = '') { return $this->_max_min_avg_sum($select, $alias, 'AVG'); } @@ -159,12 +154,11 @@ function select_avg($select = '', $alias = '') * * Generates a SELECT SUM(field) portion of a query * - * @access public * @param string the field * @param string an alias * @return object */ - function select_sum($select = '', $alias = '') + public function select_sum($select = '', $alias = '') { return $this->_max_min_avg_sum($select, $alias, 'SUM'); } @@ -178,41 +172,40 @@ function select_sum($select = '', $alias = '') * select_min() * select_avg() * select_sum() - * - * @access public + * * @param string the field * @param string an alias * @return object */ - function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX') + protected function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX') { if ( ! is_string($select) OR $select == '') { $this->display_error('db_invalid_query'); } - + $type = strtoupper($type); - + if ( ! in_array($type, array('MAX', 'MIN', 'AVG', 'SUM'))) { show_error('Invalid function type: '.$type); } - + if ($alias == '') { $alias = $this->_create_alias_from_table(trim($select)); } - + $sql = $type.'('.$this->_protect_identifiers(trim($select)).') AS '.$alias; $this->ar_select[] = $sql; - + if ($this->ar_caching === TRUE) { $this->ar_cache_select[] = $sql; $this->ar_cache_exists[] = 'select'; } - + return $this; } @@ -221,17 +214,16 @@ function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX') /** * Determines the alias name based on the table * - * @access private * @param string * @return string */ - function _create_alias_from_table($item) + protected function _create_alias_from_table($item) { if (strpos($item, '.') !== FALSE) { return end(explode('.', $item)); } - + return $item; } @@ -242,16 +234,15 @@ function _create_alias_from_table($item) * * Sets a flag which tells the query string compiler to add DISTINCT * - * @access public * @param bool * @return object */ - function distinct($val = TRUE) + public function distinct($val = TRUE) { $this->ar_distinct = (is_bool($val)) ? $val : TRUE; return $this; } - + // -------------------------------------------------------------------- /** @@ -259,13 +250,12 @@ function distinct($val = TRUE) * * Generates the FROM portion of the query * - * @access public * @param mixed can be a string or array * @return object */ - function from($from) + public function from($from) { - foreach ((array)$from as $val) + foreach ((array) $from as $val) { if (strpos($val, ',') !== FALSE) { @@ -275,12 +265,12 @@ function from($from) $this->_track_aliases($v); $this->ar_from[] = $this->_protect_identifiers($v, TRUE, NULL, FALSE); - + if ($this->ar_caching === TRUE) { $this->ar_cache_from[] = $this->_protect_identifiers($v, TRUE, NULL, FALSE); $this->ar_cache_exists[] = 'from'; - } + } } } @@ -289,11 +279,11 @@ function from($from) $val = trim($val); // Extract any aliases that might exist. We use this information - // in the _protect_identifiers to know whether to add a table prefix + // in the _protect_identifiers to know whether to add a table prefix $this->_track_aliases($val); - + $this->ar_from[] = $this->_protect_identifiers($val, TRUE, NULL, FALSE); - + if ($this->ar_caching === TRUE) { $this->ar_cache_from[] = $this->_protect_identifiers($val, TRUE, NULL, FALSE); @@ -312,14 +302,13 @@ function from($from) * * Generates the JOIN portion of the query * - * @access public * @param string * @param string the join condition * @param string the type of join * @return object */ - function join($table, $cond, $type = '') - { + public function join($table, $cond, $type = '') + { if ($type != '') { $type = strtoupper(trim($type)); @@ -335,7 +324,7 @@ function join($table, $cond, $type = '') } // Extract any aliases that might exist. We use this information - // in the _protect_identifiers to know whether to add a table prefix + // in the _protect_identifiers to know whether to add a table prefix $this->_track_aliases($table); // Strip apart the condition and protect the identifiers @@ -343,10 +332,10 @@ function join($table, $cond, $type = '') { $match[1] = $this->_protect_identifiers($match[1]); $match[3] = $this->_protect_identifiers($match[3]); - - $cond = $match[1].$match[2].$match[3]; + + $cond = $match[1].$match[2].$match[3]; } - + // Assemble the JOIN statement $join = $type.'JOIN '.$this->_protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond; @@ -368,16 +357,15 @@ function join($table, $cond, $type = '') * Generates the WHERE portion of the query. Separates * multiple calls with AND * - * @access public * @param mixed * @param mixed * @return object */ - function where($key, $value = NULL, $escape = TRUE) + public function where($key, $value = NULL, $escape = TRUE) { return $this->_where($key, $value, 'AND ', $escape); } - + // -------------------------------------------------------------------- /** @@ -386,48 +374,34 @@ function where($key, $value = NULL, $escape = TRUE) * Generates the WHERE portion of the query. Separates * multiple calls with OR * - * @access public * @param mixed * @param mixed * @return object */ - function or_where($key, $value = NULL, $escape = TRUE) + public function or_where($key, $value = NULL, $escape = TRUE) { return $this->_where($key, $value, 'OR ', $escape); } // -------------------------------------------------------------------- - /** - * orwhere() is an alias of or_where() - * this function is here for backwards compatibility, as - * orwhere() has been deprecated - */ - function orwhere($key, $value = NULL, $escape = TRUE) - { - return $this->or_where($key, $value, $escape); - } - - // -------------------------------------------------------------------- - /** * Where * - * Called by where() or orwhere() + * Called by where() or or_where() * - * @access private * @param mixed * @param mixed * @param string * @return object */ - function _where($key, $value = NULL, $type = 'AND ', $escape = NULL) + protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL) { if ( ! is_array($key)) { $key = array($key => $value); } - + // If the escape value was not set will will base it on the global setting if ( ! is_bool($escape)) { @@ -443,36 +417,36 @@ function _where($key, $value = NULL, $type = 'AND ', $escape = NULL) // value appears not to have been set, assign the test to IS NULL $k .= ' IS NULL'; } - + if ( ! is_null($v)) { if ($escape === TRUE) { $k = $this->_protect_identifiers($k, FALSE, $escape); - + $v = ' '.$this->escape($v); } - + if ( ! $this->_has_operator($k)) { - $k .= ' ='; + $k .= ' = '; } } else { - $k = $this->_protect_identifiers($k, FALSE, $escape); + $k = $this->_protect_identifiers($k, FALSE, $escape); } $this->ar_where[] = $prefix.$k.$v; - + if ($this->ar_caching === TRUE) { $this->ar_cache_where[] = $prefix.$k.$v; $this->ar_cache_exists[] = 'where'; } - + } - + return $this; } @@ -484,16 +458,15 @@ function _where($key, $value = NULL, $type = 'AND ', $escape = NULL) * Generates a WHERE field IN ('item', 'item') SQL query joined with * AND if appropriate * - * @access public * @param string The field to search * @param array The values searched on * @return object */ - function where_in($key = NULL, $values = NULL) + public function where_in($key = NULL, $values = NULL) { return $this->_where_in($key, $values); } - + // -------------------------------------------------------------------- /** @@ -502,12 +475,11 @@ function where_in($key = NULL, $values = NULL) * Generates a WHERE field IN ('item', 'item') SQL query joined with * OR if appropriate * - * @access public * @param string The field to search * @param array The values searched on * @return object */ - function or_where_in($key = NULL, $values = NULL) + public function or_where_in($key = NULL, $values = NULL) { return $this->_where_in($key, $values, FALSE, 'OR '); } @@ -520,16 +492,15 @@ function or_where_in($key = NULL, $values = NULL) * Generates a WHERE field NOT IN ('item', 'item') SQL query joined * with AND if appropriate * - * @access public * @param string The field to search * @param array The values searched on * @return object */ - function where_not_in($key = NULL, $values = NULL) + public function where_not_in($key = NULL, $values = NULL) { return $this->_where_in($key, $values, TRUE); } - + // -------------------------------------------------------------------- /** @@ -538,12 +509,11 @@ function where_not_in($key = NULL, $values = NULL) * Generates a WHERE field NOT IN ('item', 'item') SQL query joined * with OR if appropriate * - * @access public * @param string The field to search * @param array The values searched on * @return object */ - function or_where_not_in($key = NULL, $values = NULL) + public function or_where_not_in($key = NULL, $values = NULL) { return $this->_where_in($key, $values, TRUE, 'OR '); } @@ -555,25 +525,24 @@ function or_where_not_in($key = NULL, $values = NULL) * * Called by where_in, where_in_or, where_not_in, where_not_in_or * - * @access public * @param string The field to search * @param array The values searched on * @param boolean If the statement would be IN or NOT IN - * @param string + * @param string * @return object */ - function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ') + protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ') { if ($key === NULL OR $values === NULL) { return; } - + if ( ! is_array($values)) { $values = array($values); } - + $not = ($not) ? ' NOT' : ''; foreach ($values as $value) @@ -582,7 +551,7 @@ function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ') } $prefix = (count($this->ar_where) == 0) ? '' : $type; - + $where_in = $prefix . $this->_protect_identifiers($key) . $not . " IN (" . implode(", ", $this->ar_wherein) . ") "; $this->ar_where[] = $where_in; @@ -596,7 +565,7 @@ function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ') $this->ar_wherein = array(); return $this; } - + // -------------------------------------------------------------------- /** @@ -605,12 +574,11 @@ function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ') * Generates a %LIKE% portion of the query. Separates * multiple calls with AND * - * @access public * @param mixed * @param mixed * @return object */ - function like($field, $match = '', $side = 'both') + public function like($field, $match = '', $side = 'both') { return $this->_like($field, $match, 'AND ', $side); } @@ -623,16 +591,15 @@ function like($field, $match = '', $side = 'both') * Generates a NOT LIKE portion of the query. Separates * multiple calls with AND * - * @access public * @param mixed * @param mixed * @return object */ - function not_like($field, $match = '', $side = 'both') + public function not_like($field, $match = '', $side = 'both') { return $this->_like($field, $match, 'AND ', $side, 'NOT'); } - + // -------------------------------------------------------------------- /** @@ -641,12 +608,11 @@ function not_like($field, $match = '', $side = 'both') * Generates a %LIKE% portion of the query. Separates * multiple calls with OR * - * @access public * @param mixed * @param mixed * @return object */ - function or_like($field, $match = '', $side = 'both') + public function or_like($field, $match = '', $side = 'both') { return $this->_like($field, $match, 'OR ', $side); } @@ -659,28 +625,15 @@ function or_like($field, $match = '', $side = 'both') * Generates a NOT LIKE portion of the query. Separates * multiple calls with OR * - * @access public * @param mixed * @param mixed * @return object */ - function or_not_like($field, $match = '', $side = 'both') + public function or_not_like($field, $match = '', $side = 'both') { return $this->_like($field, $match, 'OR ', $side, 'NOT'); } - - // -------------------------------------------------------------------- - /** - * orlike() is an alias of or_like() - * this function is here for backwards compatibility, as - * orlike() has been deprecated - */ - function orlike($field, $match = '', $side = 'both') - { - return $this->or_like($field, $match, $side); - } - // -------------------------------------------------------------------- /** @@ -688,19 +641,18 @@ function orlike($field, $match = '', $side = 'both') * * Called by like() or orlike() * - * @access private * @param mixed * @param mixed * @param string * @return object */ - function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '') + protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '') { if ( ! is_array($field)) { $field = array($field => $match); } - + foreach ($field as $k => $v) { $k = $this->_protect_identifiers($k); @@ -708,8 +660,12 @@ function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '') $prefix = (count($this->ar_like) == 0) ? '' : $type; $v = $this->escape_like_str($v); - - if ($side == 'before') + + if ($side == 'none') + { + $like_statement = $prefix." $k $not LIKE '{$v}'"; + } + elseif ($side == 'before') { $like_statement = $prefix." $k $not LIKE '%{$v}'"; } @@ -721,48 +677,47 @@ function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '') { $like_statement = $prefix." $k $not LIKE '%{$v}%'"; } - + // some platforms require an escape sequence definition for LIKE wildcards if ($this->_like_escape_str != '') { - $like_statement = $like_statement.sprintf($this->_like_escape_str, $this->_like_escape_char); + $like_statement = $like_statement.sprintf($this->_like_escape_str, $this->_like_escape_chr); } - + $this->ar_like[] = $like_statement; if ($this->ar_caching === TRUE) { $this->ar_cache_like[] = $like_statement; $this->ar_cache_exists[] = 'like'; } - + } return $this; } - + // -------------------------------------------------------------------- /** * GROUP BY * - * @access public * @param string * @return object */ - function group_by($by) + public function group_by($by) { if (is_string($by)) { $by = explode(',', $by); } - + foreach ($by as $val) { $val = trim($val); - + if ($val != '') { $this->ar_groupby[] = $this->_protect_identifiers($val); - + if ($this->ar_caching === TRUE) { $this->ar_cache_groupby[] = $this->_protect_identifiers($val); @@ -775,62 +730,36 @@ function group_by($by) // -------------------------------------------------------------------- - /** - * groupby() is an alias of group_by() - * this function is here for backwards compatibility, as - * groupby() has been deprecated - */ - function groupby($by) - { - return $this->group_by($by); - } - - // -------------------------------------------------------------------- - /** * Sets the HAVING value * * Separates multiple calls with AND * - * @access public * @param string * @param string * @return object */ - function having($key, $value = '', $escape = TRUE) + public function having($key, $value = '', $escape = TRUE) { return $this->_having($key, $value, 'AND ', $escape); } // -------------------------------------------------------------------- - /** - * orhaving() is an alias of or_having() - * this function is here for backwards compatibility, as - * orhaving() has been deprecated - */ - - function orhaving($key, $value = '', $escape = TRUE) - { - return $this->or_having($key, $value, $escape); - } - // -------------------------------------------------------------------- - /** * Sets the OR HAVING value * * Separates multiple calls with OR * - * @access public * @param string * @param string * @return object */ - function or_having($key, $value = '', $escape = TRUE) + public function or_having($key, $value = '', $escape = TRUE) { return $this->_having($key, $value, 'OR ', $escape); } - + // -------------------------------------------------------------------- /** @@ -838,18 +767,17 @@ function or_having($key, $value = '', $escape = TRUE) * * Called by having() or or_having() * - * @access private * @param string * @param string * @return object */ - function _having($key, $value = '', $type = 'AND ', $escape = TRUE) + protected function _having($key, $value = '', $type = 'AND ', $escape = TRUE) { if ( ! is_array($key)) { $key = array($key => $value); } - + foreach ($key as $k => $v) { $prefix = (count($this->ar_having) == 0) ? '' : $type; @@ -866,9 +794,9 @@ function _having($key, $value = '', $type = 'AND ', $escape = TRUE) if ($v != '') { - $v = ' '.$this->escape_str($v); + $v = ' '.$this->escape($v); } - + $this->ar_having[] = $prefix.$k.$v; if ($this->ar_caching === TRUE) { @@ -876,21 +804,20 @@ function _having($key, $value = '', $type = 'AND ', $escape = TRUE) $this->ar_cache_exists[] = 'having'; } } - + return $this; } - + // -------------------------------------------------------------------- /** * Sets the ORDER BY value * - * @access public * @param string * @param string direction: asc or desc * @return object */ - function order_by($orderby, $direction = '') + public function order_by($orderby, $direction = '') { if (strtolower($direction) == 'random') { @@ -901,8 +828,8 @@ function order_by($orderby, $direction = '') { $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC'; } - - + + if (strpos($orderby, ',') !== FALSE) { $temp = array(); @@ -913,19 +840,19 @@ function order_by($orderby, $direction = '') { $part = $this->_protect_identifiers(trim($part)); } - + $temp[] = $part; } - - $orderby = implode(', ', $temp); + + $orderby = implode(', ', $temp); } else if ($direction != $this->_random_keyword) { $orderby = $this->_protect_identifiers($orderby); } - + $orderby_statement = $orderby.$direction; - + $this->ar_orderby[] = $orderby_statement; if ($this->ar_caching === TRUE) { @@ -935,75 +862,60 @@ function order_by($orderby, $direction = '') return $this; } - - // -------------------------------------------------------------------- - /** - * orderby() is an alias of order_by() - * this function is here for backwards compatibility, as - * orderby() has been deprecated - */ - function orderby($orderby, $direction = '') - { - return $this->order_by($orderby, $direction); - } - // -------------------------------------------------------------------- /** * Sets the LIMIT value * - * @access public * @param integer the limit value * @param integer the offset value * @return object */ - function limit($value, $offset = '') + public function limit($value, $offset = '') { - $this->ar_limit = $value; + $this->ar_limit = (int) $value; if ($offset != '') { - $this->ar_offset = $offset; + $this->ar_offset = (int) $offset; } - + return $this; } - + // -------------------------------------------------------------------- /** * Sets the OFFSET value * - * @access public * @param integer the offset value * @return object */ - function offset($offset) + public function offset($offset) { $this->ar_offset = $offset; return $this; } - + // -------------------------------------------------------------------- /** * The "set" function. Allows key/value pairs to be set for inserting or updating * - * @access public * @param mixed * @param string * @param boolean * @return object */ - function set($key, $value = '', $escape = TRUE) + public function set($key, $value = '', $escape = TRUE) { $key = $this->_object_to_array($key); - + if ( ! is_array($key)) { $key = array($key => $value); - } + } foreach ($key as $k => $v) { @@ -1013,13 +925,13 @@ function set($key, $value = '', $escape = TRUE) } else { - $this->ar_set[$this->_protect_identifiers($k)] = $this->escape($v); + $this->ar_set[$this->_protect_identifiers($k, FALSE, TRUE)] = $this->escape($v); } } - + return $this; } - + // -------------------------------------------------------------------- /** @@ -1028,25 +940,24 @@ function set($key, $value = '', $escape = TRUE) * Compiles the select statement based on the other functions called * and runs the query * - * @access public * @param string the table * @param string the limit clause * @param string the offset clause * @return object */ - function get($table = '', $limit = null, $offset = null) + public function get($table = '', $limit = null, $offset = null) { if ($table != '') { $this->_track_aliases($table); $this->from($table); } - + if ( ! is_null($limit)) { $this->limit($limit, $offset); } - + $sql = $this->_compile_select(); $result = $this->query($sql); @@ -1057,33 +968,32 @@ function get($table = '', $limit = null, $offset = null) /** * "Count All Results" query * - * Generates a platform-specific query string that counts all records + * Generates a platform-specific query string that counts all records * returned by an Active Record query. * - * @access public * @param string * @return string */ - function count_all_results($table = '') + public function count_all_results($table = '') { if ($table != '') { $this->_track_aliases($table); $this->from($table); } - + $sql = $this->_compile_select($this->_count_string . $this->_protect_identifiers('numrows')); $query = $this->query($sql); $this->_reset_select(); - + if ($query->num_rows() == 0) { - return '0'; + return 0; } $row = $query->row(); - return $row->numrows; + return (int) $row->numrows; } // -------------------------------------------------------------------- @@ -1093,13 +1003,12 @@ function count_all_results($table = '') * * Allows the where clause, limit and offset to be added directly * - * @access public * @param string the where clause * @param string the limit clause * @param string the offset clause * @return object */ - function get_where($table = '', $where = null, $limit = null, $offset = null) + public function get_where($table = '', $where = null, $limit = null, $offset = null) { if ($table != '') { @@ -1110,12 +1019,12 @@ function get_where($table = '', $where = null, $limit = null, $offset = null) { $this->where($where); } - + if ( ! is_null($limit)) { $this->limit($limit, $offset); } - + $sql = $this->_compile_select(); $result = $this->query($sql); @@ -1126,38 +1035,26 @@ function get_where($table = '', $where = null, $limit = null, $offset = null) // -------------------------------------------------------------------- /** - * getwhere() is an alias of get_where() - * this function is here for backwards compatibility, as - * getwhere() has been deprecated - */ - function getwhere($table = '', $where = null, $limit = null, $offset = null) - { - return $this->get_where($table, $where, $limit, $offset); - } - - // -------------------------------------------------------------------- - - /** - * Insert + * Insert_Batch * - * Compiles an insert string and runs the query + * Compiles batch insert strings and runs the queries * - * @access public * @param string the table to retrieve the results from * @param array an associative array of insert values * @return object */ - function insert($table = '', $set = NULL) - { + public function insert_batch($table = '', $set = NULL) + { if ( ! is_null($set)) { - $this->set($set); + $this->set_insert_batch($set); } - + if (count($this->ar_set) == 0) { if ($this->db_debug) { + //No valid data array. Folds in cases where keys and values did not match up return $this->display_error('db_must_use_set'); } return FALSE; @@ -1173,39 +1070,103 @@ function insert($table = '', $set = NULL) } return FALSE; } - + $table = $this->ar_from[0]; } - $sql = $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set), array_values($this->ar_set)); - + // Batch this baby + for ($i = 0, $total = count($this->ar_set); $i < $total; $i = $i + 100) + { + + $sql = $this->_insert_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_keys, array_slice($this->ar_set, $i, 100)); + + //echo $sql; + + $this->query($sql); + } + $this->_reset_write(); - return $this->query($sql); + + + return TRUE; } - + // -------------------------------------------------------------------- /** - * Update - * - * Compiles an update string and runs the query + * The "set_insert_batch" function. Allows key/value pairs to be set for batch inserts * - * @access public - * @param string the table to retrieve the results from - * @param array an associative array of update values - * @param mixed the where clause + * @param mixed + * @param string + * @param boolean * @return object */ - function update($table = '', $set = NULL, $where = NULL, $limit = NULL) + public function set_insert_batch($key, $value = '', $escape = TRUE) { - // Combine any cached components with the current statements - $this->_merge_cache(); + $key = $this->_object_to_array_batch($key); + + if ( ! is_array($key)) + { + $key = array($key => $value); + } + + $keys = array_keys(current($key)); + sort($keys); + + foreach ($key as $row) + { + if (count(array_diff($keys, array_keys($row))) > 0 OR count(array_diff(array_keys($row), $keys)) > 0) + { + // batch function above returns an error on an empty array + $this->ar_set[] = array(); + return; + } + + ksort($row); // puts $row in the same order as our keys + if ($escape === FALSE) + { + $this->ar_set[] = '('.implode(',', $row).')'; + } + else + { + $clean = array(); + + foreach ($row as $value) + { + $clean[] = $this->escape($value); + } + + $this->ar_set[] = '('.implode(',', $clean).')'; + } + } + + foreach ($keys as $k) + { + $this->ar_keys[] = $this->_protect_identifiers($k); + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Insert + * + * Compiles an insert string and runs the query + * + * @param string the table to insert data into + * @param array an associative array of insert values + * @return object + */ + function insert($table = '', $set = NULL) + { if ( ! is_null($set)) { $this->set($set); } - + if (count($this->ar_set) == 0) { if ($this->db_debug) @@ -1225,10 +1186,108 @@ function update($table = '', $set = NULL, $where = NULL, $limit = NULL) } return FALSE; } - + + $table = $this->ar_from[0]; + } + + $sql = $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set), array_values($this->ar_set)); + + $this->_reset_write(); + return $this->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Replace + * + * Compiles an replace into string and runs the query + * + * @param string the table to replace data into + * @param array an associative array of insert values + * @return object + */ + public function replace($table = '', $set = NULL) + { + if ( ! is_null($set)) + { + $this->set($set); + } + + if (count($this->ar_set) == 0) + { + if ($this->db_debug) + { + return $this->display_error('db_must_use_set'); + } + return FALSE; + } + + if ($table == '') + { + if ( ! isset($this->ar_from[0])) + { + if ($this->db_debug) + { + return $this->display_error('db_must_set_table'); + } + return FALSE; + } + $table = $this->ar_from[0]; } - + + $sql = $this->_replace($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set), array_values($this->ar_set)); + + $this->_reset_write(); + return $this->query($sql); + } + + // -------------------------------------------------------------------- + + /** + * Update + * + * Compiles an update string and runs the query + * + * @param string the table to retrieve the results from + * @param array an associative array of update values + * @param mixed the where clause + * @return object + */ + public function update($table = '', $set = NULL, $where = NULL, $limit = NULL) + { + // Combine any cached components with the current statements + $this->_merge_cache(); + + if ( ! is_null($set)) + { + $this->set($set); + } + + if (count($this->ar_set) == 0) + { + if ($this->db_debug) + { + return $this->display_error('db_must_use_set'); + } + return FALSE; + } + + if ($table == '') + { + if ( ! isset($this->ar_from[0])) + { + if ($this->db_debug) + { + return $this->display_error('db_must_set_table'); + } + return FALSE; + } + + $table = $this->ar_from[0]; + } + if ($where != NULL) { $this->where($where); @@ -1238,13 +1297,137 @@ function update($table = '', $set = NULL, $where = NULL, $limit = NULL) { $this->limit($limit); } - + $sql = $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit); - + $this->_reset_write(); return $this->query($sql); } + + // -------------------------------------------------------------------- + + /** + * Update_Batch + * + * Compiles an update string and runs the query + * + * @param string the table to retrieve the results from + * @param array an associative array of update values + * @param string the where key + * @return object + */ + public function update_batch($table = '', $set = NULL, $index = NULL) + { + // Combine any cached components with the current statements + $this->_merge_cache(); + + if (is_null($index)) + { + if ($this->db_debug) + { + return $this->display_error('db_must_use_index'); + } + + return FALSE; + } + + if ( ! is_null($set)) + { + $this->set_update_batch($set, $index); + } + + if (count($this->ar_set) == 0) + { + if ($this->db_debug) + { + return $this->display_error('db_must_use_set'); + } + + return FALSE; + } + + if ($table == '') + { + if ( ! isset($this->ar_from[0])) + { + if ($this->db_debug) + { + return $this->display_error('db_must_set_table'); + } + return FALSE; + } + + $table = $this->ar_from[0]; + } + + // Batch this baby + for ($i = 0, $total = count($this->ar_set); $i < $total; $i = $i + 100) + { + $sql = $this->_update_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->ar_set, $i, 100), $this->_protect_identifiers($index), $this->ar_where); + + $this->query($sql); + } + + $this->_reset_write(); + } + + // -------------------------------------------------------------------- + + /** + * The "set_update_batch" function. Allows key/value pairs to be set for batch updating + * + * @param array + * @param string + * @param boolean + * @return object + */ + public function set_update_batch($key, $index = '', $escape = TRUE) + { + $key = $this->_object_to_array_batch($key); + + if ( ! is_array($key)) + { + // @todo error + } + + foreach ($key as $k => $v) + { + $index_set = FALSE; + $clean = array(); + + foreach ($v as $k2 => $v2) + { + if ($k2 == $index) + { + $index_set = TRUE; + } + else + { + $not[] = $k2.'-'.$v2; + } + + if ($escape === FALSE) + { + $clean[$this->_protect_identifiers($k2)] = $v2; + } + else + { + $clean[$this->_protect_identifiers($k2)] = $this->escape($v2); + } + } + + if ($index_set == FALSE) + { + return $this->display_error('db_batch_missing_index'); + } + + $this->ar_set[] = $clean; + } + + return $this; + } + // -------------------------------------------------------------------- /** @@ -1252,11 +1435,10 @@ function update($table = '', $set = NULL, $where = NULL, $limit = NULL) * * Compiles a delete string and runs "DELETE FROM table" * - * @access public * @param string the table to empty * @return object */ - function empty_table($table = '') + public function empty_table($table = '') { if ($table == '') { @@ -1279,7 +1461,7 @@ function empty_table($table = '') $sql = $this->_delete($table); $this->_reset_write(); - + return $this->query($sql); } @@ -1292,11 +1474,10 @@ function empty_table($table = '') * If the database does not support the truncate() command * This function maps to "DELETE FROM table" * - * @access public * @param string the table to truncate * @return object */ - function truncate($table = '') + public function truncate($table = '') { if ($table == '') { @@ -1319,10 +1500,10 @@ function truncate($table = '') $sql = $this->_truncate($table); $this->_reset_write(); - + return $this->query($sql); } - + // -------------------------------------------------------------------- /** @@ -1330,14 +1511,13 @@ function truncate($table = '') * * Compiles a delete string and runs the query * - * @access public * @param mixed the table(s) to delete from. String or array * @param mixed the where clause * @param mixed the limit clause * @param boolean * @return object */ - function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE) + public function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE) { // Combine any cached components with the current statements $this->_merge_cache(); @@ -1357,7 +1537,7 @@ function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE) } elseif (is_array($table)) { - foreach($table as $single_table) + foreach ($table as $single_table) { $this->delete($single_table, $where, $limit, FALSE); } @@ -1388,7 +1568,7 @@ function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE) } return FALSE; - } + } $sql = $this->_delete($table, $this->ar_where, $this->ar_like, $this->ar_limit); @@ -1396,7 +1576,7 @@ function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE) { $this->_reset_write(); } - + return $this->query($sql); } @@ -1407,11 +1587,10 @@ function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE) * * Prepends a database prefix if one exists in configuration * - * @access public * @param string the table * @return string */ - function dbprefix($table = '') + public function dbprefix($table = '') { if ($table == '') { @@ -1423,16 +1602,30 @@ function dbprefix($table = '') // -------------------------------------------------------------------- + /** + * Set DB Prefix + * + * Set's the DB Prefix to something new without needing to reconnect + * + * @param string the prefix + * @return string + */ + public function set_dbprefix($prefix = '') + { + return $this->dbprefix = $prefix; + } + + // -------------------------------------------------------------------- + /** * Track Aliases * * Used to track SQL statements written with aliased tables. * - * @access private * @param string The table to inspect * @return string - */ - function _track_aliases($table) + */ + protected function _track_aliases($table) { if (is_array($table)) { @@ -1442,23 +1635,23 @@ function _track_aliases($table) } return; } - + // Does the string contain a comma? If so, we need to separate // the string into discreet statements if (strpos($table, ',') !== FALSE) { return $this->_track_aliases(explode(',', $table)); } - + // if a table alias is used we can recognize it by a space if (strpos($table, " ") !== FALSE) { // if the alias is written with the AS keyword, remove it - $table = preg_replace('/ AS /i', ' ', $table); - + $table = preg_replace('/\s+AS\s+/i', ' ', $table); + // Grab the alias $table = trim(strrchr($table, " ")); - + // Store the alias, if it doesn't already exist if ( ! in_array($table, $this->ar_aliased_tables)) { @@ -1475,16 +1668,15 @@ function _track_aliases($table) * Generates a query string based on which functions were used. * Should not be called directly. The get() function calls it. * - * @access private * @return string */ - function _compile_select($select_override = FALSE) + protected function _compile_select($select_override = FALSE) { // Combine any cached components with the current statements $this->_merge_cache(); // ---------------------------------------------------------------- - + // Write the "select" portion of the query if ($select_override !== FALSE) @@ -1494,27 +1686,28 @@ function _compile_select($select_override = FALSE) else { $sql = ( ! $this->ar_distinct) ? 'SELECT ' : 'SELECT DISTINCT '; - + if (count($this->ar_select) == 0) { - $sql .= '*'; + $sql .= '*'; } else - { + { // Cycle through the "select" portion of the query and prep each column name. // The reason we protect identifiers here rather then in the select() function // is because until the user calls the from() function we don't know if there are aliases foreach ($this->ar_select as $key => $val) { - $this->ar_select[$key] = $this->_protect_identifiers($val); + $no_escape = isset($this->ar_no_escape[$key]) ? $this->ar_no_escape[$key] : NULL; + $this->ar_select[$key] = $this->_protect_identifiers($val, FALSE, $no_escape); } - + $sql .= implode(', ', $this->ar_select); } } // ---------------------------------------------------------------- - + // Write the "FROM" portion of the query if (count($this->ar_from) > 0) @@ -1525,7 +1718,7 @@ function _compile_select($select_override = FALSE) } // ---------------------------------------------------------------- - + // Write the "JOIN" portion of the query if (count($this->ar_join) > 0) @@ -1536,22 +1729,20 @@ function _compile_select($select_override = FALSE) } // ---------------------------------------------------------------- - + // Write the "WHERE" portion of the query if (count($this->ar_where) > 0 OR count($this->ar_like) > 0) { - $sql .= "\n"; - - $sql .= "WHERE "; + $sql .= "\nWHERE "; } $sql .= implode("\n", $this->ar_where); // ---------------------------------------------------------------- - + // Write the "LIKE" portion of the query - + if (count($this->ar_like) > 0) { if (count($this->ar_where) > 0) @@ -1563,20 +1754,20 @@ function _compile_select($select_override = FALSE) } // ---------------------------------------------------------------- - + // Write the "GROUP BY" portion of the query - + if (count($this->ar_groupby) > 0) { $sql .= "\nGROUP BY "; - + $sql .= implode(', ', $this->ar_groupby); } // ---------------------------------------------------------------- - + // Write the "HAVING" portion of the query - + if (count($this->ar_having) > 0) { $sql .= "\nHAVING "; @@ -1584,24 +1775,24 @@ function _compile_select($select_override = FALSE) } // ---------------------------------------------------------------- - + // Write the "ORDER BY" portion of the query if (count($this->ar_orderby) > 0) { $sql .= "\nORDER BY "; $sql .= implode(', ', $this->ar_orderby); - + if ($this->ar_order !== FALSE) { $sql .= ($this->ar_order == 'desc') ? ' DESC' : ' ASC'; - } + } } // ---------------------------------------------------------------- - + // Write the "LIMIT" portion of the query - + if (is_numeric($this->ar_limit)) { $sql .= "\n"; @@ -1618,30 +1809,68 @@ function _compile_select($select_override = FALSE) * * Takes an object as input and converts the class variables to array key/vals * - * @access public * @param object * @return array */ - function _object_to_array($object) + public function _object_to_array($object) { if ( ! is_object($object)) { return $object; } - + $array = array(); foreach (get_object_vars($object) as $key => $val) { // There are some built in keys we need to ignore for this conversion - if ( ! is_object($val) && ! is_array($val) && $key != '_parent_name' && $key != '_ci_scaffolding' && $key != '_ci_scaff_table') + if ( ! is_object($val) && ! is_array($val) && $key != '_parent_name') { $array[$key] = $val; } } - + return $array; } - + + // -------------------------------------------------------------------- + + /** + * Object to Array + * + * Takes an object as input and converts the class variables to array key/vals + * + * @param object + * @return array + */ + public function _object_to_array_batch($object) + { + if ( ! is_object($object)) + { + return $object; + } + + $array = array(); + $out = get_object_vars($object); + $fields = array_keys($out); + + foreach ($fields as $val) + { + // There are some built in keys we need to ignore for this conversion + if ($val != '_parent_name') + { + + $i = 0; + foreach ($out[$val] as $data) + { + $array[$i][$val] = $data; + $i++; + } + } + } + + return $array; + } + // -------------------------------------------------------------------- /** @@ -1649,10 +1878,9 @@ function _object_to_array($object) * * Starts AR caching * - * @access public * @return void - */ - function start_cache() + */ + public function start_cache() { $this->ar_caching = TRUE; } @@ -1664,10 +1892,9 @@ function start_cache() * * Stops AR caching * - * @access public * @return void - */ - function stop_cache() + */ + public function stop_cache() { $this->ar_caching = FALSE; } @@ -1681,23 +1908,22 @@ function stop_cache() * * @access public * @return void - */ - function flush_cache() - { - $this->_reset_run( - array( - 'ar_cache_select' => array(), - 'ar_cache_from' => array(), - 'ar_cache_join' => array(), - 'ar_cache_where' => array(), - 'ar_cache_like' => array(), - 'ar_cache_groupby' => array(), - 'ar_cache_having' => array(), - 'ar_cache_orderby' => array(), - 'ar_cache_set' => array(), - 'ar_cache_exists' => array() - ) - ); + */ + public function flush_cache() + { + $this->_reset_run(array( + 'ar_cache_select' => array(), + 'ar_cache_from' => array(), + 'ar_cache_join' => array(), + 'ar_cache_where' => array(), + 'ar_cache_like' => array(), + 'ar_cache_groupby' => array(), + 'ar_cache_having' => array(), + 'ar_cache_orderby' => array(), + 'ar_cache_set' => array(), + 'ar_cache_exists' => array(), + 'ar_cache_no_escape' => array() + )); } // -------------------------------------------------------------------- @@ -1705,13 +1931,12 @@ function flush_cache() /** * Merge Cache * - * When called, this function merges any cached AR arrays with + * When called, this function merges any cached AR arrays with * locally called ones. * - * @access private * @return void */ - function _merge_cache() + protected function _merge_cache() { if (count($this->ar_cache_exists) == 0) { @@ -1737,6 +1962,8 @@ function _merge_cache() { $this->_track_aliases($this->ar_from); } + + $this->ar_no_escape = $this->ar_cache_no_escape; } // -------------------------------------------------------------------- @@ -1744,11 +1971,10 @@ function _merge_cache() /** * Resets the active record values. Called by the get() function * - * @access private * @param array An array of fields to reset * @return void */ - function _reset_run($ar_reset_items) + protected function _reset_run($ar_reset_items) { foreach ($ar_reset_items as $item => $default_value) { @@ -1764,56 +1990,55 @@ function _reset_run($ar_reset_items) /** * Resets the active record values. Called by the get() function * - * @access private * @return void */ - function _reset_select() + protected function _reset_select() { $ar_reset_items = array( - 'ar_select' => array(), - 'ar_from' => array(), - 'ar_join' => array(), - 'ar_where' => array(), - 'ar_like' => array(), - 'ar_groupby' => array(), - 'ar_having' => array(), - 'ar_orderby' => array(), - 'ar_wherein' => array(), - 'ar_aliased_tables' => array(), - 'ar_distinct' => FALSE, - 'ar_limit' => FALSE, - 'ar_offset' => FALSE, - 'ar_order' => FALSE, - ); - + 'ar_select' => array(), + 'ar_from' => array(), + 'ar_join' => array(), + 'ar_where' => array(), + 'ar_like' => array(), + 'ar_groupby' => array(), + 'ar_having' => array(), + 'ar_orderby' => array(), + 'ar_wherein' => array(), + 'ar_aliased_tables' => array(), + 'ar_no_escape' => array(), + 'ar_distinct' => FALSE, + 'ar_limit' => FALSE, + 'ar_offset' => FALSE, + 'ar_order' => FALSE, + ); + $this->_reset_run($ar_reset_items); } - + // -------------------------------------------------------------------- /** * Resets the active record "write" values. * - * Called by the insert() update() and delete() functions + * Called by the insert() update() insert_batch() update_batch() and delete() functions * - * @access private * @return void */ - function _reset_write() - { + protected function _reset_write() + { $ar_reset_items = array( - 'ar_set' => array(), - 'ar_from' => array(), - 'ar_where' => array(), - 'ar_like' => array(), - 'ar_orderby' => array(), - 'ar_limit' => FALSE, - 'ar_order' => FALSE - ); + 'ar_set' => array(), + 'ar_from' => array(), + 'ar_where' => array(), + 'ar_like' => array(), + 'ar_orderby' => array(), + 'ar_keys' => array(), + 'ar_limit' => FALSE, + 'ar_order' => FALSE + ); $this->_reset_run($ar_reset_items); } - } /* End of file DB_active_rec.php */ diff --git a/system/database/DB_cache.php b/system/database/DB_cache.php index 8b0ad4fb..ad1c28d7 100644 --- a/system/database/DB_cache.php +++ b/system/database/DB_cache.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -32,14 +32,14 @@ class CI_DB_Cache { * * Grabs the CI super object instance so we can access it. * - */ - function CI_DB_Cache(&$db) + */ + function __construct(&$db) { // Assign the main CI object to $this->CI // and load the file helper since we use it a lot $this->CI =& get_instance(); $this->db =& $db; - $this->CI->load->helper('file'); + $this->CI->load->helper('file'); } // -------------------------------------------------------------------- @@ -50,7 +50,7 @@ function CI_DB_Cache(&$db) * @access public * @param string the path to the cache directory * @return bool - */ + */ function check_path($path = '') { if ($path == '') @@ -59,10 +59,10 @@ function check_path($path = '') { return $this->db->cache_off(); } - + $path = $this->db->cachedir; } - + // Add a trailing slash to the path if needed $path = preg_replace("/(.+?)\/*$/", "\\1/", $path); @@ -71,11 +71,11 @@ function check_path($path = '') // If the path is wrong we'll turn off caching return $this->db->cache_off(); } - + $this->db->cachedir = $path; return TRUE; } - + // -------------------------------------------------------------------- /** @@ -95,18 +95,18 @@ function read($sql) } $segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1); - + $segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2); - - $filepath = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'.md5($sql); - + + $filepath = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'.md5($sql); + if (FALSE === ($cachedata = read_file($filepath))) - { + { return FALSE; } - - return unserialize($cachedata); - } + + return unserialize($cachedata); + } // -------------------------------------------------------------------- @@ -124,29 +124,29 @@ function write($sql, $object) } $segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1); - + $segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2); - + $dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'; - + $filename = md5($sql); - + if ( ! @is_dir($dir_path)) { if ( ! @mkdir($dir_path, DIR_WRITE_MODE)) { return FALSE; } - - @chmod($dir_path, DIR_WRITE_MODE); + + @chmod($dir_path, DIR_WRITE_MODE); } - + if (write_file($dir_path.$filename, serialize($object)) === FALSE) { return FALSE; } - - @chmod($dir_path.$filename, DIR_WRITE_MODE); + + @chmod($dir_path.$filename, FILE_WRITE_MODE); return TRUE; } @@ -159,19 +159,19 @@ function write($sql, $object) * @return bool */ function delete($segment_one = '', $segment_two = '') - { + { if ($segment_one == '') { $segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1); } - + if ($segment_two == '') { $segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2); } - + $dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'; - + delete_files($dir_path, TRUE); } diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php index 70df1a2f..775fd335 100644 --- a/system/database/DB_driver.php +++ b/system/database/DB_driver.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -71,14 +71,14 @@ class CI_DB_driver { var $limit_used; - + /** * Constructor. Accepts one parameter containing the database * connection settings. * * @param array - */ - function CI_DB_driver($params) + */ + function __construct($params) { if (is_array($params)) { @@ -90,7 +90,7 @@ function CI_DB_driver($params) log_message('debug', 'Database Driver Class Initialized'); } - + // -------------------------------------------------------------------- /** @@ -99,7 +99,7 @@ function CI_DB_driver($params) * @access private Called by the constructor * @param mixed * @return void - */ + */ function initialize() { // If an existing connection resource is available @@ -108,9 +108,9 @@ function initialize() { return TRUE; } - + // ---------------------------------------------------------------- - + // Connect to the database and set the connection ID $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect(); @@ -118,7 +118,7 @@ function initialize() if ( ! $this->conn_id) { log_message('error', 'Unable to connect to the database'); - + if ($this->db_debug) { $this->display_error('db_unable_to_connect'); @@ -134,12 +134,12 @@ function initialize() if ( ! $this->db_select()) { log_message('error', 'Unable to select database: '.$this->database); - + if ($this->db_debug) { $this->display_error('db_unable_to_select', $this->database); } - return FALSE; + return FALSE; } else { @@ -148,14 +148,14 @@ function initialize() { return FALSE; } - + return TRUE; } } return TRUE; } - + // -------------------------------------------------------------------- /** @@ -171,26 +171,26 @@ function db_set_charset($charset, $collation) if ( ! $this->_db_set_charset($this->char_set, $this->dbcollat)) { log_message('error', 'Unable to set database connection charset: '.$this->char_set); - + if ($this->db_debug) { $this->display_error('db_unable_to_set_charset', $this->char_set); } - + return FALSE; } - + return TRUE; } - + // -------------------------------------------------------------------- /** * The name of the platform in use (mysql, mssql, etc...) * * @access public - * @return string - */ + * @return string + */ function platform() { return $this->dbdriver; @@ -203,8 +203,8 @@ function platform() * version of the database being used * * @access public - * @return string - */ + * @return string + */ function version() { if (FALSE === ($sql = $this->_version())) @@ -215,16 +215,22 @@ function version() } return FALSE; } - - if ($this->dbdriver == 'oci8') + + // Some DBs have functions that return the version, and don't run special + // SQL queries per se. In these instances, just return the result. + $driver_version_exceptions = array('oci8', 'sqlite', 'cubrid'); + + if (in_array($this->dbdriver, $driver_version_exceptions)) { return $sql; } - - $query = $this->query($sql); - return $query->row('ver'); + else + { + $query = $this->query($sql); + return $query->row('ver'); + } } - + // -------------------------------------------------------------------- /** @@ -239,8 +245,8 @@ function version() * @access public * @param string An SQL query string * @param array An array of binding data - * @return mixed - */ + * @return mixed + */ function query($sql, $binds = FALSE, $return_object = TRUE) { if ($sql == '') @@ -255,10 +261,16 @@ function query($sql, $binds = FALSE, $return_object = TRUE) // Verify table prefix and replace if necessary if ( ($this->dbprefix != '' AND $this->swap_pre != '') AND ($this->dbprefix != $this->swap_pre) ) - { + { $sql = preg_replace("/(\W)".$this->swap_pre."(\S+?)/", "\\1".$this->dbprefix."\\2", $sql); } - + + // Compile binds if needed + if ($binds !== FALSE) + { + $sql = $this->compile_binds($sql, $binds); + } + // Is query caching enabled? If the query is a "read type" // we will load the caching class and return the previously // cached query if it exists @@ -273,22 +285,16 @@ function query($sql, $binds = FALSE, $return_object = TRUE) } } } - - // Compile binds if needed - if ($binds !== FALSE) - { - $sql = $this->compile_binds($sql, $binds); - } // Save the query for debugging if ($this->save_queries == TRUE) { $this->queries[] = $sql; } - + // Start the Query Timer $time_start = list($sm, $ss) = explode(' ', microtime()); - + // Run the Query if (FALSE === ($this->result_id = $this->simple_query($sql))) { @@ -296,7 +302,7 @@ function query($sql, $binds = FALSE, $return_object = TRUE) { $this->query_times[] = 0; } - + // This will trigger a rollback if transactions are being used $this->_trans_status = FALSE; @@ -306,10 +312,10 @@ function query($sql, $binds = FALSE, $return_object = TRUE) // additional queries before displaying the error $error_no = $this->_error_number(); $error_msg = $this->_error_message(); - + // We call this function in order to roll-back queries // if transactions are enabled. If we don't call this here - // the error message will trigger an exit, causing the + // the error message will trigger an exit, causing the // transactions to remain in limbo. $this->trans_complete(); @@ -323,10 +329,10 @@ function query($sql, $binds = FALSE, $return_object = TRUE) ) ); } - + return FALSE; } - + // Stop and aggregate the query time results $time_end = list($em, $es) = explode(' ', microtime()); $this->benchmark += ($em + $es) - ($sm + $ss); @@ -335,10 +341,10 @@ function query($sql, $binds = FALSE, $return_object = TRUE) { $this->query_times[] = ($em + $es) - ($sm + $ss); } - + // Increment the query counter $this->query_count++; - + // Was the query a "write" type? // If so we'll simply return true if ($this->is_write_type($sql) === TRUE) @@ -349,10 +355,10 @@ function query($sql, $binds = FALSE, $return_object = TRUE) { $this->CACHE->delete(); } - + return TRUE; } - + // Return TRUE if we don't need to create a result object // Currently only the Oracle driver uses this when stored // procedures are used @@ -360,11 +366,11 @@ function query($sql, $binds = FALSE, $return_object = TRUE) { return TRUE; } - - // Load and instantiate the result driver - - $driver = $this->load_rdriver(); - $RES = new $driver(); + + // Load and instantiate the result driver + + $driver = $this->load_rdriver(); + $RES = new $driver(); $RES->conn_id = $this->conn_id; $RES->result_id = $this->result_id; @@ -375,10 +381,10 @@ function query($sql, $binds = FALSE, $return_object = TRUE) $RES->limit_used = $this->limit_used; $this->stmt_id = FALSE; } - + // oci8 vars must be set before calling this $RES->num_rows = $RES->num_rows(); - + // Is query caching enabled? If so, we'll serialize the // result object and save it to a cache file. if ($this->cache_on == TRUE AND $this->_cache_init()) @@ -390,17 +396,17 @@ function query($sql, $binds = FALSE, $return_object = TRUE) // result object, so we'll have to compile the data // and save it) $CR = new CI_DB_result(); - $CR->num_rows = $RES->num_rows(); + $CR->num_rows = $RES->num_rows(); $CR->result_object = $RES->result_object(); $CR->result_array = $RES->result_array(); - + // Reset these since cached objects can not utilize resource IDs. $CR->conn_id = NULL; $CR->result_id = NULL; $this->CACHE->write($sql, $CR); } - + return $RES; } @@ -410,21 +416,21 @@ function query($sql, $binds = FALSE, $return_object = TRUE) * Load the result drivers * * @access public - * @return string the name of the result class - */ + * @return string the name of the result class + */ function load_rdriver() { $driver = 'CI_DB_'.$this->dbdriver.'_result'; if ( ! class_exists($driver)) { - include_once(BASEPATH.'database/DB_result'.EXT); - include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result'.EXT); + include_once(BASEPATH.'database/DB_result.php'); + include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result.php'); } - + return $driver; } - + // -------------------------------------------------------------------- /** @@ -435,8 +441,8 @@ function load_rdriver() * * @access public * @param string the sql query - * @return mixed - */ + * @return mixed + */ function simple_query($sql) { if ( ! $this->conn_id) @@ -446,7 +452,7 @@ function simple_query($sql) return $this->_execute($sql); } - + // -------------------------------------------------------------------- /** @@ -454,8 +460,8 @@ function simple_query($sql) * This permits transactions to be disabled at run-time. * * @access public - * @return void - */ + * @return void + */ function trans_off() { $this->trans_enabled = FALSE; @@ -471,23 +477,23 @@ function trans_off() * a failure of one group will not affect any others * * @access public - * @return void - */ + * @return void + */ function trans_strict($mode = TRUE) { $this->trans_strict = is_bool($mode) ? $mode : TRUE; } - + // -------------------------------------------------------------------- /** * Start Transaction * * @access public - * @return void - */ + * @return void + */ function trans_start($test_mode = FALSE) - { + { if ( ! $this->trans_enabled) { return FALSE; @@ -499,7 +505,7 @@ function trans_start($test_mode = FALSE) $this->_trans_depth += 1; return; } - + $this->trans_begin($test_mode); } @@ -509,27 +515,27 @@ function trans_start($test_mode = FALSE) * Complete Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_complete() { if ( ! $this->trans_enabled) { return FALSE; } - + // When transactions are nested we only begin/commit/rollback the outermost ones if ($this->_trans_depth > 1) { $this->_trans_depth -= 1; return TRUE; } - + // The query() function will set this flag to FALSE in the event that a query failed if ($this->_trans_status === FALSE) { $this->trans_rollback(); - + // If we are NOT running in strict mode, we will reset // the _trans_status flag so that subsequent groups of transactions // will be permitted. @@ -541,7 +547,7 @@ function trans_complete() log_message('debug', 'DB Transaction Failure'); return FALSE; } - + $this->trans_commit(); return TRUE; } @@ -552,8 +558,8 @@ function trans_complete() * Lets you retrieve the transaction flag to determine if it has failed * * @access public - * @return bool - */ + * @return bool + */ function trans_status() { return $this->_trans_status; @@ -567,20 +573,20 @@ function trans_status() * @access public * @param string the sql statement * @param array an array of bind data - * @return string - */ + * @return string + */ function compile_binds($sql, $binds) { if (strpos($sql, $this->bind_marker) === FALSE) { return $sql; } - + if ( ! is_array($binds)) { $binds = array($binds); } - + // Get the sql segments around the bind markers $segments = explode($this->bind_marker, $sql); @@ -601,7 +607,7 @@ function compile_binds($sql, $binds) return $result; } - + // -------------------------------------------------------------------- /** @@ -609,8 +615,8 @@ function compile_binds($sql, $binds) * * @access public * @param string An SQL query string - * @return boolean - */ + * @return boolean + */ function is_write_type($sql) { if ( ! preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i', $sql)) @@ -619,7 +625,7 @@ function is_write_type($sql) } return TRUE; } - + // -------------------------------------------------------------------- /** @@ -627,34 +633,34 @@ function is_write_type($sql) * * @access public * @param integer The number of decimal places - * @return integer - */ + * @return integer + */ function elapsed_time($decimals = 6) { return number_format($this->benchmark, $decimals); } - + // -------------------------------------------------------------------- /** * Returns the total number of queries * * @access public - * @return integer - */ + * @return integer + */ function total_queries() { return $this->query_count; } - + // -------------------------------------------------------------------- /** * Returns the last query that was executed * * @access public - * @return void - */ + * @return void + */ function last_query() { return end($this->queries); @@ -670,8 +676,8 @@ function last_query() * * @access public * @param string - * @return mixed - */ + * @return mixed + */ function escape($str) { if (is_string($str)) @@ -691,24 +697,24 @@ function escape($str) } // -------------------------------------------------------------------- - + /** * Escape LIKE String * * Calls the individual driver for platform * specific escaping for LIKE conditions - * + * * @access public * @param string * @return mixed */ - function escape_like_str($str) - { + function escape_like_str($str) + { return $this->escape_str($str, TRUE); } // -------------------------------------------------------------------- - + /** * Primary * @@ -717,12 +723,12 @@ function escape_like_str($str) * * @access public * @param string the table name - * @return string - */ + * @return string + */ function primary($table = '') - { + { $fields = $this->list_fields($table); - + if ( ! is_array($fields)) { return FALSE; @@ -737,8 +743,8 @@ function primary($table = '') * Returns an array of table names * * @access public - * @return array - */ + * @return array + */ function list_tables($constrain_by_prefix = FALSE) { // Is there a cached result? @@ -746,7 +752,7 @@ function list_tables($constrain_by_prefix = FALSE) { return $this->data_cache['table_names']; } - + if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix))) { if ($this->db_debug) @@ -758,10 +764,10 @@ function list_tables($constrain_by_prefix = FALSE) $retval = array(); $query = $this->query($sql); - + if ($query->num_rows() > 0) { - foreach($query->result_array() as $row) + foreach ($query->result_array() as $row) { if (isset($row['TABLE_NAME'])) { @@ -777,7 +783,7 @@ function list_tables($constrain_by_prefix = FALSE) $this->data_cache['table_names'] = $retval; return $this->data_cache['table_names']; } - + // -------------------------------------------------------------------- /** @@ -786,10 +792,10 @@ function list_tables($constrain_by_prefix = FALSE) * @return boolean */ function table_exists($table_name) - { + { return ( ! in_array($this->_protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables())) ? FALSE : TRUE; } - + // -------------------------------------------------------------------- /** @@ -797,7 +803,7 @@ function table_exists($table_name) * * @access public * @param string the table name - * @return array + * @return array */ function list_fields($table = '') { @@ -806,7 +812,7 @@ function list_fields($table = '') { return $this->data_cache['field_names'][$table]; } - + if ($table == '') { if ($this->db_debug) @@ -815,8 +821,8 @@ function list_fields($table = '') } return FALSE; } - - if (FALSE === ($sql = $this->_list_columns($this->_protect_identifiers($table, TRUE, NULL, FALSE)))) + + if (FALSE === ($sql = $this->_list_columns($table))) { if ($this->db_debug) { @@ -824,11 +830,11 @@ function list_fields($table = '') } return FALSE; } - + $query = $this->query($sql); - + $retval = array(); - foreach($query->result_array() as $row) + foreach ($query->result_array() as $row) { if (isset($row['COLUMN_NAME'])) { @@ -837,9 +843,9 @@ function list_fields($table = '') else { $retval[] = current($row); - } + } } - + $this->data_cache['field_names'][$table] = $retval; return $this->data_cache['field_names'][$table]; } @@ -854,10 +860,10 @@ function list_fields($table = '') * @return boolean */ function field_exists($field_name, $table_name) - { + { return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE; } - + // -------------------------------------------------------------------- /** @@ -865,8 +871,8 @@ function field_exists($field_name, $table_name) * * @access public * @param string the table name - * @return object - */ + * @return object + */ function field_data($table = '') { if ($table == '') @@ -877,36 +883,36 @@ function field_data($table = '') } return FALSE; } - + $query = $this->query($this->_field_data($this->_protect_identifiers($table, TRUE, NULL, FALSE))); return $query->field_data(); - } + } // -------------------------------------------------------------------- - + /** * Generate an insert string * * @access public * @param string the table upon which the query will be performed * @param array an associative array data of key/values - * @return string - */ + * @return string + */ function insert_string($table, $data) { $fields = array(); $values = array(); - - foreach($data as $key => $val) + + foreach ($data as $key => $val) { $fields[] = $this->_escape_identifiers($key); $values[] = $this->escape($val); } - + return $this->_insert($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $values); - } - + } + // -------------------------------------------------------------------- /** @@ -916,17 +922,17 @@ function insert_string($table, $data) * @param string the table upon which the query will be performed * @param array an associative array data of key/values * @param mixed the "where" statement - * @return string - */ + * @return string + */ function update_string($table, $data, $where) { if ($where == '') { return false; } - + $fields = array(); - foreach($data as $key => $val) + foreach ($data as $key => $val) { $fields[$this->_protect_identifiers($key)] = $this->escape($val); } @@ -941,23 +947,23 @@ function update_string($table, $data, $where) foreach ($where as $key => $val) { $prefix = (count($dest) == 0) ? '' : ' AND '; - + if ($val !== '') { if ( ! $this->_has_operator($key)) { $key .= ' ='; } - + $val = ' '.$this->escape($val); } - + $dest[] = $prefix.$key.$val; } - } + } return $this->_update($this->_protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest); - } + } // -------------------------------------------------------------------- @@ -987,17 +993,17 @@ function _has_operator($str) * @access public * @param string the function name * @param mixed any parameters needed by the function - * @return mixed - */ + * @return mixed + */ function call_function($function) { $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_'; - + if (FALSE === strpos($driver, $function)) { $function = $driver.$function; } - + if ( ! function_exists($function)) { if ($this->db_debug) @@ -1009,8 +1015,14 @@ function call_function($function) else { $args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null; - - return call_user_func_array($function, $args); + if (is_null($args)) + { + return call_user_func($function); + } + else + { + return call_user_func_array($function, $args); + } } } @@ -1022,7 +1034,7 @@ function call_function($function) * @access public * @param string the path to the cache directory * @return void - */ + */ function cache_set_path($path = '') { $this->cachedir = $path; @@ -1035,7 +1047,7 @@ function cache_set_path($path = '') * * @access public * @return void - */ + */ function cache_on() { $this->cache_on = TRUE; @@ -1049,13 +1061,13 @@ function cache_on() * * @access public * @return void - */ + */ function cache_off() { $this->cache_on = FALSE; return FALSE; } - + // -------------------------------------------------------------------- @@ -1064,7 +1076,7 @@ function cache_off() * * @access public * @return void - */ + */ function cache_delete($segment_one = '', $segment_two = '') { if ( ! $this->_cache_init()) @@ -1081,7 +1093,7 @@ function cache_delete($segment_one = '', $segment_two = '') * * @access public * @return void - */ + */ function cache_delete_all() { if ( ! $this->_cache_init()) @@ -1099,7 +1111,7 @@ function cache_delete_all() * * @access private * @return void - */ + */ function _cache_init() { if (is_object($this->CACHE) AND class_exists('CI_DB_Cache')) @@ -1109,7 +1121,7 @@ function _cache_init() if ( ! class_exists('CI_DB_Cache')) { - if ( ! @include(BASEPATH.'database/DB_cache'.EXT)) + if ( ! @include(BASEPATH.'database/DB_cache.php')) { return $this->cache_off(); } @@ -1125,8 +1137,8 @@ function _cache_init() * Close DB Connection * * @access public - * @return void - */ + * @return void + */ function close() { if (is_resource($this->conn_id) OR is_object($this->conn_id)) @@ -1135,7 +1147,7 @@ function close() } $this->conn_id = FALSE; } - + // -------------------------------------------------------------------- /** @@ -1145,11 +1157,11 @@ function close() * @param string the error message * @param string any "swap" values * @param boolean whether to localize the message - * @return string sends the application/error_db.php template - */ + * @return string sends the application/error_db.php template + */ function display_error($error = '', $swap = '', $native = FALSE) { - $LANG =& load_class('Language'); + $LANG =& load_class('Lang', 'core'); $LANG->load('db'); $heading = $LANG->line('db_error_heading'); @@ -1162,8 +1174,26 @@ function display_error($error = '', $swap = '', $native = FALSE) { $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error; } - - $error =& load_class('Exceptions'); + + // Find the most likely culprit of the error by going through + // the backtrace until the source file is no longer in the + // database folder. + + $trace = debug_backtrace(); + + foreach ($trace as $call) + { + if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE) + { + // Found it - use a relative path for safety + $message[] = 'Filename: '.str_replace(array(BASEPATH, APPPATH), '', $call['file']); + $message[] = 'Line Number: '.$call['line']; + + break; + } + } + + $error =& load_class('Exceptions', 'core'); echo $error->show_error($heading, $message, 'error_db'); exit; } @@ -1190,7 +1220,7 @@ function protect_identifiers($item, $prefix_single = FALSE) * Protect Identifiers * * This function is used extensively by the Active Record class, and by - * a couple functions in this class. + * a couple functions in this class. * It takes a column or table name (optionally with an alias) and inserts * the table prefix onto it. Some logic is necessary in order to deal with * column names that include the path. Consider a query like this: @@ -1212,7 +1242,7 @@ function protect_identifiers($item, $prefix_single = FALSE) * @param mixed * @param bool * @return string - */ + */ function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE) { if ( ! is_bool($protect_identifiers)) @@ -1224,7 +1254,7 @@ function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifier { $escaped_array = array(); - foreach($item as $k => $v) + foreach ($item as $k => $v) { $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v); } @@ -1234,18 +1264,21 @@ function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifier // Convert tabs or multiple spaces into single spaces $item = preg_replace('/[\t ]+/', ' ', $item); - + // If the item has an alias declaration we remove it and set it aside. // Basically we remove everything to the right of the first space - $alias = ''; if (strpos($item, ' ') !== FALSE) { - $alias = strstr($item, " "); + $alias = strstr($item, ' '); $item = substr($item, 0, - strlen($alias)); } + else + { + $alias = ''; + } // This is basically a bug fix for queries that use MAX, MIN, etc. - // If a parenthesis is found we know that we do not need to + // If a parenthesis is found we know that we do not need to // escape the data or add a prefix. There's probably a more graceful // way to deal with this, but I'm not thinking of it -- Rick if (strpos($item, '(') !== FALSE) @@ -1259,7 +1292,7 @@ function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifier if (strpos($item, '.') !== FALSE) { $parts = explode('.', $item); - + // Does the first segment of the exploded item match // one of the aliases previously identified? If so, // we have nothing more to do other than escape the item @@ -1274,12 +1307,12 @@ function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifier $parts[$key] = $this->_escape_identifiers($val); } } - + $item = implode('.', $parts); - } + } return $item.$alias; } - + // Is there a table prefix defined in the config file? If not, no need to do anything if ($this->dbprefix != '') { @@ -1302,7 +1335,7 @@ function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifier { $i = 0; } - + // This flag is set when the supplied $item does not contain a field name. // This can happen when this function is being called from a JOIN. if ($field_exists == FALSE) @@ -1315,22 +1348,22 @@ function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifier { $parts[$i] = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $parts[$i]); } - + // We only add the table prefix if it does not already exist if (substr($parts[$i], 0, strlen($this->dbprefix)) != $this->dbprefix) { $parts[$i] = $this->dbprefix.$parts[$i]; } - + // Put the parts back together $item = implode('.', $parts); } - + if ($protect_identifiers === TRUE) { $item = $this->_escape_identifiers($item); } - + return $item.$alias; } @@ -1347,20 +1380,31 @@ function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifier if ($prefix_single == TRUE AND substr($item, 0, strlen($this->dbprefix)) != $this->dbprefix) { $item = $this->dbprefix.$item; - } + } } if ($protect_identifiers === TRUE AND ! in_array($item, $this->_reserved_identifiers)) { $item = $this->_escape_identifiers($item); } - + return $item.$alias; } + // -------------------------------------------------------------------- -} + /** + * Dummy method that allows Active Record class to be disabled + * + * This function is used extensively by every db driver. + * + * @return void + */ + protected function _reset_select() + { + } +} /* End of file DB_driver.php */ /* Location: ./system/database/DB_driver.php */ \ No newline at end of file diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php index 4050e300..6bc40411 100644 --- a/system/database/DB_forge.php +++ b/system/database/DB_forge.php @@ -2,11 +2,11 @@ /** * Code Igniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -24,9 +24,9 @@ */ class CI_DB_forge { - var $fields = array(); + var $fields = array(); var $keys = array(); - var $primary_keys = array(); + var $primary_keys = array(); var $db_char_set = ''; /** @@ -34,8 +34,8 @@ class CI_DB_forge { * * Grabs the CI super object instance so we can access it. * - */ - function CI_DB_forge() + */ + function __construct() { // Assign the main database object to $this->db $CI =& get_instance(); @@ -55,12 +55,12 @@ function CI_DB_forge() function create_database($db_name) { $sql = $this->_create_database($db_name); - + if (is_bool($sql)) { return $sql; } - + return $this->db->query($sql); } @@ -76,12 +76,12 @@ function create_database($db_name) function drop_database($db_name) { $sql = $this->_drop_database($db_name); - + if (is_bool($sql)) { return $sql; } - + return $this->db->query($sql); } @@ -99,19 +99,19 @@ function add_key($key = '', $primary = FALSE) { if (is_array($key)) { - foreach($key as $one) + foreach ($key as $one) { $this->add_key($one, $primary); } - + return; } - + if ($key == '') { show_error('Key information is required for that operation.'); } - + if ($primary === TRUE) { $this->primary_keys[] = $key; @@ -137,7 +137,7 @@ function add_field($field = '') { show_error('Field information is required.'); } - + if (is_string($field)) { if ($field == 'id') @@ -157,16 +157,16 @@ function add_field($field = '') { show_error('Field information is required for that operation.'); } - + $this->fields[] = $field; } } - + if (is_array($field)) { $this->fields = array_merge($this->fields, $field); } - + } // -------------------------------------------------------------------- @@ -179,19 +179,19 @@ function add_field($field = '') * @return bool */ function create_table($table = '', $if_not_exists = FALSE) - { + { if ($table == '') { show_error('A table name is required for that operation.'); } - + if (count($this->fields) == 0) - { + { show_error('Field information is required.'); } $sql = $this->_create_table($this->db->dbprefix.$table, $this->fields, $this->primary_keys, $this->keys, $if_not_exists); - + $this->_reset(); return $this->db->query($sql); } @@ -208,12 +208,12 @@ function create_table($table = '', $if_not_exists = FALSE) function drop_table($table_name) { $sql = $this->_drop_table($this->db->dbprefix.$table_name); - + if (is_bool($sql)) { return $sql; } - + return $this->db->query($sql); } @@ -233,8 +233,8 @@ function rename_table($table_name, $new_table_name) { show_error('A table name is required for that operation.'); } - - $sql = $this->_rename_table($table_name, $new_table_name); + + $sql = $this->_rename_table($this->db->dbprefix.$table_name, $this->db->dbprefix.$new_table_name); return $this->db->query($sql); } @@ -261,24 +261,25 @@ function add_column($table = '', $field = array(), $after_field = '') foreach ($field as $k => $v) { - $this->add_field(array($k => $field[$k])); + $this->add_field(array($k => $field[$k])); if (count($this->fields) == 0) - { + { show_error('Field information is required.'); } - + $sql = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->fields, $after_field); $this->_reset(); - + if ($this->db->query($sql) === FALSE) { return FALSE; } } - + return TRUE; + } // -------------------------------------------------------------------- @@ -293,7 +294,7 @@ function add_column($table = '', $field = array(), $after_field = '') */ function drop_column($table = '', $column_name = '') { - + if ($table == '') { show_error('A table name is required for that operation.'); @@ -305,7 +306,7 @@ function drop_column($table = '', $column_name = '') } $sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name); - + return $this->db->query($sql); } @@ -332,23 +333,29 @@ function modify_column($table = '', $field = array()) foreach ($field as $k => $v) { + // If no name provided, use the current name + if ( ! isset($field[$k]['name'])) + { + $field[$k]['name'] = $k; + } + $this->add_field(array($k => $field[$k])); if (count($this->fields) == 0) - { + { show_error('Field information is required.'); } - + $sql = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->fields); $this->_reset(); - + if ($this->db->query($sql) === FALSE) { return FALSE; } } - + return TRUE; } @@ -364,9 +371,9 @@ function modify_column($table = '', $field = array()) */ function _reset() { - $this->fields = array(); + $this->fields = array(); $this->keys = array(); - $this->primary_keys = array(); + $this->primary_keys = array(); } } diff --git a/system/database/DB_result.php b/system/database/DB_result.php index 4614e29f..48d66c8e 100644 --- a/system/database/DB_result.php +++ b/system/database/DB_result.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -28,13 +28,14 @@ */ class CI_DB_result { - var $conn_id = NULL; - var $result_id = NULL; - var $result_array = array(); - var $result_object = array(); - var $current_row = 0; - var $num_rows = 0; - var $row_data = NULL; + var $conn_id = NULL; + var $result_id = NULL; + var $result_array = array(); + var $result_object = array(); + var $custom_result_object = array(); + var $current_row = 0; + var $num_rows = 0; + var $row_data = NULL; /** @@ -42,11 +43,53 @@ class CI_DB_result { * * @access public * @param string can be "object" or "array" - * @return mixed either a result object or array - */ - function result($type = 'object') - { - return ($type == 'object') ? $this->result_object() : $this->result_array(); + * @return mixed either a result object or array + */ + public function result($type = 'object') + { + if ($type == 'array') return $this->result_array(); + else if ($type == 'object') return $this->result_object(); + else return $this->custom_result_object($type); + } + + // -------------------------------------------------------------------- + + /** + * Custom query result. + * + * @param class_name A string that represents the type of object you want back + * @return array of objects + */ + public function custom_result_object($class_name) + { + if (array_key_exists($class_name, $this->custom_result_object)) + { + return $this->custom_result_object[$class_name]; + } + + if ($this->result_id === FALSE OR $this->num_rows() == 0) + { + return array(); + } + + // add the data to the object + $this->_data_seek(0); + $result_object = array(); + + while ($row = $this->_fetch_object()) + { + $object = new $class_name(); + + foreach ($row as $key => $value) + { + $object->$key = $value; + } + + $result_object[] = $object; + } + + // return the array + return $this->custom_result_object[$class_name] = $result_object; } // -------------------------------------------------------------------- @@ -56,16 +99,16 @@ function result($type = 'object') * * @access public * @return object - */ - function result_object() + */ + public function result_object() { if (count($this->result_object) > 0) { return $this->result_object; } - - // In the event that query caching is on the result_id variable - // will return FALSE since there isn't a valid SQL resource so + + // In the event that query caching is on the result_id variable + // will return FALSE since there isn't a valid SQL resource so // we'll simply return an empty array. if ($this->result_id === FALSE OR $this->num_rows() == 0) { @@ -77,10 +120,10 @@ function result_object() { $this->result_object[] = $row; } - + return $this->result_object; } - + // -------------------------------------------------------------------- /** @@ -88,16 +131,16 @@ function result_object() * * @access public * @return array - */ - function result_array() + */ + public function result_array() { if (count($this->result_array) > 0) { return $this->result_array; } - // In the event that query caching is on the result_id variable - // will return FALSE since there isn't a valid SQL resource so + // In the event that query caching is on the result_id variable + // will return FALSE since there isn't a valid SQL resource so // we'll simply return an empty array. if ($this->result_id === FALSE OR $this->num_rows() == 0) { @@ -109,7 +152,7 @@ function result_array() { $this->result_array[] = $row; } - + return $this->result_array; } @@ -121,9 +164,9 @@ function result_array() * @access public * @param string * @param string can be "object" or "array" - * @return mixed either a result object or array - */ - function row($n = 0, $type = 'object') + * @return mixed either a result object or array + */ + public function row($n = 0, $type = 'object') { if ( ! is_numeric($n)) { @@ -132,17 +175,19 @@ function row($n = 0, $type = 'object') { $this->row_data = $this->row_array(0); } - + // array_key_exists() instead of isset() to allow for MySQL NULL values if (array_key_exists($n, $this->row_data)) { return $this->row_data[$n]; } - // reset the $n variable if the result was not achieved + // reset the $n variable if the result was not achieved $n = 0; } - - return ($type == 'object') ? $this->row_object($n) : $this->row_array($n); + + if ($type == 'object') return $this->row_object($n); + else if ($type == 'array') return $this->row_array($n); + else return $this->custom_row_object($n, $type); } // -------------------------------------------------------------------- @@ -152,25 +197,25 @@ function row($n = 0, $type = 'object') * * @access public * @return object - */ - function set_row($key, $value = NULL) + */ + public function set_row($key, $value = NULL) { // We cache the row data for subsequent uses if ( ! is_array($this->row_data)) { $this->row_data = $this->row_array(0); } - + if (is_array($key)) { foreach ($key as $k => $v) { $this->row_data[$k] = $v; } - + return; } - + if ($key != '' AND ! is_null($value)) { $this->row_data[$key] = $value; @@ -179,16 +224,39 @@ function set_row($key, $value = NULL) // -------------------------------------------------------------------- + /** + * Returns a single result row - custom object version + * + * @access public + * @return object + */ + public function custom_row_object($n, $type) + { + $result = $this->custom_result_object($type); + + if (count($result) == 0) + { + return $result; + } + + if ($n != $this->current_row AND isset($result[$n])) + { + $this->current_row = $n; + } + + return $result[$this->current_row]; + } + /** * Returns a single result row - object version * * @access public * @return object - */ - function row_object($n = 0) + */ + public function row_object($n = 0) { $result = $this->result_object(); - + if (count($result) == 0) { return $result; @@ -209,8 +277,8 @@ function row_object($n = 0) * * @access public * @return array - */ - function row_array($n = 0) + */ + public function row_array($n = 0) { $result = $this->result_array(); @@ -218,16 +286,16 @@ function row_array($n = 0) { return $result; } - + if ($n != $this->current_row AND isset($result[$n])) { $this->current_row = $n; } - + return $result[$this->current_row]; } - + // -------------------------------------------------------------------- /** @@ -235,8 +303,8 @@ function row_array($n = 0) * * @access public * @return object - */ - function first_row($type = 'object') + */ + public function first_row($type = 'object') { $result = $this->result($type); @@ -246,7 +314,7 @@ function first_row($type = 'object') } return $result[0]; } - + // -------------------------------------------------------------------- /** @@ -254,8 +322,8 @@ function first_row($type = 'object') * * @access public * @return object - */ - function last_row($type = 'object') + */ + public function last_row($type = 'object') { $result = $this->result($type); @@ -264,7 +332,7 @@ function last_row($type = 'object') return $result; } return $result[count($result) -1]; - } + } // -------------------------------------------------------------------- @@ -273,8 +341,8 @@ function last_row($type = 'object') * * @access public * @return object - */ - function next_row($type = 'object') + */ + public function next_row($type = 'object') { $result = $this->result($type); @@ -287,10 +355,10 @@ function next_row($type = 'object') { ++$this->current_row; } - + return $result[$this->current_row]; } - + // -------------------------------------------------------------------- /** @@ -298,8 +366,8 @@ function next_row($type = 'object') * * @access public * @return object - */ - function previous_row($type = 'object') + */ + public function previous_row($type = 'object') { $result = $this->result($type); @@ -326,17 +394,17 @@ function previous_row($type = 'object') * operational due to the unavailability of the database resource IDs with * cached results. */ - function num_rows() { return $this->num_rows; } - function num_fields() { return 0; } - function list_fields() { return array(); } - function field_data() { return array(); } - function free_result() { return TRUE; } - function _data_seek() { return TRUE; } - function _fetch_assoc() { return array(); } - function _fetch_object() { return array(); } - + public function num_rows() { return $this->num_rows; } + public function num_fields() { return 0; } + public function list_fields() { return array(); } + public function field_data() { return array(); } + public function free_result() { return TRUE; } + protected function _data_seek() { return TRUE; } + protected function _fetch_assoc() { return array(); } + protected function _fetch_object() { return array(); } + } // END DB_result class /* End of file DB_result.php */ -/* Location: ./system/database/DB_result.php */ \ No newline at end of file +/* Location: ./system/database/DB_result.php */ diff --git a/system/database/DB_utility.php b/system/database/DB_utility.php index 33c68fae..52196b7c 100644 --- a/system/database/DB_utility.php +++ b/system/database/DB_utility.php @@ -2,11 +2,11 @@ /** * Code Igniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -25,20 +25,20 @@ class CI_DB_utility extends CI_DB_forge { var $db; - var $data_cache = array(); + var $data_cache = array(); /** * Constructor * * Grabs the CI super object instance so we can access it. * - */ - function CI_DB_utility() + */ + function __construct() { // Assign the main database object to $this->db $CI =& get_instance(); $this->db =& $CI->db; - + log_message('debug', "Database Utility Class Initialized"); } @@ -51,13 +51,13 @@ function CI_DB_utility() * @return bool */ function list_databases() - { + { // Is there a cached result? if (isset($this->data_cache['db_names'])) { return $this->data_cache['db_names']; } - + $query = $this->db->query($this->_list_databases()); $dbs = array(); if ($query->num_rows() > 0) @@ -67,11 +67,36 @@ function list_databases() $dbs[] = current($row); } } - + $this->data_cache['db_names'] = $dbs; return $this->data_cache['db_names']; } + // -------------------------------------------------------------------- + + /** + * Determine if a particular database exists + * + * @access public + * @param string + * @return boolean + */ + function database_exists($database_name) + { + // Some databases won't have access to the list_databases() function, so + // this is intended to allow them to override with their own functions as + // defined in $driver_utility.php + if (method_exists($this, '_database_exists')) + { + return $this->_database_exists($database_name); + } + else + { + return ( ! in_array($database_name, $this->list_databases())) ? FALSE : TRUE; + } + } + + // -------------------------------------------------------------------- /** @@ -84,15 +109,15 @@ function list_databases() function optimize_table($table_name) { $sql = $this->_optimize_table($table_name); - + if (is_bool($sql)) { show_error('db_must_use_set'); } - + $query = $this->db->query($sql); $res = $query->result_array(); - + // Note: Due to a bug in current() that affects some versions // of PHP we can not pass function call directly into it return current($res); @@ -112,14 +137,14 @@ function optimize_database() foreach ($this->db->list_tables() as $table_name) { $sql = $this->_optimize_table($table_name); - + if (is_bool($sql)) { return $sql; } - + $query = $this->db->query($sql); - + // Build the result array... // Note: Due to a bug in current() that affects some versions // of PHP we can not pass function call directly into it @@ -128,7 +153,7 @@ function optimize_database() $key = str_replace($this->db->database.'.', '', current($res)); $keys = array_keys($res); unset($res[$keys[0]]); - + $result[$key] = $res; } @@ -147,20 +172,20 @@ function optimize_database() function repair_table($table_name) { $sql = $this->_repair_table($table_name); - + if (is_bool($sql)) { return $sql; } - + $query = $this->db->query($sql); - + // Note: Due to a bug in current() that affects some versions // of PHP we can not pass function call directly into it $res = $query->result_array(); return current($res); } - + // -------------------------------------------------------------------- /** @@ -178,25 +203,25 @@ function csv_from_result($query, $delim = ",", $newline = "\n", $enclosure = '"' if ( ! is_object($query) OR ! method_exists($query, 'list_fields')) { show_error('You must submit a valid result object'); - } - + } + $out = ''; - + // First generate the headings from the table column names foreach ($query->list_fields() as $name) { $out .= $enclosure.str_replace($enclosure, $enclosure.$enclosure, $name).$enclosure.$delim; } - + $out = rtrim($out); $out .= $newline; - + // Next blast through the result array and build out the rows foreach ($query->result_array() as $row) { foreach ($row as $item) { - $out .= $enclosure.str_replace($enclosure, $enclosure.$enclosure, $item).$enclosure.$delim; + $out .= $enclosure.str_replace($enclosure, $enclosure.$enclosure, $item).$enclosure.$delim; } $out = rtrim($out); $out .= $newline; @@ -204,7 +229,7 @@ function csv_from_result($query, $delim = ",", $newline = "\n", $enclosure = '"' return $out; } - + // -------------------------------------------------------------------- /** @@ -221,7 +246,7 @@ function xml_from_result($query, $params = array()) { show_error('You must submit a valid result object'); } - + // Set our default values foreach (array('root' => 'root', 'element' => 'element', 'newline' => "\n", 'tab' => "\t") as $key => $val) { @@ -230,10 +255,10 @@ function xml_from_result($query, $params = array()) $params[$key] = $val; } } - + // Create variables for convenience extract($params); - + // Load the xml helper $CI =& get_instance(); $CI->load->helper('xml'); @@ -243,7 +268,7 @@ function xml_from_result($query, $params = array()) foreach ($query->result_array() as $row) { $xml .= $tab."<{$element}>".$newline; - + foreach ($row as $key => $val) { $xml .= $tab.$tab."<{$key}>".xml_convert($val)."".$newline; @@ -251,7 +276,7 @@ function xml_from_result($query, $params = array()) $xml .= $tab."".$newline; } $xml .= "".$newline; - + return $xml; } @@ -272,9 +297,9 @@ function backup($params = array()) { $params = array('tables' => $params); } - + // ------------------------------------------------------ - + // Set up our default preferences $prefs = array( 'tables' => array(), @@ -300,13 +325,13 @@ function backup($params = array()) // ------------------------------------------------------ - // Are we backing up a complete database or individual tables? + // Are we backing up a complete database or individual tables? // If no table names were submitted we'll fetch the entire table list if (count($prefs['tables']) == 0) { $prefs['tables'] = $this->db->list_tables(); } - + // ------------------------------------------------------ // Validate the format @@ -320,13 +345,13 @@ function backup($params = array()) // Is the encoder supported? If not, we'll either issue an // error or use plain text depending on the debug settings if (($prefs['format'] == 'gzip' AND ! @function_exists('gzencode')) - OR ($prefs['format'] == 'zip' AND ! @function_exists('gzcompress'))) + OR ($prefs['format'] == 'zip' AND ! @function_exists('gzcompress'))) { if ($this->db->db_debug) { return $this->db->display_error('db_unsuported_compression'); } - + $prefs['format'] = 'txt'; } @@ -340,7 +365,7 @@ function backup($params = array()) } // ------------------------------------------------------ - + // Was a Gzip file requested? if ($prefs['format'] == 'gzip') { @@ -348,7 +373,7 @@ function backup($params = array()) } // ------------------------------------------------------ - + // Was a text file requested? if ($prefs['format'] == 'txt') { @@ -357,7 +382,7 @@ function backup($params = array()) // ------------------------------------------------------ - // Was a Zip file requested? + // Was a Zip file requested? if ($prefs['format'] == 'zip') { // If they included the .zip file extension we'll remove it @@ -365,7 +390,7 @@ function backup($params = array()) { $prefs['filename'] = str_replace('.zip', '', $prefs['filename']); } - + // Tack on the ".sql" file extension if needed if ( ! preg_match("|.+?\.sql$|", $prefs['filename'])) { @@ -373,13 +398,13 @@ function backup($params = array()) } // Load the Zip class and output it - + $CI =& get_instance(); $CI->load->library('zip'); - $CI->zip->add_data($prefs['filename'], $this->_backup($prefs)); + $CI->zip->add_data($prefs['filename'], $this->_backup($prefs)); return $CI->zip->get_zip(); } - + } } diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php new file mode 100644 index 00000000..d0114041 --- /dev/null +++ b/system/database/drivers/cubrid/cubrid_driver.php @@ -0,0 +1,792 @@ +port == '') + { + $this->port = self::DEFAULT_PORT; + } + + $conn = cubrid_connect($this->hostname, $this->port, $this->database, $this->username, $this->password); + + if ($conn) + { + // Check if a user wants to run queries in dry, i.e. run the + // queries but not commit them. + if (isset($this->auto_commit) && ! $this->auto_commit) + { + cubrid_set_autocommit($conn, CUBRID_AUTOCOMMIT_FALSE); + } + else + { + cubrid_set_autocommit($conn, CUBRID_AUTOCOMMIT_TRUE); + $this->auto_commit = TRUE; + } + } + + return $conn; + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * In CUBRID persistent DB connection is supported natively in CUBRID + * engine which can be configured in the CUBRID Broker configuration + * file by setting the CCI_PCONNECT parameter to ON. In that case, all + * connections established between the client application and the + * server will become persistent. This is calling the same + * @cubrid_connect function will establish persisten connection + * considering that the CCI_PCONNECT is ON. + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + return $this->db_connect(); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + if (cubrid_ping($this->conn_id) === FALSE) + { + $this->conn_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + // In CUBRID there is no need to select a database as the database + // is chosen at the connection time. + // So, to determine if the database is "selected", all we have to + // do is ping the server and return that value. + return cubrid_ping($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + // In CUBRID, there is no need to set charset or collation. + // This is why returning true will allow the application continue + // its normal process. + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + // To obtain the CUBRID Server version, no need to run the SQL query. + // CUBRID PHP API provides a function to determin this value. + // This is why we also need to add 'cubrid' value to the list of + // $driver_version_exceptions array in DB_driver class in + // version() function. + return cubrid_get_server_info($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return resource + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + return @cubrid_query($sql, $this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + // No need to prepare + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; + + if (cubrid_get_autocommit($this->conn_id)) + { + cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_FALSE); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + cubrid_commit($this->conn_id); + + if ($this->auto_commit && ! cubrid_get_autocommit($this->conn_id)) + { + cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_TRUE); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + cubrid_rollback($this->conn_id); + + if ($this->auto_commit && ! cubrid_get_autocommit($this->conn_id)) + { + cubrid_set_autocommit($this->conn_id, CUBRID_AUTOCOMMIT_TRUE); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + if (function_exists('cubrid_real_escape_string') AND is_resource($this->conn_id)) + { + $str = cubrid_real_escape_string($str, $this->conn_id); + } + else + { + $str = addslashes($str); + } + + // escape LIKE condition wildcards + if ($like === TRUE) + { + $str = str_replace(array('%', '_'), array('\\%', '\\_'), $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return @cubrid_affected_rows($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @access public + * @return integer + */ + function insert_id() + { + return @cubrid_insert_id($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified table + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + { + return 0; + } + + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + + if ($query->num_rows() == 0) + { + return 0; + } + + $row = $query->row(); + $this->_reset_select(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * List table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + $sql = "SHOW TABLES"; + + if ($prefix_limit !== FALSE AND $this->dbprefix != '') + { + $sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%'"; + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access public + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + return "SHOW COLUMNS FROM ".$this->_protect_identifiers($table, TRUE, NULL, FALSE); + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "SELECT * FROM ".$table." LIMIT 1"; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + return cubrid_error($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + return cubrid_errno($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + if ($this->_escape_char == '') + { + return $item; + } + + foreach ($this->_reserved_identifiers as $id) + { + if (strpos($item, '.'.$id) !== FALSE) + { + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + } + + if (strpos($item, '.') !== FALSE) + { + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + } + else + { + $str = $this->_escape_char.$item.$this->_escape_char; + } + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return '('.implode(', ', $tables).')'; + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$table." (\"".implode('", "', $keys)."\") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + + /** + * Replace statement + * + * Generates a platform-specific replace string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _replace($table, $keys, $values) + { + return "REPLACE INTO ".$table." (\"".implode('", "', $keys)."\") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert_batch($table, $keys, $values) + { + return "INSERT INTO ".$table." (\"".implode('", "', $keys)."\") VALUES ".implode(', ', $values); + } + + // -------------------------------------------------------------------- + + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + { + foreach ($values as $key => $val) + { + $valstr[] = sprintf('"%s" = %s', $key, $val); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + + $sql .= $orderby.$limit; + + return $sql; + } + + // -------------------------------------------------------------------- + + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @return string + */ + function _update_batch($table, $values, $index, $where = NULL) + { + $ids = array(); + $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : ''; + + foreach ($values as $key => $val) + { + $ids[] = $val[$index]; + + foreach (array_keys($val) as $field) + { + if ($field != $index) + { + $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; + } + } + } + + $sql = "UPDATE ".$table." SET "; + $cases = ''; + + foreach ($final as $k => $v) + { + $cases .= $k.' = CASE '."\n"; + foreach ($v as $row) + { + $cases .= $row."\n"; + } + + $cases .= 'ELSE '.$k.' END, '; + } + + $sql .= substr($cases, 0, -2); + + $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; + + return $sql; + } + + // -------------------------------------------------------------------- + + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return "TRUNCATE ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where = array(), $like = array(), $limit = FALSE) + { + $conditions = ''; + + if (count($where) > 0 OR count($like) > 0) + { + $conditions = "\nWHERE "; + $conditions .= implode("\n", $this->ar_where); + + if (count($where) > 0 && count($like) > 0) + { + $conditions .= " AND "; + } + $conditions .= implode("\n", $like); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + if ($offset == 0) + { + $offset = ''; + } + else + { + $offset .= ", "; + } + + return $sql."LIMIT ".$offset.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + @cubrid_close($conn_id); + } + +} + + +/* End of file cubrid_driver.php */ +/* Location: ./system/database/drivers/cubrid/cubrid_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/cubrid/cubrid_forge.php b/system/database/drivers/cubrid/cubrid_forge.php new file mode 100644 index 00000000..bab03f74 --- /dev/null +++ b/system/database/drivers/cubrid/cubrid_forge.php @@ -0,0 +1,288 @@ +$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t\"" . $this->db->_protect_identifiers($field) . "\""; + + if (array_key_exists('NAME', $attributes)) + { + $sql .= ' '.$this->db->_protect_identifiers($attributes['NAME']).' '; + } + + if (array_key_exists('TYPE', $attributes)) + { + $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + switch ($attributes['TYPE']) + { + case 'decimal': + case 'float': + case 'numeric': + $sql .= '('.implode(',', $attributes['CONSTRAINT']).')'; + break; + case 'enum': // As of version 8.4.0 CUBRID does not support + // enum data type. + break; + case 'set': + $sql .= '("'.implode('","', $attributes['CONSTRAINT']).'")'; + break; + default: + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + } + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + //$sql .= ' UNSIGNED'; + // As of version 8.4.0 CUBRID does not support UNSIGNED INTEGER data type. + // Will be supported in the next release as a part of MySQL Compatibility. + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + + if (array_key_exists('UNIQUE', $attributes) && $attributes['UNIQUE'] === TRUE) + { + $sql .= ' UNIQUE'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access private + * @param string the table name + * @param mixed the fields + * @param mixed primary key(s) + * @param mixed key(s) + * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @return bool + */ + function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + { + $sql = 'CREATE TABLE '; + + if ($if_not_exists === TRUE) + { + //$sql .= 'IF NOT EXISTS '; + // As of version 8.4.0 CUBRID does not support this SQL syntax. + } + + $sql .= $this->db->_escape_identifiers($table)." ("; + + $sql .= $this->_process_fields($fields); + + // If there is a PK defined + if (count($primary_keys) > 0) + { + $key_name = "pk_" . $table . "_" . + $this->db->_protect_identifiers(implode('_', $primary_keys)); + + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tCONSTRAINT " . $key_name . " PRIMARY KEY(" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key_name = $this->db->_protect_identifiers(implode('_', $key)); + $key = $this->db->_protect_identifiers($key); + } + else + { + $key_name = $this->db->_protect_identifiers($key); + $key = array($key_name); + } + + $sql .= ",\n\tKEY \"{$key_name}\" (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n);"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * @access private + * @return string + */ + function _drop_table($table) + { + return "DROP TABLE IF EXISTS ".$this->db->_escape_identifiers($table); + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param array fields + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $fields, $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type "; + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql.$this->db->_protect_identifiers($fields); + } + + $sql .= $this->_process_fields($fields); + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + $sql = 'RENAME TABLE '.$this->db->_protect_identifiers($table_name)." AS ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + +} + +/* End of file cubrid_forge.php */ +/* Location: ./system/database/drivers/cubrid/cubrid_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/cubrid/cubrid_result.php b/system/database/drivers/cubrid/cubrid_result.php new file mode 100644 index 00000000..6f0c2b5f --- /dev/null +++ b/system/database/drivers/cubrid/cubrid_result.php @@ -0,0 +1,202 @@ +result_id); + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return @cubrid_num_fields($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + return cubrid_column_names($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $retval = array(); + + $tablePrimaryKeys = array(); + + while ($field = cubrid_fetch_field($this->result_id)) + { + $F = new stdClass(); + $F->name = $field->name; + $F->type = $field->type; + $F->default = $field->def; + $F->max_length = $field->max_length; + + // At this moment primary_key property is not returned when + // cubrid_fetch_field is called. The following code will + // provide a patch for it. primary_key property will be added + // in the next release. + + // TODO: later version of CUBRID will provide primary_key + // property. + // When PK is defined in CUBRID, an index is automatically + // created in the db_index system table in the form of + // pk_tblname_fieldname. So the following will count how many + // columns are there which satisfy this format. + // The query will search for exact single columns, thus + // compound PK is not supported. + $res = cubrid_query($this->conn_id, + "SELECT COUNT(*) FROM db_index WHERE class_name = '" . $field->table . + "' AND is_primary_key = 'YES' AND index_name = 'pk_" . + $field->table . "_" . $field->name . "'" + ); + + if ($res) + { + $row = cubrid_fetch_array($res, CUBRID_NUM); + $F->primary_key = ($row[0] > 0 ? 1 : null); + } + else + { + $F->primary_key = null; + } + + if (is_resource($res)) + { + cubrid_close_request($res); + $this->result_id = FALSE; + } + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if(is_resource($this->result_id) || + get_resource_type($this->result_id) == "Unknown" && + preg_match('/Resource id #/', strval($this->result_id))) + { + cubrid_close_request($this->result_id); + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + return cubrid_data_seek($this->result_id, $n); + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + return cubrid_fetch_assoc($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + return cubrid_fetch_object($this->result_id); + } + +} + + +/* End of file cubrid_result.php */ +/* Location: ./system/database/drivers/cubrid/cubrid_result.php */ \ No newline at end of file diff --git a/system/database/drivers/cubrid/cubrid_utility.php b/system/database/drivers/cubrid/cubrid_utility.php new file mode 100644 index 00000000..cd16d1e1 --- /dev/null +++ b/system/database/drivers/cubrid/cubrid_utility.php @@ -0,0 +1,108 @@ +conn_id) + { + return "SELECT '" . $this->database . "'"; + } + else + { + return FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Optimize table query + * + * Generates a platform-specific query so that a table can be optimized + * + * @access private + * @param string the table name + * @return object + * @link http://www.cubrid.org/manual/840/en/Optimize%20Database + */ + function _optimize_table($table) + { + // No SQL based support in CUBRID as of version 8.4.0. Database or + // table optimization can be performed using CUBRID Manager + // database administration tool. See the link above for more info. + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Repair table query + * + * Generates a platform-specific query so that a table can be repaired + * + * @access private + * @param string the table name + * @return object + * @link http://www.cubrid.org/manual/840/en/Checking%20Database%20Consistency + */ + function _repair_table($table) + { + // Not supported in CUBRID as of version 8.4.0. Database or + // table consistency can be checked using CUBRID Manager + // database administration tool. See the link above for more info. + return FALSE; + } + + // -------------------------------------------------------------------- + /** + * CUBRID Export + * + * @access private + * @param array Preferences + * @return mixed + */ + function _backup($params = array()) + { + // No SQL based support in CUBRID as of version 8.4.0. Database or + // table backup can be performed using CUBRID Manager + // database administration tool. + return $this->db->display_error('db_unsuported_feature'); + } +} + +/* End of file cubrid_utility.php */ +/* Location: ./system/database/drivers/cubrid/cubrid_utility.php */ \ No newline at end of file diff --git a/system/codeigniter/index.html b/system/database/drivers/cubrid/index.html similarity index 100% rename from system/codeigniter/index.html rename to system/database/drivers/cubrid/index.html diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php index 97ac971b..b39bd936 100644 --- a/system/database/drivers/mssql/mssql_driver.php +++ b/system/database/drivers/mssql/mssql_driver.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -31,14 +31,14 @@ class CI_DB_mssql_driver extends CI_DB { var $dbdriver = 'mssql'; - + // The character used for escaping var $_escape_char = ''; // clause and character used for LIKE escape sequences var $_like_escape_str = " ESCAPE '%s' "; var $_like_escape_chr = '!'; - + /** * The syntax to count rows is slightly different across different * database engines, so this string appears in each driver and is @@ -52,7 +52,7 @@ class CI_DB_mssql_driver extends CI_DB { * * @access private called by the base class * @return resource - */ + */ function db_connect() { if ($this->port != '') @@ -62,7 +62,7 @@ function db_connect() return @mssql_connect($this->hostname, $this->username, $this->password); } - + // -------------------------------------------------------------------- /** @@ -70,7 +70,7 @@ function db_connect() * * @access private called by the base class * @return resource - */ + */ function db_pconnect() { if ($this->port != '') @@ -80,9 +80,9 @@ function db_pconnect() return @mssql_pconnect($this->hostname, $this->username, $this->password); } - + // -------------------------------------------------------------------- - + /** * Reconnect * @@ -98,13 +98,13 @@ function reconnect() } // -------------------------------------------------------------------- - + /** * Select the database * * @access private called by the base class * @return resource - */ + */ function db_select() { // Note: The brackets are required in the event that the DB name @@ -113,7 +113,7 @@ function db_select() } // -------------------------------------------------------------------- - + /** * Set client character set * @@ -129,20 +129,20 @@ function db_set_charset($charset, $collation) } // -------------------------------------------------------------------- - + /** * Execute the query * * @access private called by the base class * @param string an SQL query * @return resource - */ + */ function _execute($sql) { $sql = $this->_prep_query($sql); return @mssql_query($sql, $this->conn_id); } - + // -------------------------------------------------------------------- /** @@ -153,7 +153,7 @@ function _execute($sql) * @access private called by execute() * @param string an SQL query * @return string - */ + */ function _prep_query($sql) { return $sql; @@ -165,15 +165,15 @@ function _prep_query($sql) * Begin Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_begin($test_mode = FALSE) { if ( ! $this->trans_enabled) { return TRUE; } - + // When transactions are nested we only begin/commit/rollback the outermost ones if ($this->_trans_depth > 0) { @@ -195,8 +195,8 @@ function trans_begin($test_mode = FALSE) * Commit Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_commit() { if ( ! $this->trans_enabled) @@ -220,8 +220,8 @@ function trans_commit() * Rollback Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_rollback() { if ( ! $this->trans_enabled) @@ -238,7 +238,7 @@ function trans_rollback() $this->simple_query('ROLLBACK TRAN'); return TRUE; } - + // -------------------------------------------------------------------- /** @@ -253,31 +253,30 @@ function escape_str($str, $like = FALSE) { if (is_array($str)) { - foreach($str as $key => $val) - { + foreach ($str as $key => $val) + { $str[$key] = $this->escape_str($val, $like); - } - - return $str; - } - - // Access the CI object - $CI =& get_instance(); - + } + + return $str; + } + // Escape single quotes - $str = str_replace("'", "''", $CI->input->_remove_invisible_characters($str)); - + $str = str_replace("'", "''", remove_invisible_characters($str)); + // escape LIKE condition wildcards if ($like === TRUE) { - $str = str_replace( array('%', '_', $this->_like_escape_chr), - array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), - $str); + $str = str_replace( + array($this->_like_escape_chr, '%', '_'), + array($this->_like_escape_chr.$this->_like_escape_chr, $this->_like_escape_chr.'%', $this->_like_escape_chr.'_'), + $str + ); } - + return $str; } - + // -------------------------------------------------------------------- /** @@ -290,7 +289,7 @@ function affected_rows() { return @mssql_rows_affected($this->conn_id); } - + // -------------------------------------------------------------------- /** @@ -315,7 +314,7 @@ function insert_id() /** * Parse major version * - * Grabs the major version number from the + * Grabs the major version number from the * database server version string passed in. * * @access private @@ -368,6 +367,7 @@ function count_all($table = '') } $row = $query->row(); + $this->_reset_select(); return (int) $row->numrows; } @@ -385,14 +385,14 @@ function count_all($table = '') function _list_tables($prefix_limit = FALSE) { $sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name"; - + // for future compatibility if ($prefix_limit !== FALSE AND $this->dbprefix != '') { - //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_char); + //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); return FALSE; // not currently supported } - + return $sql; } @@ -409,7 +409,7 @@ function _list_tables($prefix_limit = FALSE) */ function _list_columns($table = '') { - return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$table."'"; + return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$table."'"; } // -------------------------------------------------------------------- @@ -425,7 +425,7 @@ function _list_columns($table = '') */ function _field_data($table) { - return "SELECT TOP 1 * FROM ".$table; + return "SELECT TOP 1 * FROM ".$table; } // -------------------------------------------------------------------- @@ -440,7 +440,7 @@ function _error_message() { return mssql_get_last_message(); } - + // -------------------------------------------------------------------- /** @@ -477,26 +477,26 @@ function _escape_identifiers($item) { if (strpos($item, '.'.$id) !== FALSE) { - $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); - + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); - } + } } if (strpos($item, '.') !== FALSE) { - $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; } else { $str = $this->_escape_char.$item.$this->_escape_char; } - + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); } - + // -------------------------------------------------------------------- /** @@ -515,12 +515,12 @@ function _from_tables($tables) { $tables = array($tables); } - + return implode(', ', $tables); } // -------------------------------------------------------------------- - + /** * Insert statement * @@ -533,10 +533,10 @@ function _from_tables($tables) * @return string */ function _insert($table, $keys, $values) - { + { return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; } - + // -------------------------------------------------------------------- /** @@ -554,25 +554,25 @@ function _insert($table, $keys, $values) */ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) { - foreach($values as $key => $val) + foreach ($values as $key => $val) { $valstr[] = $key." = ".$val; } - + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; - + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; $sql .= $orderby.$limit; - + return $sql; } - + // -------------------------------------------------------------------- /** @@ -585,12 +585,12 @@ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) * @access public * @param string the table name * @return string - */ + */ function _truncate($table) { return "TRUNCATE ".$table; } - + // -------------------------------------------------------------------- /** @@ -603,7 +603,7 @@ function _truncate($table) * @param array the where clause * @param string the limit clause * @return string - */ + */ function _delete($table, $where = array(), $like = array(), $limit = FALSE) { $conditions = ''; @@ -621,7 +621,7 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) } $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + return "DELETE FROM ".$table.$conditions.$limit; } @@ -641,8 +641,8 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) function _limit($sql, $limit, $offset) { $i = $limit + $offset; - - return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$i.' ', $sql); + + return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$i.' ', $sql); } // -------------------------------------------------------------------- @@ -657,7 +657,7 @@ function _limit($sql, $limit, $offset) function _close($conn_id) { @mssql_close($conn_id); - } + } } diff --git a/system/database/drivers/mssql/mssql_forge.php b/system/database/drivers/mssql/mssql_forge.php index 632b4d90..70b20ecf 100644 --- a/system/database/drivers/mssql/mssql_forge.php +++ b/system/database/drivers/mssql/mssql_forge.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -79,12 +79,12 @@ function _drop_table($table) function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) { $sql = 'CREATE TABLE '; - + if ($if_not_exists === TRUE) { $sql .= 'IF NOT EXISTS '; } - + $sql .= $this->db->_escape_identifiers($table)." ("; $current_field_count = 0; @@ -100,41 +100,41 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) else { $attributes = array_change_key_case($attributes, CASE_UPPER); - + $sql .= "\n\t".$this->db->_protect_identifiers($field); - + $sql .= ' '.$attributes['TYPE']; - + if (array_key_exists('CONSTRAINT', $attributes)) { $sql .= '('.$attributes['CONSTRAINT'].')'; } - + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) { $sql .= ' UNSIGNED'; } - + if (array_key_exists('DEFAULT', $attributes)) { $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; } - + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) { $sql .= ' NULL'; } else { - $sql .= ' NOT NULL'; + $sql .= ' NOT NULL'; } - + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) { $sql .= ' AUTO_INCREMENT'; } } - + // don't add a comma on the end of the last field if (++$current_field_count < count($fields)) { @@ -147,24 +147,24 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) $primary_keys = $this->db->_protect_identifiers($primary_keys); $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; } - + if (is_array($keys) && count($keys) > 0) { foreach ($keys as $key) { if (is_array($key)) { - $key = $this->db->_protect_identifiers($key); + $key = $this->db->_protect_identifiers($key); } else { $key = array($this->db->_protect_identifiers($key)); } - + $sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")"; } } - + $sql .= "\n)"; return $sql; @@ -218,9 +218,9 @@ function _alter_table($alter_type, $table, $column_name, $column_definition = '' { $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); } - + return $sql; - + } // -------------------------------------------------------------------- diff --git a/system/database/drivers/mssql/mssql_result.php b/system/database/drivers/mssql/mssql_result.php index a56a3a9e..2897ca5a 100644 --- a/system/database/drivers/mssql/mssql_result.php +++ b/system/database/drivers/mssql/mssql_result.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -25,7 +25,7 @@ * @link http://codeigniter.com/user_guide/database/ */ class CI_DB_mssql_result extends CI_DB_result { - + /** * Number of rows in the result set * @@ -36,7 +36,7 @@ function num_rows() { return @mssql_num_rows($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -67,7 +67,7 @@ function list_fields() { $field_names[] = $field->name; } - + return $field_names; } @@ -85,17 +85,17 @@ function field_data() { $retval = array(); while ($field = mssql_fetch_field($this->result_id)) - { - $F = new stdClass(); - $F->name = $field->name; - $F->type = $field->type; + { + $F = new stdClass(); + $F->name = $field->name; + $F->type = $field->type; $F->max_length = $field->max_length; $F->primary_key = 0; $F->default = ''; - + $retval[] = $F; } - + return $retval; } @@ -105,7 +105,7 @@ function field_data() * Free the result * * @return null - */ + */ function free_result() { if (is_resource($this->result_id)) @@ -131,7 +131,7 @@ function _data_seek($n = 0) { return mssql_data_seek($this->result_id, $n); } - + // -------------------------------------------------------------------- /** @@ -146,7 +146,7 @@ function _fetch_assoc() { return mssql_fetch_assoc($this->result_id); } - + // -------------------------------------------------------------------- /** diff --git a/system/database/drivers/mssql/mssql_utility.php b/system/database/drivers/mssql/mssql_utility.php index 9fa257a6..48ecbc72 100644 --- a/system/database/drivers/mssql/mssql_utility.php +++ b/system/database/drivers/mssql/mssql_utility.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -52,7 +52,7 @@ function _optimize_table($table) } // -------------------------------------------------------------------- - + /** * Repair table query * @@ -82,42 +82,7 @@ function _backup($params = array()) return $this->db->display_error('db_unsuported_feature'); } - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access private - * @param string the database name - * @return bool - */ - function _create_database($name) - { - return "CREATE DATABASE ".$name; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - return "DROP DATABASE ".$name; - } - } - /* End of file mssql_utility.php */ /* Location: ./system/database/drivers/mssql/mssql_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php index fe185980..f87cfea4 100644 --- a/system/database/drivers/mysql/mysql_driver.php +++ b/system/database/drivers/mysql/mysql_driver.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -43,9 +43,9 @@ class CI_DB_mysql_driver extends CI_DB { * Whether to use the MySQL "delete hack" which allows the number * of affected rows to be shown. Uses a preg_replace when enabled, * adding a bit more processing to all queries. - */ + */ var $delete_hack = TRUE; - + /** * The syntax to count rows is slightly different across different * database engines, so this string appears in each driver and is @@ -54,22 +54,25 @@ class CI_DB_mysql_driver extends CI_DB { var $_count_string = 'SELECT COUNT(*) AS '; var $_random_keyword = ' RAND()'; // database specific random keyword + // whether SET NAMES must be used to set the character set + var $use_set_names; + /** * Non-persistent database connection * * @access private called by the base class * @return resource - */ + */ function db_connect() { if ($this->port != '') { $this->hostname .= ':'.$this->port; } - + return @mysql_connect($this->hostname, $this->username, $this->password, TRUE); } - + // -------------------------------------------------------------------- /** @@ -77,7 +80,7 @@ function db_connect() * * @access private called by the base class * @return resource - */ + */ function db_pconnect() { if ($this->port != '') @@ -87,7 +90,7 @@ function db_pconnect() return @mysql_pconnect($this->hostname, $this->username, $this->password); } - + // -------------------------------------------------------------------- /** @@ -108,13 +111,13 @@ function reconnect() } // -------------------------------------------------------------------- - + /** * Select the database * * @access private called by the base class * @return resource - */ + */ function db_select() { return @mysql_select_db($this->database, $this->conn_id); @@ -132,11 +135,24 @@ function db_select() */ function db_set_charset($charset, $collation) { - return @mysql_query("SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'", $this->conn_id); + if ( ! isset($this->use_set_names)) + { + // mysql_set_charset() requires PHP >= 5.2.3 and MySQL >= 5.0.7, use SET NAMES as fallback + $this->use_set_names = (version_compare(PHP_VERSION, '5.2.3', '>=') && version_compare(mysql_get_server_info(), '5.0.7', '>=')) ? FALSE : TRUE; + } + + if ($this->use_set_names === TRUE) + { + return @mysql_query("SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'", $this->conn_id); + } + else + { + return @mysql_set_charset($charset, $this->conn_id); + } } // -------------------------------------------------------------------- - + /** * Version number query string * @@ -156,13 +172,13 @@ function _version() * @access private called by the base class * @param string an SQL query * @return resource - */ + */ function _execute($sql) { $sql = $this->_prep_query($sql); return @mysql_query($sql, $this->conn_id); } - + // -------------------------------------------------------------------- /** @@ -173,7 +189,7 @@ function _execute($sql) * @access private called by execute() * @param string an SQL query * @return string - */ + */ function _prep_query($sql) { // "DELETE FROM TABLE" returns 0 affected rows This hack modifies @@ -185,7 +201,7 @@ function _prep_query($sql) $sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $sql); } } - + return $sql; } @@ -195,15 +211,15 @@ function _prep_query($sql) * Begin Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_begin($test_mode = FALSE) { if ( ! $this->trans_enabled) { return TRUE; } - + // When transactions are nested we only begin/commit/rollback the outermost ones if ($this->_trans_depth > 0) { @@ -214,7 +230,7 @@ function trans_begin($test_mode = FALSE) // If the $test_mode flag is set to TRUE transactions will be rolled back // even if the queries produce a successful result. $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; - + $this->simple_query('SET AUTOCOMMIT=0'); $this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK return TRUE; @@ -226,8 +242,8 @@ function trans_begin($test_mode = FALSE) * Commit Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_commit() { if ( ! $this->trans_enabled) @@ -252,8 +268,8 @@ function trans_commit() * Rollback Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_rollback() { if ( ! $this->trans_enabled) @@ -271,7 +287,7 @@ function trans_rollback() $this->simple_query('SET AUTOCOMMIT=1'); return TRUE; } - + // -------------------------------------------------------------------- /** @@ -282,15 +298,15 @@ function trans_rollback() * @param bool whether or not the string will be used in a LIKE condition * @return string */ - function escape_str($str, $like = FALSE) - { + function escape_str($str, $like = FALSE) + { if (is_array($str)) { - foreach($str as $key => $val) + foreach ($str as $key => $val) { $str[$key] = $this->escape_str($val, $like); } - + return $str; } @@ -306,16 +322,16 @@ function escape_str($str, $like = FALSE) { $str = addslashes($str); } - + // escape LIKE condition wildcards if ($like === TRUE) { $str = str_replace(array('%', '_'), array('\\%', '\\_'), $str); } - + return $str; } - + // -------------------------------------------------------------------- /** @@ -328,7 +344,7 @@ function affected_rows() { return @mysql_affected_rows($this->conn_id); } - + // -------------------------------------------------------------------- /** @@ -360,7 +376,7 @@ function count_all($table = '') { return 0; } - + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); if ($query->num_rows() == 0) @@ -369,6 +385,7 @@ function count_all($table = '') } $row = $query->row(); + $this->_reset_select(); return (int) $row->numrows; } @@ -385,7 +402,7 @@ function count_all($table = '') */ function _list_tables($prefix_limit = FALSE) { - $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char; + $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char; if ($prefix_limit !== FALSE AND $this->dbprefix != '') { @@ -394,7 +411,7 @@ function _list_tables($prefix_limit = FALSE) return $sql; } - + // -------------------------------------------------------------------- /** @@ -408,7 +425,7 @@ function _list_tables($prefix_limit = FALSE) */ function _list_columns($table = '') { - return "SHOW COLUMNS FROM ".$table; + return "SHOW COLUMNS FROM ".$this->_protect_identifiers($table, TRUE, NULL, FALSE); } // -------------------------------------------------------------------- @@ -424,7 +441,7 @@ function _list_columns($table = '') */ function _field_data($table) { - return "SELECT * FROM ".$table." LIMIT 1"; + return "DESCRIBE ".$table; } // -------------------------------------------------------------------- @@ -439,7 +456,7 @@ function _error_message() { return mysql_error($this->conn_id); } - + // -------------------------------------------------------------------- /** @@ -475,26 +492,26 @@ function _escape_identifiers($item) { if (strpos($item, '.'.$id) !== FALSE) { - $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); - + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); - } + } } - + if (strpos($item, '.') !== FALSE) { - $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; } else { $str = $this->_escape_char.$item.$this->_escape_char; } - + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); } - + // -------------------------------------------------------------------- /** @@ -513,12 +530,12 @@ function _from_tables($tables) { $tables = array($tables); } - + return '('.implode(', ', $tables).')'; } // -------------------------------------------------------------------- - + /** * Insert statement * @@ -531,12 +548,50 @@ function _from_tables($tables) * @return string */ function _insert($table, $keys, $values) - { + { return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; } - + + // -------------------------------------------------------------------- + + + /** + * Replace statement + * + * Generates a platform-specific replace string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _replace($table, $keys, $values) + { + return "REPLACE INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + // -------------------------------------------------------------------- + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert_batch($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values); + } + + // -------------------------------------------------------------------- + + /** * Update statement * @@ -552,26 +607,80 @@ function _insert($table, $keys, $values) */ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) { - foreach($values as $key => $val) + foreach ($values as $key => $val) { - $valstr[] = $key." = ".$val; + $valstr[] = $key . ' = ' . $val; } - + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; - + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; $sql .= $orderby.$limit; - + + return $sql; + } + + // -------------------------------------------------------------------- + + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @return string + */ + function _update_batch($table, $values, $index, $where = NULL) + { + $ids = array(); + $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : ''; + + foreach ($values as $key => $val) + { + $ids[] = $val[$index]; + + foreach (array_keys($val) as $field) + { + if ($field != $index) + { + $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; + } + } + } + + $sql = "UPDATE ".$table." SET "; + $cases = ''; + + foreach ($final as $k => $v) + { + $cases .= $k.' = CASE '."\n"; + foreach ($v as $row) + { + $cases .= $row."\n"; + } + + $cases .= 'ELSE '.$k.' END, '; + } + + $sql .= substr($cases, 0, -2); + + $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; + return $sql; } // -------------------------------------------------------------------- + /** * Truncate statement * @@ -582,12 +691,12 @@ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) * @access public * @param string the table name * @return string - */ + */ function _truncate($table) { return "TRUNCATE ".$table; } - + // -------------------------------------------------------------------- /** @@ -600,7 +709,7 @@ function _truncate($table) * @param array the where clause * @param string the limit clause * @return string - */ + */ function _delete($table, $where = array(), $like = array(), $limit = FALSE) { $conditions = ''; @@ -618,7 +727,7 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) } $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + return "DELETE FROM ".$table.$conditions.$limit; } @@ -636,7 +745,7 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) * @return string */ function _limit($sql, $limit, $offset) - { + { if ($offset == 0) { $offset = ''; @@ -645,7 +754,7 @@ function _limit($sql, $limit, $offset) { $offset .= ", "; } - + return $sql."LIMIT ".$offset.$limit; } @@ -662,7 +771,7 @@ function _close($conn_id) { @mysql_close($conn_id); } - + } diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php index d343b36a..c1cae136 100644 --- a/system/database/drivers/mysql/mysql_forge.php +++ b/system/database/drivers/mysql/mysql_forge.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -23,7 +23,7 @@ * @link http://codeigniter.com/user_guide/database/ */ class CI_DB_mysql_forge extends CI_DB_forge { - + /** * Create database * @@ -76,52 +76,71 @@ function _process_fields($fields) else { $attributes = array_change_key_case($attributes, CASE_UPPER); - + $sql .= "\n\t".$this->db->_protect_identifiers($field); if (array_key_exists('NAME', $attributes)) { $sql .= ' '.$this->db->_protect_identifiers($attributes['NAME']).' '; } - + if (array_key_exists('TYPE', $attributes)) { $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + switch ($attributes['TYPE']) + { + case 'decimal': + case 'float': + case 'numeric': + $sql .= '('.implode(',', $attributes['CONSTRAINT']).')'; + break; + + case 'enum': + case 'set': + $sql .= '("'.implode('","', $attributes['CONSTRAINT']).'")'; + break; + + default: + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + } } - - if (array_key_exists('CONSTRAINT', $attributes)) - { - $sql .= '('.$attributes['CONSTRAINT'].')'; - } - + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) { $sql .= ' UNSIGNED'; } - + if (array_key_exists('DEFAULT', $attributes)) { $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; } - - if (array_key_exists('NULL', $attributes)) + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) { - $sql .= ($attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL'; + $sql .= ' NULL'; } - + else + { + $sql .= ' NOT NULL'; + } + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) { $sql .= ' AUTO_INCREMENT'; } } - + // don't add a comma on the end of the last field if (++$current_field_count < count($fields)) { $sql .= ','; } } - + return $sql; } @@ -141,12 +160,12 @@ function _process_fields($fields) function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) { $sql = 'CREATE TABLE '; - + if ($if_not_exists === TRUE) { $sql .= 'IF NOT EXISTS '; } - + $sql .= $this->db->_escape_identifiers($table)." ("; $sql .= $this->_process_fields($fields); @@ -165,14 +184,14 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) if (is_array($key)) { $key_name = $this->db->_protect_identifiers(implode('_', $key)); - $key = $this->db->_protect_identifiers($key); + $key = $this->db->_protect_identifiers($key); } else { $key_name = $this->db->_protect_identifiers($key); $key = array($key_name); } - + $sql .= ",\n\tKEY {$key_name} (" . implode(', ', $key) . ")"; } } @@ -226,7 +245,7 @@ function _alter_table($alter_type, $table, $fields, $after_field = '') { $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); } - + return $sql; } diff --git a/system/database/drivers/mysql/mysql_result.php b/system/database/drivers/mysql/mysql_result.php index 2e955070..e1a6e93c 100644 --- a/system/database/drivers/mysql/mysql_result.php +++ b/system/database/drivers/mysql/mysql_result.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -36,7 +36,7 @@ function num_rows() { return @mysql_num_rows($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -49,7 +49,7 @@ function num_fields() { return @mysql_num_fields($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -67,7 +67,7 @@ function list_fields() { $field_names[] = $field->name; } - + return $field_names; } @@ -84,28 +84,33 @@ function list_fields() function field_data() { $retval = array(); - while ($field = mysql_fetch_field($this->result_id)) - { + while ($field = mysql_fetch_object($this->result_id)) + { + preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field->Type, $matches); + + $type = (array_key_exists(1, $matches)) ? $matches[1] : NULL; + $length = (array_key_exists(2, $matches)) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL; + $F = new stdClass(); - $F->name = $field->name; - $F->type = $field->type; - $F->default = $field->def; - $F->max_length = $field->max_length; - $F->primary_key = $field->primary_key; - + $F->name = $field->Field; + $F->type = $type; + $F->default = $field->Default; + $F->max_length = $length; + $F->primary_key = ( $field->Key == 'PRI' ? 1 : 0 ); + $retval[] = $F; } - + return $retval; } - + // -------------------------------------------------------------------- /** * Free the result * * @return null - */ + */ function free_result() { if (is_resource($this->result_id)) @@ -146,7 +151,7 @@ function _fetch_assoc() { return mysql_fetch_assoc($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -161,7 +166,7 @@ function _fetch_object() { return mysql_fetch_object($this->result_id); } - + } diff --git a/system/database/drivers/mysql/mysql_utility.php b/system/database/drivers/mysql/mysql_utility.php index 2c8b264c..48c4d631 100644 --- a/system/database/drivers/mysql/mysql_utility.php +++ b/system/database/drivers/mysql/mysql_utility.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -84,7 +84,7 @@ function _backup($params = array()) // Extract the prefs for simplicity extract($params); - + // Build the output $output = ''; foreach ((array)$tables as $table) @@ -96,32 +96,32 @@ function _backup($params = array()) } // Get the table schema - $query = $this->db->query("SHOW CREATE TABLE `".$this->db->database.'`.'.$table); - + $query = $this->db->query("SHOW CREATE TABLE `".$this->db->database.'`.`'.$table.'`'); + // No result means the table name was invalid if ($query === FALSE) { continue; } - + // Write out the table schema $output .= '#'.$newline.'# TABLE STRUCTURE FOR: '.$table.$newline.'#'.$newline.$newline; - if ($add_drop == TRUE) - { + if ($add_drop == TRUE) + { $output .= 'DROP TABLE IF EXISTS '.$table.';'.$newline.$newline; } - + $i = 0; $result = $query->result_array(); foreach ($result[0] as $val) { if ($i++ % 2) - { + { $output .= $val.';'.$newline.$newline; } } - + // If inserts are not needed we're done... if ($add_insert == FALSE) { @@ -130,16 +130,16 @@ function _backup($params = array()) // Grab all the data from the current table $query = $this->db->query("SELECT * FROM $table"); - + if ($query->num_rows() == 0) { continue; } - + // Fetch the field names and determine if the field is an // integer type. We use this info to decide whether to // surround the data with quotes or not - + $i = 0; $field_str = ''; $is_int = array(); @@ -148,24 +148,24 @@ function _backup($params = array()) // Most versions of MySQL store timestamp as a string $is_int[$i] = (in_array( strtolower(mysql_field_type($query->result_id, $i)), - array('tinyint', 'smallint', 'mediumint', 'int', 'bigint'), //, 'timestamp'), + array('tinyint', 'smallint', 'mediumint', 'int', 'bigint'), //, 'timestamp'), TRUE) ) ? TRUE : FALSE; - + // Create a string of field names $field_str .= '`'.$field->name.'`, '; $i++; } - + // Trim off the end comma $field_str = preg_replace( "/, $/" , "" , $field_str); - - + + // Build the insert string foreach ($query->result_array() as $row) { $val_str = ''; - + $i = 0; foreach ($row as $v) { @@ -184,61 +184,26 @@ function _backup($params = array()) else { $val_str .= $v; - } - } - + } + } + // Append a comma $val_str .= ', '; $i++; } - + // Remove the comma at the end of the string $val_str = preg_replace( "/, $/" , "" , $val_str); - + // Build the INSERT string $output .= 'INSERT INTO '.$table.' ('.$field_str.') VALUES ('.$val_str.');'.$newline; } - + $output .= $newline.$newline; } return $output; } - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access private - * @param string the database name - * @return bool - */ - function _create_database($name) - { - return "CREATE DATABASE ".$name; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - return "DROP DATABASE ".$name; - } - } /* End of file mysql_utility.php */ diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php index 488b074a..d3200f32 100644 --- a/system/database/drivers/mysqli/mysqli_driver.php +++ b/system/database/drivers/mysqli/mysqli_driver.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -31,7 +31,7 @@ class CI_DB_mysqli_driver extends CI_DB { var $dbdriver = 'mysqli'; - + // The character used for escaping var $_escape_char = '`'; @@ -51,9 +51,12 @@ class CI_DB_mysqli_driver extends CI_DB { * Whether to use the MySQL "delete hack" which allows the number * of affected rows to be shown. Uses a preg_replace when enabled, * adding a bit more processing to all queries. - */ + */ var $delete_hack = TRUE; + // whether SET NAMES must be used to set the character set + var $use_set_names; + // -------------------------------------------------------------------- /** @@ -61,12 +64,12 @@ class CI_DB_mysqli_driver extends CI_DB { * * @access private called by the base class * @return resource - */ + */ function db_connect() { if ($this->port != '') { - return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database, $this->port); + return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database, $this->port); } else { @@ -82,12 +85,12 @@ function db_connect() * * @access private called by the base class * @return resource - */ + */ function db_pconnect() { return $this->db_connect(); } - + // -------------------------------------------------------------------- /** @@ -114,7 +117,7 @@ function reconnect() * * @access private called by the base class * @return resource - */ + */ function db_select() { return @mysqli_select_db($this->conn_id, $this->database); @@ -132,11 +135,24 @@ function db_select() */ function _db_set_charset($charset, $collation) { - return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'"); + if ( ! isset($this->use_set_names)) + { + // mysqli_set_charset() requires MySQL >= 5.0.7, use SET NAMES as fallback + $this->use_set_names = (version_compare(mysqli_get_server_info($this->conn_id), '5.0.7', '>=')) ? FALSE : TRUE; + } + + if ($this->use_set_names === TRUE) + { + return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'"); + } + else + { + return @mysqli_set_charset($this->conn_id, $charset); + } } // -------------------------------------------------------------------- - + /** * Version number query string * @@ -156,14 +172,14 @@ function _version() * @access private called by the base class * @param string an SQL query * @return resource - */ + */ function _execute($sql) { - $sql = $this->_prep_query($sql); + $sql = $this->_prep_query($sql); $result = @mysqli_query($this->conn_id, $sql); return $result; } - + // -------------------------------------------------------------------- /** @@ -174,7 +190,7 @@ function _execute($sql) * @access private called by execute() * @param string an SQL query * @return string - */ + */ function _prep_query($sql) { // "DELETE FROM TABLE" returns 0 affected rows This hack modifies @@ -186,7 +202,7 @@ function _prep_query($sql) $sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $sql); } } - + return $sql; } @@ -196,15 +212,15 @@ function _prep_query($sql) * Begin Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_begin($test_mode = FALSE) { if ( ! $this->trans_enabled) { return TRUE; } - + // When transactions are nested we only begin/commit/rollback the outermost ones if ($this->_trans_depth > 0) { @@ -227,8 +243,8 @@ function trans_begin($test_mode = FALSE) * Commit Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_commit() { if ( ! $this->trans_enabled) @@ -253,8 +269,8 @@ function trans_commit() * Rollback Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_rollback() { if ( ! $this->trans_enabled) @@ -283,17 +299,17 @@ function trans_rollback() * @param bool whether or not the string will be used in a LIKE condition * @return string */ - function escape_str($str, $like = FALSE) + function escape_str($str, $like = FALSE) { if (is_array($str)) { - foreach($str as $key => $val) - { + foreach ($str as $key => $val) + { $str[$key] = $this->escape_str($val, $like); - } - - return $str; - } + } + + return $str; + } if (function_exists('mysqli_real_escape_string') AND is_object($this->conn_id)) { @@ -307,16 +323,16 @@ function escape_str($str, $like = FALSE) { $str = addslashes($str); } - + // escape LIKE condition wildcards if ($like === TRUE) { $str = str_replace(array('%', '_'), array('\\%', '\\_'), $str); } - + return $str; } - + // -------------------------------------------------------------------- /** @@ -329,7 +345,7 @@ function affected_rows() { return @mysqli_affected_rows($this->conn_id); } - + // -------------------------------------------------------------------- /** @@ -370,6 +386,7 @@ function count_all($table = '') } $row = $query->row(); + $this->_reset_select(); return (int) $row->numrows; } @@ -386,13 +403,13 @@ function count_all($table = '') */ function _list_tables($prefix_limit = FALSE) { - $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char; - + $sql = "SHOW TABLES FROM ".$this->_escape_char.$this->database.$this->_escape_char; + if ($prefix_limit !== FALSE AND $this->dbprefix != '') { $sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%'"; } - + return $sql; } @@ -409,7 +426,7 @@ function _list_tables($prefix_limit = FALSE) */ function _list_columns($table = '') { - return "SHOW COLUMNS FROM ".$table; + return "SHOW COLUMNS FROM ".$this->_protect_identifiers($table, TRUE, NULL, FALSE); } // -------------------------------------------------------------------- @@ -425,7 +442,7 @@ function _list_columns($table = '') */ function _field_data($table) { - return "SELECT * FROM ".$table." LIMIT 1"; + return "DESCRIBE ".$table; } // -------------------------------------------------------------------- @@ -440,7 +457,7 @@ function _error_message() { return mysqli_error($this->conn_id); } - + // -------------------------------------------------------------------- /** @@ -471,31 +488,31 @@ function _escape_identifiers($item) { return $item; } - + foreach ($this->_reserved_identifiers as $id) { if (strpos($item, '.'.$id) !== FALSE) { - $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); - + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); - } + } } - + if (strpos($item, '.') !== FALSE) { - $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; } else { $str = $this->_escape_char.$item.$this->_escape_char; } - + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); } - + // -------------------------------------------------------------------- /** @@ -514,12 +531,12 @@ function _from_tables($tables) { $tables = array($tables); } - + return '('.implode(', ', $tables).')'; } // -------------------------------------------------------------------- - + /** * Insert statement * @@ -532,9 +549,46 @@ function _from_tables($tables) * @return string */ function _insert($table, $keys, $values) - { + { return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; } + + // -------------------------------------------------------------------- + + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert_batch($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values); + } + + // -------------------------------------------------------------------- + + + /** + * Replace statement + * + * Generates a platform-specific replace string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _replace($table, $keys, $values) + { + return "REPLACE INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } // -------------------------------------------------------------------- @@ -553,25 +607,76 @@ function _insert($table, $keys, $values) */ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) { - foreach($values as $key => $val) + foreach ($values as $key => $val) { $valstr[] = $key." = ".$val; } - + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; - + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); - + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; - + $sql .= $orderby.$limit; - + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @return string + */ + function _update_batch($table, $values, $index, $where = NULL) + { + $ids = array(); + $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : ''; + + foreach ($values as $key => $val) + { + $ids[] = $val[$index]; + + foreach (array_keys($val) as $field) + { + if ($field != $index) + { + $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; + } + } + } + + $sql = "UPDATE ".$table." SET "; + $cases = ''; + + foreach ($final as $k => $v) + { + $cases .= $k.' = CASE '."\n"; + foreach ($v as $row) + { + $cases .= $row."\n"; + } + + $cases .= 'ELSE '.$k.' END, '; + } + + $sql .= substr($cases, 0, -2); + + $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; + return $sql; } - // -------------------------------------------------------------------- /** @@ -584,12 +689,12 @@ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) * @access public * @param string the table name * @return string - */ + */ function _truncate($table) { return "TRUNCATE ".$table; } - + // -------------------------------------------------------------------- /** @@ -602,7 +707,7 @@ function _truncate($table) * @param array the where clause * @param string the limit clause * @return string - */ + */ function _delete($table, $where = array(), $like = array(), $limit = FALSE) { $conditions = ''; @@ -620,7 +725,7 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) } $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + return "DELETE FROM ".$table.$conditions.$limit; } @@ -638,14 +743,14 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) * @return string */ function _limit($sql, $limit, $offset) - { + { $sql .= "LIMIT ".$limit; - + if ($offset > 0) { $sql .= " OFFSET ".$offset; } - + return $sql; } diff --git a/system/database/drivers/mysqli/mysqli_forge.php b/system/database/drivers/mysqli/mysqli_forge.php index 0992274e..26054945 100644 --- a/system/database/drivers/mysqli/mysqli_forge.php +++ b/system/database/drivers/mysqli/mysqli_forge.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -23,7 +23,7 @@ * @link http://codeigniter.com/user_guide/database/ */ class CI_DB_mysqli_forge extends CI_DB_forge { - + /** * Create database * @@ -76,52 +76,56 @@ function _process_fields($fields) else { $attributes = array_change_key_case($attributes, CASE_UPPER); - + $sql .= "\n\t".$this->db->_protect_identifiers($field); if (array_key_exists('NAME', $attributes)) { $sql .= ' '.$this->db->_protect_identifiers($attributes['NAME']).' '; } - + if (array_key_exists('TYPE', $attributes)) { $sql .= ' '.$attributes['TYPE']; } - + if (array_key_exists('CONSTRAINT', $attributes)) { $sql .= '('.$attributes['CONSTRAINT'].')'; } - + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) { $sql .= ' UNSIGNED'; } - + if (array_key_exists('DEFAULT', $attributes)) { $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; } - - if (array_key_exists('NULL', $attributes)) + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) { - $sql .= ($attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL'; + $sql .= ' NULL'; } - + else + { + $sql .= ' NOT NULL'; + } + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) { $sql .= ' AUTO_INCREMENT'; } } - + // don't add a comma on the end of the last field if (++$current_field_count < count($fields)) { $sql .= ','; } } - + return $sql; } @@ -141,12 +145,12 @@ function _process_fields($fields) function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) { $sql = 'CREATE TABLE '; - + if ($if_not_exists === TRUE) { $sql .= 'IF NOT EXISTS '; } - + $sql .= $this->db->_escape_identifiers($table)." ("; $sql .= $this->_process_fields($fields); @@ -165,14 +169,14 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) if (is_array($key)) { $key_name = $this->db->_protect_identifiers(implode('_', $key)); - $key = $this->db->_protect_identifiers($key); + $key = $this->db->_protect_identifiers($key); } else { $key_name = $this->db->_protect_identifiers($key); $key = array($key_name); } - + $sql .= ",\n\tKEY {$key_name} (" . implode(', ', $key) . ")"; } } @@ -226,7 +230,7 @@ function _alter_table($alter_type, $table, $fields, $after_field = '') { $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); } - + return $sql; } diff --git a/system/database/drivers/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php index 00fc0db4..124d4e59 100644 --- a/system/database/drivers/mysqli/mysqli_result.php +++ b/system/database/drivers/mysqli/mysqli_result.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -25,7 +25,7 @@ * @link http://codeigniter.com/user_guide/database/ */ class CI_DB_mysqli_result extends CI_DB_result { - + /** * Number of rows in the result set * @@ -36,7 +36,7 @@ function num_rows() { return @mysqli_num_rows($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -67,7 +67,7 @@ function list_fields() { $field_names[] = $field->name; } - + return $field_names; } @@ -84,28 +84,33 @@ function list_fields() function field_data() { $retval = array(); - while ($field = mysqli_fetch_field($this->result_id)) - { - $F = new stdClass(); - $F->name = $field->name; - $F->type = $field->type; - $F->default = $field->def; - $F->max_length = $field->max_length; - $F->primary_key = ($field->flags & MYSQLI_PRI_KEY_FLAG) ? 1 : 0; - + while ($field = mysqli_fetch_object($this->result_id)) + { + preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field->Type, $matches); + + $type = (array_key_exists(1, $matches)) ? $matches[1] : NULL; + $length = (array_key_exists(2, $matches)) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL; + + $F = new stdClass(); + $F->name = $field->Field; + $F->type = $type; + $F->default = $field->Default; + $F->max_length = $length; + $F->primary_key = ( $field->Key == 'PRI' ? 1 : 0 ); + $retval[] = $F; } - + return $retval; } - + // -------------------------------------------------------------------- /** * Free the result * * @return null - */ + */ function free_result() { if (is_object($this->result_id)) @@ -146,7 +151,7 @@ function _fetch_assoc() { return mysqli_fetch_assoc($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -161,7 +166,7 @@ function _fetch_object() { return mysqli_fetch_object($this->result_id); } - + } diff --git a/system/database/drivers/mysqli/mysqli_utility.php b/system/database/drivers/mysqli/mysqli_utility.php index 7ebda4c5..e17889b8 100644 --- a/system/database/drivers/mysqli/mysqli_utility.php +++ b/system/database/drivers/mysqli/mysqli_utility.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -23,7 +23,7 @@ * @link http://codeigniter.com/user_guide/database/ */ class CI_DB_mysqli_utility extends CI_DB_utility { - + /** * List databases * @@ -34,7 +34,7 @@ function _list_databases() { return "SHOW DATABASES"; } - + // -------------------------------------------------------------------- /** @@ -81,42 +81,6 @@ function _backup($params = array()) // Currently unsupported return $this->db->display_error('db_unsuported_feature'); } - - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access private - * @param string the database name - * @return bool - */ - function _create_database($name) - { - return "CREATE DATABASE ".$name; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - return "DROP DATABASE ".$name; - } - } /* End of file mysqli_utility.php */ diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php index 61457194..930177e6 100644 --- a/system/database/drivers/oci8/oci8_driver.php +++ b/system/database/drivers/oci8/oci8_driver.php @@ -2,14 +2,14 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * - * @package CodeIgniter - * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. - * @license http://codeigniter.com/user_guide/license.html + * @package CodeIgniter + * @author ExpressionEngine Dev Team + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. + * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com - * @since Version 1.0 + * @since Version 1.0 * @filesource */ @@ -22,10 +22,10 @@ * creates dynamically based on whether the active record * class is being used or not. * - * @package CodeIgniter + * @package CodeIgniter * @subpackage Drivers * @category Database - * @author ExpressionEngine Dev Team + * @author ExpressionEngine Dev Team * @link http://codeigniter.com/user_guide/database/ */ @@ -35,8 +35,6 @@ * This is a modification of the DB_driver class to * permit access to oracle databases * - * NOTE: this uses the PHP 4 oci methods - * * @author Kelly McArdle * */ @@ -44,14 +42,14 @@ class CI_DB_oci8_driver extends CI_DB { var $dbdriver = 'oci8'; - + // The character used for excaping var $_escape_char = '"'; - + // clause and character used for LIKE escape sequences var $_like_escape_str = " escape '%s' "; var $_like_escape_chr = '!'; - + /** * The syntax to count rows is slightly different across different * database engines, so this string appears in each driver and is @@ -77,9 +75,9 @@ class CI_DB_oci8_driver extends CI_DB { * @access private called by the base class * @return resource */ - function db_connect() + public function db_connect() { - return @ocilogon($this->username, $this->password, $this->hostname); + return @oci_connect($this->username, $this->password, $this->hostname, $this->char_set); } // -------------------------------------------------------------------- @@ -90,9 +88,9 @@ function db_connect() * @access private called by the base class * @return resource */ - function db_pconnect() + public function db_pconnect() { - return @ociplogon($this->username, $this->password, $this->hostname); + return @oci_pconnect($this->username, $this->password, $this->hostname, $this->char_set); } // -------------------------------------------------------------------- @@ -106,9 +104,10 @@ function db_pconnect() * @access public * @return void */ - function reconnect() + public function reconnect() { // not implemented in oracle + return; } // -------------------------------------------------------------------- @@ -119,8 +118,9 @@ function reconnect() * @access private called by the base class * @return resource */ - function db_select() + public function db_select() { + // Not in Oracle - schemas are actually usernames return TRUE; } @@ -134,23 +134,23 @@ function db_select() * @param string * @return resource */ - function db_set_charset($charset, $collation) + public function db_set_charset($charset, $collation) { // @todo - add support if needed return TRUE; } // -------------------------------------------------------------------- - + /** * Version number query string * - * @access public + * @access protected * @return string */ - function _version() + protected function _version() { - return ociserverversion($this->conn_id); + return oci_server_version($this->conn_id); } // -------------------------------------------------------------------- @@ -158,18 +158,18 @@ function _version() /** * Execute the query * - * @access private called by the base class + * @access protected called by the base class * @param string an SQL query * @return resource */ - function _execute($sql) + protected function _execute($sql) { // oracle must parse the query before it is run. All of the actions with // the query are based on the statement id returned by ociparse $this->stmt_id = FALSE; $this->_set_stmt_id($sql); - ocisetprefetch($this->stmt_id, 1000); - return @ociexecute($this->stmt_id, $this->_commit); + oci_set_prefetch($this->stmt_id, 1000); + return @oci_execute($this->stmt_id, $this->_commit); } /** @@ -179,11 +179,11 @@ function _execute($sql) * @param string an SQL query * @return none */ - function _set_stmt_id($sql) + private function _set_stmt_id($sql) { if ( ! is_resource($this->stmt_id)) { - $this->stmt_id = ociparse($this->conn_id, $this->_prep_query($sql)); + $this->stmt_id = oci_parse($this->conn_id, $this->_prep_query($sql)); } } @@ -198,7 +198,7 @@ function _set_stmt_id($sql) * @param string an SQL query * @return string */ - function _prep_query($sql) + private function _prep_query($sql) { return $sql; } @@ -211,9 +211,9 @@ function _prep_query($sql) * @access public * @return cursor id */ - function get_cursor() + public function get_cursor() { - $this->curs_id = ocinewcursor($this->conn_id); + $this->curs_id = oci_new_cursor($this->conn_id); return $this->curs_id; } @@ -237,7 +237,7 @@ function get_cursor() * type yes the type of the parameter * length yes the max size of the parameter */ - function stored_procedure($package, $procedure, $params) + public function stored_procedure($package, $procedure, $params) { if ($package == '' OR $procedure == '' OR ! is_array($params)) { @@ -248,28 +248,28 @@ function stored_procedure($package, $procedure, $params) } return FALSE; } - + // build the query string $sql = "begin $package.$procedure("; $have_cursor = FALSE; - foreach($params as $param) + foreach ($params as $param) { $sql .= $param['name'] . ","; - - if (array_key_exists('type', $param) && ($param['type'] == OCI_B_CURSOR)) + + if (array_key_exists('type', $param) && ($param['type'] === OCI_B_CURSOR)) { $have_cursor = TRUE; } } $sql = trim($sql, ",") . "); end;"; - + $this->stmt_id = FALSE; $this->_set_stmt_id($sql); $this->_bind_params($params); $this->query($sql, FALSE, $have_cursor); } - + // -------------------------------------------------------------------- /** @@ -278,16 +278,16 @@ function stored_procedure($package, $procedure, $params) * @access private * @return none */ - function _bind_params($params) + private function _bind_params($params) { if ( ! is_array($params) OR ! is_resource($this->stmt_id)) { return; } - + foreach ($params as $param) { - foreach (array('name', 'value', 'type', 'length') as $val) + foreach (array('name', 'value', 'type', 'length') as $val) { if ( ! isset($param[$val])) { @@ -295,7 +295,7 @@ function _bind_params($params) } } - ocibindbyname($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']); + oci_bind_by_name($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']); } } @@ -305,26 +305,26 @@ function _bind_params($params) * Begin Transaction * * @access public - * @return bool - */ - function trans_begin($test_mode = FALSE) + * @return bool + */ + public function trans_begin($test_mode = FALSE) { if ( ! $this->trans_enabled) { return TRUE; } - + // When transactions are nested we only begin/commit/rollback the outermost ones if ($this->_trans_depth > 0) { return TRUE; } - + // Reset the transaction failure flag. // If the $test_mode flag is set to TRUE transactions will be rolled back // even if the queries produce a successful result. $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; - + $this->_commit = OCI_DEFAULT; return TRUE; } @@ -335,9 +335,9 @@ function trans_begin($test_mode = FALSE) * Commit Transaction * * @access public - * @return bool - */ - function trans_commit() + * @return bool + */ + public function trans_commit() { if ( ! $this->trans_enabled) { @@ -350,7 +350,7 @@ function trans_commit() return TRUE; } - $ret = OCIcommit($this->conn_id); + $ret = oci_commit($this->conn_id); $this->_commit = OCI_COMMIT_ON_SUCCESS; return $ret; } @@ -361,9 +361,9 @@ function trans_commit() * Rollback Transaction * * @access public - * @return bool - */ - function trans_rollback() + * @return bool + */ + public function trans_rollback() { if ( ! $this->trans_enabled) { @@ -376,7 +376,7 @@ function trans_rollback() return TRUE; } - $ret = OCIrollback($this->conn_id); + $ret = oci_rollback($this->conn_id); $this->_commit = OCI_COMMIT_ON_SUCCESS; return $ret; } @@ -391,23 +391,20 @@ function trans_rollback() * @param bool whether or not the string will be used in a LIKE condition * @return string */ - function escape_str($str, $like = FALSE) + public function escape_str($str, $like = FALSE) { if (is_array($str)) { - foreach($str as $key => $val) - { + foreach ($str as $key => $val) + { $str[$key] = $this->escape_str($val, $like); - } - - return $str; - } + } + + return $str; + } - // Access the CI object - $CI =& get_instance(); + $str = remove_invisible_characters($str); - $str = $CI->input->_remove_invisible_characters($str); - // escape LIKE condition wildcards if ($like === TRUE) { @@ -415,7 +412,7 @@ function escape_str($str, $like = FALSE) array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), $str); } - + return $str; } @@ -427,9 +424,9 @@ function escape_str($str, $like = FALSE) * @access public * @return integer */ - function affected_rows() + public function affected_rows() { - return @ocirowcount($this->stmt_id); + return @oci_num_rows($this->stmt_id); } // -------------------------------------------------------------------- @@ -440,7 +437,7 @@ function affected_rows() * @access public * @return integer */ - function insert_id() + public function insert_id() { // not supported in oracle return $this->display_error('db_unsupported_function'); @@ -458,7 +455,7 @@ function insert_id() * @param string * @return string */ - function count_all($table = '') + public function count_all($table = '') { if ($table == '') { @@ -473,6 +470,7 @@ function count_all($table = '') } $row = $query->row(); + $this->_reset_select(); return (int) $row->numrows; } @@ -483,19 +481,19 @@ function count_all($table = '') * * Generates a platform-specific query string so that the table names can be fetched * - * @access private + * @access protected * @param boolean - * @return string + * @return string */ - function _list_tables($prefix_limit = FALSE) + protected function _list_tables($prefix_limit = FALSE) { $sql = "SELECT TABLE_NAME FROM ALL_TABLES"; if ($prefix_limit !== FALSE AND $this->dbprefix != '') { - $sql .= " WHERE TABLE_NAME LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_char); + $sql .= " WHERE TABLE_NAME LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); } - + return $sql; } @@ -506,11 +504,11 @@ function _list_tables($prefix_limit = FALSE) * * Generates a platform-specific query string so that the column names can be fetched * - * @access public + * @access protected * @param string the table name * @return string */ - function _list_columns($table = '') + protected function _list_columns($table = '') { return "SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = '$table'"; } @@ -526,7 +524,7 @@ function _list_columns($table = '') * @param string the table name * @return object */ - function _field_data($table) + protected function _field_data($table) { return "SELECT * FROM ".$table." where rownum = 1"; } @@ -536,12 +534,13 @@ function _field_data($table) /** * The error message string * - * @access private + * @access protected * @return string */ - function _error_message() + protected function _error_message() { - $error = ocierror($this->conn_id); + // If the error was during connection, no conn_id should be passed + $error = is_resource($this->conn_id) ? oci_error($this->conn_id) : oci_error(); return $error['message']; } @@ -550,15 +549,16 @@ function _error_message() /** * The error message number * - * @access private + * @access protected * @return integer */ - function _error_number() + protected function _error_number() { - $error = ocierror($this->conn_id); + // Same as _error_message() + $error = is_resource($this->conn_id) ? oci_error($this->conn_id) : oci_error(); return $error['code']; } - + // -------------------------------------------------------------------- /** @@ -566,11 +566,11 @@ function _error_number() * * This function escapes column and table names * - * @access private + * @access protected * @param string * @return string */ - function _escape_identifiers($item) + protected function _escape_identifiers($item) { if ($this->_escape_char == '') { @@ -581,26 +581,26 @@ function _escape_identifiers($item) { if (strpos($item, '.'.$id) !== FALSE) { - $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); - + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); - } + } } - + if (strpos($item, '.') !== FALSE) { - $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; } else { $str = $this->_escape_char.$item.$this->_escape_char; } - + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); } - + // -------------------------------------------------------------------- /** @@ -609,22 +609,22 @@ function _escape_identifiers($item) * This function implicitly groups FROM tables so there is no confusion * about operator precedence in harmony with SQL standards * - * @access public + * @access protected * @param type * @return type */ - function _from_tables($tables) + protected function _from_tables($tables) { if ( ! is_array($tables)) { $tables = array($tables); } - + return implode(', ', $tables); } // -------------------------------------------------------------------- - + /** * Insert statement * @@ -636,9 +636,37 @@ function _from_tables($tables) * @param array the insert values * @return string */ - function _insert($table, $keys, $values) + protected function _insert($table, $keys, $values) { - return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access protected + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + protected function _insert_batch($table, $keys, $values) + { + $keys = implode(', ', $keys); + $sql = "INSERT ALL\n"; + + for ($i = 0, $c = count($values); $i < $c; $i++) + { + $sql .= ' INTO ' . $table . ' (' . $keys . ') VALUES ' . $values[$i] . "\n"; + } + + $sql .= 'SELECT * FROM dual'; + + return $sql; } // -------------------------------------------------------------------- @@ -648,7 +676,7 @@ function _insert($table, $keys, $values) * * Generates a platform-specific update string from the supplied data * - * @access public + * @access protected * @param string the table name * @param array the update data * @param array the where clause @@ -656,23 +684,23 @@ function _insert($table, $keys, $values) * @param array the limit clause * @return string */ - function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE) { - foreach($values as $key => $val) + foreach ($values as $key => $val) { $valstr[] = $key." = ".$val; } - + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; - + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; $sql .= $orderby.$limit; - + return $sql; } @@ -685,15 +713,15 @@ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) * If the database does not support the truncate() command * This function maps to "DELETE FROM table" * - * @access public + * @access protected * @param string the table name * @return string - */ - function _truncate($table) + */ + protected function _truncate($table) { return "TRUNCATE TABLE ".$table; } - + // -------------------------------------------------------------------- /** @@ -701,13 +729,13 @@ function _truncate($table) * * Generates a platform-specific delete string from the supplied data * - * @access public + * @access protected * @param string the table name * @param array the where clause * @param string the limit clause * @return string - */ - function _delete($table, $where = array(), $like = array(), $limit = FALSE) + */ + protected function _delete($table, $where = array(), $like = array(), $limit = FALSE) { $conditions = ''; @@ -724,7 +752,7 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) } $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + return "DELETE FROM ".$table.$conditions.$limit; } @@ -735,13 +763,13 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) * * Generates a platform-specific LIMIT clause * - * @access public + * @access protected * @param string the sql query string * @param integer the number of rows to limit the query to * @param integer the offset value * @return string */ - function _limit($sql, $limit, $offset) + protected function _limit($sql, $limit, $offset) { $limit = $offset + $limit; $newsql = "SELECT * FROM (select inner_query.*, rownum rnum FROM ($sql) inner_query WHERE rownum < $limit)"; @@ -755,20 +783,20 @@ function _limit($sql, $limit, $offset) $this->limit_used = TRUE; return $newsql; - } + } // -------------------------------------------------------------------- /** * Close DB Connection * - * @access public + * @access protected * @param resource * @return void */ - function _close($conn_id) + protected function _close($conn_id) { - @ocilogoff($conn_id); + @oci_close($conn_id); } @@ -777,4 +805,4 @@ function _close($conn_id) /* End of file oci8_driver.php */ -/* Location: ./system/database/drivers/oci8/oci8_driver.php */ \ No newline at end of file +/* Location: ./system/database/drivers/oci8/oci8_driver.php */ diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php index c3e9cb98..3cd17585 100644 --- a/system/database/drivers/oci8/oci8_forge.php +++ b/system/database/drivers/oci8/oci8_forge.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -66,12 +66,12 @@ function _drop_database($name) function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) { $sql = 'CREATE TABLE '; - + if ($if_not_exists === TRUE) { $sql .= 'IF NOT EXISTS '; } - + $sql .= $this->db->_escape_identifiers($table)." ("; $current_field_count = 0; @@ -87,41 +87,41 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) else { $attributes = array_change_key_case($attributes, CASE_UPPER); - + $sql .= "\n\t".$this->db->_protect_identifiers($field); - + $sql .= ' '.$attributes['TYPE']; - + if (array_key_exists('CONSTRAINT', $attributes)) { $sql .= '('.$attributes['CONSTRAINT'].')'; } - + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) { $sql .= ' UNSIGNED'; } - + if (array_key_exists('DEFAULT', $attributes)) { $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; } - + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) { $sql .= ' NULL'; } else { - $sql .= ' NOT NULL'; + $sql .= ' NOT NULL'; } - + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) { $sql .= ' AUTO_INCREMENT'; } } - + // don't add a comma on the end of the last field if (++$current_field_count < count($fields)) { @@ -141,17 +141,17 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) { if (is_array($key)) { - $key = $this->db->_protect_identifiers($key); + $key = $this->db->_protect_identifiers($key); } else { $key = array($this->db->_protect_identifiers($key)); } - + $sql .= ",\n\tUNIQUE COLUMNS (" . implode(', ', $key) . ")"; } } - + $sql .= "\n)"; return $sql; @@ -218,9 +218,9 @@ function _alter_table($alter_type, $table, $column_name, $column_definition = '' { $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); } - + return $sql; - + } // -------------------------------------------------------------------- diff --git a/system/database/drivers/oci8/oci8_result.php b/system/database/drivers/oci8/oci8_result.php index 1d0b7db2..3421278a 100644 --- a/system/database/drivers/oci8/oci8_result.php +++ b/system/database/drivers/oci8/oci8_result.php @@ -2,14 +2,14 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * - * @package CodeIgniter - * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. - * @license http://codeigniter.com/user_guide/license.html + * @package CodeIgniter + * @author ExpressionEngine Dev Team + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. + * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com - * @since Version 1.0 + * @since Version 1.0 * @filesource */ @@ -21,36 +21,37 @@ * This class extends the parent result class: CI_DB_result * * @category Database - * @author ExpressionEngine Dev Team + * @author ExpressionEngine Dev Team * @link http://codeigniter.com/user_guide/database/ */ class CI_DB_oci8_result extends CI_DB_result { - var $stmt_id; - var $curs_id; - var $limit_used; + public $stmt_id; + public $curs_id; + public $limit_used; /** * Number of rows in the result set. * * Oracle doesn't have a graceful way to retun the number of rows * so we have to use what amounts to a hack. - * * - * @access public * @return integer */ - function num_rows() + public function num_rows() { - $rowcount = count($this->result_array()); - @ociexecute($this->stmt_id); - - if ($this->curs_id) + if ($this->num_rows === 0 && count($this->result_array()) > 0) { - @ociexecute($this->curs_id); + $this->num_rows = count($this->result_array()); + @oci_execute($this->stmt_id); + + if ($this->curs_id) + { + @oci_execute($this->curs_id); + } } - return $rowcount; + return $this->num_rows; } // -------------------------------------------------------------------- @@ -61,9 +62,9 @@ function num_rows() * @access public * @return integer */ - function num_fields() + public function num_fields() { - $count = @ocinumcols($this->stmt_id); + $count = @oci_num_fields($this->stmt_id); // if we used a limit we subtract it if ($this->limit_used) @@ -84,13 +85,12 @@ function num_fields() * @access public * @return array */ - function list_fields() + public function list_fields() { $field_names = array(); - $fieldCount = $this->num_fields(); - for ($c = 1; $c <= $fieldCount; $c++) + for ($c = 1, $fieldCount = $this->num_fields(); $c <= $fieldCount; $c++) { - $field_names[] = ocicolumnname($this->stmt_id, $c); + $field_names[] = oci_field_name($this->stmt_id, $c); } return $field_names; } @@ -105,16 +105,15 @@ function list_fields() * @access public * @return array */ - function field_data() + public function field_data() { $retval = array(); - $fieldCount = $this->num_fields(); - for ($c = 1; $c <= $fieldCount; $c++) + for ($c = 1, $fieldCount = $this->num_fields(); $c <= $fieldCount; $c++) { - $F = new stdClass(); - $F->name = ocicolumnname($this->stmt_id, $c); - $F->type = ocicolumntype($this->stmt_id, $c); - $F->max_length = ocicolumnsize($this->stmt_id, $c); + $F = new stdClass(); + $F->name = oci_field_name($this->stmt_id, $c); + $F->type = oci_field_type($this->stmt_id, $c); + $F->max_length = oci_field_size($this->stmt_id, $c); $retval[] = $F; } @@ -128,12 +127,12 @@ function field_data() * Free the result * * @return null - */ - function free_result() + */ + public function free_result() { if (is_resource($this->result_id)) { - ocifreestatement($this->result_id); + oci_free_statement($this->result_id); $this->result_id = FALSE; } } @@ -145,14 +144,13 @@ function free_result() * * Returns the result set as an array * - * @access private + * @access protected * @return array */ - function _fetch_assoc(&$row) + protected function _fetch_assoc() { $id = ($this->curs_id) ? $this->curs_id : $this->stmt_id; - - return ocifetchinto($id, $row, OCI_ASSOC + OCI_RETURN_NULLS); + return oci_fetch_assoc($id); } // -------------------------------------------------------------------- @@ -162,41 +160,13 @@ function _fetch_assoc(&$row) * * Returns the result set as an object * - * @access private + * @access protected * @return object */ - function _fetch_object() - { - $result = array(); - - // If PHP 5 is being used we can fetch an result object - if (function_exists('oci_fetch_object')) - { - $id = ($this->curs_id) ? $this->curs_id : $this->stmt_id; - - return @oci_fetch_object($id); - } - - // If PHP 4 is being used we have to build our own result - foreach ($this->result_array() as $key => $val) - { - $obj = new stdClass(); - if (is_array($val)) - { - foreach ($val as $k => $v) - { - $obj->$k = $v; - } - } - else - { - $obj->$key = $val; - } - - $result[] = $obj; - } - - return $result; + protected function _fetch_object() + { + $id = ($this->curs_id) ? $this->curs_id : $this->stmt_id; + return @oci_fetch_object($id); } // -------------------------------------------------------------------- @@ -207,17 +177,15 @@ function _fetch_object() * @access public * @return array */ - function result_array() + public function result_array() { if (count($this->result_array) > 0) { return $this->result_array; } - // oracle's fetch functions do not return arrays. - // The information is returned in reference parameters $row = NULL; - while ($this->_fetch_assoc($row)) + while ($row = $this->_fetch_assoc()) { $this->result_array[] = $row; } @@ -234,10 +202,10 @@ function result_array() * this internally before fetching results to make sure the * result set starts at zero * - * @access private + * @access protected * @return array */ - function _data_seek($n = 0) + protected function _data_seek($n = 0) { return FALSE; // Not needed } @@ -246,4 +214,4 @@ function _data_seek($n = 0) /* End of file oci8_result.php */ -/* Location: ./system/database/drivers/oci8/oci8_result.php */ \ No newline at end of file +/* Location: ./system/database/drivers/oci8/oci8_result.php */ diff --git a/system/database/drivers/oci8/oci8_utility.php b/system/database/drivers/oci8/oci8_utility.php index c8049c24..854b467e 100644 --- a/system/database/drivers/oci8/oci8_utility.php +++ b/system/database/drivers/oci8/oci8_utility.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -81,41 +81,6 @@ function _backup($params = array()) // Currently unsupported return $this->db->display_error('db_unsuported_feature'); } - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access public - * @param string the database name - * @return bool - */ - function _create_database($name) - { - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - return FALSE; - } - } /* End of file oci8_utility.php */ diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php index dacbaaba..bcd7937d 100644 --- a/system/database/drivers/odbc/odbc_driver.php +++ b/system/database/drivers/odbc/odbc_driver.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -31,14 +31,14 @@ class CI_DB_odbc_driver extends CI_DB { var $dbdriver = 'odbc'; - + // the character used to excape - not necessary for ODBC var $_escape_char = ''; - + // clause and character used for LIKE escape sequences var $_like_escape_str = " {escape '%s'} "; var $_like_escape_chr = '!'; - + /** * The syntax to count rows is slightly different across different * database engines, so this string appears in each driver and is @@ -48,10 +48,10 @@ class CI_DB_odbc_driver extends CI_DB { var $_random_keyword; - function CI_DB_odbc_driver($params) + function __construct($params) { - parent::CI_DB($params); - + parent::__construct($params); + $this->_random_keyword = ' RND('.time().')'; // database specific random keyword } @@ -60,12 +60,12 @@ function CI_DB_odbc_driver($params) * * @access private called by the base class * @return resource - */ + */ function db_connect() { return @odbc_connect($this->hostname, $this->username, $this->password); } - + // -------------------------------------------------------------------- /** @@ -73,12 +73,12 @@ function db_connect() * * @access private called by the base class * @return resource - */ + */ function db_pconnect() { return @odbc_pconnect($this->hostname, $this->username, $this->password); } - + // -------------------------------------------------------------------- /** @@ -102,7 +102,7 @@ function reconnect() * * @access private called by the base class * @return resource - */ + */ function db_select() { // Not needed for ODBC @@ -126,7 +126,7 @@ function db_set_charset($charset, $collation) } // -------------------------------------------------------------------- - + /** * Version number query string * @@ -146,13 +146,13 @@ function _version() * @access private called by the base class * @param string an SQL query * @return resource - */ + */ function _execute($sql) { $sql = $this->_prep_query($sql); return @odbc_exec($this->conn_id, $sql); } - + // -------------------------------------------------------------------- /** @@ -163,7 +163,7 @@ function _execute($sql) * @access private called by execute() * @param string an SQL query * @return string - */ + */ function _prep_query($sql) { return $sql; @@ -175,15 +175,15 @@ function _prep_query($sql) * Begin Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_begin($test_mode = FALSE) { if ( ! $this->trans_enabled) { return TRUE; } - + // When transactions are nested we only begin/commit/rollback the outermost ones if ($this->_trans_depth > 0) { @@ -204,8 +204,8 @@ function trans_begin($test_mode = FALSE) * Commit Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_commit() { if ( ! $this->trans_enabled) @@ -230,8 +230,8 @@ function trans_commit() * Rollback Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_rollback() { if ( ! $this->trans_enabled) @@ -264,20 +264,17 @@ function escape_str($str, $like = FALSE) { if (is_array($str)) { - foreach($str as $key => $val) - { + foreach ($str as $key => $val) + { $str[$key] = $this->escape_str($val, $like); - } - - return $str; - } - - // Access the CI object - $CI =& get_instance(); - + } + + return $str; + } + // ODBC doesn't require escaping - $str = $CI->input->_remove_invisible_characters($str); - + $str = remove_invisible_characters($str); + // escape LIKE condition wildcards if ($like === TRUE) { @@ -285,10 +282,10 @@ function escape_str($str, $like = FALSE) array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), $str); } - + return $str; } - + // -------------------------------------------------------------------- /** @@ -301,7 +298,7 @@ function affected_rows() { return @odbc_num_rows($this->conn_id); } - + // -------------------------------------------------------------------- /** @@ -342,6 +339,7 @@ function count_all($table = '') } $row = $query->row(); + $this->_reset_select(); return (int) $row->numrows; } @@ -362,13 +360,13 @@ function _list_tables($prefix_limit = FALSE) if ($prefix_limit !== FALSE AND $this->dbprefix != '') { - //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_char); + //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); return FALSE; // not currently supported } - + return $sql; } - + // -------------------------------------------------------------------- /** @@ -413,7 +411,7 @@ function _error_message() { return odbc_errormsg($this->conn_id); } - + // -------------------------------------------------------------------- /** @@ -449,26 +447,26 @@ function _escape_identifiers($item) { if (strpos($item, '.'.$id) !== FALSE) { - $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); - + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); - } + } } - + if (strpos($item, '.') !== FALSE) { - $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; } else { $str = $this->_escape_char.$item.$this->_escape_char; } - + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); } - + // -------------------------------------------------------------------- /** @@ -487,12 +485,12 @@ function _from_tables($tables) { $tables = array($tables); } - + return '('.implode(', ', $tables).')'; } // -------------------------------------------------------------------- - + /** * Insert statement * @@ -505,10 +503,10 @@ function _from_tables($tables) * @return string */ function _insert($table, $keys, $values) - { + { return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; } - + // -------------------------------------------------------------------- /** @@ -526,25 +524,25 @@ function _insert($table, $keys, $values) */ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) { - foreach($values as $key => $val) + foreach ($values as $key => $val) { $valstr[] = $key." = ".$val; } - + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; - + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; $sql .= $orderby.$limit; - + return $sql; } - + // -------------------------------------------------------------------- /** @@ -557,12 +555,12 @@ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) * @access public * @param string the table name * @return string - */ + */ function _truncate($table) { return $this->_delete($table); } - + // -------------------------------------------------------------------- /** @@ -575,7 +573,7 @@ function _truncate($table) * @param array the where clause * @param string the limit clause * @return string - */ + */ function _delete($table, $where = array(), $like = array(), $limit = FALSE) { $conditions = ''; @@ -593,7 +591,7 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) } $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + return "DELETE FROM ".$table.$conditions.$limit; } @@ -630,7 +628,7 @@ function _close($conn_id) @odbc_close($conn_id); } - + } diff --git a/system/database/drivers/odbc/odbc_forge.php b/system/database/drivers/odbc/odbc_forge.php index 99cb282a..3ec86b4e 100644 --- a/system/database/drivers/odbc/odbc_forge.php +++ b/system/database/drivers/odbc/odbc_forge.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -54,7 +54,7 @@ function _create_database() function _drop_database($name) { // ODBC has no "drop database" command since it's - // designed to connect to an existing database + // designed to connect to an existing database if ($this->db->db_debug) { return $this->db->display_error('db_unsuported_feature'); @@ -78,12 +78,12 @@ function _drop_database($name) function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) { $sql = 'CREATE TABLE '; - + if ($if_not_exists === TRUE) { $sql .= 'IF NOT EXISTS '; } - + $sql .= $this->db->_escape_identifiers($table)." ("; $current_field_count = 0; @@ -99,41 +99,41 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) else { $attributes = array_change_key_case($attributes, CASE_UPPER); - + $sql .= "\n\t".$this->db->_protect_identifiers($field); - + $sql .= ' '.$attributes['TYPE']; - + if (array_key_exists('CONSTRAINT', $attributes)) { $sql .= '('.$attributes['CONSTRAINT'].')'; } - + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) { $sql .= ' UNSIGNED'; } - + if (array_key_exists('DEFAULT', $attributes)) { $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; } - + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) { $sql .= ' NULL'; } else { - $sql .= ' NOT NULL'; + $sql .= ' NOT NULL'; } - + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) { $sql .= ' AUTO_INCREMENT'; } } - + // don't add a comma on the end of the last field if (++$current_field_count < count($fields)) { @@ -146,24 +146,24 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) $primary_keys = $this->db->_protect_identifiers($primary_keys); $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; } - + if (is_array($keys) && count($keys) > 0) { foreach ($keys as $key) { if (is_array($key)) { - $key = $this->db->_protect_identifiers($key); + $key = $this->db->_protect_identifiers($key); } else { $key = array($this->db->_protect_identifiers($key)); } - + $sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")"; } } - + $sql .= "\n)"; return $sql; @@ -179,7 +179,7 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) */ function _drop_table($table) { - // Not a supported ODBC feature + // Not a supported ODBC feature if ($this->db->db_debug) { return $this->db->display_error('db_unsuported_feature'); @@ -235,9 +235,9 @@ function _alter_table($alter_type, $table, $column_name, $column_definition = '' { $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); } - + return $sql; - + } diff --git a/system/database/drivers/odbc/odbc_result.php b/system/database/drivers/odbc/odbc_result.php index d6f15015..5d64a464 100644 --- a/system/database/drivers/odbc/odbc_result.php +++ b/system/database/drivers/odbc/odbc_result.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -25,7 +25,7 @@ * @link http://codeigniter.com/user_guide/database/ */ class CI_DB_odbc_result extends CI_DB_result { - + /** * Number of rows in the result set * @@ -36,7 +36,7 @@ function num_rows() { return @odbc_num_rows($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -65,9 +65,9 @@ function list_fields() $field_names = array(); for ($i = 0; $i < $this->num_fields(); $i++) { - $field_names[] = odbc_field_name($this->result_id, $i); + $field_names[] = odbc_field_name($this->result_id, $i); } - + return $field_names; } @@ -86,16 +86,16 @@ function field_data() $retval = array(); for ($i = 0; $i < $this->num_fields(); $i++) { - $F = new stdClass(); - $F->name = odbc_field_name($this->result_id, $i); - $F->type = odbc_field_type($this->result_id, $i); + $F = new stdClass(); + $F->name = odbc_field_name($this->result_id, $i); + $F->type = odbc_field_type($this->result_id, $i); $F->max_length = odbc_field_len($this->result_id, $i); $F->primary_key = 0; $F->default = ''; $retval[] = $F; } - + return $retval; } @@ -105,7 +105,7 @@ function field_data() * Free the result * * @return null - */ + */ function free_result() { if (is_resource($this->result_id)) @@ -188,7 +188,7 @@ function _fetch_object() */ function _odbc_fetch_object(& $odbc_result) { $rs = array(); - $rs_obj = false; + $rs_obj = FALSE; if (odbc_fetch_into($odbc_result, $rs)) { foreach ($rs as $k=>$v) { $field_name= odbc_field_name($odbc_result, $k+1); @@ -210,7 +210,7 @@ function _odbc_fetch_object(& $odbc_result) { */ function _odbc_fetch_array(& $odbc_result) { $rs = array(); - $rs_assoc = false; + $rs_assoc = FALSE; if (odbc_fetch_into($odbc_result, $rs)) { $rs_assoc=array(); foreach ($rs as $k=>$v) { diff --git a/system/database/drivers/odbc/odbc_utility.php b/system/database/drivers/odbc/odbc_utility.php index 85707a07..d335bed9 100644 --- a/system/database/drivers/odbc/odbc_utility.php +++ b/system/database/drivers/odbc/odbc_utility.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -32,7 +32,7 @@ class CI_DB_odbc_utility extends CI_DB_utility { */ function _list_databases() { - // Not sure if ODBC lets you list all databases... + // Not sure if ODBC lets you list all databases... if ($this->db->db_debug) { return $this->db->display_error('db_unsuported_feature'); @@ -53,7 +53,7 @@ function _list_databases() */ function _optimize_table($table) { - // Not a supported ODBC feature + // Not a supported ODBC feature if ($this->db->db_debug) { return $this->db->display_error('db_unsuported_feature'); @@ -74,7 +74,7 @@ function _optimize_table($table) */ function _repair_table($table) { - // Not a supported ODBC feature + // Not a supported ODBC feature if ($this->db->db_debug) { return $this->db->display_error('db_unsuported_feature'); @@ -96,52 +96,7 @@ function _backup($params = array()) // Currently unsupported return $this->db->display_error('db_unsuported_feature'); } - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - /** - * Create database - * - * @access private - * @param string the database name - * @return bool - */ - function _create_database() - { - // ODBC has no "create database" command since it's - // designed to connect to an existing database - if ($this->db->db_debug) - { - return $this->db->display_error('db_unsuported_feature'); - } - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - // ODBC has no "drop database" command since it's - // designed to connect to an existing database - if ($this->db->db_debug) - { - return $this->db->display_error('db_unsuported_feature'); - } - return FALSE; - } } /* End of file odbc_utility.php */ diff --git a/system/logs/index.html b/system/database/drivers/pdo/index.html similarity index 100% rename from system/logs/index.html rename to system/database/drivers/pdo/index.html diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php new file mode 100644 index 00000000..1ecc90a8 --- /dev/null +++ b/system/database/drivers/pdo/pdo_driver.php @@ -0,0 +1,812 @@ +hostname, 'mysql') !== FALSE) + { + $this->_like_escape_str = ''; + $this->_like_escape_chr = ''; + + //Prior to this version, the charset can't be set in the dsn + if(is_php('5.3.6')) + { + $this->hostname .= ";charset={$this->char_set}"; + } + + //Set the charset with the connection options + $this->options['PDO::MYSQL_ATTR_INIT_COMMAND'] = "SET NAMES {$this->char_set}"; + } + elseif (strpos($this->hostname, 'odbc') !== FALSE) + { + $this->_like_escape_str = " {escape '%s'} "; + $this->_like_escape_chr = '!'; + } + else + { + $this->_like_escape_str = " ESCAPE '%s' "; + $this->_like_escape_chr = '!'; + } + + empty($this->database) OR $this->hostname .= ';dbname='.$this->database; + + $this->trans_enabled = FALSE; + + $this->_random_keyword = ' RND('.time().')'; // database specific random keyword + } + + /** + * Non-persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_connect() + { + $this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT; + + return new PDO($this->hostname, $this->username, $this->password, $this->options); + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + $this->options['PDO::ATTR_ERRMODE'] = PDO::ERRMODE_SILENT; + $this->options['PDO::ATTR_PERSISTENT'] = TRUE; + + return new PDO($this->hostname, $this->username, $this->password, $this->options); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + // Not needed for PDO + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + // @todo - add support if needed + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + return $this->conn_id->getAttribute(PDO::ATTR_CLIENT_VERSION); + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return object + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + $result_id = $this->conn_id->prepare($sql); + $result_id->execute(); + + if (is_object($result_id)) + { + if (is_numeric(stripos($sql, 'SELECT'))) + { + $this->affect_rows = count($result_id->fetchAll()); + $result_id->execute(); + } + else + { + $this->affect_rows = $result_id->rowCount(); + } + } + else + { + $this->affect_rows = 0; + } + + return $result_id; + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = (bool) ($test_mode === TRUE); + + return $this->conn_id->beginTransaction(); + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $ret = $this->conn->commit(); + return $ret; + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + $ret = $this->conn_id->rollBack(); + return $ret; + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach ($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + //Escape the string + $str = $this->conn_id->quote($str); + + //If there are duplicated quotes, trim them away + if (strpos($str, "'") === 0) + { + $str = substr($str, 1, -1); + } + + // escape LIKE condition wildcards + if ($like === TRUE) + { + $str = str_replace( array('%', '_', $this->_like_escape_chr), + array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), + $str); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return $this->affect_rows; + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @access public + * @return integer + */ + function insert_id($name=NULL) + { + //Convenience method for postgres insertid + if (strpos($this->hostname, 'pgsql') !== FALSE) + { + $v = $this->_version(); + + $table = func_num_args() > 0 ? func_get_arg(0) : NULL; + + if ($table == NULL && $v >= '8.1') + { + $sql='SELECT LASTVAL() as ins_id'; + } + $query = $this->query($sql); + $row = $query->row(); + return $row->ins_id; + } + else + { + return $this->conn_id->lastInsertId($name); + } + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + { + return 0; + } + + $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); + + if ($query->num_rows() == 0) + { + return 0; + } + + $row = $query->row(); + $this->_reset_select(); + return (int) $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + $sql = "SHOW TABLES FROM `".$this->database."`"; + + if ($prefix_limit !== FALSE AND $this->dbprefix != '') + { + //$sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); + return FALSE; // not currently supported + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access public + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + return "SHOW COLUMNS FROM ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "SELECT TOP 1 FROM ".$table; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + $error_array = $this->conn_id->errorInfo(); + return $error_array[2]; + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + return $this->conn_id->errorCode(); + } + + // -------------------------------------------------------------------- + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + if ($this->_escape_char == '') + { + return $item; + } + + foreach ($this->_reserved_identifiers as $id) + { + if (strpos($item, '.'.$id) !== FALSE) + { + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + } + + if (strpos($item, '.') !== FALSE) + { + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + + } + else + { + $str = $this->_escape_char.$item.$this->_escape_char; + } + + // remove duplicates if the user already included the escape + return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return (count($tables) == 1) ? $tables[0] : '('.implode(', ', $tables).')'; + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert_batch($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values); + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where, $orderby = array(), $limit = FALSE) + { + foreach ($values as $key => $val) + { + $valstr[] = $key." = ".$val; + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; + + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); + + $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; + + $sql .= $orderby.$limit; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @return string + */ + function _update_batch($table, $values, $index, $where = NULL) + { + $ids = array(); + $where = ($where != '' AND count($where) >=1) ? implode(" ", $where).' AND ' : ''; + + foreach ($values as $key => $val) + { + $ids[] = $val[$index]; + + foreach (array_keys($val) as $field) + { + if ($field != $index) + { + $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; + } + } + } + + $sql = "UPDATE ".$table." SET "; + $cases = ''; + + foreach ($final as $k => $v) + { + $cases .= $k.' = CASE '."\n"; + foreach ($v as $row) + { + $cases .= $row."\n"; + } + + $cases .= 'ELSE '.$k.' END, '; + } + + $sql .= substr($cases, 0, -2); + + $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; + + return $sql; + } + + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return $this->_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where = array(), $like = array(), $limit = FALSE) + { + $conditions = ''; + + if (count($where) > 0 OR count($like) > 0) + { + $conditions = "\nWHERE "; + $conditions .= implode("\n", $this->ar_where); + + if (count($where) > 0 && count($like) > 0) + { + $conditions .= " AND "; + } + $conditions .= implode("\n", $like); + } + + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; + + return "DELETE FROM ".$table.$conditions.$limit; + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + if (strpos($this->hostname, 'cubrid') !== FALSE || strpos($this->hostname, 'sqlite') !== FALSE) + { + if ($offset == 0) + { + $offset = ''; + } + else + { + $offset .= ", "; + } + + return $sql."LIMIT ".$offset.$limit; + } + else + { + $sql .= "LIMIT ".$limit; + + if ($offset > 0) + { + $sql .= " OFFSET ".$offset; + } + + return $sql; + } + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + $this->conn_id = null; + } + + +} + + + +/* End of file pdo_driver.php */ +/* Location: ./system/database/drivers/pdo/pdo_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/pdo/pdo_forge.php b/system/database/drivers/pdo/pdo_forge.php new file mode 100644 index 00000000..9a782208 --- /dev/null +++ b/system/database/drivers/pdo/pdo_forge.php @@ -0,0 +1,266 @@ +db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @access private + * @param string the database name + * @return bool + */ + function _drop_database($name) + { + // PDO has no "drop database" command since it's + // designed to connect to an existing database + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access private + * @param string the table name + * @param array the fields + * @param mixed primary key(s) + * @param mixed key(s) + * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @return bool + */ + function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + { + $sql = 'CREATE TABLE '; + + if ($if_not_exists === TRUE) + { + $sql .= 'IF NOT EXISTS '; + } + + $sql .= $this->db->_escape_identifiers($table)." ("; + $current_field_count = 0; + + foreach ($fields as $field=>$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t".$this->db->_protect_identifiers($field); + + $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + $sql .= ' UNSIGNED'; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + if (count($primary_keys) > 0) + { + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key = $this->db->_protect_identifiers($key); + } + else + { + $key = array($this->db->_protect_identifiers($key)); + } + + $sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n)"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * @access private + * @return bool + */ + function _drop_table($table) + { + // Not a supported PDO feature + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param string the table name + * @param string the column definition + * @param string the default value + * @param boolean should 'NOT NULL' be added + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name); + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql; + } + + $sql .= " $column_definition"; + + if ($default_value != '') + { + $sql .= " DEFAULT \"$default_value\""; + } + + if ($null === NULL) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + + } + + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + + +} + +/* End of file pdo_forge.php */ +/* Location: ./system/database/drivers/pdo/pdo_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php new file mode 100644 index 00000000..44fdd6dc --- /dev/null +++ b/system/database/drivers/pdo/pdo_result.php @@ -0,0 +1,183 @@ +num_rows)) + { + return $this->num_rows; + } + elseif (($this->num_rows = $this->result_id->rowCount()) > 0) + { + return $this->num_rows; + } + + $this->num_rows = count($this->result_id->fetchAll()); + $this->result_id->execute(); + return $this->num_rows; + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return $this->result_id->columnCount(); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $data = array(); + + try + { + for($i = 0; $i < $this->num_fields(); $i++) + { + $data[] = $this->result_id->getColumnMeta($i); + } + + return $data; + } + catch (Exception $e) + { + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if (is_object($this->result_id)) + { + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + return $this->result_id->fetch(PDO::FETCH_ASSOC); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + return $this->result_id->fetchObject(); + } + +} + + +/* End of file pdo_result.php */ +/* Location: ./system/database/drivers/pdo/pdo_result.php */ \ No newline at end of file diff --git a/system/database/drivers/pdo/pdo_utility.php b/system/database/drivers/pdo/pdo_utility.php new file mode 100644 index 00000000..88ce033a --- /dev/null +++ b/system/database/drivers/pdo/pdo_utility.php @@ -0,0 +1,103 @@ +db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Optimize table query + * + * Generates a platform-specific query so that a table can be optimized + * + * @access private + * @param string the table name + * @return object + */ + function _optimize_table($table) + { + // Not a supported PDO feature + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Repair table query + * + * Generates a platform-specific query so that a table can be repaired + * + * @access private + * @param string the table name + * @return object + */ + function _repair_table($table) + { + // Not a supported PDO feature + if ($this->db->db_debug) + { + return $this->db->display_error('db_unsuported_feature'); + } + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * PDO Export + * + * @access private + * @param array Preferences + * @return mixed + */ + function _backup($params = array()) + { + // Currently unsupported + return $this->db->display_error('db_unsuported_feature'); + } + +} + +/* End of file pdo_utility.php */ +/* Location: ./system/database/drivers/pdo/pdo_utility.php */ \ No newline at end of file diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php index 9258da68..5367f975 100644 --- a/system/database/drivers/postgre/postgre_driver.php +++ b/system/database/drivers/postgre/postgre_driver.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -31,7 +31,7 @@ class CI_DB_postgre_driver extends CI_DB { var $dbdriver = 'postgre'; - + var $_escape_char = '"'; // clause and character used for LIKE escape sequences @@ -51,7 +51,7 @@ class CI_DB_postgre_driver extends CI_DB { * * @access private * @return string - */ + */ function _connect_string() { $components = array( @@ -61,7 +61,7 @@ function _connect_string() 'username' => 'user', 'password' => 'password' ); - + $connect_string = ""; foreach ($components as $key => $val) { @@ -80,9 +80,9 @@ function _connect_string() * * @access private called by the base class * @return resource - */ + */ function db_connect() - { + { return @pg_connect($this->_connect_string()); } @@ -93,12 +93,12 @@ function db_connect() * * @access private called by the base class * @return resource - */ + */ function db_pconnect() { return @pg_pconnect($this->_connect_string()); } - + // -------------------------------------------------------------------- /** @@ -125,7 +125,7 @@ function reconnect() * * @access private called by the base class * @return resource - */ + */ function db_select() { // Not needed for Postgre so we'll return TRUE @@ -149,7 +149,7 @@ function db_set_charset($charset, $collation) } // -------------------------------------------------------------------- - + /** * Version number query string * @@ -169,13 +169,13 @@ function _version() * @access private called by the base class * @param string an SQL query * @return resource - */ + */ function _execute($sql) { $sql = $this->_prep_query($sql); return @pg_query($this->conn_id, $sql); } - + // -------------------------------------------------------------------- /** @@ -186,7 +186,7 @@ function _execute($sql) * @access private called by execute() * @param string an SQL query * @return string - */ + */ function _prep_query($sql) { return $sql; @@ -198,15 +198,15 @@ function _prep_query($sql) * Begin Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_begin($test_mode = FALSE) { if ( ! $this->trans_enabled) { return TRUE; } - + // When transactions are nested we only begin/commit/rollback the outermost ones if ($this->_trans_depth > 0) { @@ -227,8 +227,8 @@ function trans_begin($test_mode = FALSE) * Commit Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_commit() { if ( ! $this->trans_enabled) @@ -251,8 +251,8 @@ function trans_commit() * Rollback Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_rollback() { if ( ! $this->trans_enabled) @@ -283,16 +283,16 @@ function escape_str($str, $like = FALSE) { if (is_array($str)) { - foreach($str as $key => $val) - { + foreach ($str as $key => $val) + { $str[$key] = $this->escape_str($val, $like); - } - - return $str; - } + } + + return $str; + } $str = pg_escape_string($str); - + // escape LIKE condition wildcards if ($like === TRUE) { @@ -300,10 +300,10 @@ function escape_str($str, $like = FALSE) array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), $str); } - + return $str; } - + // -------------------------------------------------------------------- /** @@ -316,7 +316,7 @@ function affected_rows() { return @pg_affected_rows($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -329,22 +329,22 @@ function insert_id() { $v = $this->_version(); $v = $v['server']; - - $table = func_num_args() > 0 ? func_get_arg(0) : null; - $column = func_num_args() > 1 ? func_get_arg(1) : null; - - if ($table == null && $v >= '8.1') + + $table = func_num_args() > 0 ? func_get_arg(0) : NULL; + $column = func_num_args() > 1 ? func_get_arg(1) : NULL; + + if ($table == NULL && $v >= '8.1') { $sql='SELECT LASTVAL() as ins_id'; } - elseif ($table != null && $column != null && $v >= '8.0') + elseif ($table != NULL && $column != NULL && $v >= '8.0') { $sql = sprintf("SELECT pg_get_serial_sequence('%s','%s') as seq", $table, $column); $query = $this->query($sql); $row = $query->row(); $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $row->seq); } - elseif ($table != null) + elseif ($table != NULL) { // seq_name passed in table parameter $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $table); @@ -385,6 +385,7 @@ function count_all($table = '') } $row = $query->row(); + $this->_reset_select(); return (int) $row->numrows; } @@ -400,17 +401,17 @@ function count_all($table = '') * @return string */ function _list_tables($prefix_limit = FALSE) - { - $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'"; - + { + $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'"; + if ($prefix_limit !== FALSE AND $this->dbprefix != '') { - $sql .= " AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_char); + $sql .= " AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); } - + return $sql; } - + // -------------------------------------------------------------------- /** @@ -455,7 +456,7 @@ function _error_message() { return pg_last_error($this->conn_id); } - + // -------------------------------------------------------------------- /** @@ -491,26 +492,26 @@ function _escape_identifiers($item) { if (strpos($item, '.'.$id) !== FALSE) { - $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); - + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); - } + } } - + if (strpos($item, '.') !== FALSE) { - $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; } else { $str = $this->_escape_char.$item.$this->_escape_char; } - + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); } - + // -------------------------------------------------------------------- /** @@ -529,12 +530,12 @@ function _from_tables($tables) { $tables = array($tables); } - + return implode(', ', $tables); } // -------------------------------------------------------------------- - + /** * Insert statement * @@ -547,10 +548,28 @@ function _from_tables($tables) * @return string */ function _insert($table, $keys, $values) - { + { return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; } - + + // -------------------------------------------------------------------- + + /** + * Insert_batch statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert_batch($table, $keys, $values) + { + return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES ".implode(', ', $values); + } + // -------------------------------------------------------------------- /** @@ -568,21 +587,21 @@ function _insert($table, $keys, $values) */ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) { - foreach($values as $key => $val) + foreach ($values as $key => $val) { $valstr[] = $key." = ".$val; } - + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; - + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; $sql .= $orderby.$limit; - + return $sql; } @@ -598,12 +617,12 @@ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) * @access public * @param string the table name * @return string - */ + */ function _truncate($table) { return "TRUNCATE ".$table; } - + // -------------------------------------------------------------------- /** @@ -616,7 +635,7 @@ function _truncate($table) * @param array the where clause * @param string the limit clause * @return string - */ + */ function _delete($table, $where = array(), $like = array(), $limit = FALSE) { $conditions = ''; @@ -634,7 +653,7 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) } $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + return "DELETE FROM ".$table.$conditions.$limit; } @@ -651,14 +670,14 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) * @return string */ function _limit($sql, $limit, $offset) - { + { $sql .= "LIMIT ".$limit; - + if ($offset > 0) { $sql .= " OFFSET ".$offset; } - + return $sql; } diff --git a/system/database/drivers/postgre/postgre_forge.php b/system/database/drivers/postgre/postgre_forge.php index 471dd80c..91a1c686 100644 --- a/system/database/drivers/postgre/postgre_forge.php +++ b/system/database/drivers/postgre/postgre_forge.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -66,12 +66,15 @@ function _drop_database($name) function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) { $sql = 'CREATE TABLE '; - + if ($if_not_exists === TRUE) { - $sql .= 'IF NOT EXISTS '; + if ($this->db->table_exists($table)) + { + return "SELECT * FROM $table"; // Needs to return innocous but valid SQL statement + } } - + $sql .= $this->db->_escape_identifiers($table)." ("; $current_field_count = 0; @@ -87,41 +90,81 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) else { $attributes = array_change_key_case($attributes, CASE_UPPER); - + $sql .= "\n\t".$this->db->_protect_identifiers($field); - - $sql .= ' '.$attributes['TYPE']; - - if (array_key_exists('CONSTRAINT', $attributes)) + + $is_unsigned = (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE); + + // Convert datatypes to be PostgreSQL-compatible + switch (strtoupper($attributes['TYPE'])) { - $sql .= '('.$attributes['CONSTRAINT'].')'; + case 'TINYINT': + $attributes['TYPE'] = 'SMALLINT'; + break; + case 'SMALLINT': + $attributes['TYPE'] = ($is_unsigned) ? 'INTEGER' : 'SMALLINT'; + break; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + break; + case 'INT': + $attributes['TYPE'] = ($is_unsigned) ? 'BIGINT' : 'INTEGER'; + break; + case 'BIGINT': + $attributes['TYPE'] = ($is_unsigned) ? 'NUMERIC' : 'BIGINT'; + break; + case 'DOUBLE': + $attributes['TYPE'] = 'DOUBLE PRECISION'; + break; + case 'DATETIME': + $attributes['TYPE'] = 'TIMESTAMP'; + break; + case 'LONGTEXT': + $attributes['TYPE'] = 'TEXT'; + break; + case 'BLOB': + $attributes['TYPE'] = 'BYTEA'; + break; + } + + // If this is an auto-incrementing primary key, use the serial data type instead + if (in_array($field, $primary_keys) && array_key_exists('AUTO_INCREMENT', $attributes) + && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' SERIAL'; } - - if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + else { - $sql .= ' UNSIGNED'; + $sql .= ' '.$attributes['TYPE']; } - + + // Modified to prevent constraints with integer data types + if (array_key_exists('CONSTRAINT', $attributes) && strpos($attributes['TYPE'], 'INT') === false) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + if (array_key_exists('DEFAULT', $attributes)) { $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; } - + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) { $sql .= ' NULL'; } else { - $sql .= ' NOT NULL'; + $sql .= ' NOT NULL'; } - - if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + + // Added new attribute to create unqite fields. Also works with MySQL + if (array_key_exists('UNIQUE', $attributes) && $attributes['UNIQUE'] === TRUE) { - $sql .= ' AUTO_INCREMENT'; + $sql .= ' UNIQUE'; } } - + // don't add a comma on the end of the last field if (++$current_field_count < count($fields)) { @@ -131,29 +174,37 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) if (count($primary_keys) > 0) { - $primary_keys = $this->db->_protect_identifiers($primary_keys); + // Something seems to break when passing an array to _protect_identifiers() + foreach ($primary_keys as $index => $key) + { + $primary_keys[$index] = $this->db->_protect_identifiers($key); + } + $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; } - + + $sql .= "\n);"; + if (is_array($keys) && count($keys) > 0) { foreach ($keys as $key) { if (is_array($key)) { - $key = $this->db->_protect_identifiers($key); + $key = $this->db->_protect_identifiers($key); } else { $key = array($this->db->_protect_identifiers($key)); } - - $sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")"; + + foreach ($key as $field) + { + $sql .= "CREATE INDEX " . $table . "_" . str_replace(array('"', "'"), '', $field) . "_index ON $table ($field); "; + } } } - $sql .= "\n);"; - return $sql; } @@ -162,12 +213,12 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) /** * Drop Table * - * @access private - * @return bool + * @access private + * @return bool */ function _drop_table($table) { - return "DROP TABLE ".$this->db->_escape_identifiers($table)." CASCADE"; + return "DROP TABLE IF EXISTS ".$this->db->_escape_identifiers($table)." CASCADE"; } // -------------------------------------------------------------------- @@ -218,9 +269,9 @@ function _alter_table($alter_type, $table, $column_name, $column_definition = '' { $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); } - + return $sql; - + } // -------------------------------------------------------------------- diff --git a/system/database/drivers/postgre/postgre_result.php b/system/database/drivers/postgre/postgre_result.php index 8e45eb1c..e9a1d160 100644 --- a/system/database/drivers/postgre/postgre_result.php +++ b/system/database/drivers/postgre/postgre_result.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -36,7 +36,7 @@ function num_rows() { return @pg_num_rows($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -67,7 +67,7 @@ function list_fields() { $field_names[] = pg_field_name($this->result_id, $i); } - + return $field_names; } @@ -86,16 +86,16 @@ function field_data() $retval = array(); for ($i = 0; $i < $this->num_fields(); $i++) { - $F = new stdClass(); - $F->name = pg_field_name($this->result_id, $i); - $F->type = pg_field_type($this->result_id, $i); + $F = new stdClass(); + $F->name = pg_field_name($this->result_id, $i); + $F->type = pg_field_type($this->result_id, $i); $F->max_length = pg_field_size($this->result_id, $i); $F->primary_key = 0; $F->default = ''; $retval[] = $F; } - + return $retval; } @@ -105,7 +105,7 @@ function field_data() * Free the result * * @return null - */ + */ function free_result() { if (is_resource($this->result_id)) @@ -146,7 +146,7 @@ function _fetch_assoc() { return pg_fetch_assoc($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -161,7 +161,7 @@ function _fetch_object() { return pg_fetch_object($this->result_id); } - + } diff --git a/system/database/drivers/postgre/postgre_utility.php b/system/database/drivers/postgre/postgre_utility.php index 235954fa..741c52ea 100644 --- a/system/database/drivers/postgre/postgre_utility.php +++ b/system/database/drivers/postgre/postgre_utility.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -81,42 +81,6 @@ function _backup($params = array()) // Currently unsupported return $this->db->display_error('db_unsuported_feature'); } - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access private - * @param string the database name - * @return bool - */ - function _create_database($name) - { - return "CREATE DATABASE ".$name; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - return "DROP DATABASE ".$name; - } - - } diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php index 0cb79977..0cc898b3 100644 --- a/system/database/drivers/sqlite/sqlite_driver.php +++ b/system/database/drivers/sqlite/sqlite_driver.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -33,14 +33,14 @@ class CI_DB_sqlite_driver extends CI_DB { var $dbdriver = 'sqlite'; - + // The character used to escape with - not needed for SQLite var $_escape_char = ''; // clause and character used for LIKE escape sequences - var $_like_escape_str = " ESCAPE '%s' "; + var $_like_escape_str = " ESCAPE '%s' "; var $_like_escape_chr = '!'; - + /** * The syntax to count rows is slightly different across different * database engines, so this string appears in each driver and is @@ -54,24 +54,24 @@ class CI_DB_sqlite_driver extends CI_DB { * * @access private called by the base class * @return resource - */ + */ function db_connect() { if ( ! $conn_id = @sqlite_open($this->database, FILE_WRITE_MODE, $error)) { log_message('error', $error); - + if ($this->db_debug) { $this->display_error($error, '', TRUE); } - + return FALSE; } - + return $conn_id; } - + // -------------------------------------------------------------------- /** @@ -79,24 +79,24 @@ function db_connect() * * @access private called by the base class * @return resource - */ + */ function db_pconnect() { if ( ! $conn_id = @sqlite_popen($this->database, FILE_WRITE_MODE, $error)) { log_message('error', $error); - + if ($this->db_debug) { $this->display_error($error, '', TRUE); } - + return FALSE; } - + return $conn_id; } - + // -------------------------------------------------------------------- /** @@ -120,7 +120,7 @@ function reconnect() * * @access private called by the base class * @return resource - */ + */ function db_select() { return TRUE; @@ -143,7 +143,7 @@ function db_set_charset($charset, $collation) } // -------------------------------------------------------------------- - + /** * Version number query string * @@ -154,7 +154,7 @@ function _version() { return sqlite_libversion(); } - + // -------------------------------------------------------------------- /** @@ -163,13 +163,13 @@ function _version() * @access private called by the base class * @param string an SQL query * @return resource - */ + */ function _execute($sql) { $sql = $this->_prep_query($sql); return @sqlite_query($this->conn_id, $sql); } - + // -------------------------------------------------------------------- /** @@ -180,7 +180,7 @@ function _execute($sql) * @access private called by execute() * @param string an SQL query * @return string - */ + */ function _prep_query($sql) { return $sql; @@ -192,15 +192,15 @@ function _prep_query($sql) * Begin Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_begin($test_mode = FALSE) { if ( ! $this->trans_enabled) { return TRUE; } - + // When transactions are nested we only begin/commit/rollback the outermost ones if ($this->_trans_depth > 0) { @@ -222,8 +222,8 @@ function trans_begin($test_mode = FALSE) * Commit Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_commit() { if ( ! $this->trans_enabled) @@ -247,8 +247,8 @@ function trans_commit() * Rollback Transaction * * @access public - * @return bool - */ + * @return bool + */ function trans_rollback() { if ( ! $this->trans_enabled) @@ -265,7 +265,7 @@ function trans_rollback() $this->simple_query('ROLLBACK'); return TRUE; } - + // -------------------------------------------------------------------- /** @@ -280,16 +280,16 @@ function escape_str($str, $like = FALSE) { if (is_array($str)) { - foreach($str as $key => $val) - { + foreach ($str as $key => $val) + { $str[$key] = $this->escape_str($val, $like); - } - - return $str; - } - + } + + return $str; + } + $str = sqlite_escape_string($str); - + // escape LIKE condition wildcards if ($like === TRUE) { @@ -297,10 +297,10 @@ function escape_str($str, $like = FALSE) array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr), $str); } - + return $str; } - + // -------------------------------------------------------------------- /** @@ -313,7 +313,7 @@ function affected_rows() { return sqlite_changes($this->conn_id); } - + // -------------------------------------------------------------------- /** @@ -347,13 +347,14 @@ function count_all($table = '') } $query = $this->query($this->_count_string . $this->_protect_identifiers('numrows') . " FROM " . $this->_protect_identifiers($table, TRUE, NULL, FALSE)); - + if ($query->num_rows() == 0) { return 0; } $row = $query->row(); + $this->_reset_select(); return (int) $row->numrows; } @@ -374,7 +375,7 @@ function _list_tables($prefix_limit = FALSE) if ($prefix_limit !== FALSE AND $this->dbprefix != '') { - $sql .= " AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_char); + $sql .= " AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); } return $sql; } @@ -424,7 +425,7 @@ function _error_message() { return sqlite_error_string(sqlite_last_error($this->conn_id)); } - + // -------------------------------------------------------------------- /** @@ -460,26 +461,26 @@ function _escape_identifiers($item) { if (strpos($item, '.'.$id) !== FALSE) { - $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); - + $str = $this->_escape_char. str_replace('.', $this->_escape_char.'.', $item); + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); - } + } } - + if (strpos($item, '.') !== FALSE) { - $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; + $str = $this->_escape_char.str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item).$this->_escape_char; } else { $str = $this->_escape_char.$item.$this->_escape_char; } - + // remove duplicates if the user already included the escape return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $str); } - + // -------------------------------------------------------------------- /** @@ -498,12 +499,12 @@ function _from_tables($tables) { $tables = array($tables); } - + return '('.implode(', ', $tables).')'; } // -------------------------------------------------------------------- - + /** * Insert statement * @@ -516,10 +517,10 @@ function _from_tables($tables) * @return string */ function _insert($table, $keys, $values) - { + { return "INSERT INTO ".$table." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; } - + // -------------------------------------------------------------------- /** @@ -537,25 +538,25 @@ function _insert($table, $keys, $values) */ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) { - foreach($values as $key => $val) + foreach ($values as $key => $val) { $valstr[] = $key." = ".$val; } - + $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + $orderby = (count($orderby) >= 1)?' ORDER BY '.implode(", ", $orderby):''; - + $sql = "UPDATE ".$table." SET ".implode(', ', $valstr); $sql .= ($where != '' AND count($where) >=1) ? " WHERE ".implode(" ", $where) : ''; $sql .= $orderby.$limit; - + return $sql; } - + // -------------------------------------------------------------------- /** @@ -568,12 +569,12 @@ function _update($table, $values, $where, $orderby = array(), $limit = FALSE) * @access public * @param string the table name * @return string - */ + */ function _truncate($table) { return $this->_delete($table); } - + // -------------------------------------------------------------------- /** @@ -586,7 +587,7 @@ function _truncate($table) * @param array the where clause * @param string the limit clause * @return string - */ + */ function _delete($table, $where = array(), $like = array(), $limit = FALSE) { $conditions = ''; @@ -604,10 +605,10 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) } $limit = ( ! $limit) ? '' : ' LIMIT '.$limit; - + return "DELETE FROM ".$table.$conditions.$limit; } - + // -------------------------------------------------------------------- /** @@ -622,7 +623,7 @@ function _delete($table, $where = array(), $like = array(), $limit = FALSE) * @return string */ function _limit($sql, $limit, $offset) - { + { if ($offset == 0) { $offset = ''; @@ -631,7 +632,7 @@ function _limit($sql, $limit, $offset) { $offset .= ", "; } - + return $sql."LIMIT ".$offset.$limit; } diff --git a/system/database/drivers/sqlite/sqlite_forge.php b/system/database/drivers/sqlite/sqlite_forge.php index 0688ba36..56904082 100644 --- a/system/database/drivers/sqlite/sqlite_forge.php +++ b/system/database/drivers/sqlite/sqlite_forge.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -75,13 +75,13 @@ function _drop_database($name) function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) { $sql = 'CREATE TABLE '; - + // IF NOT EXISTS added to SQLite in 3.3.0 - if ($if_not_exists === TRUE && version_compare($this->_version(), '3.3.0', '>=') === TRUE) + if ($if_not_exists === TRUE && version_compare($this->db->_version(), '3.3.0', '>=') === TRUE) { $sql .= 'IF NOT EXISTS '; } - + $sql .= $this->db->_escape_identifiers($table)."("; $current_field_count = 0; @@ -97,41 +97,41 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) else { $attributes = array_change_key_case($attributes, CASE_UPPER); - + $sql .= "\n\t".$this->db->_protect_identifiers($field); - + $sql .= ' '.$attributes['TYPE']; - + if (array_key_exists('CONSTRAINT', $attributes)) { $sql .= '('.$attributes['CONSTRAINT'].')'; } - + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) { $sql .= ' UNSIGNED'; } - + if (array_key_exists('DEFAULT', $attributes)) { $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; } - + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) { $sql .= ' NULL'; } else { - $sql .= ' NOT NULL'; + $sql .= ' NOT NULL'; } - + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) { $sql .= ' AUTO_INCREMENT'; } } - + // don't add a comma on the end of the last field if (++$current_field_count < count($fields)) { @@ -151,13 +151,13 @@ function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) { if (is_array($key)) { - $key = $this->db->_protect_identifiers($key); + $key = $this->db->_protect_identifiers($key); } else { $key = array($this->db->_protect_identifiers($key)); } - + $sql .= ",\n\tUNIQUE (" . implode(', ', $key) . ")"; } } @@ -237,9 +237,9 @@ function _alter_table($alter_type, $table, $column_name, $column_definition = '' { $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); } - + return $sql; - + } // -------------------------------------------------------------------- diff --git a/system/database/drivers/sqlite/sqlite_result.php b/system/database/drivers/sqlite/sqlite_result.php index c1c24c78..7bd30db7 100644 --- a/system/database/drivers/sqlite/sqlite_result.php +++ b/system/database/drivers/sqlite/sqlite_result.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -25,7 +25,7 @@ * @link http://codeigniter.com/user_guide/database/ */ class CI_DB_sqlite_result extends CI_DB_result { - + /** * Number of rows in the result set * @@ -36,7 +36,7 @@ function num_rows() { return @sqlite_num_rows($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -67,7 +67,7 @@ function list_fields() { $field_names[] = sqlite_field_name($this->result_id, $i); } - + return $field_names; } @@ -86,16 +86,16 @@ function field_data() $retval = array(); for ($i = 0; $i < $this->num_fields(); $i++) { - $F = new stdClass(); - $F->name = sqlite_field_name($this->result_id, $i); - $F->type = 'varchar'; + $F = new stdClass(); + $F->name = sqlite_field_name($this->result_id, $i); + $F->type = 'varchar'; $F->max_length = 0; $F->primary_key = 0; $F->default = ''; $retval[] = $F; } - + return $retval; } @@ -105,7 +105,7 @@ function field_data() * Free the result * * @return null - */ + */ function free_result() { // Not implemented in SQLite @@ -142,7 +142,7 @@ function _fetch_assoc() { return sqlite_fetch_array($this->result_id); } - + // -------------------------------------------------------------------- /** @@ -168,7 +168,7 @@ function _fetch_object() return $obj; } else { return NULL; - } + } } } diff --git a/system/database/drivers/sqlite/sqlite_utility.php b/system/database/drivers/sqlite/sqlite_utility.php index f66464e3..508023e2 100644 --- a/system/database/drivers/sqlite/sqlite_utility.php +++ b/system/database/drivers/sqlite/sqlite_utility.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -39,7 +39,7 @@ function _list_databases() { if ($this->db_debug) { - return $this->display_error('db_unsuported_feature'); + return $this->db->display_error('db_unsuported_feature'); } return array(); } @@ -90,51 +90,6 @@ function _backup($params = array()) // Currently unsupported return $this->db->display_error('db_unsuported_feature'); } - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access public - * @param string the database name - * @return bool - */ - function _create_database() - { - // In SQLite, a database is created when you connect to the database. - // We'll return TRUE so that an error isn't generated - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - if ( ! @file_exists($this->db->database) OR ! @unlink($this->db->database)) - { - if ($this->db->db_debug) - { - return $this->db->display_error('db_unable_to_drop'); - } - return FALSE; - } - return TRUE; - } - } /* End of file sqlite_utility.php */ diff --git a/system/plugins/index.html b/system/database/drivers/sqlsrv/index.html similarity index 100% rename from system/plugins/index.html rename to system/database/drivers/sqlsrv/index.html diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php new file mode 100644 index 00000000..400fd31c --- /dev/null +++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php @@ -0,0 +1,599 @@ +char_set)) ? 'UTF-8' : $this->char_set; + + $connection = array( + 'UID' => empty($this->username) ? '' : $this->username, + 'PWD' => empty($this->password) ? '' : $this->password, + 'Database' => $this->database, + 'ConnectionPooling' => $pooling ? 1 : 0, + 'CharacterSet' => $character_set, + 'ReturnDatesAsStrings' => 1 + ); + + // If the username and password are both empty, assume this is a + // 'Windows Authentication Mode' connection. + if(empty($connection['UID']) && empty($connection['PWD'])) { + unset($connection['UID'], $connection['PWD']); + } + + return sqlsrv_connect($this->hostname, $connection); + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + $this->db_connect(TRUE); + } + + // -------------------------------------------------------------------- + + /** + * Reconnect + * + * Keep / reestablish the db connection if no queries have been + * sent for a length of time exceeding the server's idle timeout + * + * @access public + * @return void + */ + function reconnect() + { + // not implemented in MSSQL + } + + // -------------------------------------------------------------------- + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + return $this->_execute('USE ' . $this->database); + } + + // -------------------------------------------------------------------- + + /** + * Set client character set + * + * @access public + * @param string + * @param string + * @return resource + */ + function db_set_charset($charset, $collation) + { + // @todo - add support if needed + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return resource + */ + function _execute($sql) + { + $sql = $this->_prep_query($sql); + return sqlsrv_query($this->conn_id, $sql, null, array( + 'Scrollable' => SQLSRV_CURSOR_STATIC, + 'SendStreamParamsAtExec' => true + )); + } + + // -------------------------------------------------------------------- + + /** + * Prep the query + * + * If needed, each database adapter can prep the query string + * + * @access private called by execute() + * @param string an SQL query + * @return string + */ + function _prep_query($sql) + { + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Begin Transaction + * + * @access public + * @return bool + */ + function trans_begin($test_mode = FALSE) + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + // Reset the transaction failure flag. + // If the $test_mode flag is set to TRUE transactions will be rolled back + // even if the queries produce a successful result. + $this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE; + + return sqlsrv_begin_transaction($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Commit Transaction + * + * @access public + * @return bool + */ + function trans_commit() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + return sqlsrv_commit($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Rollback Transaction + * + * @access public + * @return bool + */ + function trans_rollback() + { + if ( ! $this->trans_enabled) + { + return TRUE; + } + + // When transactions are nested we only begin/commit/rollback the outermost ones + if ($this->_trans_depth > 0) + { + return TRUE; + } + + return sqlsrv_rollback($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Escape String + * + * @access public + * @param string + * @param bool whether or not the string will be used in a LIKE condition + * @return string + */ + function escape_str($str, $like = FALSE) + { + // Escape single quotes + return str_replace("'", "''", $str); + } + + // -------------------------------------------------------------------- + + /** + * Affected Rows + * + * @access public + * @return integer + */ + function affected_rows() + { + return @sqlrv_rows_affected($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * Returns the last id created in the Identity column. + * + * @access public + * @return integer + */ + function insert_id() + { + return $this->query('select @@IDENTITY as insert_id')->row('insert_id'); + } + + // -------------------------------------------------------------------- + + /** + * Parse major version + * + * Grabs the major version number from the + * database server version string passed in. + * + * @access private + * @param string $version + * @return int16 major version number + */ + function _parse_major_version($version) + { + preg_match('/([0-9]+)\.([0-9]+)\.([0-9]+)/', $version, $ver_info); + return $ver_info[1]; // return the major version b/c that's all we're interested in. + } + + // -------------------------------------------------------------------- + + /** + * Version number query string + * + * @access public + * @return string + */ + function _version() + { + $info = sqlsrv_server_info($this->conn_id); + return sprintf("select '%s' as ver", $info['SQLServerVersion']); + } + + // -------------------------------------------------------------------- + + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @access public + * @param string + * @return string + */ + function count_all($table = '') + { + if ($table == '') + return '0'; + + $query = $this->query("SELECT COUNT(*) AS numrows FROM " . $this->dbprefix . $table); + + if ($query->num_rows() == 0) + return '0'; + + $row = $query->row(); + $this->_reset_select(); + return $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * List table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access private + * @param boolean + * @return string + */ + function _list_tables($prefix_limit = FALSE) + { + return "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name"; + } + + // -------------------------------------------------------------------- + + /** + * List column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @access private + * @param string the table name + * @return string + */ + function _list_columns($table = '') + { + return "SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = '".$this->_escape_table($table)."'"; + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @access public + * @param string the table name + * @return object + */ + function _field_data($table) + { + return "SELECT TOP 1 * FROM " . $this->_escape_table($table); + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + $error = array_shift(sqlsrv_errors()); + return !empty($error['message']) ? $error['message'] : null; + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + $error = array_shift(sqlsrv_errors()); + return isset($error['SQLSTATE']) ? $error['SQLSTATE'] : null; + } + + // -------------------------------------------------------------------- + + /** + * Escape Table Name + * + * This function adds backticks if the table name has a period + * in it. Some DBs will get cranky unless periods are escaped + * + * @access private + * @param string the table name + * @return string + */ + function _escape_table($table) + { + return $table; + } + + + /** + * Escape the SQL Identifiers + * + * This function escapes column and table names + * + * @access private + * @param string + * @return string + */ + function _escape_identifiers($item) + { + return $item; + } + + // -------------------------------------------------------------------- + + /** + * From Tables + * + * This function implicitly groups FROM tables so there is no confusion + * about operator precedence in harmony with SQL standards + * + * @access public + * @param type + * @return type + */ + function _from_tables($tables) + { + if ( ! is_array($tables)) + { + $tables = array($tables); + } + + return implode(', ', $tables); + } + + // -------------------------------------------------------------------- + + /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @access public + * @param string the table name + * @param array the insert keys + * @param array the insert values + * @return string + */ + function _insert($table, $keys, $values) + { + return "INSERT INTO ".$this->_escape_table($table)." (".implode(', ', $keys).") VALUES (".implode(', ', $values).")"; + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @access public + * @param string the table name + * @param array the update data + * @param array the where clause + * @param array the orderby clause + * @param array the limit clause + * @return string + */ + function _update($table, $values, $where) + { + foreach($values as $key => $val) + { + $valstr[] = $key." = ".$val; + } + + return "UPDATE ".$this->_escape_table($table)." SET ".implode(', ', $valstr)." WHERE ".implode(" ", $where); + } + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * If the database does not support the truncate() command + * This function maps to "DELETE FROM table" + * + * @access public + * @param string the table name + * @return string + */ + function _truncate($table) + { + return "TRUNCATE ".$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @param string the limit clause + * @return string + */ + function _delete($table, $where) + { + return "DELETE FROM ".$this->_escape_table($table)." WHERE ".implode(" ", $where); + } + + // -------------------------------------------------------------------- + + /** + * Limit string + * + * Generates a platform-specific LIMIT clause + * + * @access public + * @param string the sql query string + * @param integer the number of rows to limit the query to + * @param integer the offset value + * @return string + */ + function _limit($sql, $limit, $offset) + { + $i = $limit + $offset; + + return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$i.' ', $sql); + } + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + @sqlsrv_close($conn_id); + } + +} + + + +/* End of file mssql_driver.php */ +/* Location: ./system/database/drivers/mssql/mssql_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/sqlsrv/sqlsrv_forge.php b/system/database/drivers/sqlsrv/sqlsrv_forge.php new file mode 100644 index 00000000..cc88ec5c --- /dev/null +++ b/system/database/drivers/sqlsrv/sqlsrv_forge.php @@ -0,0 +1,248 @@ +db->_escape_identifiers($table); + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @access private + * @param string the table name + * @param array the fields + * @param mixed primary key(s) + * @param mixed key(s) + * @param boolean should 'IF NOT EXISTS' be added to the SQL + * @return bool + */ + function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + { + $sql = 'CREATE TABLE '; + + if ($if_not_exists === TRUE) + { + $sql .= 'IF NOT EXISTS '; + } + + $sql .= $this->db->_escape_identifiers($table)." ("; + $current_field_count = 0; + + foreach ($fields as $field=>$attributes) + { + // Numeric field names aren't allowed in databases, so if the key is + // numeric, we know it was assigned by PHP and the developer manually + // entered the field information, so we'll simply add it to the list + if (is_numeric($field)) + { + $sql .= "\n\t$attributes"; + } + else + { + $attributes = array_change_key_case($attributes, CASE_UPPER); + + $sql .= "\n\t".$this->db->_protect_identifiers($field); + + $sql .= ' '.$attributes['TYPE']; + + if (array_key_exists('CONSTRAINT', $attributes)) + { + $sql .= '('.$attributes['CONSTRAINT'].')'; + } + + if (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE) + { + $sql .= ' UNSIGNED'; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; + } + + if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $sql .= ' AUTO_INCREMENT'; + } + } + + // don't add a comma on the end of the last field + if (++$current_field_count < count($fields)) + { + $sql .= ','; + } + } + + if (count($primary_keys) > 0) + { + $primary_keys = $this->db->_protect_identifiers($primary_keys); + $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + } + + if (is_array($keys) && count($keys) > 0) + { + foreach ($keys as $key) + { + if (is_array($key)) + { + $key = $this->db->_protect_identifiers($key); + } + else + { + $key = array($this->db->_protect_identifiers($key)); + } + + $sql .= ",\n\tFOREIGN KEY (" . implode(', ', $key) . ")"; + } + } + + $sql .= "\n)"; + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Alter table query + * + * Generates a platform-specific query so that a table can be altered + * Called by add_column(), drop_column(), and column_alter(), + * + * @access private + * @param string the ALTER type (ADD, DROP, CHANGE) + * @param string the column name + * @param string the table name + * @param string the column definition + * @param string the default value + * @param boolean should 'NOT NULL' be added + * @param string the field after which we should add the new field + * @return object + */ + function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + { + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table)." $alter_type ".$this->db->_protect_identifiers($column_name); + + // DROP has everything it needs now. + if ($alter_type == 'DROP') + { + return $sql; + } + + $sql .= " $column_definition"; + + if ($default_value != '') + { + $sql .= " DEFAULT \"$default_value\""; + } + + if ($null === NULL) + { + $sql .= ' NULL'; + } + else + { + $sql .= ' NOT NULL'; + } + + if ($after_field != '') + { + $sql .= ' AFTER ' . $this->db->_protect_identifiers($after_field); + } + + return $sql; + + } + + // -------------------------------------------------------------------- + + /** + * Rename a table + * + * Generates a platform-specific query so that a table can be renamed + * + * @access private + * @param string the old table name + * @param string the new table name + * @return string + */ + function _rename_table($table_name, $new_table_name) + { + // I think this syntax will work, but can find little documentation on renaming tables in MSSQL + $sql = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name); + return $sql; + } + +} + +/* End of file mssql_forge.php */ +/* Location: ./system/database/drivers/mssql/mssql_forge.php */ \ No newline at end of file diff --git a/system/database/drivers/sqlsrv/sqlsrv_result.php b/system/database/drivers/sqlsrv/sqlsrv_result.php new file mode 100644 index 00000000..bf0abd1c --- /dev/null +++ b/system/database/drivers/sqlsrv/sqlsrv_result.php @@ -0,0 +1,169 @@ +result_id); + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + return @sqlsrv_num_fields($this->result_id); + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names + * + * @access public + * @return array + */ + function list_fields() + { + $field_names = array(); + foreach(sqlsrv_field_metadata($this->result_id) as $offset => $field) + { + $field_names[] = $field['Name']; + } + + return $field_names; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $retval = array(); + foreach(sqlsrv_field_metadata($this->result_id) as $offset => $field) + { + $F = new stdClass(); + $F->name = $field['Name']; + $F->type = $field['Type']; + $F->max_length = $field['Size']; + $F->primary_key = 0; + $F->default = ''; + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if (is_resource($this->result_id)) + { + sqlsrv_free_stmt($this->result_id); + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Data Seek + * + * Moves the internal pointer to the desired offset. We call + * this internally before fetching results to make sure the + * result set starts at zero + * + * @access private + * @return array + */ + function _data_seek($n = 0) + { + // Not implemented + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + return sqlsrv_fetch_array($this->result_id, SQLSRV_FETCH_ASSOC); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + return sqlsrv_fetch_object($this->result_id); + } + +} + + +/* End of file mssql_result.php */ +/* Location: ./system/database/drivers/mssql/mssql_result.php */ \ No newline at end of file diff --git a/system/database/drivers/sqlsrv/sqlsrv_utility.php b/system/database/drivers/sqlsrv/sqlsrv_utility.php new file mode 100644 index 00000000..13a1850c --- /dev/null +++ b/system/database/drivers/sqlsrv/sqlsrv_utility.php @@ -0,0 +1,88 @@ +db->display_error('db_unsuported_feature'); + } + +} + +/* End of file mssql_utility.php */ +/* Location: ./system/database/drivers/mssql/mssql_utility.php */ \ No newline at end of file diff --git a/system/fonts/index.html b/system/fonts/index.html new file mode 100644 index 00000000..c942a79c --- /dev/null +++ b/system/fonts/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/system/fonts/texb.ttf b/system/fonts/texb.ttf new file mode 100644 index 00000000..383c88b8 Binary files /dev/null and b/system/fonts/texb.ttf differ diff --git a/system/helpers/array_helper.php b/system/helpers/array_helper.php index 39d0c88c..075a31fd 100644 --- a/system/helpers/array_helper.php +++ b/system/helpers/array_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -38,7 +38,7 @@ * @param array * @param mixed * @return mixed depends on what the array contains - */ + */ if ( ! function_exists('element')) { function element($item, $array, $default = FALSE) @@ -49,7 +49,7 @@ function element($item, $array, $default = FALSE) } return $array[$item]; - } + } } // ------------------------------------------------------------------------ @@ -60,7 +60,7 @@ function element($item, $array, $default = FALSE) * @access public * @param array * @return mixed depends on what the array contains - */ + */ if ( ! function_exists('random_element')) { function random_element($array) @@ -69,10 +69,51 @@ function random_element($array) { return $array; } + return $array[array_rand($array)]; - } + } } +// -------------------------------------------------------------------- + +/** + * Elements + * + * Returns only the array items specified. Will return a default value if + * it is not set. + * + * @access public + * @param array + * @param array + * @param mixed + * @return mixed depends on what the array contains + */ +if ( ! function_exists('elements')) +{ + function elements($items, $array, $default = FALSE) + { + $return = array(); + + if ( ! is_array($items)) + { + $items = array($items); + } + + foreach ($items as $item) + { + if (isset($array[$item])) + { + $return[$item] = $array[$item]; + } + else + { + $return[$item] = $default; + } + } + + return $return; + } +} /* End of file array_helper.php */ /* Location: ./system/helpers/array_helper.php */ \ No newline at end of file diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php new file mode 100644 index 00000000..19ec0c77 --- /dev/null +++ b/system/helpers/captcha_helper.php @@ -0,0 +1,246 @@ + '', 'img_path' => '', 'img_url' => '', 'img_width' => '150', 'img_height' => '30', 'font_path' => '', 'expiration' => 7200); + + foreach ($defaults as $key => $val) + { + if ( ! is_array($data)) + { + if ( ! isset($$key) OR $$key == '') + { + $$key = $val; + } + } + else + { + $$key = ( ! isset($data[$key])) ? $val : $data[$key]; + } + } + + if ($img_path == '' OR $img_url == '') + { + return FALSE; + } + + if ( ! @is_dir($img_path)) + { + return FALSE; + } + + if ( ! is_writable($img_path)) + { + return FALSE; + } + + if ( ! extension_loaded('gd')) + { + return FALSE; + } + + // ----------------------------------- + // Remove old images + // ----------------------------------- + + list($usec, $sec) = explode(" ", microtime()); + $now = ((float)$usec + (float)$sec); + + $current_dir = @opendir($img_path); + + while ($filename = @readdir($current_dir)) + { + if ($filename != "." and $filename != ".." and $filename != "index.html") + { + $name = str_replace(".jpg", "", $filename); + + if (($name + $expiration) < $now) + { + @unlink($img_path.$filename); + } + } + } + + @closedir($current_dir); + + // ----------------------------------- + // Do we have a "word" yet? + // ----------------------------------- + + if ($word == '') + { + $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $str = ''; + for ($i = 0; $i < 8; $i++) + { + $str .= substr($pool, mt_rand(0, strlen($pool) -1), 1); + } + + $word = $str; + } + + // ----------------------------------- + // Determine angle and position + // ----------------------------------- + + $length = strlen($word); + $angle = ($length >= 6) ? rand(-($length-6), ($length-6)) : 0; + $x_axis = rand(6, (360/$length)-16); + $y_axis = ($angle >= 0 ) ? rand($img_height, $img_width) : rand(6, $img_height); + + // ----------------------------------- + // Create image + // ----------------------------------- + + // PHP.net recommends imagecreatetruecolor(), but it isn't always available + if (function_exists('imagecreatetruecolor')) + { + $im = imagecreatetruecolor($img_width, $img_height); + } + else + { + $im = imagecreate($img_width, $img_height); + } + + // ----------------------------------- + // Assign colors + // ----------------------------------- + + $bg_color = imagecolorallocate ($im, 255, 255, 255); + $border_color = imagecolorallocate ($im, 153, 102, 102); + $text_color = imagecolorallocate ($im, 204, 153, 153); + $grid_color = imagecolorallocate($im, 255, 182, 182); + $shadow_color = imagecolorallocate($im, 255, 240, 240); + + // ----------------------------------- + // Create the rectangle + // ----------------------------------- + + ImageFilledRectangle($im, 0, 0, $img_width, $img_height, $bg_color); + + // ----------------------------------- + // Create the spiral pattern + // ----------------------------------- + + $theta = 1; + $thetac = 7; + $radius = 16; + $circles = 20; + $points = 32; + + for ($i = 0; $i < ($circles * $points) - 1; $i++) + { + $theta = $theta + $thetac; + $rad = $radius * ($i / $points ); + $x = ($rad * cos($theta)) + $x_axis; + $y = ($rad * sin($theta)) + $y_axis; + $theta = $theta + $thetac; + $rad1 = $radius * (($i + 1) / $points); + $x1 = ($rad1 * cos($theta)) + $x_axis; + $y1 = ($rad1 * sin($theta )) + $y_axis; + imageline($im, $x, $y, $x1, $y1, $grid_color); + $theta = $theta - $thetac; + } + + // ----------------------------------- + // Write the text + // ----------------------------------- + + $use_font = ($font_path != '' AND file_exists($font_path) AND function_exists('imagettftext')) ? TRUE : FALSE; + + if ($use_font == FALSE) + { + $font_size = 5; + $x = rand(0, $img_width/($length/3)); + $y = 0; + } + else + { + $font_size = 16; + $x = rand(0, $img_width/($length/1.5)); + $y = $font_size+2; + } + + for ($i = 0; $i < strlen($word); $i++) + { + if ($use_font == FALSE) + { + $y = rand(0 , $img_height/2); + imagestring($im, $font_size, $x, $y, substr($word, $i, 1), $text_color); + $x += ($font_size*2); + } + else + { + $y = rand($img_height/2, $img_height-3); + imagettftext($im, $font_size, $angle, $x, $y, $text_color, $font_path, substr($word, $i, 1)); + $x += $font_size; + } + } + + + // ----------------------------------- + // Create the border + // ----------------------------------- + + imagerectangle($im, 0, 0, $img_width-1, $img_height-1, $border_color); + + // ----------------------------------- + // Generate the image + // ----------------------------------- + + $img_name = $now.'.jpg'; + + ImageJPEG($im, $img_path.$img_name); + + $img = "\""; + + ImageDestroy($im); + + return array('word' => $word, 'time' => $now, 'image' => $img); + } +} + +// ------------------------------------------------------------------------ + +/* End of file captcha_helper.php */ +/* Location: ./system/heleprs/captcha_helper.php */ \ No newline at end of file diff --git a/system/helpers/compatibility_helper.php b/system/helpers/compatibility_helper.php deleted file mode 100644 index c217f7f5..00000000 --- a/system/helpers/compatibility_helper.php +++ /dev/null @@ -1,498 +0,0 @@ - 0) // 8 = FILE_APPEND flag - { - $mode = FOPEN_WRITE_CREATE; - } - else - { - $mode = FOPEN_WRITE_CREATE_DESTRUCTIVE; - } - - // Check if we're using the include path - if (($flags & 1) > 0) // 1 = FILE_USE_INCLUDE_PATH flag - { - $use_include_path = TRUE; - } - else - { - $use_include_path = FALSE; - } - - $fp = @fopen($filename, $mode, $use_include_path); - - if ($fp === FALSE) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'file_put_contents('.htmlentities($filename).') failed to open stream', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - if (($flags & LOCK_EX) > 0) - { - if ( ! flock($fp, LOCK_EX)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'file_put_contents('.htmlentities($filename).') unable to acquire an exclusive lock on file', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - } - - // write it - if (($written = @fwrite($fp, $data)) === FALSE) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'file_put_contents('.htmlentities($filename).') failed to write to '.htmlentities($filename), $backtrace[0]['file'], $backtrace[0]['line']); - } - - // Close the handle - @fclose($fp); - - // Return length - return $written; - } -} - -// ------------------------------------------------------------------------ - -/** - * fputcsv() - * - * Format line as CSV and write to file pointer - * http://us.php.net/manual/en/function.fputcsv.php - * - * @access public - * @param resource file pointer - * @param array data to be written - * @param string delimiter - * @param string enclosure - * @return int length of written string - */ -if ( ! function_exists('fputcsv')) -{ - function fputcsv($handle, $fields, $delimiter = ',', $enclosure = '"') - { - // Checking for a handle resource - if ( ! is_resource($handle)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'fputcsv() expects parameter 1 to be stream resource, '.gettype($handle).' given', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - // OK, it is a resource, but is it a stream? - if (get_resource_type($handle) !== 'stream') - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'fputcsv() expects parameter 1 to be stream resource, '.get_resource_type($handle).' given', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - // Checking for an array of fields - if ( ! is_array($fields)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'fputcsv() expects parameter 2 to be array, '.gettype($fields).' given', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - // validate delimiter - if (strlen($delimiter) > 1) - { - $delimiter = substr($delimiter, 0, 1); - $backtrace = debug_backtrace(); - _exception_handler(E_NOTICE, 'fputcsv() delimiter must be one character long, "'.htmlentities($delimiter).'" used', $backtrace[0]['file'], $backtrace[0]['line']); - } - - // validate enclosure - if (strlen($enclosure) > 1) - { - $enclosure = substr($enclosure, 0, 1); - $backtrace = debug_backtrace(); - _exception_handler(E_NOTICE, 'fputcsv() enclosure must be one character long, "'.htmlentities($enclosure).'" used', $backtrace[0]['file'], $backtrace[0]['line']); - - } - - $out = ''; - - foreach ($fields as $cell) - { - $cell = str_replace($enclosure, $enclosure.$enclosure, $cell); - - if (strpos($cell, $delimiter) !== FALSE OR strpos($cell, $enclosure) !== FALSE OR strpos($cell, "\n") !== FALSE) - { - $out .= $enclosure.$cell.$enclosure.$delimiter; - } - else - { - $out .= $cell.$delimiter; - } - } - - $length = @fwrite($handle, substr($out, 0, -1)."\n"); - - return $length; - } -} - -// ------------------------------------------------------------------------ - -/** - * stripos() - * - * Find position of first occurrence of a case-insensitive string - * http://us.php.net/manual/en/function.stripos.php - * - * @access public - * @param string haystack - * @param string needle - * @param int offset - * @return int numeric position of the first occurrence of needle in the haystack - */ -if ( ! function_exists('stripos')) -{ - function stripos($haystack, $needle, $offset = NULL) - { - // Cast non string scalar values - if (is_scalar($haystack)) - { - settype($haystack, 'STRING'); - } - - if ( ! is_string($haystack)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'stripos() expects parameter 1 to be string, '.gettype($haystack).' given', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - if ( ! is_scalar($needle)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'stripos() needle is not a string or an integer in '.$backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - if (is_float($offset)) - { - $offset = (int)$offset; - } - - if ( ! is_int($offset) && ! is_bool($offset) && ! is_null($offset)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'stripos() expects parameter 3 to be long, '.gettype($offset).' given', $backtrace[0]['file'], $backtrace[0]['line']); - return NULL; - } - - return strpos(strtolower($haystack), strtolower($needle), $offset); - } -} - -// ------------------------------------------------------------------------ - -/** - * str_ireplace() - * - * Find position of first occurrence of a case-insensitive string - * http://us.php.net/manual/en/function.str-ireplace.php - * (parameter 4, $count, is not supported as to do so in PHP 4 would make - * it a required parameter) - * - * @access public - * @param mixed search - * @param mixed replace - * @param mixed subject - * @return int numeric position of the first occurrence of needle in the haystack - */ -if ( ! function_exists('str_ireplace')) -{ - function str_ireplace($search, $replace, $subject) - { - // Nothing to do here - if ($search === NULL OR $subject === NULL) - { - return $subject; - } - - // Crazy arguments - if (is_scalar($search) && is_array($replace)) - { - $backtrace = debug_backtrace(); - - if (is_object($replace)) - { - show_error('Object of class '.get_class($replace).' could not be converted to string in '.$backtrace[0]['file'].' on line '.$backtrace[0]['line']); - } - else - { - _exception_handler(E_USER_NOTICE, 'Array to string conversion in '.$backtrace[0]['file'], $backtrace[0]['line']); - } - } - - // Searching for an array - if (is_array($search)) - { - // Replacing with an array - if (is_array($replace)) - { - $search = array_values($search); - $replace = array_values($replace); - - if (count($search) >= count($replace)) - { - $replace = array_pad($replace, count($search), ''); - } - else - { - $replace = array_slice($replace, 0, count($search)); - } - } - else - { - // Replacing with a string all positions - $replace = array_fill(0, count($search), $replace); - } - } - else - { - //Searching for a string and replacing with a string. - $search = array((string)$search); - $replace = array((string)$replace); - } - - // Prepare the search array - foreach ($search as $search_key => $search_value) - { - $search[$search_key] = '/'.preg_quote($search_value, '/').'/i'; - } - - // Prepare the replace array (escape backreferences) - foreach ($replace as $k => $v) - { - $replace[$k] = str_replace(array(chr(92), '$'), array(chr(92).chr(92), '\$'), $v); - } - - // do the replacement - $result = preg_replace($search, $replace, (array)$subject); - - // Check if subject was initially a string and return it as a string - if ( ! is_array($subject)) - { - return current($result); - } - - // Otherwise, just return the array - return $result; - } -} - -// ------------------------------------------------------------------------ - -/** - * http_build_query() - * - * Generate URL-encoded query string - * http://us.php.net/manual/en/function.http-build-query.php - * - * @access public - * @param array form data - * @param string numeric prefix - * @param string argument separator - * @return string URL-encoded string - */ -if ( ! function_exists('http_build_query')) -{ - function http_build_query($formdata, $numeric_prefix = NULL, $separator = NULL) - { - // Check the data - if ( ! is_array($formdata) && ! is_object($formdata)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'http_build_query() Parameter 1 expected to be Array or Object. Incorrect value given', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - // Cast it as array - if (is_object($formdata)) - { - $formdata = get_object_vars($formdata); - } - - // If the array is empty, return NULL - if (empty($formdata)) - { - return NULL; - } - - // Argument separator - if ($separator === NULL) - { - $separator = ini_get('arg_separator.output'); - - if (strlen($separator) == 0) - { - $separator = '&'; - } - } - - // Start building the query - $tmp = array(); - - foreach ($formdata as $key => $val) - { - if ($val === NULL) - { - continue; - } - - if (is_integer($key) && $numeric_prefix != NULL) - { - $key = $numeric_prefix.$key; - } - - if (is_resource($val)) - { - return NULL; - } - - // hand it off to a recursive parser - $tmp[] = _http_build_query_helper($key, $val, $separator); - } - - return implode($separator, $tmp); - } - - - // Helper helper. Remind anyone of college? - // Required to handle recursion in nested arrays. - // - // You could shave fractions of fractions of a second by moving where - // the urlencoding takes place, but it's much less intuitive, and if - // your application has 10,000 form fields, well, you have other problems ;) - function _http_build_query_helper($key, $val, $separator = '&') - { - if (is_scalar($val)) - { - return urlencode($key).'='.urlencode($val); - } - else - { - // arrays please - if (is_object($val)) - { - $val = get_object_vars($val); - } - - foreach ($val as $k => $v) - { - $tmp[] = _http_build_query_helper($key.'['.$k.']', $v, $separator); - } - } - - return implode($separator, $tmp); - } -} - - -/* End of file compatibility_helper.php */ -/* Location: ./system/helpers/compatibility_helper.php */ \ No newline at end of file diff --git a/system/helpers/cookie_helper.php b/system/helpers/cookie_helper.php index 7607ffb4..7cee0282 100644 --- a/system/helpers/cookie_helper.php +++ b/system/helpers/cookie_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -44,55 +44,14 @@ */ if ( ! function_exists('set_cookie')) { - function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '') + function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE) { - if (is_array($name)) - { - foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'name') as $item) - { - if (isset($name[$item])) - { - $$item = $name[$item]; - } - } - } - // Set the config file options $CI =& get_instance(); - - if ($prefix == '' AND $CI->config->item('cookie_prefix') != '') - { - $prefix = $CI->config->item('cookie_prefix'); - } - if ($domain == '' AND $CI->config->item('cookie_domain') != '') - { - $domain = $CI->config->item('cookie_domain'); - } - if ($path == '/' AND $CI->config->item('cookie_path') != '/') - { - $path = $CI->config->item('cookie_path'); - } - - if ( ! is_numeric($expire)) - { - $expire = time() - 86500; - } - else - { - if ($expire > 0) - { - $expire = time() + $expire; - } - else - { - $expire = 0; - } - } - - setcookie($prefix.$name, $value, $expire, $path, $domain, 0); + $CI->input->set_cookie($name, $value, $expire, $domain, $path, $prefix, $secure); } } - + // -------------------------------------------------------------------- /** @@ -108,14 +67,14 @@ function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = function get_cookie($index = '', $xss_clean = FALSE) { $CI =& get_instance(); - + $prefix = ''; - + if ( ! isset($_COOKIE[$index]) && config_item('cookie_prefix') != '') { $prefix = config_item('cookie_prefix'); } - + return $CI->input->cookie($prefix.$index, $xss_clean); } } diff --git a/system/helpers/date_helper.php b/system/helpers/date_helper.php index fae9e66e..0aeb7faf 100644 --- a/system/helpers/date_helper.php +++ b/system/helpers/date_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -34,24 +34,24 @@ * * @access public * @return integer - */ + */ if ( ! function_exists('now')) { function now() { $CI =& get_instance(); - + if (strtolower($CI->config->item('time_reference')) == 'gmt') { $now = time(); $system_time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now)); - + if (strlen($system_time) < 10) { $system_time = time(); log_message('error', 'The Date class could not set a proper GMT timestamp so the local time() value was used.'); } - + return $system_time; } else @@ -60,7 +60,7 @@ function now() } } } - + // ------------------------------------------------------------------------ /** @@ -79,22 +79,22 @@ function now() * @param string * @param integer * @return integer - */ + */ if ( ! function_exists('mdate')) { function mdate($datestr = '', $time = '') { if ($datestr == '') return ''; - + if ($time == '') $time = now(); - + $datestr = str_replace('%\\', '', preg_replace("/([a-z]+?){1}/i", "\\\\\\1", $datestr)); return date($datestr, $time); } } - + // ------------------------------------------------------------------------ /** @@ -106,7 +106,7 @@ function mdate($datestr = '', $time = '') * @param string the chosen format * @param integer Unix timestamp * @return string - */ + */ if ( ! function_exists('standard_date')) { function standard_date($fmt = 'DATE_RFC822', $time = '') @@ -114,9 +114,9 @@ function standard_date($fmt = 'DATE_RFC822', $time = '') $formats = array( 'DATE_ATOM' => '%Y-%m-%dT%H:%i:%s%Q', 'DATE_COOKIE' => '%l, %d-%M-%y %H:%i:%s UTC', - 'DATE_ISO8601' => '%Y-%m-%dT%H:%i:%s%O', + 'DATE_ISO8601' => '%Y-%m-%dT%H:%i:%s%Q', 'DATE_RFC822' => '%D, %d %M %y %H:%i:%s %O', - 'DATE_RFC850' => '%l, %d-%M-%y %H:%m:%i UTC', + 'DATE_RFC850' => '%l, %d-%M-%y %H:%i:%s UTC', 'DATE_RFC1036' => '%D, %d %M %y %H:%i:%s %O', 'DATE_RFC1123' => '%D, %d %M %Y %H:%i:%s %O', 'DATE_RSS' => '%D, %d %M %Y %H:%i:%s %O', @@ -127,11 +127,11 @@ function standard_date($fmt = 'DATE_RFC822', $time = '') { return FALSE; } - + return mdate($formats[$fmt], $time); } } - + // ------------------------------------------------------------------------ /** @@ -144,7 +144,7 @@ function standard_date($fmt = 'DATE_RFC822', $time = '') * @param integer a number of seconds * @param integer Unix timestamp * @return integer - */ + */ if ( ! function_exists('timespan')) { function timespan($seconds = 1, $time = '') @@ -156,12 +156,12 @@ function timespan($seconds = 1, $time = '') { $seconds = 1; } - + if ( ! is_numeric($time)) { $time = time(); } - + if ($time <= $seconds) { $seconds = 1; @@ -170,85 +170,85 @@ function timespan($seconds = 1, $time = '') { $seconds = $time - $seconds; } - + $str = ''; $years = floor($seconds / 31536000); - + if ($years > 0) - { + { $str .= $years.' '.$CI->lang->line((($years > 1) ? 'date_years' : 'date_year')).', '; - } - + } + $seconds -= $years * 31536000; $months = floor($seconds / 2628000); - + if ($years > 0 OR $months > 0) { if ($months > 0) - { + { $str .= $months.' '.$CI->lang->line((($months > 1) ? 'date_months' : 'date_month')).', '; - } - + } + $seconds -= $months * 2628000; } $weeks = floor($seconds / 604800); - + if ($years > 0 OR $months > 0 OR $weeks > 0) { if ($weeks > 0) - { + { $str .= $weeks.' '.$CI->lang->line((($weeks > 1) ? 'date_weeks' : 'date_week')).', '; } - + $seconds -= $weeks * 604800; - } + } $days = floor($seconds / 86400); - + if ($months > 0 OR $weeks > 0 OR $days > 0) { if ($days > 0) - { + { $str .= $days.' '.$CI->lang->line((($days > 1) ? 'date_days' : 'date_day')).', '; } - + $seconds -= $days * 86400; } - + $hours = floor($seconds / 3600); - + if ($days > 0 OR $hours > 0) { if ($hours > 0) { $str .= $hours.' '.$CI->lang->line((($hours > 1) ? 'date_hours' : 'date_hour')).', '; } - + $seconds -= $hours * 3600; } - + $minutes = floor($seconds / 60); - + if ($days > 0 OR $hours > 0 OR $minutes > 0) { if ($minutes > 0) - { + { $str .= $minutes.' '.$CI->lang->line((($minutes > 1) ? 'date_minutes' : 'date_minute')).', '; } - + $seconds -= $minutes * 60; } - + if ($str == '') { $str .= $seconds.' '.$CI->lang->line((($seconds > 1) ? 'date_seconds' : 'date_second')).', '; } - + return substr(trim($str), 0, -1); } } - + // ------------------------------------------------------------------------ /** @@ -261,7 +261,7 @@ function timespan($seconds = 1, $time = '') * @param integer a numeric month * @param integer a numeric year * @return integer - */ + */ if ( ! function_exists('days_in_month')) { function days_in_month($month = 0, $year = '') @@ -270,12 +270,12 @@ function days_in_month($month = 0, $year = '') { return 0; } - + if ( ! is_numeric($year) OR strlen($year) != 4) { $year = date('Y'); } - + if ($month == 2) { if ($year % 400 == 0 OR ($year % 4 == 0 AND $year % 100 != 0)) @@ -288,7 +288,7 @@ function days_in_month($month = 0, $year = '') return $days_in_month[$month - 1]; } } - + // ------------------------------------------------------------------------ /** @@ -297,18 +297,18 @@ function days_in_month($month = 0, $year = '') * @access public * @param integer Unix timestamp * @return integer - */ + */ if ( ! function_exists('local_to_gmt')) { function local_to_gmt($time = '') { if ($time == '') $time = time(); - + return mktime( gmdate("H", $time), gmdate("i", $time), gmdate("s", $time), gmdate("m", $time), gmdate("d", $time), gmdate("Y", $time)); } } - + // ------------------------------------------------------------------------ /** @@ -323,27 +323,27 @@ function local_to_gmt($time = '') * @param string timezone * @param bool whether DST is active * @return integer - */ + */ if ( ! function_exists('gmt_to_local')) { function gmt_to_local($time = '', $timezone = 'UTC', $dst = FALSE) - { + { if ($time == '') { return now(); } - + $time += timezones($timezone) * 3600; if ($dst == TRUE) { $time += 3600; } - + return $time; } } - + // ------------------------------------------------------------------------ /** @@ -352,7 +352,7 @@ function gmt_to_local($time = '', $timezone = 'UTC', $dst = FALSE) * @access public * @param integer Unix timestamp * @return integer - */ + */ if ( ! function_exists('mysql_to_unix')) { function mysql_to_unix($time = '') @@ -360,11 +360,11 @@ function mysql_to_unix($time = '') // We'll remove certain characters for backward compatibility // since the formatting changed with MySQL 4.1 // YYYY-MM-DD HH:MM:SS - + $time = str_replace('-', '', $time); $time = str_replace(':', '', $time); $time = str_replace(' ', '', $time); - + // YYYYMMDDHHMMSS return mktime( substr($time, 8, 2), @@ -376,7 +376,7 @@ function mysql_to_unix($time = '') ); } } - + // ------------------------------------------------------------------------ /** @@ -389,13 +389,13 @@ function mysql_to_unix($time = '') * @param bool whether to show seconds * @param string format: us or euro * @return string - */ + */ if ( ! function_exists('unix_to_human')) { function unix_to_human($time = '', $seconds = FALSE, $fmt = 'us') { $r = date('Y', $time).'-'.date('m', $time).'-'.date('d', $time).' '; - + if ($fmt == 'us') { $r .= date('h', $time).':'.date('i', $time); @@ -404,21 +404,21 @@ function unix_to_human($time = '', $seconds = FALSE, $fmt = 'us') { $r .= date('H', $time).':'.date('i', $time); } - + if ($seconds) { $r .= ':'.date('s', $time); } - + if ($fmt == 'us') { $r .= ' '.date('A', $time); } - + return $r; } } - + // ------------------------------------------------------------------------ /** @@ -429,7 +429,7 @@ function unix_to_human($time = '', $seconds = FALSE, $fmt = 'us') * @access public * @param string format: us or euro * @return integer - */ + */ if ( ! function_exists('human_to_unix')) { function human_to_unix($datestr = '') @@ -438,25 +438,25 @@ function human_to_unix($datestr = '') { return FALSE; } - + $datestr = trim($datestr); - $datestr = preg_replace("/\040+/", "\040", $datestr); + $datestr = preg_replace("/\040+/", ' ', $datestr); if ( ! preg_match('/^[0-9]{2,4}\-[0-9]{1,2}\-[0-9]{1,2}\s[0-9]{1,2}:[0-9]{1,2}(?::[0-9]{1,2})?(?:\s[AP]M)?$/i', $datestr)) { return FALSE; } - $split = preg_split("/\040/", $datestr); + $split = explode(' ', $datestr); $ex = explode("-", $split['0']); - + $year = (strlen($ex['0']) == 2) ? '20'.$ex['0'] : $ex['0']; $month = (strlen($ex['1']) == 1) ? '0'.$ex['1'] : $ex['1']; $day = (strlen($ex['2']) == 1) ? '0'.$ex['2'] : $ex['2']; $ex = explode(":", $split['1']); - + $hour = (strlen($ex['0']) == 1) ? '0'.$ex['0'] : $ex['0']; $min = (strlen($ex['1']) == 1) ? '0'.$ex['1'] : $ex['1']; @@ -469,25 +469,25 @@ function human_to_unix($datestr = '') // Unless specified, seconds get set to zero. $sec = '00'; } - + if (isset($split['2'])) { $ampm = strtolower($split['2']); - + if (substr($ampm, 0, 1) == 'p' AND $hour < 12) $hour = $hour + 12; - + if (substr($ampm, 0, 1) == 'a' AND $hour == 12) $hour = '00'; - + if (strlen($hour) == 1) $hour = '0'.$hour; } - + return mktime($hour, $min, $sec, $month, $day, $year); } } - + // ------------------------------------------------------------------------ /** @@ -500,26 +500,26 @@ function human_to_unix($datestr = '') * @param string classname * @param string menu name * @return string - */ + */ if ( ! function_exists('timezone_menu')) { function timezone_menu($default = 'UTC', $class = "", $name = 'timezones') { $CI =& get_instance(); $CI->lang->load('date'); - + if ($default == 'GMT') $default = 'UTC'; $menu = '"; } @@ -257,7 +278,7 @@ function form_textarea($data = '', $value = '', $extra = '') * @param string * @return type */ -if (! function_exists('form_multiselect')) +if ( ! function_exists('form_multiselect')) { function form_multiselect($name = '', $options = array(), $selected = array(), $extra = '') { @@ -265,7 +286,7 @@ function form_multiselect($name = '', $options = array(), $selected = array(), $ { $extra .= ' multiple="multiple"'; } - + return form_dropdown($name, $options, $selected, $extra); } } @@ -311,18 +332,12 @@ function form_dropdown($name = '', $options = array(), $selected = array(), $ext { $key = (string) $key; - $key = htmlspecialchars($key); - $val = htmlspecialchars($val); - - if (is_array($val)) + if (is_array($val) && ! empty($val)) { $form .= ''."\n"; foreach ($val as $optgroup_key => $optgroup_val) { - $optgroup_key = htmlspecialchars($optgroup_key); - $optgroup_val = htmlspecialchars($optgroup_val); - $sel = (in_array($optgroup_key, $selected)) ? ' selected="selected"' : ''; $form .= '\n"; @@ -360,8 +375,6 @@ function form_dropdown($name = '', $options = array(), $selected = array(), $ext { function form_checkbox($data = '', $value = '', $checked = FALSE, $extra = '') { - $value = htmlspecialchars($value); - $defaults = array('type' => 'checkbox', 'name' => (( ! is_array($data)) ? $data : ''), 'value' => $value); if (is_array($data) AND array_key_exists('checked', $data)) @@ -408,7 +421,7 @@ function form_checkbox($data = '', $value = '', $checked = FALSE, $extra = '') function form_radio($data = '', $value = '', $checked = FALSE, $extra = '') { if ( ! is_array($data)) - { + { $data = array('name' => $data); } @@ -429,7 +442,7 @@ function form_radio($data = '', $value = '', $checked = FALSE, $extra = '') * @return string */ if ( ! function_exists('form_submit')) -{ +{ function form_submit($data = '', $value = '', $extra = '') { $defaults = array('type' => 'submit', 'name' => (( ! is_array($data)) ? $data : ''), 'value' => $value); @@ -506,7 +519,7 @@ function form_label($label_text = '', $id = '', $attributes = array()) if ($id != '') { - $label .= " for=\"$id\""; + $label .= " for=\"$id\""; } if (is_array($attributes) AND count($attributes) > 0) @@ -604,7 +617,7 @@ function form_close($extra = '') function form_prep($str = '', $field_name = '') { static $prepped_fields = array(); - + // if the field name is an array we do this recursively if (is_array($str)) { @@ -629,7 +642,7 @@ function form_prep($str = '', $field_name = '') { return $str; } - + $str = htmlspecialchars($str); // In case htmlspecialchars misses these. @@ -637,9 +650,9 @@ function form_prep($str = '', $field_name = '') if ($field_name != '') { - $prepped_fields[$field_name] = $str; + $prepped_fields[$field_name] = $field_name; } - + return $str; } } @@ -751,7 +764,7 @@ function set_checkbox($field = '', $value = '', $default = FALSE) $OBJ =& _get_validation_object(); if ($OBJ === FALSE) - { + { if ( ! isset($_POST[$field])) { if (count($_POST) === 0 AND $default == TRUE) @@ -762,7 +775,7 @@ function set_checkbox($field = '', $value = '', $default = FALSE) } $field = $_POST[$field]; - + if (is_array($field)) { if ( ! in_array($value, $field)) @@ -817,7 +830,7 @@ function set_radio($field = '', $value = '', $default = FALSE) } $field = $_POST[$field]; - + if (is_array($field)) { if ( ! in_array($value, $field)) @@ -927,7 +940,7 @@ function _parse_form_attributes($attributes, $default) } $att = ''; - + foreach ($default as $key => $val) { if ($key == 'value') @@ -935,7 +948,7 @@ function _parse_form_attributes($attributes, $default) $val = form_prep($val, $default['name']); } - $att .= $key . '="' . htmlspecialchars($val) . '" '; + $att .= $key . '="' . $val . '" '; } return $att; @@ -965,9 +978,14 @@ function _attributes_to_string($attributes, $formtag = FALSE) $attributes .= ' method="post"'; } + if ($formtag == TRUE AND strpos($attributes, 'accept-charset=') === FALSE) + { + $attributes .= ' accept-charset="'.strtolower(config_item('charset')).'"'; + } + return ' '.$attributes; } - + if (is_object($attributes) AND count($attributes) > 0) { $attributes = (array)$attributes; @@ -975,19 +993,24 @@ function _attributes_to_string($attributes, $formtag = FALSE) if (is_array($attributes) AND count($attributes) > 0) { - $atts = ''; + $atts = ''; - if ( ! isset($attributes['method']) AND $formtag === TRUE) - { - $atts .= ' method="post"'; - } + if ( ! isset($attributes['method']) AND $formtag === TRUE) + { + $atts .= ' method="post"'; + } - foreach ($attributes as $key => $val) - { - $atts .= ' '.$key.'="'.$val.'"'; - } + if ( ! isset($attributes['accept-charset']) AND $formtag === TRUE) + { + $atts .= ' accept-charset="'.strtolower(config_item('charset')).'"'; + } - return $atts; + foreach ($attributes as $key => $val) + { + $atts .= ' '.$key.'="'.$val.'"'; + } + + return $atts; } } } @@ -1009,25 +1032,23 @@ function &_get_validation_object() { $CI =& get_instance(); - // We set this as a variable since we're returning by reference + // We set this as a variable since we're returning by reference. $return = FALSE; - - if ( ! isset($CI->load->_ci_classes) OR ! isset($CI->load->_ci_classes['form_validation'])) - { - return $return; - } - - $object = $CI->load->_ci_classes['form_validation']; - - if ( ! isset($CI->$object) OR ! is_object($CI->$object)) + + if (FALSE !== ($object = $CI->load->is_loaded('form_validation'))) { - return $return; + if ( ! isset($CI->$object) OR ! is_object($CI->$object)) + { + return $return; + } + + return $CI->$object; } - - return $CI->$object; + + return $return; } } /* End of file form_helper.php */ -/* Location: ./system/helpers/form_helper.php */ \ No newline at end of file +/* Location: ./system/helpers/form_helper.php */ diff --git a/system/helpers/html_helper.php b/system/helpers/html_helper.php index 427d1ce3..b64b6065 100644 --- a/system/helpers/html_helper.php +++ b/system/helpers/html_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -40,9 +40,10 @@ */ if ( ! function_exists('heading')) { - function heading($data = '', $h = '1') + function heading($data = '', $h = '1', $attributes = '') { - return "".$data.""; + $attributes = ($attributes != '') ? ' '.$attributes : $attributes; + return "".$data.""; } } @@ -97,7 +98,7 @@ function ol($list, $attributes = '') * @param string * @param mixed * @param mixed - * @param intiger + * @param integer * @return string */ if ( ! function_exists('_list')) @@ -123,6 +124,10 @@ function _list($type = 'ul', $list, $attributes = '', $depth = 0) } $attributes = $atts; } + elseif (is_string($attributes) AND strlen($attributes) > 0) + { + $attributes = ' '. $attributes; + } // Write the opening list tag $out .= "<".$type.$attributes.">\n"; @@ -199,6 +204,12 @@ function img($src = '', $index_page = FALSE) $src = array('src' => $src); } + // If there is no alt attribute defined, set it to an empty string + if ( ! isset($src['alt'])) + { + $src['alt'] = ''; + } + $img = '$v) @@ -210,16 +221,16 @@ function img($src = '', $index_page = FALSE) if ($index_page === TRUE) { - $img .= ' src="'.$CI->config->site_url($v).'" '; + $img .= ' src="'.$CI->config->site_url($v).'"'; } else { - $img .= ' src="'.$CI->config->slash_item('base_url').$v.'" '; + $img .= ' src="'.$CI->config->slash_item('base_url').$v.'"'; } } else { - $img .= " $k=\"$v\" "; + $img .= " $k=\"$v\""; } } @@ -252,7 +263,16 @@ function doctype($type = 'xhtml1-strict') if ( ! is_array($_doctypes)) { - if ( ! require_once(APPPATH.'config/doctypes.php')) + if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/doctypes.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/doctypes.php'); + } + elseif (is_file(APPPATH.'config/doctypes.php')) + { + include(APPPATH.'config/doctypes.php'); + } + + if ( ! is_array($_doctypes)) { return FALSE; } @@ -301,11 +321,11 @@ function link_tag($href = '', $rel = 'stylesheet', $type = 'text/css', $title = { if ($index_page === TRUE) { - $link .= ' href="'.$CI->config->site_url($v).'" '; + $link .= 'href="'.$CI->config->site_url($v).'" '; } else { - $link .= ' href="'.$CI->config->slash_item('base_url').$v.'" '; + $link .= 'href="'.$CI->config->slash_item('base_url').$v.'" '; } } else @@ -320,15 +340,15 @@ function link_tag($href = '', $rel = 'stylesheet', $type = 'text/css', $title = { if ( strpos($href, '://') !== FALSE) { - $link .= ' href="'.$href.'" '; + $link .= 'href="'.$href.'" '; } elseif ($index_page === TRUE) { - $link .= ' href="'.$CI->config->site_url($href).'" '; + $link .= 'href="'.$CI->config->site_url($href).'" '; } else { - $link .= ' href="'.$CI->config->slash_item('base_url').$href.'" '; + $link .= 'href="'.$CI->config->slash_item('base_url').$href.'" '; } $link .= 'rel="'.$rel.'" type="'.$type.'" '; @@ -382,9 +402,9 @@ function meta($name = '', $content = '', $type = 'name', $newline = "\n") $str = ''; foreach ($name as $meta) { - $type = ( ! isset($meta['type']) OR $meta['type'] == 'name') ? 'name' : 'http-equiv'; - $name = ( ! isset($meta['name'])) ? '' : $meta['name']; - $content = ( ! isset($meta['content'])) ? '' : $meta['content']; + $type = ( ! isset($meta['type']) OR $meta['type'] == 'name') ? 'name' : 'http-equiv'; + $name = ( ! isset($meta['name'])) ? '' : $meta['name']; + $content = ( ! isset($meta['content'])) ? '' : $meta['content']; $newline = ( ! isset($meta['newline'])) ? "\n" : $meta['newline']; $str .= ''.$newline; diff --git a/system/helpers/inflector_helper.php b/system/helpers/inflector_helper.php index f5ccd439..7b99bc5b 100644 --- a/system/helpers/inflector_helper.php +++ b/system/helpers/inflector_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -36,36 +36,53 @@ * @access public * @param string * @return str - */ + */ if ( ! function_exists('singular')) -{ +{ function singular($str) { - $str = strtolower(trim($str)); - $end = substr($str, -3); - - if ($end == 'ies') - { - $str = substr($str, 0, strlen($str)-3).'y'; - } - elseif ($end == 'ses') - { - $str = substr($str, 0, strlen($str)-2); - } - else - { - if($end == 'ess') - return $str; - - $end = substr($str, -1); + $result = strval($str); + + $singular_rules = array( + '/(matr)ices$/' => '\1ix', + '/(vert|ind)ices$/' => '\1ex', + '/^(ox)en/' => '\1', + '/(alias)es$/' => '\1', + '/([octop|vir])i$/' => '\1us', + '/(cris|ax|test)es$/' => '\1is', + '/(shoe)s$/' => '\1', + '/(o)es$/' => '\1', + '/(bus|campus)es$/' => '\1', + '/([m|l])ice$/' => '\1ouse', + '/(x|ch|ss|sh)es$/' => '\1', + '/(m)ovies$/' => '\1\2ovie', + '/(s)eries$/' => '\1\2eries', + '/([^aeiouy]|qu)ies$/' => '\1y', + '/([lr])ves$/' => '\1f', + '/(tive)s$/' => '\1', + '/(hive)s$/' => '\1', + '/([^f])ves$/' => '\1fe', + '/(^analy)ses$/' => '\1sis', + '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/' => '\1\2sis', + '/([ti])a$/' => '\1um', + '/(p)eople$/' => '\1\2erson', + '/(m)en$/' => '\1an', + '/(s)tatuses$/' => '\1\2tatus', + '/(c)hildren$/' => '\1\2hild', + '/(n)ews$/' => '\1\2ews', + '/([^u])s$/' => '\1', + ); - if ($end == 's') + foreach ($singular_rules as $rule => $replacement) + { + if (preg_match($rule, $result)) { - $str = substr($str, 0, strlen($str)-1); + $result = preg_replace($rule, $replacement, $result); + break; } } - - return $str; + + return $result; } } @@ -80,33 +97,45 @@ function singular($str) * @param string * @param bool * @return str - */ + */ if ( ! function_exists('plural')) -{ +{ function plural($str, $force = FALSE) { - $str = strtolower(trim($str)); - $end = substr($str, -1); - - if ($end == 'y') - { - // Y preceded by vowel => regular plural - $vowels = array('a', 'e', 'i', 'o', 'u'); - $str = in_array(substr($str, -2, 1), $vowels) ? $str.'s' : substr($str, 0, -1).'ies'; - } - elseif ($end == 's') + $result = strval($str); + + $plural_rules = array( + '/^(ox)$/' => '\1\2en', // ox + '/([m|l])ouse$/' => '\1ice', // mouse, louse + '/(matr|vert|ind)ix|ex$/' => '\1ices', // matrix, vertex, index + '/(x|ch|ss|sh)$/' => '\1es', // search, switch, fix, box, process, address + '/([^aeiouy]|qu)y$/' => '\1ies', // query, ability, agency + '/(hive)$/' => '\1s', // archive, hive + '/(?:([^f])fe|([lr])f)$/' => '\1\2ves', // half, safe, wife + '/sis$/' => 'ses', // basis, diagnosis + '/([ti])um$/' => '\1a', // datum, medium + '/(p)erson$/' => '\1eople', // person, salesperson + '/(m)an$/' => '\1en', // man, woman, spokesman + '/(c)hild$/' => '\1hildren', // child + '/(buffal|tomat)o$/' => '\1\2oes', // buffalo, tomato + '/(bu|campu)s$/' => '\1\2ses', // bus, campus + '/(alias|status|virus)/' => '\1es', // alias + '/(octop)us$/' => '\1i', // octopus + '/(ax|cris|test)is$/' => '\1es', // axis, crisis + '/s$/' => 's', // no change (compatibility) + '/$/' => 's', + ); + + foreach ($plural_rules as $rule => $replacement) { - if ($force == TRUE) + if (preg_match($rule, $result)) { - $str .= 'es'; + $result = preg_replace($rule, $replacement, $result); + break; } } - else - { - $str .= 's'; - } - return $str; + return $result; } } @@ -120,11 +149,11 @@ function plural($str, $force = FALSE) * @access public * @param string * @return str - */ + */ if ( ! function_exists('camelize')) -{ +{ function camelize($str) - { + { $str = 'x'.strtolower(trim($str)); $str = ucwords(preg_replace('/[\s_]+/', ' ', $str)); return substr(str_replace(' ', '', $str), 1); @@ -141,7 +170,7 @@ function camelize($str) * @access public * @param string * @return str - */ + */ if ( ! function_exists('underscore')) { function underscore($str) @@ -160,15 +189,15 @@ function underscore($str) * @access public * @param string * @return str - */ + */ if ( ! function_exists('humanize')) -{ +{ function humanize($str) { return ucwords(preg_replace('/[_]+/', ' ', strtolower(trim($str)))); } } - + /* End of file inflector_helper.php */ /* Location: ./system/helpers/inflector_helper.php */ \ No newline at end of file diff --git a/system/helpers/language_helper.php b/system/helpers/language_helper.php index e97a8c78..ac0d69da 100644 --- a/system/helpers/language_helper.php +++ b/system/helpers/language_helper.php @@ -1,12 +1,12 @@ -lang->load('number'); - - if ($num >= 1000000000000) + + if ($num >= 1000000000000) { - $num = round($num / 1099511627776, 1); + $num = round($num / 1099511627776, $precision); $unit = $CI->lang->line('terabyte_abbr'); } - elseif ($num >= 1000000000) + elseif ($num >= 1000000000) { - $num = round($num / 1073741824, 1); + $num = round($num / 1073741824, $precision); $unit = $CI->lang->line('gigabyte_abbr'); } - elseif ($num >= 1000000) + elseif ($num >= 1000000) { - $num = round($num / 1048576, 1); + $num = round($num / 1048576, $precision); $unit = $CI->lang->line('megabyte_abbr'); } - elseif ($num >= 1000) + elseif ($num >= 1000) { - $num = round($num / 1024, 1); + $num = round($num / 1024, $precision); $unit = $CI->lang->line('kilobyte_abbr'); } else @@ -67,9 +67,10 @@ function byte_format($num) return number_format($num).' '.$unit; } - return number_format($num, 1).' '.$unit; - } + return number_format($num, $precision).' '.$unit; + } } + /* End of file number_helper.php */ /* Location: ./system/helpers/number_helper.php */ \ No newline at end of file diff --git a/system/helpers/path_helper.php b/system/helpers/path_helper.php index 502fae4b..ffcf4684 100644 --- a/system/helpers/path_helper.php +++ b/system/helpers/path_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -34,7 +34,7 @@ * @param string * @param bool checks to see if the path exists * @return string - */ + */ if ( ! function_exists('set_realpath')) { function set_realpath($path, $check_existance = FALSE) @@ -44,16 +44,16 @@ function set_realpath($path, $check_existance = FALSE) { show_error('The path you submitted must be a local server path, not a URL'); } - + // Resolve the path if (function_exists('realpath') AND @realpath($path) !== FALSE) { $path = realpath($path).'/'; } - + // Add a trailing slash $path = preg_replace("#([^/])/*$#", "\\1/", $path); - + // Make sure the path exists if ($check_existance == TRUE) { @@ -62,7 +62,7 @@ function set_realpath($path, $check_existance = FALSE) show_error('Not a valid path: '.$path); } } - + return $path; } } diff --git a/system/helpers/security_helper.php b/system/helpers/security_helper.php index 9cc70aaf..678dac82 100644 --- a/system/helpers/security_helper.php +++ b/system/helpers/security_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -34,13 +34,31 @@ * @param string * @param bool whether or not the content is an image file * @return string - */ + */ if ( ! function_exists('xss_clean')) { function xss_clean($str, $is_image = FALSE) { $CI =& get_instance(); - return $CI->input->xss_clean($str, $is_image); + return $CI->security->xss_clean($str, $is_image); + } +} + +// ------------------------------------------------------------------------ + +/** + * Sanitize Filename + * + * @access public + * @param string + * @return string + */ +if ( ! function_exists('sanitize_filename')) +{ + function sanitize_filename($filename) + { + $CI =& get_instance(); + return $CI->security->sanitize_filename($filename); } } @@ -52,30 +70,14 @@ function xss_clean($str, $is_image = FALSE) * @access public * @param string * @return string - */ -if ( ! function_exists('dohash')) -{ - function dohash($str, $type = 'sha1') + */ +if ( ! function_exists('do_hash')) +{ + function do_hash($str, $type = 'sha1') { if ($type == 'sha1') { - if ( ! function_exists('sha1')) - { - if ( ! function_exists('mhash')) - { - require_once(BASEPATH.'libraries/Sha1'.EXT); - $SH = new CI_SHA; - return $SH->generate($str); - } - else - { - return bin2hex(mhash(MHASH_SHA1, $str)); - } - } - else - { - return sha1($str); - } + return sha1($str); } else { @@ -83,7 +85,7 @@ function dohash($str, $type = 'sha1') } } } - + // ------------------------------------------------------------------------ /** @@ -92,18 +94,18 @@ function dohash($str, $type = 'sha1') * @access public * @param string * @return string - */ + */ if ( ! function_exists('strip_image_tags')) { function strip_image_tags($str) { $str = preg_replace("##", "\\1", $str); $str = preg_replace("##", "\\1", $str); - + return $str; } } - + // ------------------------------------------------------------------------ /** @@ -112,7 +114,7 @@ function strip_image_tags($str) * @access public * @param string * @return string - */ + */ if ( ! function_exists('encode_php_tags')) { function encode_php_tags($str) diff --git a/system/helpers/smiley_helper.php b/system/helpers/smiley_helper.php index f085e53b..6d888935 100644 --- a/system/helpers/smiley_helper.php +++ b/system/helpers/smiley_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -40,12 +40,12 @@ */ if ( ! function_exists('smiley_js')) { - function smiley_js($alias = '', $field_id = '') + function smiley_js($alias = '', $field_id = '', $inline = TRUE) { static $do_setup = TRUE; $r = ''; - + if ($alias != '' && ! is_array($alias)) { $alias = array($alias => $field_id); @@ -54,33 +54,32 @@ function smiley_js($alias = '', $field_id = '') if ($do_setup === TRUE) { $do_setup = FALSE; - + $m = array(); - + if (is_array($alias)) { - foreach($alias as $name => $id) + foreach ($alias as $name => $id) { $m[] = '"'.$name.'" : "'.$id.'"'; } } - + $m = '{'.implode(',', $m).'}'; - + $r .= << $id) + foreach ($alias as $name => $id) { $r .= 'smiley_map["'.$name.'"] = "'.$id.'";'."\n"; } } } - return ''; + if ($inline) + { + return ''; + } + else + { + return $r; + } } } @@ -118,8 +124,8 @@ function insert_smiley(smiley, field_id) { /** * Get Clickable Smileys * - * Returns an array of image tag links that can be clicked to be inserted - * into a form field. + * Returns an array of image tag links that can be clicked to be inserted + * into a form field. * * @access public * @param string the URL to the folder containing the smiley images @@ -130,12 +136,12 @@ function insert_smiley(smiley, field_id) { function get_clickable_smileys($image_url, $alias = '', $smileys = NULL) { // For backward compatibility with js_insert_smiley - + if (is_array($alias)) { $smileys = $alias; } - + if ( ! is_array($smileys)) { if (FALSE === ($smileys = _get_smiley_array())) @@ -146,7 +152,7 @@ function get_clickable_smileys($image_url, $alias = '', $smileys = NULL) // Add a trailing slash to the file path if needed $image_url = rtrim($image_url, '/').'/'; - + $used = array(); foreach ($smileys as $key => $val) { @@ -158,12 +164,12 @@ function get_clickable_smileys($image_url, $alias = '', $smileys = NULL) { continue; } - - $link[] = "
\"".$smileys[$key][3]."\""; - + + $link[] = "\"".$smileys[$key][3]."\""; + $used[$smileys[$key][0]] = TRUE; } - + return $link; } } @@ -223,19 +229,21 @@ function parse_smileys($str = '', $image_url = '', $smileys = NULL) { function _get_smiley_array() { - if ( ! file_exists(APPPATH.'config/smileys'.EXT)) + if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/smileys.php')) { - return FALSE; + include(APPPATH.'config/'.ENVIRONMENT.'/smileys.php'); } - - include(APPPATH.'config/smileys'.EXT); - - if ( ! isset($smileys) OR ! is_array($smileys)) + elseif (file_exists(APPPATH.'config/smileys.php')) + { + include(APPPATH.'config/smileys.php'); + } + + if (isset($smileys) AND is_array($smileys)) { - return FALSE; + return $smileys; } - return $smileys; + return FALSE; } } diff --git a/system/helpers/string_helper.php b/system/helpers/string_helper.php index 3f7f09a1..9fa69f46 100644 --- a/system/helpers/string_helper.php +++ b/system/helpers/string_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -30,7 +30,7 @@ /** * Trim Slashes * - * Removes any leading/traling slashes from a string: + * Removes any leading/trailing slashes from a string: * * /this/that/theother/ * @@ -41,15 +41,15 @@ * @access public * @param string * @return string - */ + */ if ( ! function_exists('trim_slashes')) { function trim_slashes($str) { return trim($str, '/'); - } + } } - + // ------------------------------------------------------------------------ /** @@ -60,13 +60,13 @@ function trim_slashes($str) * @access public * @param mixed string or array * @return mixed string or array - */ + */ if ( ! function_exists('strip_slashes')) { function strip_slashes($str) { if (is_array($str)) - { + { foreach ($str as $key => $val) { $str[$key] = strip_slashes($val); @@ -76,7 +76,7 @@ function strip_slashes($str) { $str = stripslashes($str); } - + return $str; } } @@ -91,7 +91,7 @@ function strip_slashes($str) * @access public * @param string * @return string - */ + */ if ( ! function_exists('strip_quotes')) { function strip_quotes($str) @@ -110,16 +110,17 @@ function strip_quotes($str) * @access public * @param string * @return string - */ + */ if ( ! function_exists('quotes_to_entities')) { function quotes_to_entities($str) - { + { return str_replace(array("\'","\"","'",'"'), array("'",""","'","""), $str); } } // ------------------------------------------------------------------------ + /** * Reduce Double Slashes * @@ -135,15 +136,15 @@ function quotes_to_entities($str) * @access public * @param string * @return string - */ + */ if ( ! function_exists('reduce_double_slashes')) { function reduce_double_slashes($str) { - return preg_replace("#([^:])//+#", "\\1/", $str); + return preg_replace("#(^|[^:])//+#", "\\1/", $str); } } - + // ------------------------------------------------------------------------ /** @@ -162,7 +163,7 @@ function reduce_double_slashes($str) * @param string the character you wish to reduce * @param bool TRUE/FALSE - whether to trim the character from the beginning/end * @return string - */ + */ if ( ! function_exists('reduce_multiples')) { function reduce_multiples($str, $character = ',', $trim = FALSE) @@ -177,7 +178,7 @@ function reduce_multiples($str, $character = ',', $trim = FALSE) return $str; } } - + // ------------------------------------------------------------------------ /** @@ -186,22 +187,27 @@ function reduce_multiples($str, $character = ',', $trim = FALSE) * Useful for generating passwords or hashes. * * @access public - * @param string type of random string. Options: alunum, numeric, nozero, unique + * @param string type of random string. basic, alpha, alunum, numeric, nozero, unique, md5, encrypt and sha1 * @param integer number of characters * @return string */ if ( ! function_exists('random_string')) -{ +{ function random_string($type = 'alnum', $len = 8) - { + { switch($type) { + case 'basic' : return mt_rand(); + break; case 'alnum' : case 'numeric' : case 'nozero' : - + case 'alpha' : + switch ($type) { + case 'alpha' : $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + break; case 'alnum' : $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; break; case 'numeric' : $pool = '0123456789'; @@ -216,15 +222,43 @@ function random_string($type = 'alnum', $len = 8) $str .= substr($pool, mt_rand(0, strlen($pool) -1), 1); } return $str; - break; - case 'unique' : return md5(uniqid(mt_rand())); - break; + break; + case 'unique' : + case 'md5' : + + return md5(uniqid(mt_rand())); + break; + case 'encrypt' : + case 'sha1' : + + $CI =& get_instance(); + $CI->load->helper('security'); + + return do_hash(uniqid(mt_rand(), TRUE), 'sha1'); + break; } } } // ------------------------------------------------------------------------ +/** + * Add's _1 to a string or increment the ending number to allow _2, _3, etc + * + * @param string $str required + * @param string $separator What should the duplicate number be appended with + * @param string $first Which number should be used for the first dupe increment + * @return string + */ +function increment_string($str, $separator = '_', $first = 1) +{ + preg_match('/(.+)'.$separator.'([0-9]+)$/', $str, $match); + + return isset($match[2]) ? $match[1].$separator.($match[2] + 1) : $str.$separator.$first; +} + +// ------------------------------------------------------------------------ + /** * Alternator * @@ -233,12 +267,12 @@ function random_string($type = 'alnum', $len = 8) * @access public * @param string (as many parameters as needed) * @return string - */ + */ if ( ! function_exists('alternator')) { function alternator() { - static $i; + static $i; if (func_num_args() == 0) { @@ -259,13 +293,13 @@ function alternator() * @param string * @param integer number of repeats * @return string - */ + */ if ( ! function_exists('repeater')) { function repeater($data, $num = 1) { return (($num > 0) ? str_repeat($data, $num) : ''); - } + } } diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php index 7ae1d150..33d7fa2f 100644 --- a/system/helpers/text_helper.php +++ b/system/helpers/text_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -37,7 +37,7 @@ * @param integer * @param string the end character. Usually an ellipsis * @return string - */ + */ if ( ! function_exists('word_limiter')) { function word_limiter($str, $limit = 100, $end_char = '…') @@ -46,18 +46,18 @@ function word_limiter($str, $limit = 100, $end_char = '…') { return $str; } - + preg_match('/^\s*+(?:\S++\s*+){1,'.(int) $limit.'}/', $str, $matches); - + if (strlen($str) == strlen($matches[0])) { $end_char = ''; } - + return rtrim($matches[0]).$end_char; } } - + // ------------------------------------------------------------------------ /** @@ -71,7 +71,7 @@ function word_limiter($str, $limit = 100, $end_char = '…') * @param integer * @param string the end character. Usually an ellipsis * @return string - */ + */ if ( ! function_exists('character_limiter')) { function character_limiter($str, $n = 500, $end_char = '…') @@ -80,7 +80,7 @@ function character_limiter($str, $n = 500, $end_char = '…') { return $str; } - + $str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str)); if (strlen($str) <= $n) @@ -92,16 +92,16 @@ function character_limiter($str, $n = 500, $end_char = '…') foreach (explode(' ', trim($str)) as $val) { $out .= $val.' '; - + if (strlen($out) >= $n) { $out = trim($out); return (strlen($out) == strlen($str)) ? $out : $out.$end_char; - } + } } } } - + // ------------------------------------------------------------------------ /** @@ -112,21 +112,21 @@ function character_limiter($str, $n = 500, $end_char = '…') * @access public * @param string * @return string - */ + */ if ( ! function_exists('ascii_to_entities')) { function ascii_to_entities($str) { - $count = 1; - $out = ''; - $temp = array(); - - for ($i = 0, $s = strlen($str); $i < $s; $i++) - { - $ordinal = ord($str[$i]); - - if ($ordinal < 128) - { + $count = 1; + $out = ''; + $temp = array(); + + for ($i = 0, $s = strlen($str); $i < $s; $i++) + { + $ordinal = ord($str[$i]); + + if ($ordinal < 128) + { /* If the $temp array has a value but we have moved on, then it seems only fair that we output that entity and restart $temp before continuing. -Paul @@ -138,31 +138,31 @@ function ascii_to_entities($str) } $out .= $str[$i]; - } - else - { - if (count($temp) == 0) - { - $count = ($ordinal < 224) ? 2 : 3; - } - - $temp[] = $ordinal; - - if (count($temp) == $count) - { - $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64); - - $out .= '&#'.$number.';'; - $count = 1; - $temp = array(); - } - } - } - - return $out; + } + else + { + if (count($temp) == 0) + { + $count = ($ordinal < 224) ? 2 : 3; + } + + $temp[] = $ordinal; + + if (count($temp) == $count) + { + $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64); + + $out .= '&#'.$number.';'; + $count = 1; + $temp = array(); + } + } + } + + return $out; } } - + // ------------------------------------------------------------------------ /** @@ -174,51 +174,51 @@ function ascii_to_entities($str) * @param string * @param bool * @return string - */ + */ if ( ! function_exists('entities_to_ascii')) { function entities_to_ascii($str, $all = TRUE) { - if (preg_match_all('/\&#(\d+)\;/', $str, $matches)) - { - for ($i = 0, $s = count($matches['0']); $i < $s; $i++) - { - $digits = $matches['1'][$i]; - - $out = ''; - - if ($digits < 128) - { - $out .= chr($digits); - - } - elseif ($digits < 2048) - { - $out .= chr(192 + (($digits - ($digits % 64)) / 64)); - $out .= chr(128 + ($digits % 64)); - } - else - { - $out .= chr(224 + (($digits - ($digits % 4096)) / 4096)); - $out .= chr(128 + ((($digits % 4096) - ($digits % 64)) / 64)); - $out .= chr(128 + ($digits % 64)); - } - - $str = str_replace($matches['0'][$i], $out, $str); - } - } - - if ($all) - { - $str = str_replace(array("&", "<", ">", """, "'", "-"), - array("&","<",">","\"", "'", "-"), - $str); - } - - return $str; + if (preg_match_all('/\&#(\d+)\;/', $str, $matches)) + { + for ($i = 0, $s = count($matches['0']); $i < $s; $i++) + { + $digits = $matches['1'][$i]; + + $out = ''; + + if ($digits < 128) + { + $out .= chr($digits); + + } + elseif ($digits < 2048) + { + $out .= chr(192 + (($digits - ($digits % 64)) / 64)); + $out .= chr(128 + ($digits % 64)); + } + else + { + $out .= chr(224 + (($digits - ($digits % 4096)) / 4096)); + $out .= chr(128 + ((($digits % 4096) - ($digits % 64)) / 64)); + $out .= chr(128 + ($digits % 64)); + } + + $str = str_replace($matches['0'][$i], $out, $str); + } + } + + if ($all) + { + $str = str_replace(array("&", "<", ">", """, "'", "-"), + array("&","<",">","\"", "'", "-"), + $str); + } + + return $str; } } - + // ------------------------------------------------------------------------ /** @@ -233,7 +233,7 @@ function entities_to_ascii($str, $all = TRUE) * @param string the array of censoered words * @param string the optional replacement value * @return string - */ + */ if ( ! function_exists('word_censor')) { function word_censor($str, $censored, $replacement = '') @@ -242,13 +242,13 @@ function word_censor($str, $censored, $replacement = '') { return $str; } - + $str = ' '.$str.' '; // \w, \b and a few others do not match on a unicode character // set for performance reasons. As a result words like über // will not match on a word boundary. Instead, we'll assume that - // a bad word will be bookended by any of these characters. + // a bad word will be bookeneded by any of these characters. $delim = '[-_\'\"`(){}<>\[\]|!?@#%&,.:;^~*+=\/ 0-9\n\r\t]'; foreach ($censored as $badword) @@ -266,7 +266,7 @@ function word_censor($str, $censored, $replacement = '') return trim($str); } } - + // ------------------------------------------------------------------------ /** @@ -277,26 +277,26 @@ function word_censor($str, $censored, $replacement = '') * @access public * @param string the text string * @return string - */ + */ if ( ! function_exists('highlight_code')) { function highlight_code($str) - { + { // The highlight string function encodes and highlights // brackets so we need them to start raw $str = str_replace(array('<', '>'), array('<', '>'), $str); - + // Replace any existing PHP tags to temporary markers so they don't accidentally // break the string out of PHP, and thus, thwart the highlighting. - - $str = str_replace(array('', '<%', '%>', '\\', ''), + + $str = str_replace(array('', '<%', '%>', '\\', ''), array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), $str); // The highlight_string function requires that the text be surrounded // by PHP tags, which we will remove later $str = ''; // tags @@ -307,20 +307,20 @@ function highlight_code($str) $str = str_replace(array(''), array(''), $str); $str = preg_replace('#color="(.*?)"#', 'style="color: \\1"', $str); } - + // Remove our artificially added PHP, and the syntax highlighting that came with it $str = preg_replace('/<\?php( | )/i', '', $str); $str = preg_replace('/(.*?)\?><\/span>\n<\/span>\n<\/code>/is', "$1\n\n", $str); $str = preg_replace('/<\/span>/i', '', $str); - + // Replace our markers back to PHP tags. $str = str_replace(array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), array('<?', '?>', '<%', '%>', '\\', '</script>'), $str); - + return $str; } } - + // ------------------------------------------------------------------------ /** @@ -334,7 +334,7 @@ function highlight_code($str) * @param string the openging tag to precede the phrase with * @param string the closing tag to end the phrase with * @return string - */ + */ if ( ! function_exists('highlight_phrase')) { function highlight_phrase($str, $phrase, $tag_open = '', $tag_close = '') @@ -343,7 +343,7 @@ function highlight_phrase($str, $phrase, $tag_open = '', $tag_close = '< { return ''; } - + if ($phrase != '') { return preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open."\\1".$tag_close, $str); @@ -352,7 +352,38 @@ function highlight_phrase($str, $phrase, $tag_open = '', $tag_close = '< return $str; } } - + +// ------------------------------------------------------------------------ + +/** + * Convert Accented Foreign Characters to ASCII + * + * @access public + * @param string the text string + * @return string + */ +if ( ! function_exists('convert_accented_characters')) +{ + function convert_accented_characters($str) + { + if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php'); + } + elseif (is_file(APPPATH.'config/foreign_chars.php')) + { + include(APPPATH.'config/foreign_chars.php'); + } + + if ( ! isset($foreign_characters)) + { + return $str; + } + + return preg_replace(array_keys($foreign_characters), array_values($foreign_characters), $str); + } +} + // ------------------------------------------------------------------------ /** @@ -366,7 +397,7 @@ function highlight_phrase($str, $phrase, $tag_open = '', $tag_close = '< * @param string the text string * @param integer the number of characters to wrap at * @return string - */ + */ if ( ! function_exists('word_wrap')) { function word_wrap($str, $charlim = '76') @@ -374,47 +405,47 @@ function word_wrap($str, $charlim = '76') // Se the character limit if ( ! is_numeric($charlim)) $charlim = 76; - + // Reduce multiple spaces $str = preg_replace("| +|", " ", $str); - + // Standardize newlines if (strpos($str, "\r") !== FALSE) { - $str = str_replace(array("\r\n", "\r"), "\n", $str); + $str = str_replace(array("\r\n", "\r"), "\n", $str); } - - // If the current word is surrounded by {unwrap} tags we'll + + // If the current word is surrounded by {unwrap} tags we'll // strip the entire chunk and replace it with a marker. $unwrap = array(); if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches)) { for ($i = 0; $i < count($matches['0']); $i++) { - $unwrap[] = $matches['1'][$i]; + $unwrap[] = $matches['1'][$i]; $str = str_replace($matches['1'][$i], "{{unwrapped".$i."}}", $str); } } - - // Use PHP's native function to do the initial wordwrap. - // We set the cut flag to FALSE so that any individual words that are + + // Use PHP's native function to do the initial wordwrap. + // We set the cut flag to FALSE so that any individual words that are // too long get left alone. In the next step we'll deal with them. $str = wordwrap($str, $charlim, "\n", FALSE); - + // Split the string into individual lines of text and cycle through them $output = ""; - foreach (explode("\n", $str) as $line) + foreach (explode("\n", $str) as $line) { // Is the line within the allowed character count? // If so we'll join it to the output and continue if (strlen($line) <= $charlim) { - $output .= $line."\n"; + $output .= $line."\n"; continue; } - + $temp = ''; - while((strlen($line)) > $charlim) + while ((strlen($line)) > $charlim) { // If the over-length word is a URL we won't wrap it if (preg_match("!\[url.+\]|://|wwww.!", $line)) @@ -426,12 +457,12 @@ function word_wrap($str, $charlim = '76') $temp .= substr($line, 0, $charlim-1); $line = substr($line, $charlim-1); } - - // If $temp contains data it means we had to split up an over-length + + // If $temp contains data it means we had to split up an over-length // word into smaller chunks so we'll add it back to our current line if ($temp != '') { - $output .= $temp . "\n" . $line; + $output .= $temp."\n".$line; } else { @@ -443,7 +474,7 @@ function word_wrap($str, $charlim = '76') // Put our markers back if (count($unwrap) > 0) - { + { foreach ($unwrap as $key => $val) { $output = str_replace("{{unwrapped".$key."}}", $val, $output); @@ -453,10 +484,52 @@ function word_wrap($str, $charlim = '76') // Remove the unwrap tags $output = str_replace(array('{unwrap}', '{/unwrap}'), '', $output); - return $output; + return $output; } } +// ------------------------------------------------------------------------ + +/** + * Ellipsize String + * + * This function will strip tags from a string, split it at its max_length and ellipsize + * + * @param string string to ellipsize + * @param integer max length of string + * @param mixed int (1|0) or float, .5, .2, etc for position to split + * @param string ellipsis ; Default '...' + * @return string ellipsized string + */ +if ( ! function_exists('ellipsize')) +{ + function ellipsize($str, $max_length, $position = 1, $ellipsis = '…') + { + // Strip tags + $str = trim(strip_tags($str)); + + // Is the string long enough to ellipsize? + if (strlen($str) <= $max_length) + { + return $str; + } + + $beg = substr($str, 0, floor($max_length * $position)); + + $position = ($position > 1) ? 1 : $position; + + if ($position === 1) + { + $end = substr($str, 0, -($max_length - strlen($beg))); + } + else + { + $end = substr($str, -($max_length - strlen($beg))); + } + + return $beg.$ellipsis.$end; + } +} /* End of file text_helper.php */ /* Location: ./system/helpers/text_helper.php */ \ No newline at end of file diff --git a/system/helpers/typography_helper.php b/system/helpers/typography_helper.php index 2706d53b..19b4eec0 100644 --- a/system/helpers/typography_helper.php +++ b/system/helpers/typography_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -33,19 +33,19 @@ * @access public * @param string * @return string - */ + */ if ( ! function_exists('nl2br_except_pre')) { function nl2br_except_pre($str) { $CI =& get_instance(); - + $CI->load->library('typography'); - + return $CI->typography->nl2br_except_pre($str); } } - + // ------------------------------------------------------------------------ /** @@ -54,16 +54,38 @@ function nl2br_except_pre($str) * * @access public * @param string + * @param bool whether to allow javascript event handlers * @param bool whether to reduce multiple instances of double newlines to two * @return string */ if ( ! function_exists('auto_typography')) { - function auto_typography($str, $reduce_linebreaks = FALSE) + function auto_typography($str, $strip_js_event_handlers = TRUE, $reduce_linebreaks = FALSE) { - $CI =& get_instance(); + $CI =& get_instance(); $CI->load->library('typography'); - return $CI->typography->auto_typography($str, $reduce_linebreaks); + return $CI->typography->auto_typography($str, $strip_js_event_handlers, $reduce_linebreaks); + } +} + + +// -------------------------------------------------------------------- + +/** + * HTML Entities Decode + * + * This function is a replacement for html_entity_decode() + * + * @access public + * @param string + * @return string + */ +if ( ! function_exists('entity_decode')) +{ + function entity_decode($str, $charset='UTF-8') + { + global $SEC; + return $SEC->entity_decode($str, $charset); } } diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php index 546552a6..f1e8c6ac 100644 --- a/system/helpers/url_helper.php +++ b/system/helpers/url_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -50,18 +50,21 @@ function site_url($uri = '') /** * Base URL - * - * Returns the "base_url" item from your config file + * + * Create a local URL based on your basepath. + * Segments can be passed in as a string or an array, same as site_url + * or a URL to a file can be passed in, e.g. to an image file. * * @access public + * @param string * @return string */ if ( ! function_exists('base_url')) { - function base_url() + function base_url($uri = '') { $CI =& get_instance(); - return $CI->config->slash_item('base_url'); + return $CI->config->base_url($uri); } } @@ -70,7 +73,7 @@ function base_url() /** * Current URL * - * Returns the full URL (including segments) of the page where this + * Returns the full URL (including segments) of the page where this * function is placed * * @access public @@ -224,7 +227,7 @@ function anchor_popup($uri = '', $title = '', $attributes = FALSE) * @access public * @param string the email address * @param string the link title - * @param mixed any attributes + * @param mixed any attributes * @return string */ if ( ! function_exists('mailto')) @@ -254,7 +257,7 @@ function mailto($email, $title = '', $attributes = '') * @access public * @param string the email address * @param string the link title - * @param mixed any attributes + * @param mixed any attributes * @return string */ if ( ! function_exists('safe_mailto')) @@ -320,7 +323,7 @@ function safe_mailto($email, $title = '', $attributes = '') { $count = ($ordinal < 224) ? 2 : 3; } - + $temp[] = $ordinal; if (count($temp) == $count) { @@ -369,7 +372,7 @@ function safe_mailto($email, $title = '', $attributes = '') * @access public * @param string the string * @param string the type: email, url, or both - * @param bool whether to create pop-up links + * @param bool whether to create pop-up links * @return string */ if ( ! function_exists('auto_link')) @@ -381,7 +384,7 @@ function auto_link($str, $type = 'both', $popup = FALSE) if (preg_match_all("#(^|\s|\()((http(s?)://)|(www\.))(\w+[^\s\)\<]+)#i", $str, $matches)) { $pop = ($popup == TRUE) ? " target=\"_blank\" " : ""; - + for ($i = 0; $i < count($matches['0']); $i++) { $period = ''; @@ -390,7 +393,7 @@ function auto_link($str, $type = 'both', $popup = FALSE) $period = '.'; $matches['6'][$i] = substr($matches['6'][$i], 0, -1); } - + $str = str_replace($matches['0'][$i], $matches['1'][$i].' '', - '&\S+?;' => '', - '\s+' => $replace, - '[^a-z0-9\-\._]' => '', - $replace.'+' => $replace, - $replace.'$' => $replace, - '^'.$replace => $replace, - '\.+$' => '' - ); + '&.+?;' => '', + '[^a-z0-9 _-]' => '', + '\s+' => $separator, + '('.$q_separator.')+' => $separator + ); $str = strip_tags($str); @@ -506,8 +507,8 @@ function url_title($str, $separator = 'dash', $lowercase = FALSE) { $str = strtolower($str); } - - return trim(stripslashes($str)); + + return trim($str, $separator); } } @@ -533,7 +534,7 @@ function redirect($uri = '', $method = 'location', $http_response_code = 302) { $uri = site_url($uri); } - + switch($method) { case 'refresh' : header("Refresh:0;url=".$uri); diff --git a/system/helpers/xml_helper.php b/system/helpers/xml_helper.php index 2a4c808c..cdd81ad7 100644 --- a/system/helpers/xml_helper.php +++ b/system/helpers/xml_helper.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -33,30 +33,39 @@ * @access public * @param string * @return string - */ + */ if ( ! function_exists('xml_convert')) { - function xml_convert($str) + function xml_convert($str, $protect_all = FALSE) { $temp = '__TEMP_AMPERSANDS__'; - // Replace entities to temporary markers so that + // Replace entities to temporary markers so that // ampersands won't get messed up $str = preg_replace("/&#(\d+);/", "$temp\\1;", $str); - $str = preg_replace("/&(\w+);/", "$temp\\1;", $str); - + + if ($protect_all === TRUE) + { + $str = preg_replace("/&(\w+);/", "$temp\\1;", $str); + } + $str = str_replace(array("&","<",">","\"", "'", "-"), - array("&", "<", ">", """, "'", "-"), - $str); + array("&", "<", ">", """, "'", "-"), + $str); - // Decode the temp markers back to entities + // Decode the temp markers back to entities $str = preg_replace("/$temp(\d+);/","&#\\1;",$str); - $str = preg_replace("/$temp(\w+);/","&\\1;", $str); - + + if ($protect_all === TRUE) + { + $str = preg_replace("/$temp(\w+);/","&\\1;", $str); + } + return $str; } } +// ------------------------------------------------------------------------ /* End of file xml_helper.php */ /* Location: ./system/helpers/xml_helper.php */ \ No newline at end of file diff --git a/system/language/english/calendar_lang.php b/system/language/english/calendar_lang.php index e26f8493..3e631236 100644 --- a/system/language/english/calendar_lang.php +++ b/system/language/english/calendar_lang.php @@ -1,19 +1,19 @@ _initialize($config); + } + } + + // ------------------------------------------------------------------------ + + /** + * Get + * + * Look for a value in the cache. If it exists, return the data + * if not, return FALSE + * + * @param string + * @return mixed value that is stored/FALSE on failure + */ + public function get($id) + { + return $this->{$this->_adapter}->get($id); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Save + * + * @param string Unique Key + * @param mixed Data to store + * @param int Length of time (in seconds) to cache the data + * + * @return boolean true on success/false on failure + */ + public function save($id, $data, $ttl = 60) + { + return $this->{$this->_adapter}->save($id, $data, $ttl); + } + + // ------------------------------------------------------------------------ + + /** + * Delete from Cache + * + * @param mixed unique identifier of the item in the cache + * @return boolean true on success/false on failure + */ + public function delete($id) + { + return $this->{$this->_adapter}->delete($id); + } + + // ------------------------------------------------------------------------ + + /** + * Clean the cache + * + * @return boolean false on failure/true on success + */ + public function clean() + { + return $this->{$this->_adapter}->clean(); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Info + * + * @param string user/filehits + * @return mixed array on success, false on failure + */ + public function cache_info($type = 'user') + { + return $this->{$this->_adapter}->cache_info($type); + } + + // ------------------------------------------------------------------------ + + /** + * Get Cache Metadata + * + * @param mixed key to get cache metadata on + * @return mixed return value from child method + */ + public function get_metadata($id) + { + return $this->{$this->_adapter}->get_metadata($id); + } + + // ------------------------------------------------------------------------ + + /** + * Initialize + * + * Initialize class properties based on the configuration array. + * + * @param array + * @return void + */ + private function _initialize($config) + { + $default_config = array( + 'adapter', + 'memcached' + ); + + foreach ($default_config as $key) + { + if (isset($config[$key])) + { + $param = '_'.$key; + + $this->{$param} = $config[$key]; + } + } + + if (isset($config['backup'])) + { + if (in_array('cache_'.$config['backup'], $this->valid_drivers)) + { + $this->_backup_driver = $config['backup']; + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Is the requested driver supported in this environment? + * + * @param string The driver to test. + * @return array + */ + public function is_supported($driver) + { + static $support = array(); + + if ( ! isset($support[$driver])) + { + $support[$driver] = $this->{$driver}->is_supported(); + } + + return $support[$driver]; + } + + // ------------------------------------------------------------------------ + + /** + * __get() + * + * @param child + * @return object + */ + public function __get($child) + { + $obj = parent::__get($child); + + if ( ! $this->is_supported($child)) + { + $this->_adapter = $this->_backup_driver; + } + + return $obj; + } + + // ------------------------------------------------------------------------ +} +// End Class + +/* End of file Cache.php */ +/* Location: ./system/libraries/Cache/Cache.php */ \ No newline at end of file diff --git a/system/libraries/Cache/drivers/Cache_apc.php b/system/libraries/Cache/drivers/Cache_apc.php new file mode 100644 index 00000000..f750e6cb --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_apc.php @@ -0,0 +1,151 @@ + $time + $ttl, + 'mtime' => $time, + 'data' => $data + ); + } + + // ------------------------------------------------------------------------ + + /** + * is_supported() + * + * Check to see if APC is available on this system, bail if it isn't. + */ + public function is_supported() + { + if ( ! extension_loaded('apc') OR ini_get('apc.enabled') != "1") + { + log_message('error', 'The APC PHP extension must be loaded to use APC Cache.'); + return FALSE; + } + + return TRUE; + } + + // ------------------------------------------------------------------------ + + +} +// End Class + +/* End of file Cache_apc.php */ +/* Location: ./system/libraries/Cache/drivers/Cache_apc.php */ diff --git a/system/libraries/Cache/drivers/Cache_dummy.php b/system/libraries/Cache/drivers/Cache_dummy.php new file mode 100644 index 00000000..b11b5b8f --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_dummy.php @@ -0,0 +1,129 @@ +load->helper('file'); + + $path = $CI->config->item('cache_path'); + + $this->_cache_path = ($path == '') ? APPPATH.'cache/' : $path; + } + + // ------------------------------------------------------------------------ + + /** + * Fetch from cache + * + * @param mixed unique key id + * @return mixed data on success/false on failure + */ + public function get($id) + { + if ( ! file_exists($this->_cache_path.$id)) + { + return FALSE; + } + + $data = read_file($this->_cache_path.$id); + $data = unserialize($data); + + if (time() > $data['time'] + $data['ttl']) + { + unlink($this->_cache_path.$id); + return FALSE; + } + + return $data['data']; + } + + // ------------------------------------------------------------------------ + + /** + * Save into cache + * + * @param string unique key + * @param mixed data to store + * @param int length of time (in seconds) the cache is valid + * - Default is 60 seconds + * @return boolean true on success/false on failure + */ + public function save($id, $data, $ttl = 60) + { + $contents = array( + 'time' => time(), + 'ttl' => $ttl, + 'data' => $data + ); + + if (write_file($this->_cache_path.$id, serialize($contents))) + { + @chmod($this->_cache_path.$id, 0777); + return TRUE; + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Delete from Cache + * + * @param mixed unique identifier of item in cache + * @return boolean true on success/false on failure + */ + public function delete($id) + { + return unlink($this->_cache_path.$id); + } + + // ------------------------------------------------------------------------ + + /** + * Clean the Cache + * + * @return boolean false on failure/true on success + */ + public function clean() + { + return delete_files($this->_cache_path); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Info + * + * Not supported by file-based caching + * + * @param string user/filehits + * @return mixed FALSE + */ + public function cache_info($type = NULL) + { + return get_dir_file_info($this->_cache_path); + } + + // ------------------------------------------------------------------------ + + /** + * Get Cache Metadata + * + * @param mixed key to get cache metadata on + * @return mixed FALSE on failure, array on success. + */ + public function get_metadata($id) + { + if ( ! file_exists($this->_cache_path.$id)) + { + return FALSE; + } + + $data = read_file($this->_cache_path.$id); + $data = unserialize($data); + + if (is_array($data)) + { + $mtime = filemtime($this->_cache_path.$id); + + if ( ! isset($data['ttl'])) + { + return FALSE; + } + + return array( + 'expire' => $mtime + $data['ttl'], + 'mtime' => $mtime + ); + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Is supported + * + * In the file driver, check to see that the cache directory is indeed writable + * + * @return boolean + */ + public function is_supported() + { + return is_really_writable($this->_cache_path); + } + + // ------------------------------------------------------------------------ +} +// End Class + +/* End of file Cache_file.php */ +/* Location: ./system/libraries/Cache/drivers/Cache_file.php */ \ No newline at end of file diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php new file mode 100644 index 00000000..74784209 --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_memcached.php @@ -0,0 +1,218 @@ + array( + 'default_host' => '127.0.0.1', + 'default_port' => 11211, + 'default_weight' => 1 + ) + ); + + // ------------------------------------------------------------------------ + + /** + * Fetch from cache + * + * @param mixed unique key id + * @return mixed data on success/false on failure + */ + public function get($id) + { + $data = $this->_memcached->get($id); + + return (is_array($data)) ? $data[0] : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Save + * + * @param string unique identifier + * @param mixed data being cached + * @param int time to live + * @return boolean true on success, false on failure + */ + public function save($id, $data, $ttl = 60) + { + if (get_class($this->_memcached) == 'Memcached') + { + return $this->_memcached->set($id, array($data, time(), $ttl), $ttl); + } + else if (get_class($this->_memcached) == 'Memcache') + { + return $this->_memcached->set($id, array($data, time(), $ttl), 0, $ttl); + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Delete from Cache + * + * @param mixed key to be deleted. + * @return boolean true on success, false on failure + */ + public function delete($id) + { + return $this->_memcached->delete($id); + } + + // ------------------------------------------------------------------------ + + /** + * Clean the Cache + * + * @return boolean false on failure/true on success + */ + public function clean() + { + return $this->_memcached->flush(); + } + + // ------------------------------------------------------------------------ + + /** + * Cache Info + * + * @param null type not supported in memcached + * @return mixed array on success, false on failure + */ + public function cache_info($type = NULL) + { + return $this->_memcached->getStats(); + } + + // ------------------------------------------------------------------------ + + /** + * Get Cache Metadata + * + * @param mixed key to get cache metadata on + * @return mixed FALSE on failure, array on success. + */ + public function get_metadata($id) + { + $stored = $this->_memcached->get($id); + + if (count($stored) !== 3) + { + return FALSE; + } + + list($data, $time, $ttl) = $stored; + + return array( + 'expire' => $time + $ttl, + 'mtime' => $time, + 'data' => $data + ); + } + + // ------------------------------------------------------------------------ + + /** + * Setup memcached. + */ + private function _setup_memcached() + { + // Try to load memcached server info from the config file. + $CI =& get_instance(); + if ($CI->config->load('memcached', TRUE, TRUE)) + { + if (is_array($CI->config->config['memcached'])) + { + $this->_memcache_conf = NULL; + + foreach ($CI->config->config['memcached'] as $name => $conf) + { + $this->_memcache_conf[$name] = $conf; + } + } + } + + $this->_memcached = new Memcached(); + + foreach ($this->_memcache_conf as $name => $cache_server) + { + if ( ! array_key_exists('hostname', $cache_server)) + { + $cache_server['hostname'] = $this->_default_options['default_host']; + } + + if ( ! array_key_exists('port', $cache_server)) + { + $cache_server['port'] = $this->_default_options['default_port']; + } + + if ( ! array_key_exists('weight', $cache_server)) + { + $cache_server['weight'] = $this->_default_options['default_weight']; + } + + $this->_memcached->addServer( + $cache_server['hostname'], $cache_server['port'], $cache_server['weight'] + ); + } + } + + // ------------------------------------------------------------------------ + + + /** + * Is supported + * + * Returns FALSE if memcached is not supported on the system. + * If it is, we setup the memcached object & return TRUE + */ + public function is_supported() + { + if ( ! extension_loaded('memcached')) + { + log_message('error', 'The Memcached Extension must be loaded to use Memcached Cache.'); + + return FALSE; + } + + $this->_setup_memcached(); + return TRUE; + } + + // ------------------------------------------------------------------------ + +} +// End Class + +/* End of file Cache_memcached.php */ +/* Location: ./system/libraries/Cache/drivers/Cache_memcached.php */ \ No newline at end of file diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php index 68d40225..df0fd6ee 100644 --- a/system/libraries/Calendar.php +++ b/system/libraries/Calendar.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -33,7 +33,7 @@ class CI_Calendar { var $local_time; var $template = ''; var $start_day = 'sunday'; - var $month_type = 'long'; + var $month_type = 'long'; var $day_type = 'abr'; var $show_next_prev = FALSE; var $next_prev_url = ''; @@ -42,30 +42,28 @@ class CI_Calendar { * Constructor * * Loads the calendar language file and sets the default time reference - * - * @access public */ - function CI_Calendar($config = array()) - { + public function __construct($config = array()) + { $this->CI =& get_instance(); - - if ( ! in_array('calendar_lang'.EXT, $this->CI->lang->is_loaded, TRUE)) + + if ( ! in_array('calendar_lang.php', $this->CI->lang->is_loaded, TRUE)) { $this->CI->lang->load('calendar'); } $this->local_time = time(); - + if (count($config) > 0) { $this->initialize($config); } - + log_message('debug', "Calendar Class Initialized"); } - + // -------------------------------------------------------------------- - + /** * Initialize the user preferences * @@ -74,7 +72,7 @@ function CI_Calendar($config = array()) * @access public * @param array config preferences * @return void - */ + */ function initialize($config = array()) { foreach ($config as $key => $val) @@ -85,7 +83,7 @@ function initialize($config = array()) } } } - + // -------------------------------------------------------------------- /** @@ -102,66 +100,66 @@ function generate($year = '', $month = '', $data = array()) // Set and validate the supplied month/year if ($year == '') $year = date("Y", $this->local_time); - + if ($month == '') $month = date("m", $this->local_time); - - if (strlen($year) == 1) + + if (strlen($year) == 1) $year = '200'.$year; - - if (strlen($year) == 2) + + if (strlen($year) == 2) $year = '20'.$year; - if (strlen($month) == 1) + if (strlen($month) == 1) $month = '0'.$month; - + $adjusted_date = $this->adjust_date($month, $year); - + $month = $adjusted_date['month']; $year = $adjusted_date['year']; - + // Determine the total days in the month $total_days = $this->get_total_days($month, $year); - + // Set the starting day of the week $start_days = array('sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday' => 3, 'thursday' => 4, 'friday' => 5, 'saturday' => 6); $start_day = ( ! isset($start_days[$this->start_day])) ? 0 : $start_days[$this->start_day]; - + // Set the starting day number $local_date = mktime(12, 0, 0, $month, 1, $year); $date = getdate($local_date); $day = $start_day + 1 - $date["wday"]; - + while ($day > 1) { $day -= 7; } - + // Set the current month/year/day // We use this to determine the "today" date $cur_year = date("Y", $this->local_time); $cur_month = date("m", $this->local_time); $cur_day = date("j", $this->local_time); - + $is_current_month = ($cur_year == $year AND $cur_month == $month) ? TRUE : FALSE; - + // Generate the template data array $this->parse_template(); - - // Begin building the calendar output + + // Begin building the calendar output $out = $this->temp['table_open']; - $out .= "\n"; + $out .= "\n"; - $out .= "\n"; + $out .= "\n"; $out .= $this->temp['heading_row_start']; $out .= "\n"; - + // "previous" month link if ($this->show_next_prev == TRUE) { // Add a trailing slash to the URL if needed $this->next_prev_url = preg_replace("/(.+?)\/*$/", "\\1/", $this->next_prev_url); - + $adjusted_date = $this->adjust_date($month - 1, $year); $out .= str_replace('{previous_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->temp['heading_previous_cell']); $out .= "\n"; @@ -169,26 +167,26 @@ function generate($year = '', $month = '', $data = array()) // Heading containing the month/year $colspan = ($this->show_next_prev == TRUE) ? 5 : 7; - + $this->temp['heading_title_cell'] = str_replace('{colspan}', $colspan, $this->temp['heading_title_cell']); $this->temp['heading_title_cell'] = str_replace('{heading}', $this->get_month_name($month)." ".$year, $this->temp['heading_title_cell']); - + $out .= $this->temp['heading_title_cell']; $out .= "\n"; // "next" month link if ($this->show_next_prev == TRUE) - { + { $adjusted_date = $this->adjust_date($month + 1, $year); $out .= str_replace('{next_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->temp['heading_next_cell']); } - $out .= "\n"; + $out .= "\n"; $out .= $this->temp['heading_row_end']; $out .= "\n"; // Write the cells containing the days of the week - $out .= "\n"; + $out .= "\n"; $out .= $this->temp['week_row_start']; $out .= "\n"; @@ -213,11 +211,11 @@ function generate($year = '', $month = '', $data = array()) for ($i = 0; $i < 7; $i++) { $out .= ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_start_today'] : $this->temp['cal_cell_start']; - + if ($day > 0 AND $day <= $total_days) - { + { if (isset($data[$day])) - { + { // Cells with content $temp = ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_content_today'] : $this->temp['cal_cell_content']; $out .= str_replace('{day}', $day, str_replace('{content}', $data[$day], $temp)); @@ -234,22 +232,22 @@ function generate($year = '', $month = '', $data = array()) // Blank cells $out .= $this->temp['cal_cell_blank']; } - - $out .= ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_end_today'] : $this->temp['cal_cell_end']; + + $out .= ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_end_today'] : $this->temp['cal_cell_end']; $day++; } - - $out .= "\n"; + + $out .= "\n"; $out .= $this->temp['cal_row_end']; - $out .= "\n"; + $out .= "\n"; } - $out .= "\n"; + $out .= "\n"; $out .= $this->temp['table_close']; return $out; } - + // -------------------------------------------------------------------- /** @@ -272,9 +270,9 @@ function get_month_name($month) { $month_names = array('01' => 'cal_january', '02' => 'cal_february', '03' => 'cal_march', '04' => 'cal_april', '05' => 'cal_mayl', '06' => 'cal_june', '07' => 'cal_july', '08' => 'cal_august', '09' => 'cal_september', '10' => 'cal_october', '11' => 'cal_november', '12' => 'cal_december'); } - + $month = $month_names[$month]; - + if ($this->CI->lang->line($month) === FALSE) { return ucfirst(str_replace('cal_', '', $month)); @@ -282,7 +280,7 @@ function get_month_name($month) return $this->CI->lang->line($month); } - + // -------------------------------------------------------------------- /** @@ -299,7 +297,7 @@ function get_day_names($day_type = '') { if ($day_type != '') $this->day_type = $day_type; - + if ($this->day_type == 'long') { $day_names = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); @@ -312,16 +310,16 @@ function get_day_names($day_type = '') { $day_names = array('su', 'mo', 'tu', 'we', 'th', 'fr', 'sa'); } - + $days = array(); foreach ($day_names as $val) - { + { $days[] = ($this->CI->lang->line('cal_'.$val) === FALSE) ? ucfirst($val) : $this->CI->lang->line('cal_'.$val); } - + return $days; } - + // -------------------------------------------------------------------- /** @@ -362,7 +360,7 @@ function adjust_date($month, $year) return $date; } - + // -------------------------------------------------------------------- /** @@ -393,7 +391,7 @@ function get_total_days($month, $year) return $days_in_month[$month - 1]; } - + // -------------------------------------------------------------------- /** @@ -407,17 +405,17 @@ function get_total_days($month, $year) function default_template() { return array ( - 'table_open' => '', - 'heading_row_start' => '', + 'table_open' => '
', + 'heading_row_start' => '', 'heading_previous_cell' => '', - 'heading_title_cell' => '', - 'heading_next_cell' => '', - 'heading_row_end' => '', - 'week_row_start' => '', - 'week_day_cell' => '', - 'week_row_end' => '', - 'cal_row_start' => '', - 'cal_cell_start' => '', + 'heading_next_cell' => '', + 'heading_row_end' => '', + 'week_row_start' => '', + 'week_day_cell' => '', + 'week_row_end' => '', + 'cal_row_start' => '', + 'cal_cell_start' => '', 'cal_row_end' => '', 'table_close' => '
<<{heading}>>
{week_day}
', + 'heading_title_cell' => '{heading}>>
{week_day}
', 'cal_cell_start_today' => '', 'cal_cell_content' => '{day}', 'cal_cell_content_today' => '{day}', @@ -428,9 +426,9 @@ function default_template() 'cal_cell_end_today' => '
' - ); + ); } - + // -------------------------------------------------------------------- /** @@ -442,17 +440,17 @@ function default_template() * @access public * @return void */ - function parse_template() - { + function parse_template() + { $this->temp = $this->default_template(); - - if ($this->template == '') - { - return; - } - + + if ($this->template == '') + { + return; + } + $today = array('cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today'); - + foreach (array('table_open', 'table_close', 'heading_row_start', 'heading_previous_cell', 'heading_title_cell', 'heading_next_cell', 'heading_row_end', 'week_row_start', 'week_day_cell', 'week_row_end', 'cal_row_start', 'cal_cell_start', 'cal_cell_content', 'cal_cell_no_content', 'cal_cell_blank', 'cal_cell_end', 'cal_row_end', 'cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today') as $val) { if (preg_match("/\{".$val."\}(.*?)\{\/".$val."\}/si", $this->template, $match)) @@ -466,8 +464,8 @@ function parse_template() $this->temp[$val] = $this->temp[str_replace('_today', '', $val)]; } } - } - } + } + } } diff --git a/system/libraries/Cart.php b/system/libraries/Cart.php index 2eb8b75b..da47b5a1 100644 --- a/system/libraries/Cart.php +++ b/system/libraries/Cart.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2006 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2006 - 2012, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -29,7 +29,7 @@ class CI_Cart { // These are the regular expression rules that we use to validate the product ID and product name var $product_id_rules = '\.a-z0-9_-'; // alpha-numeric, dashes, underscores, or periods var $product_name_rules = '\.\:\-_ a-z0-9'; // alpha-numeric, dashes, underscores, colons or periods - + // Private variables. Do not change! var $CI; var $_cart_contents = array(); @@ -39,12 +39,12 @@ class CI_Cart { * Shopping Class Constructor * * The constructor loads the Session class, used to store the shopping cart contents. - */ - function CI_Cart($params = array()) - { + */ + public function __construct($params = array()) + { // Set the super object to a local variable for use later $this->CI =& get_instance(); - + // Are any config settings being passed manually? If so, set them $config = array(); if (count($params) > 0) @@ -54,10 +54,10 @@ function CI_Cart($params = array()) $config[$key] = $val; } } - + // Load the Sessions class $this->CI->load->library('session', $config); - + // Grab the shopping cart array from the session table, if it exists if ($this->CI->session->userdata('cart_contents') !== FALSE) { @@ -66,15 +66,15 @@ function CI_Cart($params = array()) else { // No cart exists so we'll set some base values - $this->_cart_contents['cart_total'] = 0; - $this->_cart_contents['total_items'] = 0; + $this->_cart_contents['cart_total'] = 0; + $this->_cart_contents['total_items'] = 0; } - + log_message('debug', "Cart Class Initialized"); } // -------------------------------------------------------------------- - + /** * Insert items into the cart and save it to the session table * @@ -90,16 +90,16 @@ function insert($items = array()) log_message('error', 'The insert method must be passed an array containing data.'); return FALSE; } - - // You can either insert a single product using a one-dimensional array, + + // You can either insert a single product using a one-dimensional array, // or multiple products using a multi-dimensional one. The way we // determine the array type is by looking for a required array key named "id" // at the top level. If it's not found, we will assume it's a multi-dimensional array. - - $save_cart = FALSE; + + $save_cart = FALSE; if (isset($items['id'])) - { - if ($this->_insert($items) == TRUE) + { + if (($rowid = $this->_insert($items))) { $save_cart = TRUE; } @@ -110,11 +110,11 @@ function insert($items = array()) { if (is_array($val) AND isset($val['id'])) { - if ($this->_insert($val) == TRUE) + if ($this->_insert($val)) { $save_cart = TRUE; } - } + } } } @@ -122,14 +122,14 @@ function insert($items = array()) if ($save_cart == TRUE) { $this->_save_cart(); - return TRUE; + return isset($rowid) ? $rowid : TRUE; } return FALSE; } // -------------------------------------------------------------------- - + /** * Insert * @@ -145,9 +145,9 @@ function _insert($items = array()) log_message('error', 'The insert method must be passed an array containing data.'); return FALSE; } - + // -------------------------------------------------------------------- - + // Does the $items array contain an id, quantity, price, and name? These are required if ( ! isset($items['id']) OR ! isset($items['qty']) OR ! isset($items['price']) OR ! isset($items['name'])) { @@ -156,7 +156,7 @@ function _insert($items = array()) } // -------------------------------------------------------------------- - + // Prep the quantity. It can only be a number. Duh... $items['qty'] = trim(preg_replace('/([^0-9])/i', '', $items['qty'])); // Trim any leading zeros @@ -167,9 +167,9 @@ function _insert($items = array()) { return FALSE; } - + // -------------------------------------------------------------------- - + // Validate the product ID. It can only be alpha-numeric, dashes, underscores or periods // Not totally sure we should impose this rule, but it seems prudent to standardize IDs. // Note: These can be user-specified by setting the $this->product_id_rules variable. @@ -180,7 +180,7 @@ function _insert($items = array()) } // -------------------------------------------------------------------- - + // Validate the product name. It can only be alpha-numeric, dashes, underscores, colons or periods. // Note: These can be user-specified by setting the $this->product_name_rules variable. if ( ! preg_match("/^[".$this->product_name_rules."]+$/i", $items['name'])) @@ -195,7 +195,7 @@ function _insert($items = array()) $items['price'] = trim(preg_replace('/([^0-9\.])/i', '', $items['price'])); // Trim any leading zeros $items['price'] = trim(preg_replace('/(^[0]+)/i', '', $items['price'])); - + // Is the price a valid number? if ( ! is_numeric($items['price'])) { @@ -204,13 +204,13 @@ function _insert($items = array()) } // -------------------------------------------------------------------- - + // We now need to create a unique identifier for the item being inserted into the cart. - // Every time something is added to the cart it is stored in the master cart array. - // Each row in the cart array, however, must have a unique index that identifies not only - // a particular product, but makes it possible to store identical products with different options. - // For example, what if someone buys two identical t-shirts (same product ID), but in - // different sizes? The product ID (and other attributes, like the name) will be identical for + // Every time something is added to the cart it is stored in the master cart array. + // Each row in the cart array, however, must have a unique index that identifies not only + // a particular product, but makes it possible to store identical products with different options. + // For example, what if someone buys two identical t-shirts (same product ID), but in + // different sizes? The product ID (and other attributes, like the name) will be identical for // both sizes because it's the same shirt. The only difference will be the size. // Internally, we need to treat identical submissions, but with different options, as a unique product. // Our solution is to convert the options array to a string and MD5 it along with the product ID. @@ -225,34 +225,34 @@ function _insert($items = array()) // Technically, we don't need to MD5 the ID in this case, but it makes // sense to standardize the format of array indexes for both conditions $rowid = md5($items['id']); - } + } // -------------------------------------------------------------------- // Now that we have our unique "row ID", we'll add our cart items to the master array - + // let's unset this first, just to make sure our index contains only the data from this submission - unset($this->_cart_contents[$rowid]); - + unset($this->_cart_contents[$rowid]); + // Create a new index with our new row ID $this->_cart_contents[$rowid]['rowid'] = $rowid; - - // And add the new items to the cart array + + // And add the new items to the cart array foreach ($items as $key => $val) { $this->_cart_contents[$rowid][$key] = $val; } // Woot! - return TRUE; + return $rowid; } // -------------------------------------------------------------------- - + /** * Update the cart * - * This function permits the quantity of a given item to be changed. + * This function permits the quantity of a given item to be changed. * Typically it is called from the "view cart" page if a user makes * changes to the quantity before checkout. That array must contain the * product ID and quantity for each item. @@ -269,8 +269,8 @@ function update($items = array()) { return FALSE; } - - // You can either update a single product using a one-dimensional array, + + // You can either update a single product using a one-dimensional array, // or multiple products using a multi-dimensional one. The way we // determine the array type is by looking for a required array key named "id". // If it's not found we assume it's a multi-dimensional array @@ -292,7 +292,7 @@ function update($items = array()) { $save_cart = TRUE; } - } + } } } @@ -307,11 +307,11 @@ function update($items = array()) } // -------------------------------------------------------------------- - + /** * Update the cart * - * This function permits the quantity of a given item to be changed. + * This function permits the quantity of a given item to be changed. * Typically it is called from the "view cart" page if a user makes * changes to the quantity before checkout. That array must contain the * product ID and quantity for each item. @@ -319,7 +319,7 @@ function update($items = array()) * @access private * @param array * @return bool - */ + */ function _update($items = array()) { // Without these array indexes there is nothing we can do @@ -327,7 +327,7 @@ function _update($items = array()) { return FALSE; } - + // Prep the quantity $items['qty'] = preg_replace('/([^0-9])/i', '', $items['qty']); @@ -336,7 +336,7 @@ function _update($items = array()) { return FALSE; } - + // Is the new quantity different than what is already saved in the cart? // If it's the same there's nothing to do if ($this->_cart_contents[$items['rowid']]['qty'] == $items['qty']) @@ -348,18 +348,18 @@ function _update($items = array()) // If the quantity is greater than zero we are updating if ($items['qty'] == 0) { - unset($this->_cart_contents[$items['rowid']]); + unset($this->_cart_contents[$items['rowid']]); } else { $this->_cart_contents[$items['rowid']]['qty'] = $items['qty']; } - + return TRUE; } // -------------------------------------------------------------------- - + /** * Save the cart array to the session DB * @@ -374,6 +374,7 @@ function _save_cart() // Lets add up the individual prices and set the cart sub-total $total = 0; + $items = 0; foreach ($this->_cart_contents as $key => $val) { // We make sure the array contains the proper indexes @@ -383,20 +384,21 @@ function _save_cart() } $total += ($val['price'] * $val['qty']); - + $items += $val['qty']; + // Set the subtotal $this->_cart_contents[$key]['subtotal'] = ($this->_cart_contents[$key]['price'] * $this->_cart_contents[$key]['qty']); } // Set the cart total and total items. - $this->_cart_contents['total_items'] = count($this->_cart_contents); + $this->_cart_contents['total_items'] = $items; $this->_cart_contents['cart_total'] = $total; - + // Is our cart empty? If so we delete it from the session if (count($this->_cart_contents) <= 2) { $this->CI->session->unset_userdata('cart_contents'); - + // Nothing more to do... coffee time! return FALSE; } @@ -406,11 +408,11 @@ function _save_cart() $this->CI->session->set_userdata(array('cart_contents' => $this->_cart_contents)); // Woot! - return TRUE; + return TRUE; } // -------------------------------------------------------------------- - + /** * Cart Total * @@ -423,7 +425,7 @@ function total() } // -------------------------------------------------------------------- - + /** * Total Items * @@ -438,7 +440,7 @@ function total_items() } // -------------------------------------------------------------------- - + /** * Cart Contents * @@ -450,16 +452,16 @@ function total_items() function contents() { $cart = $this->_cart_contents; - + // Remove these so they don't create a problem when showing the cart table unset($cart['total_items']); unset($cart['cart_total']); - + return $cart; } // -------------------------------------------------------------------- - + /** * Has options * @@ -475,12 +477,12 @@ function has_options($rowid = '') { return FALSE; } - + return TRUE; } // -------------------------------------------------------------------- - + /** * Product options * @@ -500,7 +502,7 @@ function product_options($rowid = '') } // -------------------------------------------------------------------- - + /** * Format Number * @@ -515,15 +517,15 @@ function format_number($n = '') { return ''; } - + // Remove anything that isn't a number or decimal point. $n = trim(preg_replace('/([^0-9\.])/i', '', $n)); - + return number_format($n, 2, '.', ','); } - + // -------------------------------------------------------------------- - + /** * Destroy the cart * @@ -535,9 +537,9 @@ function format_number($n = '') function destroy() { unset($this->_cart_contents); - - $this->_cart_contents['cart_total'] = 0; - $this->_cart_contents['total_items'] = 0; + + $this->_cart_contents['cart_total'] = 0; + $this->_cart_contents['total_items'] = 0; $this->CI->session->unset_userdata('cart_contents'); } diff --git a/system/libraries/Config.php b/system/libraries/Config.php deleted file mode 100644 index 4ef27863..00000000 --- a/system/libraries/Config.php +++ /dev/null @@ -1,244 +0,0 @@ -config =& get_config(); - log_message('debug', "Config Class Initialized"); - } - - // -------------------------------------------------------------------- - - /** - * Load Config File - * - * @access public - * @param string the config file name - * @return boolean if the file was loaded correctly - */ - function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) - { - $file = ($file == '') ? 'config' : str_replace(EXT, '', $file); - - if (in_array($file, $this->is_loaded, TRUE)) - { - return TRUE; - } - - if ( ! file_exists(APPPATH.'config/'.$file.EXT)) - { - if ($fail_gracefully === TRUE) - { - return FALSE; - } - show_error('The configuration file '.$file.EXT.' does not exist.'); - } - - include(APPPATH.'config/'.$file.EXT); - - if ( ! isset($config) OR ! is_array($config)) - { - if ($fail_gracefully === TRUE) - { - return FALSE; - } - show_error('Your '.$file.EXT.' file does not appear to contain a valid configuration array.'); - } - - if ($use_sections === TRUE) - { - if (isset($this->config[$file])) - { - $this->config[$file] = array_merge($this->config[$file], $config); - } - else - { - $this->config[$file] = $config; - } - } - else - { - $this->config = array_merge($this->config, $config); - } - - $this->is_loaded[] = $file; - unset($config); - - log_message('debug', 'Config file loaded: config/'.$file.EXT); - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Fetch a config file item - * - * - * @access public - * @param string the config item name - * @param string the index name - * @param bool - * @return string - */ - function item($item, $index = '') - { - if ($index == '') - { - if ( ! isset($this->config[$item])) - { - return FALSE; - } - - $pref = $this->config[$item]; - } - else - { - if ( ! isset($this->config[$index])) - { - return FALSE; - } - - if ( ! isset($this->config[$index][$item])) - { - return FALSE; - } - - $pref = $this->config[$index][$item]; - } - - return $pref; - } - - // -------------------------------------------------------------------- - - /** - * Fetch a config file item - adds slash after item - * - * The second parameter allows a slash to be added to the end of - * the item, in the case of a path. - * - * @access public - * @param string the config item name - * @param bool - * @return string - */ - function slash_item($item) - { - if ( ! isset($this->config[$item])) - { - return FALSE; - } - - $pref = $this->config[$item]; - - if ($pref != '' && substr($pref, -1) != '/') - { - $pref .= '/'; - } - - return $pref; - } - - // -------------------------------------------------------------------- - - /** - * Site URL - * - * @access public - * @param string the URI string - * @return string - */ - function site_url($uri = '') - { - if (is_array($uri)) - { - $uri = implode('/', $uri); - } - - if ($uri == '') - { - return $this->slash_item('base_url').$this->item('index_page'); - } - else - { - $suffix = ($this->item('url_suffix') == FALSE) ? '' : $this->item('url_suffix'); - return $this->slash_item('base_url').$this->slash_item('index_page').trim($uri, '/').$suffix; - } - } - - // -------------------------------------------------------------------- - - /** - * System URL - * - * @access public - * @return string - */ - function system_url() - { - $x = explode("/", preg_replace("|/*(.+?)/*$|", "\\1", BASEPATH)); - return $this->slash_item('base_url').end($x).'/'; - } - - // -------------------------------------------------------------------- - - /** - * Set a config file item - * - * @access public - * @param string the config item key - * @param string the config item value - * @return void - */ - function set_item($item, $value) - { - $this->config[$item] = $value; - } - -} - -// END CI_Config class - -/* End of file Config.php */ -/* Location: ./system/libraries/Config.php */ \ No newline at end of file diff --git a/system/libraries/Controller.php b/system/libraries/Controller.php deleted file mode 100644 index 5e93de3b..00000000 --- a/system/libraries/Controller.php +++ /dev/null @@ -1,127 +0,0 @@ -_ci_initialize(); - log_message('debug', "Controller Class Initialized"); - } - - // -------------------------------------------------------------------- - - /** - * Initialize - * - * Assigns all the bases classes loaded by the front controller to - * variables in this class. Also calls the autoload routine. - * - * @access private - * @return void - */ - function _ci_initialize() - { - // Assign all the class objects that were instantiated by the - // front controller to local class variables so that CI can be - // run as one big super object. - $classes = array( - 'config' => 'Config', - 'input' => 'Input', - 'benchmark' => 'Benchmark', - 'uri' => 'URI', - 'output' => 'Output', - 'lang' => 'Language', - 'router' => 'Router' - ); - - foreach ($classes as $var => $class) - { - $this->$var =& load_class($class); - } - - // In PHP 5 the Loader class is run as a discreet - // class. In PHP 4 it extends the Controller - if (floor(phpversion()) >= 5) - { - $this->load =& load_class('Loader'); - $this->load->_ci_autoloader(); - } - else - { - $this->_ci_autoloader(); - - // sync up the objects since PHP4 was working from a copy - foreach (array_keys(get_object_vars($this)) as $attribute) - { - if (is_object($this->$attribute)) - { - $this->load->$attribute =& $this->$attribute; - } - } - } - } - - // -------------------------------------------------------------------- - - /** - * Run Scaffolding - * - * @access private - * @return void - */ - function _ci_scaffolding() - { - if ($this->_ci_scaffolding === FALSE OR $this->_ci_scaff_table === FALSE) - { - show_404('Scaffolding unavailable'); - } - - $method = ( ! in_array($this->uri->segment(3), array('add', 'insert', 'edit', 'update', 'view', 'delete', 'do_delete'), TRUE)) ? 'view' : $this->uri->segment(3); - - require_once(BASEPATH.'scaffolding/Scaffolding'.EXT); - $scaff = new Scaffolding($this->_ci_scaff_table); - $scaff->$method(); - } - - -} -// END _Controller class - -/* End of file Controller.php */ -/* Location: ./system/libraries/Controller.php */ \ No newline at end of file diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php new file mode 100644 index 00000000..4912c4aa --- /dev/null +++ b/system/libraries/Driver.php @@ -0,0 +1,229 @@ +lib_name)) + { + $this->lib_name = get_class($this); + } + + // The class will be prefixed with the parent lib + $child_class = $this->lib_name.'_'.$child; + + // Remove the CI_ prefix and lowercase + $lib_name = ucfirst(strtolower(str_replace('CI_', '', $this->lib_name))); + $driver_name = strtolower(str_replace('CI_', '', $child_class)); + + if (in_array($driver_name, array_map('strtolower', $this->valid_drivers))) + { + // check and see if the driver is in a separate file + if ( ! class_exists($child_class)) + { + // check application path first + foreach (get_instance()->load->get_package_paths(TRUE) as $path) + { + // loves me some nesting! + foreach (array(ucfirst($driver_name), $driver_name) as $class) + { + $filepath = $path.'libraries/'.$lib_name.'/drivers/'.$class.'.php'; + + if (file_exists($filepath)) + { + include_once $filepath; + break; + } + } + } + + // it's a valid driver, but the file simply can't be found + if ( ! class_exists($child_class)) + { + log_message('error', "Unable to load the requested driver: ".$child_class); + show_error("Unable to load the requested driver: ".$child_class); + } + } + + $obj = new $child_class; + $obj->decorate($this); + $this->$child = $obj; + return $this->$child; + } + + // The requested driver isn't valid! + log_message('error', "Invalid driver requested: ".$child_class); + show_error("Invalid driver requested: ".$child_class); + } + + // -------------------------------------------------------------------- + +} +// END CI_Driver_Library CLASS + + +/** + * CodeIgniter Driver Class + * + * This class enables you to create drivers for a Library based on the Driver Library. + * It handles the drivers' access to the parent library + * + * @package CodeIgniter + * @subpackage Libraries + * @category Libraries + * @author EllisLab Dev Team + * @link + */ +class CI_Driver { + protected $parent; + + private $methods = array(); + private $properties = array(); + + private static $reflections = array(); + + /** + * Decorate + * + * Decorates the child with the parent driver lib's methods and properties + * + * @param object + * @return void + */ + public function decorate($parent) + { + $this->parent = $parent; + + // Lock down attributes to what is defined in the class + // and speed up references in magic methods + + $class_name = get_class($parent); + + if ( ! isset(self::$reflections[$class_name])) + { + $r = new ReflectionObject($parent); + + foreach ($r->getMethods() as $method) + { + if ($method->isPublic()) + { + $this->methods[] = $method->getName(); + } + } + + foreach ($r->getProperties() as $prop) + { + if ($prop->isPublic()) + { + $this->properties[] = $prop->getName(); + } + } + + self::$reflections[$class_name] = array($this->methods, $this->properties); + } + else + { + list($this->methods, $this->properties) = self::$reflections[$class_name]; + } + } + + // -------------------------------------------------------------------- + + /** + * __call magic method + * + * Handles access to the parent driver library's methods + * + * @access public + * @param string + * @param array + * @return mixed + */ + public function __call($method, $args = array()) + { + if (in_array($method, $this->methods)) + { + return call_user_func_array(array($this->parent, $method), $args); + } + + $trace = debug_backtrace(); + _exception_handler(E_ERROR, "No such method '{$method}'", $trace[1]['file'], $trace[1]['line']); + exit; + } + + // -------------------------------------------------------------------- + + /** + * __get magic method + * + * Handles reading of the parent driver library's properties + * + * @param string + * @return mixed + */ + public function __get($var) + { + if (in_array($var, $this->properties)) + { + return $this->parent->$var; + } + } + + // -------------------------------------------------------------------- + + /** + * __set magic method + * + * Handles writing to the parent driver library's properties + * + * @param string + * @param array + * @return mixed + */ + public function __set($var, $val) + { + if (in_array($var, $this->properties)) + { + $this->parent->$var = $val; + } + } + + // -------------------------------------------------------------------- + +} +// END CI_Driver CLASS + +/* End of file Driver.php */ +/* Location: ./system/libraries/Driver.php */ \ No newline at end of file diff --git a/system/libraries/Email.php b/system/libraries/Email.php index f037135b..d01d5c19 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -36,6 +36,7 @@ class CI_Email { var $smtp_pass = ""; // SMTP Password var $smtp_port = "25"; // SMTP Port var $smtp_timeout = 5; // SMTP Timeout in seconds + var $smtp_crypto = ""; // SMTP Encryption. Can be null, tls or ssl. var $wordwrap = TRUE; // TRUE/FALSE Turns word-wrap on/off var $wrapchars = "76"; // Number of characters to wrap at. var $mailtype = "text"; // text/html Defines email formatting @@ -82,7 +83,7 @@ class CI_Email { * * The constructor can be passed an array of config values */ - function CI_Email($config = array()) + public function __construct($config = array()) { if (count($config) > 0) { @@ -106,9 +107,8 @@ function CI_Email($config = array()) * @param array * @return void */ - function initialize($config = array()) + public function initialize($config = array()) { - $this->clear(); foreach ($config as $key => $val) { if (isset($this->$key)) @@ -125,11 +125,14 @@ function initialize($config = array()) } } } + $this->clear(); $this->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE; $this->_safe_mode = ((boolean)@ini_get("safe_mode") === FALSE) ? FALSE : TRUE; + + return $this; } - + // -------------------------------------------------------------------- /** @@ -138,7 +141,7 @@ function initialize($config = array()) * @access public * @return void */ - function clear($clear_attachments = FALSE) + public function clear($clear_attachments = FALSE) { $this->_subject = ""; $this->_body = ""; @@ -146,6 +149,8 @@ function clear($clear_attachments = FALSE) $this->_header_str = ""; $this->_replyto_flag = FALSE; $this->_recipients = array(); + $this->_cc_array = array(); + $this->_bcc_array = array(); $this->_headers = array(); $this->_debug_msg = array(); @@ -158,8 +163,10 @@ function clear($clear_attachments = FALSE) $this->_attach_type = array(); $this->_attach_disp = array(); } + + return $this; } - + // -------------------------------------------------------------------- /** @@ -170,7 +177,7 @@ function clear($clear_attachments = FALSE) * @param string * @return void */ - function from($from, $name = '') + public function from($from, $name = '') { if (preg_match( '/\<(.*)\>/', $from, $match)) { @@ -199,8 +206,10 @@ function from($from, $name = '') $this->_set_header('From', $name.' <'.$from.'>'); $this->_set_header('Return-Path', '<'.$from.'>'); + + return $this; } - + // -------------------------------------------------------------------- /** @@ -211,7 +220,7 @@ function from($from, $name = '') * @param string * @return void */ - function reply_to($replyto, $name = '') + public function reply_to($replyto, $name = '') { if (preg_match( '/\<(.*)\>/', $replyto, $match)) { @@ -235,8 +244,10 @@ function reply_to($replyto, $name = '') $this->_set_header('Reply-To', $name.' <'.$replyto.'>'); $this->_replyto_flag = TRUE; + + return $this; } - + // -------------------------------------------------------------------- /** @@ -246,7 +257,7 @@ function reply_to($replyto, $name = '') * @param string * @return void */ - function to($to) + public function to($to) { $to = $this->_str_to_array($to); $to = $this->clean_email($to); @@ -263,15 +274,18 @@ function to($to) switch ($this->_get_protocol()) { - case 'smtp' : $this->_recipients = $to; + case 'smtp' : + $this->_recipients = $to; break; - case 'sendmail' : $this->_recipients = implode(", ", $to); - break; - case 'mail' : $this->_recipients = implode(", ", $to); + case 'sendmail' : + case 'mail' : + $this->_recipients = implode(", ", $to); break; } + + return $this; } - + // -------------------------------------------------------------------- /** @@ -281,7 +295,7 @@ function to($to) * @param string * @return void */ - function cc($cc) + public function cc($cc) { $cc = $this->_str_to_array($cc); $cc = $this->clean_email($cc); @@ -297,8 +311,10 @@ function cc($cc) { $this->_cc_array = $cc; } + + return $this; } - + // -------------------------------------------------------------------- /** @@ -309,7 +325,7 @@ function cc($cc) * @param string * @return void */ - function bcc($bcc, $limit = '') + public function bcc($bcc, $limit = '') { if ($limit != '' && is_numeric($limit)) { @@ -333,8 +349,10 @@ function bcc($bcc, $limit = '') { $this->_set_header('Bcc', implode(", ", $bcc)); } + + return $this; } - + // -------------------------------------------------------------------- /** @@ -344,12 +362,13 @@ function bcc($bcc, $limit = '') * @param string * @return void */ - function subject($subject) + public function subject($subject) { $subject = $this->_prep_q_encoding($subject); $this->_set_header('Subject', $subject); + return $this; } - + // -------------------------------------------------------------------- /** @@ -359,11 +378,24 @@ function subject($subject) * @param string * @return void */ - function message($body) + public function message($body) { - $this->_body = stripslashes(rtrim(str_replace("\r", "", $body))); + $this->_body = rtrim(str_replace("\r", "", $body)); + + /* strip slashes only if magic quotes is ON + if we do it with magic quotes OFF, it strips real, user-inputted chars. + + NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and + it will probably not exist in future versions at all. + */ + if ( ! is_php('5.4') && get_magic_quotes_gpc()) + { + $this->_body = stripslashes($this->_body); + } + + return $this; } - + // -------------------------------------------------------------------- /** @@ -373,11 +405,12 @@ function message($body) * @param string * @return void */ - function attach($filename, $disposition = 'attachment') + public function attach($filename, $disposition = 'attachment') { $this->_attach_name[] = $filename; - $this->_attach_type[] = $this->_mime_types(next(explode('.', basename($filename)))); + $this->_attach_type[] = $this->_mime_types(pathinfo($filename, PATHINFO_EXTENSION)); $this->_attach_disp[] = $disposition; // Can also be 'inline' Not sure if it matters + return $this; } // -------------------------------------------------------------------- @@ -385,26 +418,26 @@ function attach($filename, $disposition = 'attachment') /** * Add a Header Item * - * @access private + * @access protected * @param string * @param string * @return void */ - function _set_header($header, $value) + protected function _set_header($header, $value) { $this->_headers[$header] = $value; } - + // -------------------------------------------------------------------- /** * Convert a String to an Array * - * @access private + * @access protected * @param string * @return array */ - function _str_to_array($email) + protected function _str_to_array($email) { if ( ! is_array($email)) { @@ -420,7 +453,7 @@ function _str_to_array($email) } return $email; } - + // -------------------------------------------------------------------- /** @@ -430,11 +463,12 @@ function _str_to_array($email) * @param string * @return void */ - function set_alt_message($str = '') + public function set_alt_message($str = '') { - $this->alt_message = ($str == '') ? '' : $str; + $this->alt_message = $str; + return $this; } - + // -------------------------------------------------------------------- /** @@ -444,11 +478,12 @@ function set_alt_message($str = '') * @param string * @return void */ - function set_mailtype($type = 'text') + public function set_mailtype($type = 'text') { $this->mailtype = ($type == 'html') ? 'html' : 'text'; + return $this; } - + // -------------------------------------------------------------------- /** @@ -458,11 +493,12 @@ function set_mailtype($type = 'text') * @param string * @return void */ - function set_wordwrap($wordwrap = TRUE) + public function set_wordwrap($wordwrap = TRUE) { $this->wordwrap = ($wordwrap === FALSE) ? FALSE : TRUE; + return $this; } - + // -------------------------------------------------------------------- /** @@ -472,11 +508,12 @@ function set_wordwrap($wordwrap = TRUE) * @param string * @return void */ - function set_protocol($protocol = 'mail') + public function set_protocol($protocol = 'mail') { $this->protocol = ( ! in_array($protocol, $this->_protocols, TRUE)) ? 'mail' : strtolower($protocol); + return $this; } - + // -------------------------------------------------------------------- /** @@ -486,7 +523,7 @@ function set_protocol($protocol = 'mail') * @param integer * @return void */ - function set_priority($n = 3) + public function set_priority($n = 3) { if ( ! is_numeric($n)) { @@ -501,8 +538,9 @@ function set_priority($n = 3) } $this->priority = $n; + return $this; } - + // -------------------------------------------------------------------- /** @@ -512,7 +550,7 @@ function set_priority($n = 3) * @param string * @return void */ - function set_newline($newline = "\n") + public function set_newline($newline = "\n") { if ($newline != "\n" AND $newline != "\r\n" AND $newline != "\r") { @@ -521,8 +559,10 @@ function set_newline($newline = "\n") } $this->newline = $newline; + + return $this; } - + // -------------------------------------------------------------------- /** @@ -532,7 +572,7 @@ function set_newline($newline = "\n") * @param string * @return void */ - function set_crlf($crlf = "\n") + public function set_crlf($crlf = "\n") { if ($crlf != "\n" AND $crlf != "\r\n" AND $crlf != "\r") { @@ -541,31 +581,33 @@ function set_crlf($crlf = "\n") } $this->crlf = $crlf; + + return $this; } - + // -------------------------------------------------------------------- /** * Set Message Boundary * - * @access private + * @access protected * @return void */ - function _set_boundaries() + protected function _set_boundaries() { $this->_alt_boundary = "B_ALT_".uniqid(''); // multipart/alternative $this->_atc_boundary = "B_ATC_".uniqid(''); // attachment boundary } - + // -------------------------------------------------------------------- /** * Get the Message ID * - * @access private + * @access protected * @return string */ - function _get_message_id() + protected function _get_message_id() { $from = $this->_headers['Return-Path']; $from = str_replace(">", "", $from); @@ -573,17 +615,17 @@ function _get_message_id() return "<".uniqid('').strstr($from, '@').">"; } - + // -------------------------------------------------------------------- /** * Get Mail Protocol * - * @access private + * @access protected * @param bool * @return string */ - function _get_protocol($return = TRUE) + protected function _get_protocol($return = TRUE) { $this->protocol = strtolower($this->protocol); $this->protocol = ( ! in_array($this->protocol, $this->_protocols, TRUE)) ? 'mail' : $this->protocol; @@ -593,17 +635,17 @@ function _get_protocol($return = TRUE) return $this->protocol; } } - + // -------------------------------------------------------------------- /** * Get Mail Encoding * - * @access private + * @access protected * @param bool * @return string */ - function _get_encoding($return = TRUE) + protected function _get_encoding($return = TRUE) { $this->_encoding = ( ! in_array($this->_encoding, $this->_bit_depths)) ? '8bit' : $this->_encoding; @@ -626,10 +668,10 @@ function _get_encoding($return = TRUE) /** * Get content type (text/html/attachment) * - * @access private + * @access protected * @return string */ - function _get_content_type() + protected function _get_content_type() { if ($this->mailtype == 'html' && count($this->_attach_name) == 0) { @@ -648,16 +690,16 @@ function _get_content_type() return 'plain'; } } - + // -------------------------------------------------------------------- /** * Set RFC 822 Date * - * @access private + * @access protected * @return string */ - function _set_date() + protected function _set_date() { $timezone = date("Z"); $operator = (strncmp($timezone, '-', 1) == 0) ? '-' : '+'; @@ -666,20 +708,20 @@ function _set_date() return sprintf("%s %s%04d", date("D, j M Y H:i:s"), $operator, $timezone); } - + // -------------------------------------------------------------------- /** * Mime message * - * @access private + * @access protected * @return string */ - function _get_mime_message() + protected function _get_mime_message() { return "This is a multi-part message in MIME format.".$this->newline."Your email application may not support this format."; } - + // -------------------------------------------------------------------- /** @@ -689,11 +731,11 @@ function _get_mime_message() * @param string * @return bool */ - function validate_email($email) + public function validate_email($email) { if ( ! is_array($email)) { - $this->_set_error_message('email_must_be_array'); + $this->_set_error_message('lang:email_must_be_array'); return FALSE; } @@ -701,14 +743,14 @@ function validate_email($email) { if ( ! $this->valid_email($val)) { - $this->_set_error_message('email_invalid_address', $val); + $this->_set_error_message('lang:email_invalid_address', $val); return FALSE; } } return TRUE; } - + // -------------------------------------------------------------------- /** @@ -718,11 +760,11 @@ function validate_email($email) * @param string * @return bool */ - function valid_email($address) + public function valid_email($address) { return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $address)) ? FALSE : TRUE; } - + // -------------------------------------------------------------------- /** @@ -732,17 +774,17 @@ function valid_email($address) * @param string * @return string */ - function clean_email($email) + public function clean_email($email) { if ( ! is_array($email)) { if (preg_match('/\<(.*)\>/', $email, $match)) { - return $match['1']; + return $match['1']; } - else + else { - return $email; + return $email; } } @@ -752,31 +794,31 @@ function clean_email($email) { if (preg_match( '/\<(.*)\>/', $addy, $match)) { - $clean_email[] = $match['1']; + $clean_email[] = $match['1']; } - else + else { - $clean_email[] = $addy; + $clean_email[] = $addy; } } return $clean_email; } - + // -------------------------------------------------------------------- /** * Build alternative plain text message * - * This function provides the raw message for use + * This public function provides the raw message for use * in plain-text headers of HTML-formatted emails. * If the user hasn't specified his own alternative message * it creates one by stripping the HTML * - * @access private + * @access protected * @return string */ - function _get_alt_message() + protected function _get_alt_message() { if ($this->alt_message != "") { @@ -802,7 +844,7 @@ function _get_alt_message() for ($x = 1; $x <= $i; $x ++) { - $n .= "\n"; + $n .= "\n"; } $body = str_replace($n, "\n\n", $body); @@ -810,7 +852,7 @@ function _get_alt_message() return $this->word_wrap($body, '76'); } - + // -------------------------------------------------------------------- /** @@ -821,7 +863,7 @@ function _get_alt_message() * @param integer * @return string */ - function word_wrap($str, $charlim = '') + public function word_wrap($str, $charlim = '') { // Se the character limit if ($charlim == '') @@ -850,7 +892,7 @@ function word_wrap($str, $charlim = '') } } - // Use PHP's native function to do the initial wordwrap. + // Use PHP's native public function to do the initial wordwrap. // We set the cut flag to FALSE so that any individual words that are // too long get left alone. In the next step we'll deal with them. $str = wordwrap($str, $charlim, "\n", FALSE); @@ -868,7 +910,7 @@ function word_wrap($str, $charlim = '') } $temp = ''; - while((strlen($line)) > $charlim) + while ((strlen($line)) > $charlim) { // If the over-length word is a URL we won't wrap it if (preg_match("!\[url.+\]|://|wwww.!", $line)) @@ -906,17 +948,17 @@ function word_wrap($str, $charlim = '') return $output; } - + // -------------------------------------------------------------------- /** * Build final headers * - * @access private + * @access protected * @param string * @return string */ - function _build_headers() + protected function _build_headers() { $this->_set_header('X-Sender', $this->clean_email($this->_headers['From'])); $this->_set_header('X-Mailer', $this->useragent); @@ -924,16 +966,16 @@ function _build_headers() $this->_set_header('Message-ID', $this->_get_message_id()); $this->_set_header('Mime-Version', '1.0'); } - + // -------------------------------------------------------------------- /** * Write Headers as a string * - * @access private + * @access protected * @return void */ - function _write_headers() + protected function _write_headers() { if ($this->protocol == 'mail') { @@ -944,7 +986,7 @@ function _write_headers() reset($this->_headers); $this->_header_str = ""; - foreach($this->_headers as $key => $val) + foreach ($this->_headers as $key => $val) { $val = trim($val); @@ -959,16 +1001,16 @@ function _write_headers() $this->_header_str = rtrim($this->_header_str); } } - + // -------------------------------------------------------------------- /** * Build Final Body and attachments * - * @access private + * @access protected * @return void */ - function _build_message() + protected function _build_message() { if ($this->wordwrap === TRUE AND $this->mailtype != 'html') { @@ -979,6 +1021,7 @@ function _build_message() $this->_write_headers(); $hdr = ($this->_get_protocol() == 'mail') ? $this->newline : ''; + $body = ''; switch ($this->_get_content_type()) { @@ -991,13 +1034,12 @@ function _build_message() { $this->_header_str .= $hdr; $this->_finalbody = $this->_body; - - return; + } + else + { + $this->_finalbody = $hdr . $this->newline . $this->newline . $this->_body; } - $hdr .= $this->newline . $this->newline . $this->_body; - - $this->_finalbody = $hdr; return; break; @@ -1011,93 +1053,81 @@ function _build_message() else { $hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline . $this->newline; - $hdr .= $this->_get_mime_message() . $this->newline . $this->newline; - $hdr .= "--" . $this->_alt_boundary . $this->newline; - $hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline; - $hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline; - $hdr .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline; + $body .= $this->_get_mime_message() . $this->newline . $this->newline; + $body .= "--" . $this->_alt_boundary . $this->newline; - $hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline; - $hdr .= "Content-Transfer-Encoding: quoted-printable"; + $body .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline; + $body .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline; + $body .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline; + + $body .= "Content-Type: text/html; charset=" . $this->charset . $this->newline; + $body .= "Content-Transfer-Encoding: quoted-printable" . $this->newline . $this->newline; } - $this->_body = $this->_prep_quoted_printable($this->_body); + $this->_finalbody = $body . $this->_prep_quoted_printable($this->_body) . $this->newline . $this->newline; + if ($this->_get_protocol() == 'mail') { $this->_header_str .= $hdr; - $this->_finalbody = $this->_body . $this->newline . $this->newline; - - if ($this->send_multipart !== FALSE) - { - $this->_finalbody .= "--" . $this->_alt_boundary . "--"; - } - - return; + } + else + { + $this->_finalbody = $hdr . $this->_finalbody; } - $hdr .= $this->newline . $this->newline; - $hdr .= $this->_body . $this->newline . $this->newline; if ($this->send_multipart !== FALSE) { - $hdr .= "--" . $this->_alt_boundary . "--"; + $this->_finalbody .= "--" . $this->_alt_boundary . "--"; } - $this->_finalbody = $hdr; return; break; case 'plain-attach' : $hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline . $this->newline; - $hdr .= $this->_get_mime_message() . $this->newline . $this->newline; - $hdr .= "--" . $this->_atc_boundary . $this->newline; - - $hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline; - $hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding(); if ($this->_get_protocol() == 'mail') { $this->_header_str .= $hdr; - - $body = $this->_body . $this->newline . $this->newline; } - $hdr .= $this->newline . $this->newline; - $hdr .= $this->_body . $this->newline . $this->newline; + $body .= $this->_get_mime_message() . $this->newline . $this->newline; + $body .= "--" . $this->_atc_boundary . $this->newline; + + $body .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline; + $body .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline; + + $body .= $this->_body . $this->newline . $this->newline; break; case 'html-attach' : $hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline . $this->newline; - $hdr .= $this->_get_mime_message() . $this->newline . $this->newline; - $hdr .= "--" . $this->_atc_boundary . $this->newline; - - $hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline .$this->newline; - $hdr .= "--" . $this->_alt_boundary . $this->newline; - - $hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline; - $hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline; - $hdr .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline; - - $hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline; - $hdr .= "Content-Transfer-Encoding: quoted-printable"; - - $this->_body = $this->_prep_quoted_printable($this->_body); if ($this->_get_protocol() == 'mail') { $this->_header_str .= $hdr; - - $body = $this->_body . $this->newline . $this->newline; - $body .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline; } - $hdr .= $this->newline . $this->newline; - $hdr .= $this->_body . $this->newline . $this->newline; - $hdr .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline; + $body .= $this->_get_mime_message() . $this->newline . $this->newline; + $body .= "--" . $this->_atc_boundary . $this->newline; + + $body .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline .$this->newline; + $body .= "--" . $this->_alt_boundary . $this->newline; + + $body .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline; + $body .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline; + $body .= $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline; + + $body .= "Content-Type: text/html; charset=" . $this->charset . $this->newline; + $body .= "Content-Transfer-Encoding: quoted-printable" . $this->newline . $this->newline; + + $body .= $this->_prep_quoted_printable($this->_body) . $this->newline . $this->newline; + $body .= "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline; break; } @@ -1114,7 +1144,7 @@ function _build_message() if ( ! file_exists($filename)) { - $this->_set_error_message('email_attachment_missing', $filename); + $this->_set_error_message('lang:email_attachment_missing', $filename); return FALSE; } @@ -1129,7 +1159,7 @@ function _build_message() if ( ! $fp = fopen($filename, FOPEN_READ)) { - $this->_set_error_message('email_attachment_unreadable', $filename); + $this->_set_error_message('lang:email_attachment_unreadable', $filename); return FALSE; } @@ -1137,18 +1167,21 @@ function _build_message() fclose($fp); } + $body .= implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--"; + + if ($this->_get_protocol() == 'mail') { - $this->_finalbody = $body . implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--"; - - return; + $this->_finalbody = $body; + } + else + { + $this->_finalbody = $hdr . $body; } - - $this->_finalbody = $hdr.implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--"; return; } - + // -------------------------------------------------------------------- /** @@ -1157,12 +1190,12 @@ function _build_message() * Prepares string for Quoted-Printable Content-Transfer-Encoding * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt * - * @access private + * @access protected * @param string * @param integer * @return string */ - function _prep_quoted_printable($str, $charlim = '') + protected function _prep_quoted_printable($str, $charlim = '') { // Set the character limit // Don't allow over 76, as that will make servers and MUAs barf @@ -1243,7 +1276,7 @@ function _prep_quoted_printable($str, $charlim = '') } // -------------------------------------------------------------------- - + /** * Prep Q Encoding * @@ -1255,7 +1288,7 @@ function _prep_quoted_printable($str, $charlim = '') * @param bool // set to TRUE for processing From: headers * @return str */ - function _prep_q_encoding($str, $from = FALSE) + protected function _prep_q_encoding($str, $from = FALSE) { $str = str_replace(array("\r", "\n"), array('', ''), $str); @@ -1315,14 +1348,14 @@ function _prep_q_encoding($str, $from = FALSE) } // -------------------------------------------------------------------- - + /** * Send Email * * @access public * @return bool */ - function send() + public function send() { if ($this->_replyto_flag == FALSE) { @@ -1333,7 +1366,7 @@ function send() ( ! isset($this->_bcc_array) AND ! isset($this->_headers['Bcc'])) AND ( ! isset($this->_headers['Cc']))) { - $this->_set_error_message('email_no_recipients'); + $this->_set_error_message('lang:email_no_recipients'); return FALSE; } @@ -1356,7 +1389,7 @@ function send() return TRUE; } } - + // -------------------------------------------------------------------- /** @@ -1365,7 +1398,7 @@ function send() * @access public * @return bool */ - function batch_bcc_send() + public function batch_bcc_send() { $float = $this->bcc_batch_size -1; @@ -1414,29 +1447,29 @@ function batch_bcc_send() $this->_spool_email(); } } - + // -------------------------------------------------------------------- /** * Unwrap special elements * - * @access private + * @access protected * @return void */ - function _unwrap_specials() + protected function _unwrap_specials() { $this->_finalbody = preg_replace_callback("/\{unwrap\}(.*?)\{\/unwrap\}/si", array($this, '_remove_nl_callback'), $this->_finalbody); } - + // -------------------------------------------------------------------- /** * Strip line-breaks via callback * - * @access private + * @access protected * @return string */ - function _remove_nl_callback($matches) + protected function _remove_nl_callback($matches) { if (strpos($matches[1], "\r") !== FALSE OR strpos($matches[1], "\n") !== FALSE) { @@ -1445,16 +1478,16 @@ function _remove_nl_callback($matches) return $matches[1]; } - + // -------------------------------------------------------------------- /** * Spool mail to the mail server * - * @access private + * @access protected * @return bool */ - function _spool_email() + protected function _spool_email() { $this->_unwrap_specials(); @@ -1464,7 +1497,7 @@ function _spool_email() if ( ! $this->_send_with_mail()) { - $this->_set_error_message('email_send_failure_phpmail'); + $this->_set_error_message('lang:email_send_failure_phpmail'); return FALSE; } break; @@ -1472,7 +1505,7 @@ function _spool_email() if ( ! $this->_send_with_sendmail()) { - $this->_set_error_message('email_send_failure_sendmail'); + $this->_set_error_message('lang:email_send_failure_sendmail'); return FALSE; } break; @@ -1480,26 +1513,26 @@ function _spool_email() if ( ! $this->_send_with_smtp()) { - $this->_set_error_message('email_send_failure_smtp'); + $this->_set_error_message('lang:email_send_failure_smtp'); return FALSE; } break; } - $this->_set_error_message('email_sent', $this->_get_protocol()); + $this->_set_error_message('lang:email_sent', $this->_get_protocol()); return TRUE; } - + // -------------------------------------------------------------------- /** * Send using mail() * - * @access private + * @access protected * @return bool */ - function _send_with_mail() + protected function _send_with_mail() { if ($this->_safe_mode == TRUE) { @@ -1516,6 +1549,7 @@ function _send_with_mail() { // most documentation of sendmail using the "-f" flag lacks a space after it, however // we've encountered servers that seem to require it to be in place. + if ( ! mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, "-f ".$this->clean_email($this->_headers['From']))) { return FALSE; @@ -1526,16 +1560,16 @@ function _send_with_mail() } } } - + // -------------------------------------------------------------------- /** * Send using Sendmail * - * @access private + * @access protected * @return bool */ - function _send_with_sendmail() + protected function _send_with_sendmail() { $fp = @popen($this->mailpath . " -oi -f ".$this->clean_email($this->_headers['From'])." -t", 'w'); @@ -1544,40 +1578,40 @@ function _send_with_sendmail() // server probably has popen disabled, so nothing we can do to get a verbose error. return FALSE; } - + fputs($fp, $this->_header_str); fputs($fp, $this->_finalbody); - $status = pclose($fp); - + $status = pclose($fp); + if (version_compare(PHP_VERSION, '4.2.3') == -1) { $status = $status >> 8 & 0xFF; - } - + } + if ($status != 0) { - $this->_set_error_message('email_exit_status', $status); - $this->_set_error_message('email_no_socket'); + $this->_set_error_message('lang:email_exit_status', $status); + $this->_set_error_message('lang:email_no_socket'); return FALSE; } return TRUE; } - + // -------------------------------------------------------------------- /** * Send using SMTP * - * @access private + * @access protected * @return bool */ - function _send_with_smtp() + protected function _send_with_smtp() { if ($this->smtp_host == '') { - $this->_set_error_message('email_no_hostname'); + $this->_set_error_message('lang:email_no_hostname'); return FALSE; } @@ -1586,14 +1620,14 @@ function _send_with_smtp() $this->_send_command('from', $this->clean_email($this->_headers['From'])); - foreach($this->_recipients as $val) + foreach ($this->_recipients as $val) { $this->_send_command('to', $val); } if (count($this->_cc_array) > 0) { - foreach($this->_cc_array as $val) + foreach ($this->_cc_array as $val) { if ($val != "") { @@ -1604,7 +1638,7 @@ function _send_with_smtp() if (count($this->_bcc_array) > 0) { - foreach($this->_bcc_array as $val) + foreach ($this->_bcc_array as $val) { if ($val != "") { @@ -1626,52 +1660,63 @@ function _send_with_smtp() if (strncmp($reply, '250', 3) != 0) { - $this->_set_error_message('email_smtp_error', $reply); + $this->_set_error_message('lang:email_smtp_error', $reply); return FALSE; } $this->_send_command('quit'); return TRUE; } - + // -------------------------------------------------------------------- /** * SMTP Connect * - * @access private + * @access protected * @param string * @return string */ - function _smtp_connect() + protected function _smtp_connect() { - $this->_smtp_connect = fsockopen($this->smtp_host, + $ssl = NULL; + if ($this->smtp_crypto == 'ssl') + $ssl = 'ssl://'; + $this->_smtp_connect = fsockopen($ssl.$this->smtp_host, $this->smtp_port, $errno, $errstr, $this->smtp_timeout); - if( ! is_resource($this->_smtp_connect)) + if ( ! is_resource($this->_smtp_connect)) { - $this->_set_error_message('email_smtp_error', $errno." ".$errstr); + $this->_set_error_message('lang:email_smtp_error', $errno." ".$errstr); return FALSE; } $this->_set_error_message($this->_get_smtp_data()); + + if ($this->smtp_crypto == 'tls') + { + $this->_send_command('hello'); + $this->_send_command('starttls'); + stream_socket_enable_crypto($this->_smtp_connect, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT); + } + return $this->_send_command('hello'); } - + // -------------------------------------------------------------------- /** * Send SMTP command * - * @access private + * @access protected * @param string * @param string * @return string */ - function _send_command($cmd, $data = '') + protected function _send_command($cmd, $data = '') { switch ($cmd) { @@ -1684,6 +1729,12 @@ function _send_command($cmd, $data = '') $resp = 250; break; + case 'starttls' : + + $this->_send_data('STARTTLS'); + + $resp = 220; + break; case 'from' : $this->_send_data('MAIL FROM:<'.$data.'>'); @@ -1716,7 +1767,7 @@ function _send_command($cmd, $data = '') if (substr($reply, 0, 3) != $resp) { - $this->_set_error_message('email_smtp_error', $reply); + $this->_set_error_message('lang:email_smtp_error', $reply); return FALSE; } @@ -1727,16 +1778,16 @@ function _send_command($cmd, $data = '') return TRUE; } - + // -------------------------------------------------------------------- /** * SMTP Authenticate * - * @access private + * @access protected * @return bool */ - function _smtp_authenticate() + protected function _smtp_authenticate() { if ( ! $this->_smtp_auth) { @@ -1745,7 +1796,7 @@ function _smtp_authenticate() if ($this->smtp_user == "" AND $this->smtp_pass == "") { - $this->_set_error_message('email_no_smtp_unpw'); + $this->_set_error_message('lang:email_no_smtp_unpw'); return FALSE; } @@ -1755,7 +1806,7 @@ function _smtp_authenticate() if (strncmp($reply, '334', 3) != 0) { - $this->_set_error_message('email_failed_smtp_login', $reply); + $this->_set_error_message('lang:email_failed_smtp_login', $reply); return FALSE; } @@ -1765,7 +1816,7 @@ function _smtp_authenticate() if (strncmp($reply, '334', 3) != 0) { - $this->_set_error_message('email_smtp_auth_un', $reply); + $this->_set_error_message('lang:email_smtp_auth_un', $reply); return FALSE; } @@ -1775,26 +1826,26 @@ function _smtp_authenticate() if (strncmp($reply, '235', 3) != 0) { - $this->_set_error_message('email_smtp_auth_pw', $reply); + $this->_set_error_message('lang:email_smtp_auth_pw', $reply); return FALSE; } return TRUE; } - + // -------------------------------------------------------------------- /** * Send SMTP data * - * @access private + * @access protected * @return bool */ - function _send_data($data) + protected function _send_data($data) { if ( ! fwrite($this->_smtp_connect, $data . $this->newline)) { - $this->_set_error_message('email_smtp_data_failure', $data); + $this->_set_error_message('lang:email_smtp_data_failure', $data); return FALSE; } else @@ -1802,16 +1853,16 @@ function _send_data($data) return TRUE; } } - + // -------------------------------------------------------------------- /** * Get SMTP data * - * @access private + * @access protected * @return string */ - function _get_smtp_data() + protected function _get_smtp_data() { $data = ""; @@ -1827,30 +1878,29 @@ function _get_smtp_data() return $data; } - + // -------------------------------------------------------------------- /** * Get Hostname * - * @access private + * @access protected * @return string */ - function _get_hostname() + protected function _get_hostname() { - $CI =& get_instance(); - return (!empty($CI->config->item('server_name'))) ? $CI->config->item('server_name') : 'localhost.localdomain'; + return (isset($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : 'localhost.localdomain'; } - + // -------------------------------------------------------------------- /** * Get IP * - * @access private + * @access protected * @return string */ - function _get_ip() + protected function _get_ip() { if ($this->_IP !== FALSE) { @@ -1861,12 +1911,12 @@ function _get_ip() $rip = (isset($_SERVER['REMOTE_ADDR']) AND $_SERVER['REMOTE_ADDR'] != "") ? $_SERVER['REMOTE_ADDR'] : FALSE; $fip = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND $_SERVER['HTTP_X_FORWARDED_FOR'] != "") ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE; - if ($cip && $rip) $this->_IP = $cip; + if ($cip && $rip) $this->_IP = $cip; elseif ($rip) $this->_IP = $rip; elseif ($cip) $this->_IP = $cip; elseif ($fip) $this->_IP = $fip; - if (strstr($this->_IP, ',')) + if (strpos($this->_IP, ',') !== FALSE) { $x = explode(',', $this->_IP); $this->_IP = end($x); @@ -1883,7 +1933,7 @@ function _get_ip() return $this->_IP; } - + // -------------------------------------------------------------------- /** @@ -1892,7 +1942,7 @@ function _get_ip() * @access public * @return string */ - function print_debugger() + public function print_debugger() { $msg = ''; @@ -1904,25 +1954,25 @@ function print_debugger() } } - $msg .= "
".$this->_header_str."\n".htmlspecialchars($this->_subject)."\n".htmlspecialchars($this->_finalbody).'
'; + $msg .= "
".htmlspecialchars($this->_header_str)."\n".htmlspecialchars($this->_subject)."\n".htmlspecialchars($this->_finalbody).'
'; return $msg; } - + // -------------------------------------------------------------------- /** * Set Message * - * @access private + * @access protected * @param string * @return string */ - function _set_error_message($msg, $val = '') + protected function _set_error_message($msg, $val = '') { $CI =& get_instance(); $CI->lang->load('email'); - if (FALSE === ($line = $CI->lang->line($msg))) + if (substr($msg, 0, 5) != 'lang:' || FALSE === ($line = $CI->lang->line(substr($msg, 5)))) { $this->_debug_msg[] = str_replace('%s', $val, $msg)."
"; } @@ -1931,17 +1981,17 @@ function _set_error_message($msg, $val = '') $this->_debug_msg[] = str_replace('%s', $val, $line)."
"; } } - + // -------------------------------------------------------------------- /** * Mime Types * - * @access private + * @access protected * @param string * @return string */ - function _mime_types($ext = "") + protected function _mime_types($ext = "") { $mimes = array( 'hqx' => 'application/mac-binhex40', 'cpt' => 'application/mac-compactpro', @@ -2039,4 +2089,4 @@ function _mime_types($ext = "") // END CI_Email class /* End of file Email.php */ -/* Location: ./system/libraries/Email.php */ \ No newline at end of file +/* Location: ./system/libraries/Email.php */ diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php index 95c758fb..b30a8cf0 100644 --- a/system/libraries/Encrypt.php +++ b/system/libraries/Encrypt.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -41,7 +41,7 @@ class CI_Encrypt { * Simply determines whether the mcrypt library exists. * */ - function CI_Encrypt() + public function __construct() { $this->CI =& get_instance(); $this->_mcrypt_exists = ( ! function_exists('mcrypt_encrypt')) ? FALSE : TRUE; @@ -72,7 +72,7 @@ function get_key($key = '') $CI =& get_instance(); $key = $CI->config->item('encryption_key'); - if ($key === FALSE) + if ($key == FALSE) { show_error('In order to use the encryption class requires that you set an encryption key in your config file.'); } @@ -116,12 +116,16 @@ function set_key($key = '') function encode($string, $key = '') { $key = $this->get_key($key); - $enc = $this->_xor_encode($string, $key); - + if ($this->_mcrypt_exists === TRUE) { - $enc = $this->mcrypt_encode($enc, $key); + $enc = $this->mcrypt_encode($string, $key); + } + else + { + $enc = $this->_xor_encode($string, $key); } + return base64_encode($enc); } @@ -140,7 +144,7 @@ function encode($string, $key = '') function decode($string, $key = '') { $key = $this->get_key($key); - + if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string)) { return FALSE; @@ -155,8 +159,67 @@ function decode($string, $key = '') return FALSE; } } + else + { + $dec = $this->_xor_decode($dec, $key); + } - return $this->_xor_decode($dec, $key); + return $dec; + } + + // -------------------------------------------------------------------- + + /** + * Encode from Legacy + * + * Takes an encoded string from the original Encryption class algorithms and + * returns a newly encoded string using the improved method added in 2.0.0 + * This allows for backwards compatibility and a method to transition to the + * new encryption algorithms. + * + * For more details, see http://codeigniter.com/user_guide/installation/upgrade_200.html#encryption + * + * @access public + * @param string + * @param int (mcrypt mode constant) + * @param string + * @return string + */ + function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '') + { + if ($this->_mcrypt_exists === FALSE) + { + log_message('error', 'Encoding from legacy is available only when Mcrypt is in use.'); + return FALSE; + } + + // decode it first + // set mode temporarily to what it was when string was encoded with the legacy + // algorithm - typically MCRYPT_MODE_ECB + $current_mode = $this->_get_mode(); + $this->set_mode($legacy_mode); + + $key = $this->get_key($key); + + if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string)) + { + return FALSE; + } + + $dec = base64_decode($string); + + if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE) + { + return FALSE; + } + + $dec = $this->_xor_decode($dec, $key); + + // set the mcrypt mode back to what it should be, typically MCRYPT_MODE_CBC + $this->set_mode($current_mode); + + // and re-encode + return base64_encode($this->mcrypt_encode($dec, $key)); } // -------------------------------------------------------------------- @@ -184,7 +247,7 @@ function _xor_encode($string, $key) $enc = ''; for ($i = 0; $i < strlen($string); $i++) - { + { $enc .= substr($rand, ($i % strlen($rand)), 1).(substr($rand, ($i % strlen($rand)), 1) ^ substr($string, $i, 1)); } @@ -347,7 +410,7 @@ function _remove_cipher_noise($data, $key) { $temp = $temp + 256; } - + $str .= chr($temp); } @@ -355,7 +418,7 @@ function _remove_cipher_noise($data, $key) } // -------------------------------------------------------------------- - + /** * Set the Mcrypt Cipher * @@ -412,9 +475,9 @@ function _get_mode() { if ($this->_mcrypt_mode == '') { - $this->_mcrypt_mode = MCRYPT_MODE_ECB; + $this->_mcrypt_mode = MCRYPT_MODE_CBC; } - + return $this->_mcrypt_mode; } @@ -440,7 +503,7 @@ function set_hash($type = 'sha1') * @access public * @param string * @return string - */ + */ function hash($str) { return ($this->_hash_type == 'sha1') ? $this->sha1($str) : md5($str); @@ -461,7 +524,7 @@ function sha1($str) { if ( ! function_exists('mhash')) { - require_once(BASEPATH.'libraries/Sha1'.EXT); + require_once(BASEPATH.'libraries/Sha1.php'); $SH = new CI_SHA; return $SH->generate($str); } diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php index 4acc88ab..9aab5da4 100644 --- a/system/libraries/Form_validation.php +++ b/system/libraries/Form_validation.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -25,29 +25,27 @@ * @link http://codeigniter.com/user_guide/libraries/form_validation.html */ class CI_Form_validation { - - var $CI; - var $_field_data = array(); - var $_config_rules = array(); - var $_error_array = array(); - var $_error_messages = array(); - var $_error_prefix = '

'; - var $_error_suffix = '

'; - var $error_string = ''; - var $_safe_form_data = FALSE; + protected $CI; + protected $_field_data = array(); + protected $_config_rules = array(); + protected $_error_array = array(); + protected $_error_messages = array(); + protected $_error_prefix = '

'; + protected $_error_suffix = '

'; + protected $error_string = ''; + protected $_safe_form_data = FALSE; /** * Constructor - * - */ - function CI_Form_validation($rules = array()) - { + */ + public function __construct($rules = array()) + { $this->CI =& get_instance(); - + // Validation rules can be stored in a config file. $this->_config_rules = $rules; - + // Automatically load the form helper $this->CI->load->helper('form'); @@ -56,12 +54,12 @@ function CI_Form_validation($rules = array()) { mb_internal_encoding($this->CI->config->item('charset')); } - + log_message('debug', "Form Validation Class Initialized"); } - + // -------------------------------------------------------------------- - + /** * Set Rules * @@ -73,14 +71,14 @@ function CI_Form_validation($rules = array()) * @param string * @return void */ - function set_rules($field, $label = '', $rules = '') + public function set_rules($field, $label = '', $rules = '') { // No reason to set rules if we have no POST data if (count($_POST) == 0) { - return; + return $this; } - + // If an array was passed via the first parameter instead of indidual string // values we cycle through it and recursively call this function. if (is_array($field)) @@ -99,13 +97,13 @@ function set_rules($field, $label = '', $rules = '') // Here we go! $this->set_rules($row['field'], $label, $row['rules']); } - return; + return $this; } - + // No fields? Nothing to do... if ( ! is_string($field) OR ! is_string($rules) OR $field == '') { - return; + return $this; } // If the field label wasn't passed we use the field name @@ -113,9 +111,9 @@ function set_rules($field, $label = '', $rules = '') // Is the field name an array? We test for the existence of a bracket "[" in // the field name to determine this. If it is an array, we break it apart - // into its components so that we can fetch the corresponding POST data later + // into its components so that we can fetch the corresponding POST data later if (strpos($field, '[') !== FALSE AND preg_match_all('/\[(.*?)\]/', $field, $matches)) - { + { // Note: Due to a bug in current() that affects some versions // of PHP we can not pass function call directly into it $x = explode('[', $field); @@ -128,29 +126,31 @@ function set_rules($field, $label = '', $rules = '') $indexes[] = $matches['1'][$i]; } } - + $is_array = TRUE; } else { - $indexes = array(); - $is_array = FALSE; + $indexes = array(); + $is_array = FALSE; } - - // Build our master array + + // Build our master array $this->_field_data[$field] = array( - 'field' => $field, - 'label' => $label, - 'rules' => $rules, - 'is_array' => $is_array, - 'keys' => $indexes, - 'postdata' => NULL, - 'error' => '' - ); + 'field' => $field, + 'label' => $label, + 'rules' => $rules, + 'is_array' => $is_array, + 'keys' => $indexes, + 'postdata' => NULL, + 'error' => '' + ); + + return $this; } // -------------------------------------------------------------------- - + /** * Set Error Message * @@ -162,18 +162,20 @@ function set_rules($field, $label = '', $rules = '') * @param string * @return string */ - function set_message($lang, $val = '') + public function set_message($lang, $val = '') { if ( ! is_array($lang)) { $lang = array($lang => $val); } - + $this->_error_messages = array_merge($this->_error_messages, $lang); + + return $this; } - + // -------------------------------------------------------------------- - + /** * Set The Error Delimiter * @@ -183,15 +185,17 @@ function set_message($lang, $val = '') * @param string * @param string * @return void - */ - function set_error_delimiters($prefix = '

', $suffix = '

') + */ + public function set_error_delimiters($prefix = '

', $suffix = '

') { $this->_error_prefix = $prefix; $this->_error_suffix = $suffix; + + return $this; } // -------------------------------------------------------------------- - + /** * Get Error Message * @@ -200,14 +204,14 @@ function set_error_delimiters($prefix = '

', $suffix = '

') * @access public * @param string the field name * @return void - */ - function error($field = '', $prefix = '', $suffix = '') - { + */ + public function error($field = '', $prefix = '', $suffix = '') + { if ( ! isset($this->_field_data[$field]['error']) OR $this->_field_data[$field]['error'] == '') { return ''; } - + if ($prefix == '') { $prefix = $this->_error_prefix; @@ -222,7 +226,7 @@ function error($field = '', $prefix = '', $suffix = '') } // -------------------------------------------------------------------- - + /** * Error String * @@ -232,15 +236,15 @@ function error($field = '', $prefix = '', $suffix = '') * @param string * @param string * @return str - */ - function error_string($prefix = '', $suffix = '') + */ + public function error_string($prefix = '', $suffix = '') { // No errrors, validation passes! if (count($this->_error_array) === 0) { return ''; } - + if ($prefix == '') { $prefix = $this->_error_prefix; @@ -250,7 +254,7 @@ function error_string($prefix = '', $suffix = '') { $suffix = $this->_error_suffix; } - + // Generate the error string $str = ''; foreach ($this->_error_array as $val) @@ -260,12 +264,12 @@ function error_string($prefix = '', $suffix = '') $str .= $prefix.$val.$suffix."\n"; } } - + return $str; } // -------------------------------------------------------------------- - + /** * Run the Validator * @@ -273,15 +277,15 @@ function error_string($prefix = '', $suffix = '') * * @access public * @return bool - */ - function run($group = '') + */ + public function run($group = '') { // Do we even have any data to process? Mm? if (count($_POST) == 0) { return FALSE; } - + // Does the _field_data array containing the validation rules exist? // If not, we look to see if they were assigned via a config file if (count($this->_field_data) == 0) @@ -291,10 +295,10 @@ function run($group = '') { return FALSE; } - + // Is there a validation rule for the particular URI being accessed? $uri = ($group == '') ? trim($this->CI->uri->ruri_string(), '/') : $group; - + if ($uri != '' AND isset($this->_config_rules[$uri])) { $this->set_rules($this->_config_rules[$uri]); @@ -303,7 +307,7 @@ function run($group = '') { $this->set_rules($this->_config_rules); } - + // We're we able to set the rules correctly? if (count($this->_field_data) == 0) { @@ -311,17 +315,17 @@ function run($group = '') return FALSE; } } - + // Load the language file containing error messages $this->CI->lang->load('form_validation'); - - // Cycle through the rules for each field, match the + + // Cycle through the rules for each field, match the // corresponding $_POST item and test for errors foreach ($this->_field_data as $field => $row) - { + { // Fetch the data from the corresponding $_POST array and cache it in the _field_data array. // Depending on whether the field name is an array or a string will determine where we get it from. - + if ($row['is_array'] == TRUE) { $this->_field_data[$field]['postdata'] = $this->_reduce_array($_POST, $row['keys']); @@ -333,8 +337,8 @@ function run($group = '') $this->_field_data[$field]['postdata'] = $_POST[$field]; } } - - $this->_execute($row, explode('|', $row['rules']), $this->_field_data[$field]['postdata']); + + $this->_execute($row, explode('|', $row['rules']), $this->_field_data[$field]['postdata']); } // Did we end up with any errors? @@ -347,7 +351,7 @@ function run($group = '') // Now we need to re-set the POST data with the new, processed data $this->_reset_post_array(); - + // No errors, validation passes! if ($total_errors == 0) { @@ -359,7 +363,7 @@ function run($group = '') } // -------------------------------------------------------------------- - + /** * Traverse a multidimensional $_POST array index until the data is found * @@ -368,8 +372,8 @@ function run($group = '') * @param array * @param integer * @return mixed - */ - function _reduce_array($array, $keys, $i = 0) + */ + protected function _reduce_array($array, $keys, $i = 0) { if (is_array($array)) { @@ -389,19 +393,19 @@ function _reduce_array($array, $keys, $i = 0) return $array; } } - + return $array; } // -------------------------------------------------------------------- - + /** * Re-populate the _POST array with our finalized and processed data * * @access private * @return null - */ - function _reset_post_array() + */ + protected function _reset_post_array() { foreach ($this->_field_data as $field => $row) { @@ -418,7 +422,7 @@ function _reset_post_array() { // start with a reference $post_ref =& $_POST; - + // before we assign values, make a reference to the right POST key if (count($row['keys']) == 1) { @@ -452,7 +456,7 @@ function _reset_post_array() } // -------------------------------------------------------------------- - + /** * Executes the Validation routines * @@ -462,21 +466,21 @@ function _reset_post_array() * @param mixed * @param integer * @return mixed - */ - function _execute($row, $rules, $postdata = NULL, $cycles = 0) + */ + protected function _execute($row, $rules, $postdata = NULL, $cycles = 0) { // If the $_POST data is an array we will run a recursive call if (is_array($postdata)) - { + { foreach ($postdata as $key => $val) { $this->_execute($row, $rules, $val, $cycles); $cycles++; } - + return; } - + // -------------------------------------------------------------------- // If the field is blank, but NOT required, no further tests are necessary @@ -484,7 +488,7 @@ function _execute($row, $rules, $postdata = NULL, $cycles = 0) if ( ! in_array('required', $rules) AND is_null($postdata)) { // Before we bail out, does the rule contain a callback? - if (preg_match("/(callback_\w+)/", implode(' ', $rules), $match)) + if (preg_match("/(callback_\w+(\[.*?\])?)/", implode(' ', $rules), $match)) { $callback = TRUE; $rules = (array('1' => $match[1])); @@ -496,7 +500,7 @@ function _execute($row, $rules, $postdata = NULL, $cycles = 0) } // -------------------------------------------------------------------- - + // Isset Test. Typically this rule will only apply to checkboxes. if (is_null($postdata) AND $callback == FALSE) { @@ -504,31 +508,31 @@ function _execute($row, $rules, $postdata = NULL, $cycles = 0) { // Set the message type $type = (in_array('required', $rules)) ? 'required' : 'isset'; - + if ( ! isset($this->_error_messages[$type])) { if (FALSE === ($line = $this->CI->lang->line($type))) { $line = 'The field was not set'; - } + } } else { $line = $this->_error_messages[$type]; } - + // Build the error message $message = sprintf($line, $this->_translate_fieldname($row['label'])); // Save the error message $this->_field_data[$row['field']]['error'] = $message; - + if ( ! isset($this->_error_array[$row['field']])) { $this->_error_array[$row['field']] = $message; } } - + return; } @@ -538,7 +542,7 @@ function _execute($row, $rules, $postdata = NULL, $cycles = 0) foreach ($rules As $rule) { $_in_array = FALSE; - + // We set the $postdata variable with the current data in our master array so that // each cycle of the loop is dealing with the processed data from the last cycle if ($row['is_array'] == TRUE AND is_array($this->_field_data[$row['field']]['postdata'])) @@ -549,7 +553,7 @@ function _execute($row, $rules, $postdata = NULL, $cycles = 0) { continue; } - + $postdata = $this->_field_data[$row['field']]['postdata'][$cycles]; $_in_array = TRUE; } @@ -559,32 +563,32 @@ function _execute($row, $rules, $postdata = NULL, $cycles = 0) } // -------------------------------------------------------------------- - - // Is the rule a callback? + + // Is the rule a callback? $callback = FALSE; if (substr($rule, 0, 9) == 'callback_') { $rule = substr($rule, 9); $callback = TRUE; } - + // Strip the parameter (if exists) from the rule // Rules can contain a parameter: max_length[5] $param = FALSE; - if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match)) + if (preg_match("/(.*?)\[(.*)\]/", $rule, $match)) { $rule = $match[1]; $param = $match[2]; } - + // Call the function that corresponds to the rule if ($callback === TRUE) { if ( ! method_exists($this->CI, $rule)) - { + { continue; } - + // Run the function and grab the result $result = $this->CI->$rule($postdata, $param); @@ -597,7 +601,7 @@ function _execute($row, $rules, $postdata = NULL, $cycles = 0) { $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result; } - + // If the field isn't required and we just processed a callback we'll move on... if ( ! in_array('required', $rules, TRUE) AND $result !== FALSE) { @@ -605,15 +609,15 @@ function _execute($row, $rules, $postdata = NULL, $cycles = 0) } } else - { + { if ( ! method_exists($this, $rule)) { - // If our own wrapper function doesn't exist we see if a native PHP function does. + // If our own wrapper function doesn't exist we see if a native PHP function does. // Users can use any native PHP function call that has one param. if (function_exists($rule)) { $result = $rule($postdata); - + if ($_in_array == TRUE) { $this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result; @@ -623,7 +627,11 @@ function _execute($row, $rules, $postdata = NULL, $cycles = 0) $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result; } } - + else + { + log_message('debug', "Unable to find validation rule: ".$rule); + } + continue; } @@ -638,63 +646,63 @@ function _execute($row, $rules, $postdata = NULL, $cycles = 0) $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result; } } - + // Did the rule test negatively? If so, grab the error. if ($result === FALSE) - { + { if ( ! isset($this->_error_messages[$rule])) { if (FALSE === ($line = $this->CI->lang->line($rule))) { $line = 'Unable to access an error message corresponding to your field name.'; - } + } } else { $line = $this->_error_messages[$rule]; } - + // Is the parameter we are inserting into the error message the name // of another field? If so we need to grab its "field label" if (isset($this->_field_data[$param]) AND isset($this->_field_data[$param]['label'])) { - $param = $this->_field_data[$param]['label']; + $param = $this->_translate_fieldname($this->_field_data[$param]['label']); } - + // Build the error message $message = sprintf($line, $this->_translate_fieldname($row['label']), $param); // Save the error message $this->_field_data[$row['field']]['error'] = $message; - + if ( ! isset($this->_error_array[$row['field']])) { $this->_error_array[$row['field']] = $message; } - + return; } } } // -------------------------------------------------------------------- - + /** * Translate a field name * * @access private * @param string the field name * @return string - */ - function _translate_fieldname($fieldname) + */ + protected function _translate_fieldname($fieldname) { // Do we need to translate the field name? // We look for the prefix lang: to determine this if (substr($fieldname, 0, 5) == 'lang:') { // Grab the variable - $line = substr($fieldname, 5); - + $line = substr($fieldname, 5); + // Were we able to translate the field name? If not we use $line if (FALSE === ($fieldname = $this->CI->lang->line($line))) { @@ -706,7 +714,7 @@ function _translate_fieldname($fieldname) } // -------------------------------------------------------------------- - + /** * Get the value from a form * @@ -717,19 +725,26 @@ function _translate_fieldname($fieldname) * @param string the field name * @param string * @return void - */ - function set_value($field = '', $default = '') + */ + public function set_value($field = '', $default = '') { if ( ! isset($this->_field_data[$field])) { return $default; } - + + // If the data is an array output them one at a time. + // E.g: form_input('name[]', set_value('name[]'); + if (is_array($this->_field_data[$field]['postdata'])) + { + return array_shift($this->_field_data[$field]['postdata']); + } + return $this->_field_data[$field]['postdata']; } - + // -------------------------------------------------------------------- - + /** * Set Select * @@ -740,9 +755,9 @@ function set_value($field = '', $default = '') * @param string * @param string * @return string - */ - function set_select($field = '', $value = '', $default = FALSE) - { + */ + public function set_select($field = '', $value = '', $default = FALSE) + { if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])) { if ($default === TRUE AND count($this->_field_data) === 0) @@ -751,9 +766,9 @@ function set_select($field = '', $value = '', $default = FALSE) } return ''; } - + $field = $this->_field_data[$field]['postdata']; - + if (is_array($field)) { if ( ! in_array($value, $field)) @@ -768,12 +783,12 @@ function set_select($field = '', $value = '', $default = FALSE) return ''; } } - + return ' selected="selected"'; } - + // -------------------------------------------------------------------- - + /** * Set Radio * @@ -784,8 +799,8 @@ function set_select($field = '', $value = '', $default = FALSE) * @param string * @param string * @return string - */ - function set_radio($field = '', $value = '', $default = FALSE) + */ + public function set_radio($field = '', $value = '', $default = FALSE) { if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])) { @@ -795,9 +810,9 @@ function set_radio($field = '', $value = '', $default = FALSE) } return ''; } - + $field = $this->_field_data[$field]['postdata']; - + if (is_array($field)) { if ( ! in_array($value, $field)) @@ -812,12 +827,12 @@ function set_radio($field = '', $value = '', $default = FALSE) return ''; } } - + return ' checked="checked"'; } - + // -------------------------------------------------------------------- - + /** * Set Checkbox * @@ -828,8 +843,8 @@ function set_radio($field = '', $value = '', $default = FALSE) * @param string * @param string * @return string - */ - function set_checkbox($field = '', $value = '', $default = FALSE) + */ + public function set_checkbox($field = '', $value = '', $default = FALSE) { if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])) { @@ -839,9 +854,9 @@ function set_checkbox($field = '', $value = '', $default = FALSE) } return ''; } - + $field = $this->_field_data[$field]['postdata']; - + if (is_array($field)) { if ( ! in_array($value, $field)) @@ -856,12 +871,12 @@ function set_checkbox($field = '', $value = '', $default = FALSE) return ''; } } - + return ' checked="checked"'; } - + // -------------------------------------------------------------------- - + /** * Required * @@ -869,7 +884,7 @@ function set_checkbox($field = '', $value = '', $default = FALSE) * @param string * @return bool */ - function required($str) + public function required($str) { if ( ! is_array($str)) { @@ -880,9 +895,29 @@ function required($str) return ( ! empty($str)); } } - + // -------------------------------------------------------------------- - + + /** + * Performs a Regular Expression match test. + * + * @access public + * @param string + * @param regex + * @return bool + */ + public function regex_match($str, $regex) + { + if ( ! preg_match($regex, $str)) + { + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + /** * Match one field to another * @@ -891,20 +926,38 @@ function required($str) * @param field * @return bool */ - function matches($str, $field) + public function matches($str, $field) { if ( ! isset($_POST[$field])) { - return FALSE; + return FALSE; } - + $field = $_POST[$field]; return ($str !== $field) ? FALSE : TRUE; } // -------------------------------------------------------------------- - + + /** + * Match one field to another + * + * @access public + * @param string + * @param field + * @return bool + */ + public function is_unique($str, $field) + { + list($table, $field)=explode('.', $field); + $query = $this->CI->db->limit(1)->get_where($table, array($field => $str)); + + return $query->num_rows() === 0; + } + + // -------------------------------------------------------------------- + /** * Minimum Length * @@ -912,8 +965,8 @@ function matches($str, $field) * @param string * @param value * @return bool - */ - function min_length($str, $val) + */ + public function min_length($str, $val) { if (preg_match("/[^0-9]/", $val)) { @@ -922,14 +975,14 @@ function min_length($str, $val) if (function_exists('mb_strlen')) { - return (mb_strlen($str) < $val) ? FALSE : TRUE; + return (mb_strlen($str) < $val) ? FALSE : TRUE; } - + return (strlen($str) < $val) ? FALSE : TRUE; } - + // -------------------------------------------------------------------- - + /** * Max Length * @@ -937,8 +990,8 @@ function min_length($str, $val) * @param string * @param value * @return bool - */ - function max_length($str, $val) + */ + public function max_length($str, $val) { if (preg_match("/[^0-9]/", $val)) { @@ -947,14 +1000,14 @@ function max_length($str, $val) if (function_exists('mb_strlen')) { - return (mb_strlen($str) > $val) ? FALSE : TRUE; + return (mb_strlen($str) > $val) ? FALSE : TRUE; } - + return (strlen($str) > $val) ? FALSE : TRUE; } - + // -------------------------------------------------------------------- - + /** * Exact Length * @@ -962,8 +1015,8 @@ function max_length($str, $val) * @param string * @param value * @return bool - */ - function exact_length($str, $val) + */ + public function exact_length($str, $val) { if (preg_match("/[^0-9]/", $val)) { @@ -972,119 +1025,120 @@ function exact_length($str, $val) if (function_exists('mb_strlen')) { - return (mb_strlen($str) != $val) ? FALSE : TRUE; + return (mb_strlen($str) != $val) ? FALSE : TRUE; } - + return (strlen($str) != $val) ? FALSE : TRUE; } - + // -------------------------------------------------------------------- - + /** * Valid Email * * @access public * @param string * @return bool - */ - function valid_email($str) + */ + public function valid_email($str) { return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE; } // -------------------------------------------------------------------- - + /** * Valid Emails * * @access public * @param string * @return bool - */ - function valid_emails($str) + */ + public function valid_emails($str) { if (strpos($str, ',') === FALSE) { return $this->valid_email(trim($str)); } - - foreach(explode(',', $str) as $email) + + foreach (explode(',', $str) as $email) { if (trim($email) != '' && $this->valid_email(trim($email)) === FALSE) { return FALSE; } } - + return TRUE; } // -------------------------------------------------------------------- - + /** * Validate IP Address * * @access public * @param string + * @param string "ipv4" or "ipv6" to validate a specific ip format * @return string */ - function valid_ip($ip) + public function valid_ip($ip, $which = '') { - return $this->CI->input->valid_ip($ip); + return $this->CI->input->valid_ip($ip, $which); } // -------------------------------------------------------------------- - + /** * Alpha * * @access public * @param string * @return bool - */ - function alpha($str) + */ + public function alpha($str) { return ( ! preg_match("/^([a-z])+$/i", $str)) ? FALSE : TRUE; } - + // -------------------------------------------------------------------- - + /** * Alpha-numeric * * @access public * @param string * @return bool - */ - function alpha_numeric($str) + */ + public function alpha_numeric($str) { return ( ! preg_match("/^([a-z0-9])+$/i", $str)) ? FALSE : TRUE; } - + // -------------------------------------------------------------------- - + /** * Alpha-numeric with underscores and dashes * * @access public * @param string * @return bool - */ - function alpha_dash($str) + */ + public function alpha_dash($str) { return ( ! preg_match("/^([-a-z0-9_-])+$/i", $str)) ? FALSE : TRUE; } - + // -------------------------------------------------------------------- - + /** * Numeric * * @access public * @param string * @return bool - */ - function numeric($str) + */ + public function numeric($str) { return (bool)preg_match( '/^[\-+]?[0-9]*\.?[0-9]+$/', $str); @@ -1095,29 +1149,79 @@ function numeric($str) /** * Is Numeric * - * @access public - * @param string - * @return bool + * @access public + * @param string + * @return bool */ - function is_numeric($str) + public function is_numeric($str) { return ( ! is_numeric($str)) ? FALSE : TRUE; - } + } // -------------------------------------------------------------------- - + /** * Integer * * @access public * @param string * @return bool - */ - function integer($str) + */ + public function integer($str) { - return (bool)preg_match( '/^[\-+]?[0-9]+$/', $str); + return (bool) preg_match('/^[\-+]?[0-9]+$/', $str); } - + + // -------------------------------------------------------------------- + + /** + * Decimal number + * + * @access public + * @param string + * @return bool + */ + public function decimal($str) + { + return (bool) preg_match('/^[\-+]?[0-9]+\.[0-9]+$/', $str); + } + + // -------------------------------------------------------------------- + + /** + * Greather than + * + * @access public + * @param string + * @return bool + */ + public function greater_than($str, $min) + { + if ( ! is_numeric($str)) + { + return FALSE; + } + return $str > $min; + } + + // -------------------------------------------------------------------- + + /** + * Less than + * + * @access public + * @param string + * @return bool + */ + public function less_than($str, $max) + { + if ( ! is_numeric($str)) + { + return FALSE; + } + return $str < $max; + } + // -------------------------------------------------------------------- /** @@ -1127,9 +1231,9 @@ function integer($str) * @param string * @return bool */ - function is_natural($str) - { - return (bool)preg_match( '/^[0-9]+$/', $str); + public function is_natural($str) + { + return (bool) preg_match( '/^[0-9]+$/', $str); } // -------------------------------------------------------------------- @@ -1141,23 +1245,23 @@ function is_natural($str) * @param string * @return bool */ - function is_natural_no_zero($str) + public function is_natural_no_zero($str) { if ( ! preg_match( '/^[0-9]+$/', $str)) { return FALSE; } - + if ($str == 0) { return FALSE; } - - return TRUE; + + return TRUE; } - + // -------------------------------------------------------------------- - + /** * Valid Base64 * @@ -1168,13 +1272,13 @@ function is_natural_no_zero($str) * @param string * @return bool */ - function valid_base64($str) + public function valid_base64($str) { return (bool) ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str); } - + // -------------------------------------------------------------------- - + /** * Prep data for form * @@ -1185,7 +1289,7 @@ function valid_base64($str) * @param string * @return string */ - function prep_for_form($data = '') + public function prep_for_form($data = '') { if (is_array($data)) { @@ -1193,10 +1297,10 @@ function prep_for_form($data = '') { $data[$key] = $this->prep_for_form($val); } - + return $data; } - + if ($this->_safe_form_data == FALSE OR $data === '') { return $data; @@ -1204,69 +1308,69 @@ function prep_for_form($data = '') return str_replace(array("'", '"', '<', '>'), array("'", """, '<', '>'), stripslashes($data)); } - + // -------------------------------------------------------------------- - + /** * Prep URL * * @access public * @param string * @return string - */ - function prep_url($str = '') + */ + public function prep_url($str = '') { if ($str == 'http://' OR $str == '') { return ''; } - + if (substr($str, 0, 7) != 'http://' && substr($str, 0, 8) != 'https://') { $str = 'http://'.$str; } - + return $str; } - + // -------------------------------------------------------------------- - + /** * Strip Image Tags * * @access public * @param string * @return string - */ - function strip_image_tags($str) + */ + public function strip_image_tags($str) { return $this->CI->input->strip_image_tags($str); } - + // -------------------------------------------------------------------- - + /** * XSS Clean * * @access public * @param string * @return string - */ - function xss_clean($str) + */ + public function xss_clean($str) { - return $this->CI->input->xss_clean($str); + return $this->CI->security->xss_clean($str); } - + // -------------------------------------------------------------------- - + /** * Convert PHP tags to entities * * @access public * @param string * @return string - */ - function encode_php_tags($str) + */ + public function encode_php_tags($str) { return str_replace(array(''), array('<?php', '<?PHP', '<?', '?>'), $str); } @@ -1275,4 +1379,4 @@ function encode_php_tags($str) // END Form Validation Class /* End of file Form_validation.php */ -/* Location: ./system/libraries/Form_validation.php */ \ No newline at end of file +/* Location: ./system/libraries/Form_validation.php */ diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php index 6fb17049..d7a8b3b0 100644 --- a/system/libraries/Ftp.php +++ b/system/libraries/Ftp.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -40,7 +40,7 @@ class CI_FTP { * * The constructor can be passed an array of config values */ - function CI_FTP($config = array()) + public function __construct($config = array()) { if (count($config) > 0) { @@ -280,6 +280,48 @@ function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL) // -------------------------------------------------------------------- + /** + * Download a file from a remote server to the local server + * + * @access public + * @param string + * @param string + * @param string + * @return bool + */ + function download($rempath, $locpath, $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 = $this->_getext($rempath); + $mode = $this->_settype($ext); + } + + $mode = ($mode == 'ascii') ? FTP_ASCII : FTP_BINARY; + + $result = @ftp_get($this->conn_id, $locpath, $rempath, $mode); + + if ($result === FALSE) + { + if ($this->debug == TRUE) + { + $this->_error('ftp_unable_to_download'); + } + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + /** * Rename (or move) a file * @@ -412,7 +454,7 @@ function delete_dir($filepath) * Set file permissions * * @access public - * @param string the file path + * @param string the file path * @param string the permissions * @return bool */ diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php index 169c6e48..21ec2cb4 100644 --- a/system/libraries/Image_lib.php +++ b/system/libraries/Image_lib.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -26,7 +26,7 @@ */ class CI_Image_lib { - var $image_library = 'gd2'; // Can be: imagemagick, netpbm, gd, gd2 + var $image_library = 'gd2'; // Can be: imagemagick, netpbm, gd, gd2 var $library_path = ''; var $dynamic_output = FALSE; // Whether to send to browser or write to disk var $source_image = ''; @@ -36,7 +36,7 @@ class CI_Image_lib { var $quality = '90'; var $create_thumb = FALSE; var $thumb_marker = '_thumb'; - var $maintain_ratio = TRUE; // Whether to maintain aspect ratio when resizing or use hard values + var $maintain_ratio = TRUE; // Whether to maintain aspect ratio when resizing or use hard values var $master_dim = 'auto'; // auto, height, or width. Determines what to use as the master dimension var $rotation_angle = ''; var $x_axis = ''; @@ -54,11 +54,11 @@ class CI_Image_lib { var $wm_hor_alignment = 'C'; // Horizontal alignment: L R C var $wm_padding = 0; // Padding around text var $wm_hor_offset = 0; // Lets you push text to the right - var $wm_vrt_offset = 0; // Lets you push text down + var $wm_vrt_offset = 0; // Lets you push text down var $wm_font_color = '#ffffff'; // Text color var $wm_shadow_color = ''; // Dropshadow color var $wm_shadow_distance = 2; // Dropshadow distance - var $wm_opacity = 50; // Image opacity: 1 - 100 Only works with image + var $wm_opacity = 50; // Image opacity: 1 - 100 Only works with image // Private Vars var $source_folder = ''; @@ -79,11 +79,10 @@ class CI_Image_lib { /** * Constructor * - * @access public * @param string * @return void */ - function CI_Image_lib($props = array()) + public function __construct($props = array()) { if (count($props) > 0) { @@ -105,7 +104,7 @@ function CI_Image_lib($props = array()) */ function clear() { - $props = array('source_folder', 'dest_folder', 'source_image', 'full_src_path', 'full_dst_path', 'new_image', 'image_type', 'size_str', 'quality', 'orig_width', 'orig_height', 'rotation_angle', 'x_axis', 'y_axis', 'create_fnc', 'copy_fnc', 'wm_overlay_path', 'wm_use_truetype', 'dynamic_output', 'wm_font_size', 'wm_text', 'wm_vrt_alignment', 'wm_hor_alignment', 'wm_padding', 'wm_hor_offset', 'wm_vrt_offset', 'wm_font_color', 'wm_use_drop_shadow', 'wm_shadow_color', 'wm_shadow_distance', 'wm_opacity'); + $props = array('source_folder', 'dest_folder', 'source_image', 'full_src_path', 'full_dst_path', 'new_image', 'image_type', 'size_str', 'quality', 'orig_width', 'orig_height', 'width', 'height', 'rotation_angle', 'x_axis', 'y_axis', 'create_fnc', 'copy_fnc', 'wm_overlay_path', 'wm_use_truetype', 'dynamic_output', 'wm_font_size', 'wm_text', 'wm_vrt_alignment', 'wm_hor_alignment', 'wm_padding', 'wm_hor_offset', 'wm_vrt_offset', 'wm_font_color', 'wm_use_drop_shadow', 'wm_shadow_color', 'wm_shadow_distance', 'wm_opacity'); foreach ($props as $val) { @@ -147,7 +146,7 @@ function initialize($props = array()) if ($this->source_image == '') { $this->set_error('imglib_source_image_required'); - return FALSE; + return FALSE; } /* @@ -190,7 +189,7 @@ function initialize($props = array()) // Set the Image Properties if ( ! $this->get_image_properties($this->source_folder.$this->source_image)) { - return FALSE; + return FALSE; } /* @@ -209,7 +208,7 @@ function initialize($props = array()) } else { - if (strpos($this->new_image, '/') === FALSE) + if (strpos($this->new_image, '/') === FALSE AND strpos($this->new_image, '\\') === FALSE) { $this->dest_folder = $this->source_folder; $this->dest_image = $this->new_image; @@ -400,7 +399,7 @@ function rotate() if ($this->rotation_angle == '' OR ! in_array($this->rotation_angle, $degs)) { $this->set_error('imglib_rotation_angle_required'); - return FALSE; + return FALSE; } // Reassign the width and height @@ -455,11 +454,11 @@ function image_process_gd($action = 'resize') { if ($this->orig_width == $this->width AND $this->orig_height == $this->height) { - if ($this->source_image != $this->new_image) - { + if ($this->source_image != $this->new_image) + { if (@copy($this->full_src_path, $this->full_dst_path)) { - @chmod($this->full_dst_path, DIR_WRITE_MODE); + @chmod($this->full_dst_path, FILE_WRITE_MODE); } } @@ -494,14 +493,14 @@ function image_process_gd($action = 'resize') return FALSE; } - // Create The Image + // Create The Image // // old conditional which users report cause problems with shared GD libs who report themselves as "2.0 or greater" // it appears that this is no longer the issue that it was in 2004, so we've removed it, retaining it in the comment // below should that ever prove inaccurate. // // if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor') AND $v2_override == FALSE) - if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor')) + if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor')) { $create = 'imagecreatetruecolor'; $copy = 'imagecopyresampled'; @@ -513,6 +512,13 @@ function image_process_gd($action = 'resize') } $dst_img = $create($this->width, $this->height); + + if ($this->image_type == 3) // png we can actually preserve transparency + { + imagealphablending($dst_img, FALSE); + imagesavealpha($dst_img, TRUE); + } + $copy($dst_img, $src_img, 0, 0, $this->x_axis, $this->y_axis, $this->width, $this->height, $this->orig_width, $this->orig_height); // Show the image @@ -534,7 +540,7 @@ function image_process_gd($action = 'resize') imagedestroy($src_img); // Set the file to 777 - @chmod($this->full_dst_path, DIR_WRITE_MODE); + @chmod($this->full_dst_path, FILE_WRITE_MODE); return TRUE; } @@ -577,9 +583,9 @@ function image_process_imagemagick($action = 'resize') { switch ($this->rotation_angle) { - case 'hor' : $angle = '-flop'; + case 'hor' : $angle = '-flop'; break; - case 'vrt' : $angle = '-flip'; + case 'vrt' : $angle = '-flip'; break; default : $angle = '-rotate '.$this->rotation_angle; break; @@ -604,7 +610,7 @@ function image_process_imagemagick($action = 'resize') } // Set the file to 777 - @chmod($this->full_dst_path, DIR_WRITE_MODE); + @chmod($this->full_dst_path, FILE_WRITE_MODE); return TRUE; } @@ -657,7 +663,7 @@ function image_process_netpbm($action = 'resize') break; case 180 : $angle = 'r180'; break; - case 270 : $angle = 'r90'; + case 270 : $angle = 'r90'; break; case 'vrt' : $angle = 'tb'; break; @@ -690,7 +696,7 @@ function image_process_netpbm($action = 'resize') // we have to rename the temp file. copy ($this->dest_folder.'netpbm.tmp', $this->full_dst_path); unlink ($this->dest_folder.'netpbm.tmp'); - @chmod($this->full_dst_path, DIR_WRITE_MODE); + @chmod($this->full_dst_path, FILE_WRITE_MODE); return TRUE; } @@ -705,14 +711,6 @@ function image_process_netpbm($action = 'resize') */ function image_rotate_gd() { - // Is Image Rotation Supported? - // this function is only supported as of PHP 4.3 - if ( ! function_exists('imagerotate')) - { - $this->set_error('imglib_rotate_unsupported'); - return FALSE; - } - // Create the image handle if ( ! ($src_img = $this->image_create_gd())) { @@ -749,9 +747,9 @@ function image_rotate_gd() // Set the file to 777 - @chmod($this->full_dst_path, DIR_WRITE_MODE); + @chmod($this->full_dst_path, FILE_WRITE_MODE); - return true; + return TRUE; } // -------------------------------------------------------------------- @@ -833,7 +831,7 @@ function image_mirror_gd() imagedestroy($src_img); // Set the file to 777 - @chmod($this->full_dst_path, DIR_WRITE_MODE); + @chmod($this->full_dst_path, FILE_WRITE_MODE); return TRUE; } @@ -882,7 +880,7 @@ function overlay_watermark() $this->get_image_properties(); // Fetch watermark image properties - $props = $this->get_image_properties($this->wm_overlay_path, TRUE); + $props = $this->get_image_properties($this->wm_overlay_path, TRUE); $wm_img_type = $props['image_type']; $wm_width = $props['width']; $wm_height = $props['height']; @@ -937,7 +935,7 @@ function overlay_watermark() if ($wm_img_type == 3 AND function_exists('imagealphablending')) { @imagealphablending($src_img, TRUE); - } + } // Set RGB values for text and shadow $rgba = imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp); @@ -1208,11 +1206,6 @@ function image_save_gd($resource) return FALSE; } - if (phpversion() == '4.4.1') - { - @touch($this->full_dst_path); // PHP 4.4.1 bug #35060 - workaround - } - if ( ! @imagejpeg($resource, $this->full_dst_path, $this->quality)) { $this->set_error('imglib_save_failed'); @@ -1259,7 +1252,7 @@ function image_display_gd($resource) switch ($this->image_type) { - case 1 : imagegif($resource); + case 1 : imagegif($resource); break; case 2 : imagejpeg($resource, '', $this->quality); break; @@ -1377,8 +1370,8 @@ function get_image_properties($path = '', $return = FALSE) * new variable needs to be known * * $props = array( - * 'width' => $width, - * 'height' => $height, + * 'width' => $width, + * 'height' => $height, * 'new_width' => 40, * 'new_height' => '' * ); @@ -1439,7 +1432,7 @@ function explode_name($source_image) { $ext = strrchr($source_image, '.'); $name = ($ext === FALSE) ? $source_image : substr($source_image, 0, -strlen($ext)); - + return array('ext' => $ext, 'name' => $name); } diff --git a/system/libraries/Input.php b/system/libraries/Input.php deleted file mode 100644 index e7bf7277..00000000 --- a/system/libraries/Input.php +++ /dev/null @@ -1,1067 +0,0 @@ - '[removed]', - 'document.write' => '[removed]', - '.parentNode' => '[removed]', - '.innerHTML' => '[removed]', - 'window.location' => '[removed]', - '-moz-binding' => '[removed]', - '' => '-->', - ' '<![CDATA[' - ); - /* never allowed, regex replacement */ - var $never_allowed_regex = array( - "javascript\s*:" => '[removed]', - "expression\s*(\(|&\#40;)" => '[removed]', // CSS and IE - "vbscript\s*:" => '[removed]', // IE, surprise! - "Redirect\s+302" => '[removed]' - ); - - /** - * Constructor - * - * Sets whether to globally enable the XSS processing - * and whether to allow the $_GET array - * - * @access public - */ - function CI_Input() - { - log_message('debug', "Input Class Initialized"); - - $CFG =& load_class('Config'); - $this->use_xss_clean = ($CFG->item('global_xss_filtering') === TRUE) ? TRUE : FALSE; - $this->allow_get_array = ($CFG->item('enable_query_strings') === TRUE) ? TRUE : FALSE; - $this->_sanitize_globals(); - } - - // -------------------------------------------------------------------- - - /** - * Sanitize Globals - * - * This function does the following: - * - * Unsets $_GET data (if query strings are not enabled) - * - * Unsets all globals if register_globals is enabled - * - * Standardizes newline characters to \n - * - * @access private - * @return void - */ - function _sanitize_globals() - { - // Would kind of be "wrong" to unset any of these GLOBALS - $protected = array('_SERVER', '_GET', '_POST', '_FILES', '_REQUEST', '_SESSION', '_ENV', 'GLOBALS', 'HTTP_RAW_POST_DATA', - 'system_folder', 'application_folder', 'BM', 'EXT', 'CFG', 'URI', 'RTR', 'OUT', 'IN'); - - // Unset globals for security. - // This is effectively the same as register_globals = off - foreach (array($_GET, $_POST, $_COOKIE, $_SERVER, $_FILES, $_ENV, (isset($_SESSION) && is_array($_SESSION)) ? $_SESSION : array()) as $global) - { - if ( ! is_array($global)) - { - if ( ! in_array($global, $protected)) - { - unset($GLOBALS[$global]); - } - } - else - { - foreach ($global as $key => $val) - { - if ( ! in_array($key, $protected)) - { - unset($GLOBALS[$key]); - } - - if (is_array($val)) - { - foreach($val as $k => $v) - { - if ( ! in_array($k, $protected)) - { - unset($GLOBALS[$k]); - } - } - } - } - } - } - - // Is $_GET data allowed? If not we'll set the $_GET to an empty array - if ($this->allow_get_array == FALSE) - { - $_GET = array(); - } - else - { - $_GET = $this->_clean_input_data($_GET); - } - - // Clean $_POST Data - $_POST = $this->_clean_input_data($_POST); - - // Clean $_COOKIE Data - // Also get rid of specially treated cookies that might be set by a server - // or silly application, that are of no use to a CI application anyway - // but that when present will trip our 'Disallowed Key Characters' alarm - // http://www.ietf.org/rfc/rfc2109.txt - // note that the key names below are single quoted strings, and are not PHP variables - unset($_COOKIE['$Version']); - unset($_COOKIE['$Path']); - unset($_COOKIE['$Domain']); - $_COOKIE = $this->_clean_input_data($_COOKIE); - - log_message('debug', "Global POST and COOKIE data sanitized"); - } - - // -------------------------------------------------------------------- - - /** - * Clean Input Data - * - * This is a helper function. It escapes data and - * standardizes newline characters to \n - * - * @access private - * @param string - * @return string - */ - function _clean_input_data($str) - { - if (is_array($str)) - { - $new_array = array(); - foreach ($str as $key => $val) - { - $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); - } - return $new_array; - } - - // We strip slashes if magic quotes is on to keep things consistent - if (get_magic_quotes_gpc()) - { - $str = stripslashes($str); - } - - // Should we filter the input data? - if ($this->use_xss_clean === TRUE) - { - $str = $this->xss_clean($str); - } - - // Standardize newlines - if (strpos($str, "\r") !== FALSE) - { - $str = str_replace(array("\r\n", "\r"), "\n", $str); - } - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Clean Keys - * - * This is a helper function. To prevent malicious users - * from trying to exploit keys we make sure that keys are - * only named with alpha-numeric text and a few other items. - * - * @access private - * @param string - * @return string - */ - function _clean_input_keys($str) - { - if ( ! preg_match("/^[a-z0-9:_\/-]+$/i", $str)) - { - exit('Disallowed Key Characters.'); - } - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Fetch from array - * - * This is a helper function to retrieve values from global arrays - * - * @access private - * @param array - * @param string - * @param bool - * @return string - */ - function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE) - { - if ( ! isset($array[$index])) - { - return FALSE; - } - - if ($xss_clean === TRUE) - { - return $this->xss_clean($array[$index]); - } - - return $array[$index]; - } - - // -------------------------------------------------------------------- - - /** - * Fetch an item from the GET array - * - * @access public - * @param string - * @param bool - * @return string - */ - function get($index = '', $xss_clean = FALSE) - { - return $this->_fetch_from_array($_GET, $index, $xss_clean); - } - - // -------------------------------------------------------------------- - - /** - * Fetch an item from the POST array - * - * @access public - * @param string - * @param bool - * @return string - */ - function post($index = '', $xss_clean = FALSE) - { - return $this->_fetch_from_array($_POST, $index, $xss_clean); - } - - // -------------------------------------------------------------------- - - /** - * Fetch an item from either the GET array or the POST - * - * @access public - * @param string The index key - * @param bool XSS cleaning - * @return string - */ - function get_post($index = '', $xss_clean = FALSE) - { - if ( ! isset($_POST[$index]) ) - { - return $this->get($index, $xss_clean); - } - else - { - return $this->post($index, $xss_clean); - } - } - - // -------------------------------------------------------------------- - - /** - * Fetch an item from the COOKIE array - * - * @access public - * @param string - * @param bool - * @return string - */ - function cookie($index = '', $xss_clean = FALSE) - { - return $this->_fetch_from_array($_COOKIE, $index, $xss_clean); - } - - // -------------------------------------------------------------------- - - /** - * Fetch an item from the SERVER array - * - * @access public - * @param string - * @param bool - * @return string - */ - function server($index = '', $xss_clean = FALSE) - { - return $this->_fetch_from_array($_SERVER, $index, $xss_clean); - } - - // -------------------------------------------------------------------- - - /** - * Fetch the IP Address - * - * @access public - * @return string - */ - function ip_address() - { - if ($this->ip_address !== FALSE) - { - return $this->ip_address; - } - - if (config_item('proxy_ips') != '' && $this->server('HTTP_X_FORWARDED_FOR') && $this->server('REMOTE_ADDR')) - { - $proxies = preg_split('/[\s,]/', config_item('proxy_ips'), -1, PREG_SPLIT_NO_EMPTY); - $proxies = is_array($proxies) ? $proxies : array($proxies); - - $this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']; - } - elseif ($this->server('REMOTE_ADDR') AND $this->server('HTTP_CLIENT_IP')) - { - $this->ip_address = $_SERVER['HTTP_CLIENT_IP']; - } - elseif ($this->server('REMOTE_ADDR')) - { - $this->ip_address = $_SERVER['REMOTE_ADDR']; - } - elseif ($this->server('HTTP_CLIENT_IP')) - { - $this->ip_address = $_SERVER['HTTP_CLIENT_IP']; - } - elseif ($this->server('HTTP_X_FORWARDED_FOR')) - { - $this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR']; - } - - if ($this->ip_address === FALSE) - { - $this->ip_address = '0.0.0.0'; - return $this->ip_address; - } - - if (strstr($this->ip_address, ',')) - { - $x = explode(',', $this->ip_address); - $this->ip_address = trim(end($x)); - } - - if ( ! $this->valid_ip($this->ip_address)) - { - $this->ip_address = '0.0.0.0'; - } - - return $this->ip_address; - } - - // -------------------------------------------------------------------- - - /** - * Validate IP Address - * - * Updated version suggested by Geert De Deckere - * - * @access public - * @param string - * @return string - */ - function valid_ip($ip) - { - $ip_segments = explode('.', $ip); - - // Always 4 segments needed - if (count($ip_segments) != 4) - { - return FALSE; - } - // IP can not start with 0 - if ($ip_segments[0][0] == '0') - { - return FALSE; - } - // Check each segment - foreach ($ip_segments as $segment) - { - // IP segments must be digits and can not be - // longer than 3 digits or greater then 255 - if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3) - { - return FALSE; - } - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * User Agent - * - * @access public - * @return string - */ - function user_agent() - { - if ($this->user_agent !== FALSE) - { - return $this->user_agent; - } - - $this->user_agent = ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT']; - - return $this->user_agent; - } - - // -------------------------------------------------------------------- - - /** - * Filename Security - * - * @access public - * @param string - * @return string - */ - function filename_security($str) - { - $bad = array( - "../", - "./", - "", - "<", - ">", - "'", - '"', - '&', - '$', - '#', - '{', - '}', - '[', - ']', - '=', - ';', - '?', - "%20", - "%22", - "%3c", // < - "%253c", // < - "%3e", // > - "%0e", // > - "%28", // ( - "%29", // ) - "%2528", // ( - "%26", // & - "%24", // $ - "%3f", // ? - "%3b", // ; - "%3d" // = - ); - - return stripslashes(str_replace($bad, '', $str)); - } - - // -------------------------------------------------------------------- - - /** - * XSS Clean - * - * Sanitizes data so that Cross Site Scripting Hacks can be - * prevented. This function does a fair amount of work but - * it is extremely thorough, designed to prevent even the - * most obscure XSS attempts. Nothing is ever 100% foolproof, - * of course, but I haven't been able to get anything passed - * the filter. - * - * Note: This function should only be used to deal with data - * upon submission. It's not something that should - * be used for general runtime processing. - * - * This function was based in part on some code and ideas I - * got from Bitflux: http://blog.bitflux.ch/wiki/XSS_Prevention - * - * To help develop this script I used this great list of - * vulnerabilities along with a few other hacks I've - * harvested from examining vulnerabilities in other programs: - * http://ha.ckers.org/xss.html - * - * @access public - * @param string - * @return string - */ - function xss_clean($str, $is_image = FALSE) - { - /* - * Is the string an array? - * - */ - if (is_array($str)) - { - while (list($key) = each($str)) - { - $str[$key] = $this->xss_clean($str[$key]); - } - - return $str; - } - - /* - * Remove Invisible Characters - */ - $str = $this->_remove_invisible_characters($str); - - /* - * Protect GET variables in URLs - */ - - // 901119URL5918AMP18930PROTECT8198 - - $str = preg_replace('|\&([a-z\_0-9]+)\=([a-z\_0-9]+)|i', $this->xss_hash()."\\1=\\2", $str); - - /* - * Validate standard character entities - * - * Add a semicolon if missing. We do this to enable - * the conversion of entities to ASCII later. - * - */ - $str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', "\\1;\\2", $str); - - /* - * Validate UTF16 two byte encoding (x00) - * - * Just as above, adds a semicolon if missing. - * - */ - $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str); - - /* - * Un-Protect GET variables in URLs - */ - $str = str_replace($this->xss_hash(), '&', $str); - - /* - * URL Decode - * - * Just in case stuff like this is submitted: - * - *
Google - * - * Note: Use rawurldecode() so it does not remove plus signs - * - */ - $str = rawurldecode($str); - - /* - * Convert character entities to ASCII - * - * This permits our tests below to work reliably. - * We only convert entities that are within tags since - * these are the ones that will pose security problems. - * - */ - - $str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str); - - $str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si", array($this, '_html_entity_decode_callback'), $str); - - /* - * Remove Invisible Characters Again! - */ - $str = $this->_remove_invisible_characters($str); - - /* - * Convert all tabs to spaces - * - * This prevents strings like this: ja vascript - * NOTE: we deal with spaces between characters later. - * NOTE: preg_replace was found to be amazingly slow here on large blocks of data, - * so we use str_replace. - * - */ - - if (strpos($str, "\t") !== FALSE) - { - $str = str_replace("\t", ' ', $str); - } - - /* - * Capture converted string for later comparison - */ - $converted_string = $str; - - /* - * Not Allowed Under Any Conditions - */ - - foreach ($this->never_allowed_str as $key => $val) - { - $str = str_replace($key, $val, $str); - } - - foreach ($this->never_allowed_regex as $key => $val) - { - $str = preg_replace("#".$key."#i", $val, $str); - } - - /* - * Makes PHP tags safe - * - * Note: XML tags are inadvertently replaced too: - * - * '), array('<?', '?>'), $str); - } - - /* - * Compact any exploded words - * - * This corrects words like: j a v a s c r i p t - * These words are compacted back to their correct state. - * - */ - $words = array('javascript', 'expression', 'vbscript', 'script', 'applet', 'alert', 'document', 'write', 'cookie', 'window'); - foreach ($words as $word) - { - $temp = ''; - - for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++) - { - $temp .= substr($word, $i, 1)."\s*"; - } - - // We only want to do this when it is followed by a non-word character - // That way valid stuff like "dealer to" does not become "dealerto" - $str = preg_replace_callback('#('.substr($temp, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str); - } - - /* - * Remove disallowed Javascript in links or img tags - * We used to do some version comparisons and use of stripos for PHP5, but it is dog slow compared - * to these simplified non-capturing preg_match(), especially if the pattern exists in the string - */ - do - { - $original = $str; - - if (preg_match("/]*?)(>|$)#si", array($this, '_js_link_removal'), $str); - } - - if (preg_match("/]*?)(\s?/?>|$)#si", array($this, '_js_img_removal'), $str); - } - - if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str)) - { - $str = preg_replace("#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str); - } - } - while($original != $str); - - unset($original); - - /* - * Remove JavaScript Event Handlers - * - * Note: This code is a little blunt. It removes - * the event handler and anything up to the closing >, - * but it's unlikely to be a problem. - * - */ - $event_handlers = array('[^a-z_\-]on\w*','xmlns'); - - if ($is_image === TRUE) - { - /* - * Adobe Photoshop puts XML metadata into JFIF images, including namespacing, - * so we have to allow this for images. -Paul - */ - unset($event_handlers[array_search('xmlns', $event_handlers)]); - } - - $str = preg_replace("#<([^><]+?)(".implode('|', $event_handlers).")(\s*=\s*[^><]*)([><]*)#i", "<\\1\\4", $str); - - /* - * Sanitize naughty HTML elements - * - * If a tag containing any of the words in the list - * below is found, the tag gets converted to entities. - * - * So this: - * Becomes: <blink> - * - */ - $naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss'; - $str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', array($this, '_sanitize_naughty_html'), $str); - - /* - * Sanitize naughty scripting elements - * - * Similar to above, only instead of looking for - * tags it looks for PHP and JavaScript commands - * that are disallowed. Rather than removing the - * code, it simply converts the parenthesis to entities - * rendering the code un-executable. - * - * For example: eval('some code') - * Becomes: eval('some code') - * - */ - $str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2(\\3)", $str); - - /* - * Final clean up - * - * This adds a bit of extra precaution in case - * something got through the above filters - * - */ - foreach ($this->never_allowed_str as $key => $val) - { - $str = str_replace($key, $val, $str); - } - - foreach ($this->never_allowed_regex as $key => $val) - { - $str = preg_replace("#".$key."#i", $val, $str); - } - - /* - * Images are Handled in a Special Way - * - Essentially, we want to know that after all of the character conversion is done whether - * any unwanted, likely XSS, code was found. If not, we return TRUE, as the image is clean. - * However, if the string post-conversion does not matched the string post-removal of XSS, - * then it fails, as there was unwanted XSS code found and removed/changed during processing. - */ - - if ($is_image === TRUE) - { - if ($str == $converted_string) - { - return TRUE; - } - else - { - return FALSE; - } - } - - log_message('debug', "XSS Filtering completed"); - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Random Hash for protecting URLs - * - * @access public - * @return string - */ - function xss_hash() - { - if ($this->xss_hash == '') - { - if (phpversion() >= 4.2) - mt_srand(); - else - mt_srand(hexdec(substr(md5(microtime()), -8)) & 0x7fffffff); - - $this->xss_hash = md5(time() + mt_rand(0, 1999999999)); - } - - return $this->xss_hash; - } - - // -------------------------------------------------------------------- - - /** - * Remove Invisible Characters - * - * This prevents sandwiching null characters - * between ascii characters, like Java\0script. - * - * @access public - * @param string - * @return string - */ - function _remove_invisible_characters($str) - { - static $non_displayables; - - if ( ! isset($non_displayables)) - { - // every control character except newline (dec 10), carriage return (dec 13), and horizontal tab (dec 09), - $non_displayables = array( - '/%0[0-8bcef]/', // url encoded 00-08, 11, 12, 14, 15 - '/%1[0-9a-f]/', // url encoded 16-31 - '/[\x00-\x08]/', // 00-08 - '/\x0b/', '/\x0c/', // 11, 12 - '/[\x0e-\x1f]/' // 14-31 - ); - } - - do - { - $cleaned = $str; - $str = preg_replace($non_displayables, '', $str); - } - while ($cleaned != $str); - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Compact Exploded Words - * - * Callback function for xss_clean() to remove whitespace from - * things like j a v a s c r i p t - * - * @access public - * @param type - * @return type - */ - function _compact_exploded_words($matches) - { - return preg_replace('/\s+/s', '', $matches[1]).$matches[2]; - } - - // -------------------------------------------------------------------- - - /** - * Sanitize Naughty HTML - * - * Callback function for xss_clean() to remove naughty HTML elements - * - * @access private - * @param array - * @return string - */ - function _sanitize_naughty_html($matches) - { - // encode opening brace - $str = '<'.$matches[1].$matches[2].$matches[3]; - - // encode captured opening or closing brace to prevent recursive vectors - $str .= str_replace(array('>', '<'), array('>', '<'), $matches[4]); - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * JS Link Removal - * - * Callback function for xss_clean() to sanitize links - * This limits the PCRE backtracks, making it more performance friendly - * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in - * PHP 5.2+ on link-heavy strings - * - * @access private - * @param array - * @return string - */ - function _js_link_removal($match) - { - $attributes = $this->_filter_attributes(str_replace(array('<', '>'), '', $match[1])); - return str_replace($match[1], preg_replace("#href=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])); - return str_replace($match[1], preg_replace("#src=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|', '<', '\\'), array('>', '<', '\\\\'), $match[0]); - } - - // -------------------------------------------------------------------- - - /** - * HTML Entity Decode Callback - * - * Used as a callback for XSS Clean - * - * @access public - * @param array - * @return string - */ - function _html_entity_decode_callback($match) - { - $CFG =& load_class('Config'); - $charset = $CFG->item('charset'); - - return $this->_html_entity_decode($match[0], strtoupper($charset)); - } - - // -------------------------------------------------------------------- - - /** - * HTML Entities Decode - * - * This function is a replacement for html_entity_decode() - * - * In some versions of PHP the native function does not work - * when UTF-8 is the specified character set, so this gives us - * a work-around. More info here: - * http://bugs.php.net/bug.php?id=25670 - * - * @access private - * @param string - * @param string - * @return string - */ - /* ------------------------------------------------- - /* Replacement for html_entity_decode() - /* -------------------------------------------------*/ - - /* - NOTE: html_entity_decode() has a bug in some PHP versions when UTF-8 is the - character set, and the PHP developers said they were not back porting the - fix to versions other than PHP 5.x. - */ - function _html_entity_decode($str, $charset='UTF-8') - { - if (stristr($str, '&') === FALSE) return $str; - - // The reason we are not using html_entity_decode() by itself is because - // while it is not technically correct to leave out the semicolon - // at the end of an entity most browsers will still interpret the entity - // correctly. html_entity_decode() does not convert entities without - // semicolons, so we are left with our own little solution here. Bummer. - - if (function_exists('html_entity_decode') && (strtolower($charset) != 'utf-8' OR version_compare(phpversion(), '5.0.0', '>='))) - { - $str = html_entity_decode($str, ENT_COMPAT, $charset); - $str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str); - return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str); - } - - // Numeric Entities - $str = preg_replace('~&#x(0*[0-9a-f]{2,5});{0,1}~ei', 'chr(hexdec("\\1"))', $str); - $str = preg_replace('~&#([0-9]{2,4});{0,1}~e', 'chr(\\1)', $str); - - // Literal Entities - Slightly slow so we do another check - if (stristr($str, '&') === FALSE) - { - $str = strtr($str, array_flip(get_html_translation_table(HTML_ENTITIES))); - } - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Filter Attributes - * - * Filters tag attributes for consistency and safety - * - * @access public - * @param string - * @return string - */ - function _filter_attributes($str) - { - $out = ''; - - if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches)) - { - foreach ($matches[0] as $match) - { - $out .= preg_replace("#/\*.*?\*/#s", '', $match); - } - } - - return $out; - } - - // -------------------------------------------------------------------- - -} -// END Input class - -/* End of file Input.php */ -/* Location: ./system/libraries/Input.php */ \ No newline at end of file diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php new file mode 100644 index 00000000..34e0d700 --- /dev/null +++ b/system/libraries/Javascript.php @@ -0,0 +1,871 @@ + 'jquery', 'autoload' => TRUE); + + foreach ($defaults as $key => $val) + { + if (isset($params[$key]) && $params[$key] !== "") + { + $defaults[$key] = $params[$key]; + } + } + + extract($defaults); + + $this->CI =& get_instance(); + + // load the requested js library + $this->CI->load->library('javascript/'.$js_library_driver, array('autoload' => $autoload)); + // make js to refer to current library + $this->js =& $this->CI->$js_library_driver; + + log_message('debug', "Javascript Class Initialized and loaded. Driver used: $js_library_driver"); + } + + // -------------------------------------------------------------------- + // Event Code + // -------------------------------------------------------------------- + + /** + * Blur + * + * Outputs a javascript library blur event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function blur($element = 'this', $js = '') + { + return $this->js->_blur($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Change + * + * Outputs a javascript library change event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function change($element = 'this', $js = '') + { + return $this->js->_change($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Click + * + * Outputs a javascript library click event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @param boolean whether or not to return false + * @return string + */ + function click($element = 'this', $js = '', $ret_false = TRUE) + { + return $this->js->_click($element, $js, $ret_false); + } + + // -------------------------------------------------------------------- + + /** + * Double Click + * + * Outputs a javascript library dblclick event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function dblclick($element = 'this', $js = '') + { + return $this->js->_dblclick($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Error + * + * Outputs a javascript library error event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function error($element = 'this', $js = '') + { + return $this->js->_error($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Focus + * + * Outputs a javascript library focus event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function focus($element = 'this', $js = '') + { + return $this->js->__add_event($focus, $js); + } + + // -------------------------------------------------------------------- + + /** + * Hover + * + * Outputs a javascript library hover event + * + * @access public + * @param string - element + * @param string - Javascript code for mouse over + * @param string - Javascript code for mouse out + * @return string + */ + function hover($element = 'this', $over, $out) + { + return $this->js->__hover($element, $over, $out); + } + + // -------------------------------------------------------------------- + + /** + * Keydown + * + * Outputs a javascript library keydown event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function keydown($element = 'this', $js = '') + { + return $this->js->_keydown($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Keyup + * + * Outputs a javascript library keydown event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function keyup($element = 'this', $js = '') + { + return $this->js->_keyup($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Load + * + * Outputs a javascript library load event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function load($element = 'this', $js = '') + { + return $this->js->_load($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Mousedown + * + * Outputs a javascript library mousedown event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function mousedown($element = 'this', $js = '') + { + return $this->js->_mousedown($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Mouse Out + * + * Outputs a javascript library mouseout event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function mouseout($element = 'this', $js = '') + { + return $this->js->_mouseout($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Mouse Over + * + * Outputs a javascript library mouseover event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function mouseover($element = 'this', $js = '') + { + return $this->js->_mouseover($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Mouseup + * + * Outputs a javascript library mouseup event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function mouseup($element = 'this', $js = '') + { + return $this->js->_mouseup($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Output + * + * Outputs the called javascript to the screen + * + * @access public + * @param string The code to output + * @return string + */ + function output($js) + { + return $this->js->_output($js); + } + + // -------------------------------------------------------------------- + + /** + * Ready + * + * Outputs a javascript library mouseup event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function ready($js) + { + return $this->js->_document_ready($js); + } + + // -------------------------------------------------------------------- + + /** + * Resize + * + * Outputs a javascript library resize event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function resize($element = 'this', $js = '') + { + return $this->js->_resize($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Scroll + * + * Outputs a javascript library scroll event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function scroll($element = 'this', $js = '') + { + return $this->js->_scroll($element, $js); + } + + // -------------------------------------------------------------------- + + /** + * Unload + * + * Outputs a javascript library unload event + * + * @access public + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function unload($element = 'this', $js = '') + { + return $this->js->_unload($element, $js); + } + + // -------------------------------------------------------------------- + // Effects + // -------------------------------------------------------------------- + + + /** + * Add Class + * + * Outputs a javascript library addClass event + * + * @access public + * @param string - element + * @param string - Class to add + * @return string + */ + function addClass($element = 'this', $class = '') + { + return $this->js->_addClass($element, $class); + } + + // -------------------------------------------------------------------- + + /** + * Animate + * + * Outputs a javascript library animate event + * + * @access public + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function animate($element = 'this', $params = array(), $speed = '', $extra = '') + { + return $this->js->_animate($element, $params, $speed, $extra); + } + + // -------------------------------------------------------------------- + + /** + * Fade In + * + * Outputs a javascript library hide event + * + * @access public + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function fadeIn($element = 'this', $speed = '', $callback = '') + { + return $this->js->_fadeIn($element, $speed, $callback); + } + + // -------------------------------------------------------------------- + + /** + * Fade Out + * + * Outputs a javascript library hide event + * + * @access public + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function fadeOut($element = 'this', $speed = '', $callback = '') + { + return $this->js->_fadeOut($element, $speed, $callback); + } + // -------------------------------------------------------------------- + + /** + * Slide Up + * + * Outputs a javascript library slideUp event + * + * @access public + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function slideUp($element = 'this', $speed = '', $callback = '') + { + return $this->js->_slideUp($element, $speed, $callback); + + } + + // -------------------------------------------------------------------- + + /** + * Remove Class + * + * Outputs a javascript library removeClass event + * + * @access public + * @param string - element + * @param string - Class to add + * @return string + */ + function removeClass($element = 'this', $class = '') + { + return $this->js->_removeClass($element, $class); + } + + // -------------------------------------------------------------------- + + /** + * Slide Down + * + * Outputs a javascript library slideDown event + * + * @access public + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function slideDown($element = 'this', $speed = '', $callback = '') + { + return $this->js->_slideDown($element, $speed, $callback); + } + + // -------------------------------------------------------------------- + + /** + * Slide Toggle + * + * Outputs a javascript library slideToggle event + * + * @access public + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function slideToggle($element = 'this', $speed = '', $callback = '') + { + return $this->js->_slideToggle($element, $speed, $callback); + + } + + // -------------------------------------------------------------------- + + /** + * Hide + * + * Outputs a javascript library hide action + * + * @access public + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function hide($element = 'this', $speed = '', $callback = '') + { + return $this->js->_hide($element, $speed, $callback); + } + + // -------------------------------------------------------------------- + + /** + * Toggle + * + * Outputs a javascript library toggle event + * + * @access public + * @param string - element + * @return string + */ + function toggle($element = 'this') + { + return $this->js->_toggle($element); + + } + + // -------------------------------------------------------------------- + + /** + * Toggle Class + * + * Outputs a javascript library toggle class event + * + * @access public + * @param string - element + * @return string + */ + function toggleClass($element = 'this', $class='') + { + return $this->js->_toggleClass($element, $class); + } + + // -------------------------------------------------------------------- + + /** + * Show + * + * Outputs a javascript library show event + * + * @access public + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function show($element = 'this', $speed = '', $callback = '') + { + return $this->js->_show($element, $speed, $callback); + } + + + // -------------------------------------------------------------------- + + /** + * Compile + * + * gather together all script needing to be output + * + * @access public + * @param string The element to attach the event to + * @return string + */ + function compile($view_var = 'script_foot', $script_tags = TRUE) + { + $this->js->_compile($view_var, $script_tags); + } + + /** + * Clear Compile + * + * Clears any previous javascript collected for output + * + * @access public + * @return void + */ + function clear_compile() + { + $this->js->_clear_compile(); + } + + // -------------------------------------------------------------------- + + /** + * External + * + * Outputs a + * + * @access private + * @param string + * @return string + */ + function _close_script($extra = "\n") + { + return "$extra"; + } + + + // -------------------------------------------------------------------- + // -------------------------------------------------------------------- + // AJAX-Y STUFF - still a testbed + // -------------------------------------------------------------------- + // -------------------------------------------------------------------- + + /** + * Update + * + * Outputs a javascript library slideDown event + * + * @access public + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function update($element = 'this', $speed = '', $callback = '') + { + return $this->js->_updater($element, $speed, $callback); + } + + // -------------------------------------------------------------------- + + /** + * Generate JSON + * + * Can be passed a database result or associative array and returns a JSON formatted string + * + * @param mixed result set or array + * @param bool match array types (defaults to objects) + * @return string a json formatted string + */ + function generate_json($result = NULL, $match_array_type = FALSE) + { + // JSON data can optionally be passed to this function + // either as a database result object or an array, or a user supplied array + if ( ! is_null($result)) + { + if (is_object($result)) + { + $json_result = $result->result_array(); + } + elseif (is_array($result)) + { + $json_result = $result; + } + else + { + return $this->_prep_args($result); + } + } + else + { + return 'null'; + } + + $json = array(); + $_is_assoc = TRUE; + + if ( ! is_array($json_result) AND empty($json_result)) + { + show_error("Generate JSON Failed - Illegal key, value pair."); + } + elseif ($match_array_type) + { + $_is_assoc = $this->_is_associative_array($json_result); + } + + foreach ($json_result as $k => $v) + { + if ($_is_assoc) + { + $json[] = $this->_prep_args($k, TRUE).':'.$this->generate_json($v, $match_array_type); + } + else + { + $json[] = $this->generate_json($v, $match_array_type); + } + } + + $json = implode(',', $json); + + return $_is_assoc ? "{".$json."}" : "[".$json."]"; + + } + + // -------------------------------------------------------------------- + + /** + * Is associative array + * + * Checks for an associative array + * + * @access public + * @param type + * @return type + */ + function _is_associative_array($arr) + { + foreach (array_keys($arr) as $key => $val) + { + if ($key !== $val) + { + return TRUE; + } + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Prep Args + * + * Ensures a standard json value and escapes values + * + * @access public + * @param type + * @return type + */ + function _prep_args($result, $is_key = FALSE) + { + if (is_null($result)) + { + return 'null'; + } + elseif (is_bool($result)) + { + return ($result === TRUE) ? 'true' : 'false'; + } + elseif (is_string($result) OR $is_key) + { + return '"'.str_replace(array('\\', "\t", "\n", "\r", '"', '/'), array('\\\\', '\\t', '\\n', "\\r", '\"', '\/'), $result).'"'; + } + elseif (is_scalar($result)) + { + return $result; + } + } + + // -------------------------------------------------------------------- +} +// END Javascript Class + +/* End of file Javascript.php */ +/* Location: ./system/libraries/Javascript.php */ \ No newline at end of file diff --git a/system/libraries/Log.php b/system/libraries/Log.php index d8a07a9d..9f1db76b 100644 --- a/system/libraries/Log.php +++ b/system/libraries/Log.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -26,87 +26,84 @@ */ class CI_Log { - var $log_path; - var $_threshold = 1; - var $_date_fmt = 'Y-m-d H:i:s'; - var $_enabled = TRUE; - var $_levels = array('ERROR' => '1', 'DEBUG' => '2', 'INFO' => '3', 'ALL' => '4'); + protected $_log_path; + protected $_threshold = 1; + protected $_date_fmt = 'Y-m-d H:i:s'; + protected $_enabled = TRUE; + protected $_levels = array('ERROR' => '1', 'DEBUG' => '2', 'INFO' => '3', 'ALL' => '4'); /** * Constructor - * - * @access public */ - function CI_Log() + public function __construct() { $config =& get_config(); - - $this->log_path = ($config['log_path'] != '') ? $config['log_path'] : BASEPATH.'logs/'; - - if ( ! is_dir($this->log_path) OR ! is_really_writable($this->log_path)) + + $this->_log_path = ($config['log_path'] != '') ? $config['log_path'] : APPPATH.'logs/'; + + if ( ! is_dir($this->_log_path) OR ! is_really_writable($this->_log_path)) { $this->_enabled = FALSE; } - + if (is_numeric($config['log_threshold'])) { $this->_threshold = $config['log_threshold']; } - + if ($config['log_date_format'] != '') { $this->_date_fmt = $config['log_date_format']; } } - + // -------------------------------------------------------------------- - + /** * Write Log File * * Generally this function will be called using the global log_message() function * - * @access public * @param string the error level * @param string the error message * @param bool whether the error is a native PHP error * @return bool - */ - function write_log($level = 'error', $msg, $php_error = FALSE) - { + */ + public function write_log($level = 'error', $msg, $php_error = FALSE) + { if ($this->_enabled === FALSE) { return FALSE; } - + $level = strtoupper($level); - + if ( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold)) { return FALSE; } - - $filepath = $this->log_path.'log-'.date('Y-m-d').EXT; + + $filepath = $this->_log_path.'log-'.date('Y-m-d').'.php'; $message = ''; - + if ( ! file_exists($filepath)) { $message .= "<"."?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?".">\n\n"; } - + if ( ! $fp = @fopen($filepath, FOPEN_WRITE_CREATE)) { return FALSE; } $message .= $level.' '.(($level == 'INFO') ? ' -' : '-').' '.date($this->_date_fmt). ' --> '.$msg."\n"; - - flock($fp, LOCK_EX); + + flock($fp, LOCK_EX); fwrite($fp, $message); flock($fp, LOCK_UN); fclose($fp); - - @chmod($filepath, FILE_WRITE_MODE); + + @chmod($filepath, FILE_WRITE_MODE); return TRUE; } diff --git a/system/libraries/Migration.php b/system/libraries/Migration.php new file mode 100644 index 00000000..ffa640ba --- /dev/null +++ b/system/libraries/Migration.php @@ -0,0 +1,328 @@ + $val) + { + $this->{'_' . $key} = $val; + } + + log_message('debug', 'Migrations class initialized'); + + // Are they trying to use migrations while it is disabled? + if ($this->_migration_enabled !== TRUE) + { + show_error('Migrations has been loaded but is disabled or set up incorrectly.'); + } + + // If not set, set it + $this->_migration_path == '' AND $this->_migration_path = APPPATH . 'migrations/'; + + // Add trailing slash if not set + $this->_migration_path = rtrim($this->_migration_path, '/').'/'; + + // Load migration language + $this->lang->load('migration'); + + // They'll probably be using dbforge + $this->load->dbforge(); + + // If the migrations table is missing, make it + if ( ! $this->db->table_exists('migrations')) + { + $this->dbforge->add_field(array( + 'version' => array('type' => 'INT', 'constraint' => 3), + )); + + $this->dbforge->create_table('migrations', TRUE); + + $this->db->insert('migrations', array('version' => 0)); + } + } + + // -------------------------------------------------------------------- + + /** + * Migrate to a schema version + * + * Calls each migration step required to get to the schema version of + * choice + * + * @param int Target schema version + * @return mixed TRUE if already latest, FALSE if failed, int if upgraded + */ + public function version($target_version) + { + $start = $current_version = $this->_get_version(); + $stop = $target_version; + + if ($target_version > $current_version) + { + // Moving Up + ++$start; + ++$stop; + $step = 1; + } + else + { + // Moving Down + $step = -1; + } + + $method = ($step === 1) ? 'up' : 'down'; + $migrations = array(); + + // We now prepare to actually DO the migrations + // But first let's make sure that everything is the way it should be + for ($i = $start; $i != $stop; $i += $step) + { + $f = glob(sprintf($this->_migration_path . '%03d_*.php', $i)); + + // Only one migration per step is permitted + if (count($f) > 1) + { + $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $i); + return FALSE; + } + + // Migration step not found + if (count($f) == 0) + { + // If trying to migrate up to a version greater than the last + // existing one, migrate to the last one. + if ($step == 1) + { + break; + } + + // If trying to migrate down but we're missing a step, + // something must definitely be wrong. + $this->_error_string = sprintf($this->lang->line('migration_not_found'), $i); + return FALSE; + } + + $file = basename($f[0]); + $name = basename($f[0], '.php'); + + // Filename validations + if (preg_match('/^\d{3}_(\w+)$/', $name, $match)) + { + $match[1] = strtolower($match[1]); + + // Cannot repeat a migration at different steps + if (in_array($match[1], $migrations)) + { + $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $match[1]); + return FALSE; + } + + include $f[0]; + $class = 'Migration_' . ucfirst($match[1]); + + if ( ! class_exists($class)) + { + $this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class); + return FALSE; + } + + if ( ! is_callable(array($class, $method))) + { + $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class); + return FALSE; + } + + $migrations[] = $match[1]; + } + else + { + $this->_error_string = sprintf($this->lang->line('migration_invalid_filename'), $file); + return FALSE; + } + } + + log_message('debug', 'Current migration: ' . $current_version); + + $version = $i + ($step == 1 ? -1 : 0); + + // If there is nothing to do so quit + if ($migrations === array()) + { + return TRUE; + } + + log_message('debug', 'Migrating from ' . $method . ' to version ' . $version); + + // Loop through the migrations + foreach ($migrations AS $migration) + { + // Run the migration class + $class = 'Migration_' . ucfirst(strtolower($migration)); + call_user_func(array(new $class, $method)); + + $current_version += $step; + $this->_update_version($current_version); + } + + log_message('debug', 'Finished migrating to '.$current_version); + + return $current_version; + } + + // -------------------------------------------------------------------- + + /** + * Set's the schema to the latest migration + * + * @return mixed true if already latest, false if failed, int if upgraded + */ + public function latest() + { + if ( ! $migrations = $this->find_migrations()) + { + $this->_error_string = $this->lang->line('migration_none_found'); + return false; + } + + $last_migration = basename(end($migrations)); + + // Calculate the last migration step from existing migration + // filenames and procceed to the standard version migration + return $this->version((int) substr($last_migration, 0, 3)); + } + + // -------------------------------------------------------------------- + + /** + * Set's the schema to the migration version set in config + * + * @return mixed true if already current, false if failed, int if upgraded + */ + public function current() + { + return $this->version($this->_migration_version); + } + + // -------------------------------------------------------------------- + + /** + * Error string + * + * @return string Error message returned as a string + */ + public function error_string() + { + return $this->_error_string; + } + + // -------------------------------------------------------------------- + + /** + * Set's the schema to the latest migration + * + * @return mixed true if already latest, false if failed, int if upgraded + */ + protected function find_migrations() + { + // Load all *_*.php files in the migrations path + $files = glob($this->_migration_path . '*_*.php'); + $file_count = count($files); + + for ($i = 0; $i < $file_count; $i++) + { + // Mark wrongly formatted files as false for later filtering + $name = basename($files[$i], '.php'); + if ( ! preg_match('/^\d{3}_(\w+)$/', $name)) + { + $files[$i] = FALSE; + } + } + + sort($files); + return $files; + } + + // -------------------------------------------------------------------- + + /** + * Retrieves current schema version + * + * @return int Current Migration + */ + protected function _get_version() + { + $row = $this->db->get('migrations')->row(); + return $row ? $row->version : 0; + } + + // -------------------------------------------------------------------- + + /** + * Stores the current schema version + * + * @param int Migration reached + * @return bool + */ + protected function _update_version($migrations) + { + return $this->db->update('migrations', array( + 'version' => $migrations + )); + } + + // -------------------------------------------------------------------- + + /** + * Enable the use of CI super-global + * + * @param mixed $var + * @return mixed + */ + public function __get($var) + { + return get_instance()->$var; + } +} + +/* End of file Migration.php */ +/* Location: ./system/libraries/Migration.php */ \ No newline at end of file diff --git a/system/libraries/Model.php b/system/libraries/Model.php deleted file mode 100644 index d77e99b7..00000000 --- a/system/libraries/Model.php +++ /dev/null @@ -1,80 +0,0 @@ -_assign_libraries( (method_exists($this, '__get') OR method_exists($this, '__set')) ? FALSE : TRUE ); - - // We don't want to assign the model object to itself when using the - // assign_libraries function below so we'll grab the name of the model parent - $this->_parent_name = ucfirst(get_class($this)); - - log_message('debug', "Model Class Initialized"); - } - - /** - * Assign Libraries - * - * Creates local references to all currently instantiated objects - * so that any syntax that can be legally used in a controller - * can be used within models. - * - * @access private - */ - function _assign_libraries($use_reference = TRUE) - { - $CI =& get_instance(); - foreach (array_keys(get_object_vars($CI)) as $key) - { - if ( ! isset($this->$key) AND $key != $this->_parent_name) - { - // In some cases using references can cause - // problems so we'll conditionally use them - if ($use_reference == TRUE) - { - $this->$key = NULL; // Needed to prevent reference errors with some configurations - $this->$key =& $CI->$key; - } - } - } - - } - -} -// END Model Class - -/* End of file Model.php */ -/* Location: ./system/libraries/Model.php */ \ No newline at end of file diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php index d73c58e0..cdaacf2d 100644 --- a/system/libraries/Pagination.php +++ b/system/libraries/Pagination.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -27,11 +27,15 @@ class CI_Pagination { var $base_url = ''; // The page we are linking to - var $total_rows = ''; // Total number of items (database results) - var $per_page = 10; // Max number of items you want shown per page + var $prefix = ''; // A custom prefix added to the path. + var $suffix = ''; // A custom suffix added to the path. + + var $total_rows = 0; // Total number of items (database results) + var $per_page = 10; // Max number of items you want shown per page var $num_links = 2; // Number of "digit" links to show before/after the currently viewed page - var $cur_page = 0; // The current page being viewed - var $first_link = '‹ First'; + var $cur_page = 0; // The current page being viewed + var $use_page_numbers = FALSE; // Use page number for segment instead of offset + var $first_link = '‹ First'; var $next_link = '>'; var $prev_link = '<'; var $last_link = 'Last ›'; @@ -42,6 +46,7 @@ class CI_Pagination { var $first_tag_close = ' '; var $last_tag_open = ' '; var $last_tag_close = ''; + var $first_url = ''; // Alternative URL for the First Page. var $cur_tag_open = ' '; var $cur_tag_close = ''; var $next_tag_open = ' '; @@ -52,6 +57,8 @@ class CI_Pagination { var $num_tag_close = ''; var $page_query_string = FALSE; var $query_string_segment = 'per_page'; + var $display_pages = TRUE; + var $anchor_class = ''; /** * Constructor @@ -59,13 +66,18 @@ class CI_Pagination { * @access public * @param array initialization parameters */ - function CI_Pagination($params = array()) + public function __construct($params = array()) { if (count($params) > 0) { $this->initialize($params); } + if ($this->anchor_class != '') + { + $this->anchor_class = 'class="'.$this->anchor_class.'" '; + } + log_message('debug', "Pagination Class Initialized"); } @@ -117,12 +129,22 @@ function create_links() return ''; } + // Set the base page index for starting page number + if ($this->use_page_numbers) + { + $base_page = 1; + } + else + { + $base_page = 0; + } + // Determine the current page number. $CI =& get_instance(); if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE) { - if ($CI->input->get($this->query_string_segment) != 0) + if ($CI->input->get($this->query_string_segment) != $base_page) { $this->cur_page = $CI->input->get($this->query_string_segment); @@ -132,7 +154,7 @@ function create_links() } else { - if ($CI->uri->segment($this->uri_segment) != 0) + if ($CI->uri->segment($this->uri_segment) != $base_page) { $this->cur_page = $CI->uri->segment($this->uri_segment); @@ -140,6 +162,12 @@ function create_links() $this->cur_page = (int) $this->cur_page; } } + + // Set current page to 1 if using page numbers instead of offset + if ($this->use_page_numbers AND $this->cur_page == 0) + { + $this->cur_page = $base_page; + } $this->num_links = (int)$this->num_links; @@ -150,18 +178,32 @@ function create_links() if ( ! is_numeric($this->cur_page)) { - $this->cur_page = 0; + $this->cur_page = $base_page; } // Is the page number beyond the result range? // If so we show the last page - if ($this->cur_page > $this->total_rows) + if ($this->use_page_numbers) { - $this->cur_page = ($num_pages - 1) * $this->per_page; + if ($this->cur_page > $num_pages) + { + $this->cur_page = $num_pages; + } + } + else + { + if ($this->cur_page > $this->total_rows) + { + $this->cur_page = ($num_pages - 1) * $this->per_page; + } } $uri_page_number = $this->cur_page; - $this->cur_page = floor(($this->cur_page/$this->per_page) + 1); + + if ( ! $this->use_page_numbers) + { + $this->cur_page = floor(($this->cur_page/$this->per_page) + 1); + } // Calculate the start and end numbers. These determine // which number to start and end the digit links with @@ -179,53 +221,107 @@ function create_links() $this->base_url = rtrim($this->base_url, '/') .'/'; } - // And here we go... + // And here we go... $output = ''; // Render the "First" link - if ($this->cur_page > ($this->num_links + 1)) + if ($this->first_link !== FALSE AND $this->cur_page > ($this->num_links + 1)) { - $output .= $this->first_tag_open.''.$this->first_link.''.$this->first_tag_close; + $first_url = ($this->first_url == '') ? $this->base_url : $this->first_url; + $output .= $this->first_tag_open.'anchor_class.'href="'.$first_url.'">'.$this->first_link.''.$this->first_tag_close; } // Render the "previous" link - if ($this->cur_page != 1) + if ($this->prev_link !== FALSE AND $this->cur_page != 1) { - $i = $uri_page_number - $this->per_page; - if ($i == 0) $i = ''; - $output .= $this->prev_tag_open.''.$this->prev_link.''.$this->prev_tag_close; + if ($this->use_page_numbers) + { + $i = $uri_page_number - 1; + } + else + { + $i = $uri_page_number - $this->per_page; + } + + if ($i == 0 && $this->first_url != '') + { + $output .= $this->prev_tag_open.'anchor_class.'href="'.$this->first_url.'">'.$this->prev_link.''.$this->prev_tag_close; + } + else + { + $i = ($i == 0) ? '' : $this->prefix.$i.$this->suffix; + $output .= $this->prev_tag_open.'anchor_class.'href="'.$this->base_url.$i.'">'.$this->prev_link.''.$this->prev_tag_close; + } + } - // Write the digit links - for ($loop = $start -1; $loop <= $end; $loop++) + // Render the pages + if ($this->display_pages !== FALSE) { - $i = ($loop * $this->per_page) - $this->per_page; - - if ($i >= 0) + // Write the digit links + for ($loop = $start -1; $loop <= $end; $loop++) { - if ($this->cur_page == $loop) + if ($this->use_page_numbers) { - $output .= $this->cur_tag_open.$loop.$this->cur_tag_close; // Current page + $i = $loop; } else { - $n = ($i == 0) ? '' : $i; - $output .= $this->num_tag_open.''.$loop.''.$this->num_tag_close; + $i = ($loop * $this->per_page) - $this->per_page; + } + + if ($i >= $base_page) + { + if ($this->cur_page == $loop) + { + $output .= $this->cur_tag_open.$loop.$this->cur_tag_close; // Current page + } + else + { + $n = ($i == $base_page) ? '' : $i; + + if ($n == '' && $this->first_url != '') + { + $output .= $this->num_tag_open.'anchor_class.'href="'.$this->first_url.'">'.$loop.''.$this->num_tag_close; + } + else + { + $n = ($n == '') ? '' : $this->prefix.$n.$this->suffix; + + $output .= $this->num_tag_open.'anchor_class.'href="'.$this->base_url.$n.'">'.$loop.''.$this->num_tag_close; + } + } } } } // Render the "next" link - if ($this->cur_page < $num_pages) + if ($this->next_link !== FALSE AND $this->cur_page < $num_pages) { - $output .= $this->next_tag_open.''.$this->next_link.''.$this->next_tag_close; + if ($this->use_page_numbers) + { + $i = $this->cur_page + 1; + } + else + { + $i = ($this->cur_page * $this->per_page); + } + + $output .= $this->next_tag_open.'anchor_class.'href="'.$this->base_url.$this->prefix.$i.$this->suffix.'">'.$this->next_link.''.$this->next_tag_close; } // Render the "Last" link - if (($this->cur_page + $this->num_links) < $num_pages) + if ($this->last_link !== FALSE AND ($this->cur_page + $this->num_links) < $num_pages) { - $i = (($num_pages * $this->per_page) - $this->per_page); - $output .= $this->last_tag_open.''.$this->last_link.''.$this->last_tag_close; + if ($this->use_page_numbers) + { + $i = $num_pages; + } + else + { + $i = (($num_pages * $this->per_page) - $this->per_page); + } + $output .= $this->last_tag_open.'anchor_class.'href="'.$this->base_url.$this->prefix.$i.$this->suffix.'">'.$this->last_link.''.$this->last_tag_close; } // Kill double slashes. Note: Sometimes we can end up with a double slash diff --git a/system/libraries/Parser.php b/system/libraries/Parser.php index da324375..d223da02 100644 --- a/system/libraries/Parser.php +++ b/system/libraries/Parser.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -29,11 +29,11 @@ class CI_Parser { var $l_delim = '{'; var $r_delim = '}'; var $object; - + /** * Parse a template * - * Parses pseudo-variables contained in the specified template, + * Parses pseudo-variables contained in the specified template view, * replacing them with the data in the second param * * @access public @@ -42,38 +42,77 @@ class CI_Parser { * @param bool * @return string */ - function parse($template, $data, $return = FALSE) + public function parse($template, $data, $return = FALSE) { $CI =& get_instance(); $template = $CI->load->view($template, $data, TRUE); - + + return $this->_parse($template, $data, $return); + } + + // -------------------------------------------------------------------- + + /** + * Parse a String + * + * Parses pseudo-variables contained in the specified string, + * replacing them with the data in the second param + * + * @access public + * @param string + * @param array + * @param bool + * @return string + */ + function parse_string($template, $data, $return = FALSE) + { + return $this->_parse($template, $data, $return); + } + + // -------------------------------------------------------------------- + + /** + * Parse a template + * + * Parses pseudo-variables contained in the specified template, + * replacing them with the data in the second param + * + * @access public + * @param string + * @param array + * @param bool + * @return string + */ + function _parse($template, $data, $return = FALSE) + { if ($template == '') { return FALSE; } - + foreach ($data as $key => $val) { if (is_array($val)) { - $template = $this->_parse_pair($key, $val, $template); + $template = $this->_parse_pair($key, $val, $template); } else { $template = $this->_parse_single($key, (string)$val, $template); } } - + if ($return == FALSE) { + $CI =& get_instance(); $CI->output->append_output($template); } - + return $template; } - + // -------------------------------------------------------------------- - + /** * Set the left/right variable delimiters * @@ -87,9 +126,9 @@ function set_delimiters($l = '{', $r = '}') $this->l_delim = $l; $this->r_delim = $r; } - + // -------------------------------------------------------------------- - + /** * Parse a single key/value * @@ -103,9 +142,9 @@ function _parse_single($key, $val, $string) { return str_replace($this->l_delim.$key.$this->r_delim, $val, $string); } - + // -------------------------------------------------------------------- - + /** * Parse a tag pair * @@ -118,7 +157,7 @@ function _parse_single($key, $val, $string) * @return string */ function _parse_pair($variable, $data, $string) - { + { if (FALSE === ($match = $this->_match_pair($string, $variable))) { return $string; @@ -139,15 +178,15 @@ function _parse_pair($variable, $data, $string) $temp = $this->_parse_pair($key, $val, $temp); } } - + $str .= $temp; } - + return str_replace($match['0'], $str, $string); } - + // -------------------------------------------------------------------- - + /** * Matches a variable pair * @@ -158,11 +197,11 @@ function _parse_pair($variable, $data, $string) */ function _match_pair($string, $variable) { - if ( ! preg_match("|".$this->l_delim . $variable . $this->r_delim."(.+?)".$this->l_delim . '/' . $variable . $this->r_delim."|s", $string, $match)) + if ( ! preg_match("|" . preg_quote($this->l_delim) . $variable . preg_quote($this->r_delim) . "(.+?)". preg_quote($this->l_delim) . '/' . $variable . preg_quote($this->r_delim) . "|s", $string, $match)) { return FALSE; } - + return $match; } @@ -170,4 +209,4 @@ function _match_pair($string, $variable) // END Parser Class /* End of file Parser.php */ -/* Location: ./system/libraries/Parser.php */ \ No newline at end of file +/* Location: ./system/libraries/Parser.php */ diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php index ecd0e708..882a82c1 100644 --- a/system/libraries/Profiler.php +++ b/system/libraries/Profiler.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -32,14 +32,69 @@ */ class CI_Profiler { - var $CI; - - function CI_Profiler() - { - $this->CI =& get_instance(); - $this->CI->load->language('profiler'); - } - + protected $_available_sections = array( + 'benchmarks', + 'get', + 'memory_usage', + 'post', + 'uri_string', + 'controller_info', + 'queries', + 'http_headers', + 'session_data', + 'config' + ); + + protected $_query_toggle_count = 25; + + protected $CI; + + // -------------------------------------------------------------------- + + public function __construct($config = array()) + { + $this->CI =& get_instance(); + $this->CI->load->language('profiler'); + + if (isset($config['query_toggle_count'])) + { + $this->_query_toggle_count = (int) $config['query_toggle_count']; + unset($config['query_toggle_count']); + } + + // default all sections to display + foreach ($this->_available_sections as $section) + { + if ( ! isset($config[$section])) + { + $this->_compile_{$section} = TRUE; + } + } + + $this->set_sections($config); + } + + // -------------------------------------------------------------------- + + /** + * Set Sections + * + * Sets the private _compile_* properties to enable/disable Profiler sections + * + * @param mixed + * @return void + */ + public function set_sections($config) + { + foreach ($config as $method => $enable) + { + if (in_array($method, $this->_available_sections)) + { + $this->_compile_{$method} = ($enable !== FALSE) ? TRUE : FALSE; + } + } + } + // -------------------------------------------------------------------- /** @@ -50,57 +105,55 @@ function CI_Profiler() * and "_end" respectively). It then compiles the execution times for * all points and returns it as an array * - * @access private * @return array */ - function _compile_benchmarks() - { - $profile = array(); - foreach ($this->CI->benchmark->marker as $key => $val) - { - // We match the "end" marker so that the list ends - // up in the order that it was defined - if (preg_match("/(.+?)_end/i", $key, $match)) - { - if (isset($this->CI->benchmark->marker[$match[1].'_end']) AND isset($this->CI->benchmark->marker[$match[1].'_start'])) - { - $profile[$match[1]] = $this->CI->benchmark->elapsed_time($match[1].'_start', $key); - } - } - } + protected function _compile_benchmarks() + { + $profile = array(); + foreach ($this->CI->benchmark->marker as $key => $val) + { + // We match the "end" marker so that the list ends + // up in the order that it was defined + if (preg_match("/(.+?)_end/i", $key, $match)) + { + if (isset($this->CI->benchmark->marker[$match[1].'_end']) AND isset($this->CI->benchmark->marker[$match[1].'_start'])) + { + $profile[$match[1]] = $this->CI->benchmark->elapsed_time($match[1].'_start', $key); + } + } + } // Build a table containing the profile data. // Note: At some point we should turn this into a template that can // be modified. We also might want to make this data available to be logged - + $output = "\n\n"; - $output .= '
'; + $output .= '
'; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_benchmarks').'  '; $output .= "\n"; - $output .= '  '.$this->CI->lang->line('profiler_benchmarks').'  '; - $output .= "\n"; - $output .= "\n\n\n"; - + $output .= "\n\n
\n"; + foreach ($profile as $key => $val) { $key = ucwords(str_replace(array('_', '-'), ' ', $key)); - $output .= "\n"; + $output .= "\n"; } - + $output .= "
".$key."  ".$val."
".$key."  ".$val."
\n"; $output .= "
"; - - return $output; - } - + + return $output; + } + // -------------------------------------------------------------------- /** * Compile Queries * - * @access private * @return string - */ - function _compile_queries() + */ + protected function _compile_queries() { $dbs = array(); @@ -112,100 +165,112 @@ function _compile_queries() $dbs[] = $CI_object; } } - + if (count($dbs) == 0) { $output = "\n\n"; - $output .= '
'; + $output .= '
'; $output .= "\n"; $output .= '  '.$this->CI->lang->line('profiler_queries').'  '; - $output .= "\n"; - $output .= "\n\n\n"; - $output .="\n"; + $output .= "\n"; + $output .= "\n\n
".$this->CI->lang->line('profiler_no_db')."
\n"; + $output .="\n"; $output .= "
".$this->CI->lang->line('profiler_no_db')."
\n"; $output .= "
"; - + return $output; } - + // Load the text helper so we can highlight the SQL $this->CI->load->helper('text'); // Key words we want bolded - $highlight = array('SELECT', 'DISTINCT', 'FROM', 'WHERE', 'AND', 'LEFT JOIN', 'ORDER BY', 'GROUP BY', 'LIMIT', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'OR', 'HAVING', 'OFFSET', 'NOT IN', 'IN', 'LIKE', 'NOT LIKE', 'COUNT', 'MAX', 'MIN', 'ON', 'AS', 'AVG', 'SUM', '(', ')'); + $highlight = array('SELECT', 'DISTINCT', 'FROM', 'WHERE', 'AND', 'LEFT JOIN', 'ORDER BY', 'GROUP BY', 'LIMIT', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'OR ', 'HAVING', 'OFFSET', 'NOT IN', 'IN', 'LIKE', 'NOT LIKE', 'COUNT', 'MAX', 'MIN', 'ON', 'AS', 'AVG', 'SUM', '(', ')'); $output = "\n\n"; - + + $count = 0; + foreach ($dbs as $db) { + $count++; + + $hide_queries = (count($db->queries) > $this->_query_toggle_count) ? ' display:none' : ''; + + $show_hide_js = '('.$this->CI->lang->line('profiler_section_hide').')'; + + if ($hide_queries != '') + { + $show_hide_js = '('.$this->CI->lang->line('profiler_section_show').')'; + } + $output .= '
'; $output .= "\n"; - $output .= '  '.$this->CI->lang->line('profiler_database').':  '.$db->database.'   '.$this->CI->lang->line('profiler_queries').': '.count($this->CI->db->queries).'   '; - $output .= "\n"; - $output .= "\n\n\n"; - + $output .= '  '.$this->CI->lang->line('profiler_database').':  '.$db->database.'   '.$this->CI->lang->line('profiler_queries').': '.count($db->queries).'  '.$show_hide_js.''; + $output .= "\n"; + $output .= "\n\n
\n"; + if (count($db->queries) == 0) { - $output .= "\n"; + $output .= "\n"; } else - { + { foreach ($db->queries as $key => $val) - { + { $time = number_format($db->query_times[$key], 4); $val = highlight_code($val, ENT_QUOTES); - + foreach ($highlight as $bold) { - $val = str_replace($bold, ''.$bold.'', $val); + $val = str_replace($bold, ''.$bold.'', $val); } - - $output .= "\n"; + + $output .= "\n"; } } - + $output .= "
".$this->CI->lang->line('profiler_no_queries')."
".$this->CI->lang->line('profiler_no_queries')."
".$time."  ".$val."
".$time."  ".$val."
\n"; $output .= "
"; - + } - + return $output; } - + // -------------------------------------------------------------------- /** * Compile $_GET Data * - * @access private * @return string - */ - function _compile_get() - { + */ + protected function _compile_get() + { $output = "\n\n"; - $output .= '
'; + $output .= '
'; $output .= "\n"; $output .= '  '.$this->CI->lang->line('profiler_get_data').'  '; $output .= "\n"; - + if (count($_GET) == 0) { $output .= "
".$this->CI->lang->line('profiler_no_get')."
"; } else { - $output .= "\n\n\n"; - + $output .= "\n\n
\n"; + foreach ($_GET as $key => $val) { if ( ! is_numeric($key)) { $key = "'".$key."'"; } - - $output .= "\n"; } - + $output .= "
$_GET[".$key."]   "; + + $output .= "
$_GET[".$key."]   "; if (is_array($val)) { $output .= "
" . htmlspecialchars(stripslashes(print_r($val, true))) . "
"; @@ -216,49 +281,48 @@ function _compile_get() } $output .= "
\n"; } $output .= "
"; - return $output; + return $output; } - + // -------------------------------------------------------------------- - + /** * Compile $_POST Data * - * @access private * @return string - */ - function _compile_post() - { + */ + protected function _compile_post() + { $output = "\n\n"; - $output .= '
'; + $output .= '
'; $output .= "\n"; $output .= '  '.$this->CI->lang->line('profiler_post_data').'  '; $output .= "\n"; - + if (count($_POST) == 0) { $output .= "
".$this->CI->lang->line('profiler_no_post')."
"; } else { - $output .= "\n\n\n"; - + $output .= "\n\n
\n"; + foreach ($_POST as $key => $val) { if ( ! is_numeric($key)) { $key = "'".$key."'"; } - - $output .= "\n"; } - + $output .= "
$_POST[".$key."]   "; + + $output .= "
$_POST[".$key."]   "; if (is_array($val)) { - $output .= "
" . htmlspecialchars(stripslashes(print_r($val, true))) . "
"; + $output .= "
" . htmlspecialchars(stripslashes(print_r($val, TRUE))) . "
"; } else { @@ -266,124 +330,226 @@ function _compile_post() } $output .= "
\n"; } $output .= "
"; - return $output; + return $output; } - + // -------------------------------------------------------------------- - + /** * Show query string * - * @access private * @return string - */ - function _compile_uri_string() - { + */ + protected function _compile_uri_string() + { $output = "\n\n"; - $output .= '
'; + $output .= '
'; $output .= "\n"; $output .= '  '.$this->CI->lang->line('profiler_uri_string').'  '; $output .= "\n"; - + if ($this->CI->uri->uri_string == '') { $output .= "
".$this->CI->lang->line('profiler_no_uri')."
"; } else { - $output .= "
".$this->CI->uri->uri_string."
"; + $output .= "
".$this->CI->uri->uri_string."
"; } - + $output .= "
"; - return $output; + return $output; } // -------------------------------------------------------------------- - + /** * Show the controller and function that were called * - * @access private * @return string - */ - function _compile_controller_info() - { + */ + protected function _compile_controller_info() + { $output = "\n\n"; - $output .= '
'; + $output .= '
'; $output .= "\n"; $output .= '  '.$this->CI->lang->line('profiler_controller_info').'  '; $output .= "\n"; - - $output .= "
".$this->CI->router->fetch_class()."/".$this->CI->router->fetch_method()."
"; - + $output .= "
".$this->CI->router->fetch_class()."/".$this->CI->router->fetch_method()."
"; + $output .= "
"; - return $output; + return $output; } + // -------------------------------------------------------------------- - + /** * Compile memory usage * * Display total used memory * - * @access public * @return string */ - function _compile_memory_usage() + protected function _compile_memory_usage() { $output = "\n\n"; - $output .= '
'; + $output .= '
'; $output .= "\n"; $output .= '  '.$this->CI->lang->line('profiler_memory_usage').'  '; $output .= "\n"; - + if (function_exists('memory_get_usage') && ($usage = memory_get_usage()) != '') { $output .= "
".number_format($usage).' bytes
'; } else { - $output .= "
".$this->CI->lang->line('profiler_no_memory_usage')."
"; + $output .= "
".$this->CI->lang->line('profiler_no_memory')."
"; } - + $output .= "
"; return $output; } // -------------------------------------------------------------------- - + + /** + * Compile header information + * + * Lists HTTP headers + * + * @return string + */ + protected function _compile_http_headers() + { + $output = "\n\n"; + $output .= '
'; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_headers').'  ('.$this->CI->lang->line('profiler_section_show').')'; + $output .= "\n"; + + $output .= "\n\n\n"; + + foreach (array('HTTP_ACCEPT', 'HTTP_USER_AGENT', 'HTTP_CONNECTION', 'SERVER_PORT', 'SERVER_NAME', 'REMOTE_ADDR', 'SERVER_SOFTWARE', 'HTTP_ACCEPT_LANGUAGE', 'SCRIPT_NAME', 'REQUEST_METHOD',' HTTP_HOST', 'REMOTE_HOST', 'CONTENT_TYPE', 'SERVER_PROTOCOL', 'QUERY_STRING', 'HTTP_ACCEPT_ENCODING', 'HTTP_X_FORWARDED_FOR') as $header) + { + $val = (isset($_SERVER[$header])) ? $_SERVER[$header] : ''; + $output .= "\n"; + } + + $output .= "\n"; + $output .= "
"; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Compile config information + * + * Lists developer config variables + * + * @return string + */ + protected function _compile_config() + { + $output = "\n\n"; + $output .= '
'; + $output .= "\n"; + $output .= '  '.$this->CI->lang->line('profiler_config').'  ('.$this->CI->lang->line('profiler_section_show').')'; + $output .= "\n"; + + $output .= "\n\n\n"; + + foreach ($this->CI->config->config as $config=>$val) + { + if (is_array($val)) + { + $val = print_r($val, TRUE); + } + + $output .= "\n"; + } + + $output .= "\n"; + $output .= "
"; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Compile session userdata + * + * @return string + */ + private function _compile_session_data() + { + if ( ! isset($this->CI->session)) + { + return; + } + + $output = '
'; + $output .= '  '.$this->CI->lang->line('profiler_session_data').'  ('.$this->CI->lang->line('profiler_section_show').')'; + $output .= ""; + + foreach ($this->CI->session->all_userdata() as $key => $val) + { + if (is_array($val) OR is_object($val)) + { + $val = print_r($val, TRUE); + } + + $output .= "\n"; + } + + $output .= ''; + $output .= "
"; + return $output; + } + + // -------------------------------------------------------------------- + /** * Run the Profiler * - * @access private * @return string - */ - function run() + */ + public function run() { $output = "
"; + $fields_displayed = 0; - $output .= $this->_compile_uri_string(); - $output .= $this->_compile_controller_info(); - $output .= $this->_compile_memory_usage(); - $output .= $this->_compile_benchmarks(); - $output .= $this->_compile_get(); - $output .= $this->_compile_post(); - $output .= $this->_compile_queries(); + foreach ($this->_available_sections as $section) + { + if ($this->_compile_{$section} !== FALSE) + { + $func = "_compile_{$section}"; + $output .= $this->{$func}(); + $fields_displayed++; + } + } + + if ($fields_displayed == 0) + { + $output .= '

'.$this->CI->lang->line('profiler_no_profiles').'

'; + } $output .= '
'; return $output; } - } // END CI_Profiler class diff --git a/system/libraries/Session.php b/system/libraries/Session.php index f5cf4eb7..891fdd36 100644 --- a/system/libraries/Session.php +++ b/system/libraries/Session.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -30,15 +30,17 @@ class CI_Session { var $sess_use_database = FALSE; var $sess_table_name = ''; var $sess_expiration = 7200; + var $sess_expire_on_close = FALSE; var $sess_match_ip = FALSE; var $sess_match_useragent = TRUE; var $sess_cookie_name = 'ci_session'; var $cookie_prefix = ''; var $cookie_path = ''; var $cookie_domain = ''; + var $cookie_secure = FALSE; var $sess_time_to_update = 300; var $encryption_key = ''; - var $flashdata_key = 'flash'; + var $flashdata_key = 'flash'; var $time_reference = 'time'; var $gc_probability = 5; var $userdata = array(); @@ -51,7 +53,7 @@ class CI_Session { * The constructor runs the session routines automatically * whenever the class is instantiated. */ - function CI_Session($params = array()) + public function __construct($params = array()) { log_message('debug', "Session Class Initialized"); @@ -60,11 +62,16 @@ function CI_Session($params = array()) // Set all the session preferences, which can either be set // manually via the $params array above or via the config file - foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key) + foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key) { $this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key); } + if ($this->encryption_key == '') + { + show_error('In order to use the Session class you are required to set an encryption key in your config file.'); + } + // Load the string helper so we can use the strip_slashes() function $this->CI->load->helper('string'); @@ -90,7 +97,7 @@ function CI_Session($params = array()) { $this->sess_expiration = (60*60*24*365*2); } - + // Set the cookie name $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name; @@ -106,10 +113,10 @@ function CI_Session($params = array()) } // Delete 'old' flashdata (from last request) - $this->_flashdata_sweep(); + $this->_flashdata_sweep(); // Mark all new flashdata as old (data will be deleted before next request) - $this->_flashdata_mark(); + $this->_flashdata_mark(); // Delete expired sessions if necessary $this->_sess_gc(); @@ -181,12 +188,8 @@ function sess_read() return FALSE; } - // Turning user-agent checking on will break the SWFUpload client, as it apparently sends its own - // user agent separate from the browser. - $this->sess_match_useragent = FALSE; - // Does the User Agent Match? - if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 50))) + if ($this->sess_match_useragent == TRUE AND trim($session['user_agent']) != trim(substr($this->CI->input->user_agent(), 0, 120))) { $this->sess_destroy(); return FALSE; @@ -311,10 +314,11 @@ function sess_create() $sessid .= $this->CI->input->ip_address(); $this->userdata = array( - 'session_id' => md5(uniqid($sessid, TRUE)), - 'ip_address' => $this->CI->input->ip_address(), - 'user_agent' => substr($this->CI->input->user_agent(), 0, 50), - 'last_activity' => $this->now + 'session_id' => md5(uniqid($sessid, TRUE)), + 'ip_address' => $this->CI->input->ip_address(), + 'user_agent' => substr($this->CI->input->user_agent(), 0, 120), + 'last_activity' => $this->now, + 'user_data' => '' ); @@ -395,7 +399,7 @@ function sess_update() function sess_destroy() { // Kill the session DB row - if ($this->sess_use_database === TRUE AND isset($this->userdata['session_id'])) + if ($this->sess_use_database === TRUE && isset($this->userdata['session_id'])) { $this->CI->db->where('session_id', $this->userdata['session_id']); $this->CI->db->delete($this->sess_table_name); @@ -410,6 +414,9 @@ function sess_destroy() $this->cookie_domain, 0 ); + + // Kill session data + $this->userdata = array(); } // -------------------------------------------------------------------- @@ -432,11 +439,11 @@ function userdata($item) * Fetch all session data * * @access public - * @return mixed + * @return array */ function all_userdata() { - return ( ! isset($this->userdata)) ? FALSE : $this->userdata; + return $this->userdata; } // -------------------------------------------------------------------- @@ -655,14 +662,16 @@ function _set_cookie($cookie_data = NULL) $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key); } + $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); + // Set the cookie setcookie( $this->sess_cookie_name, $cookie_data, - $this->sess_expiration + time(), + $expire, $this->cookie_path, $this->cookie_domain, - 0 + $this->cookie_secure ); } @@ -684,12 +693,18 @@ function _serialize($data) { foreach ($data as $key => $val) { - $data[$key] = str_replace('\\', '{{slash}}', $val); + if (is_string($val)) + { + $data[$key] = str_replace('\\', '{{slash}}', $val); + } } } else { - $data = str_replace('\\', '{{slash}}', $data); + if (is_string($data)) + { + $data = str_replace('\\', '{{slash}}', $data); + } } return serialize($data); @@ -715,13 +730,16 @@ function _unserialize($data) { foreach ($data as $key => $val) { - $data[$key] = str_replace('{{slash}}', '\\', $val); + if (is_string($val)) + { + $data[$key] = str_replace('{{slash}}', '\\', $val); + } } return $data; } - return str_replace('{{slash}}', '\\', $data); + return (is_string($data)) ? str_replace('{{slash}}', '\\', $data) : $data; } // -------------------------------------------------------------------- diff --git a/system/libraries/Sha1.php b/system/libraries/Sha1.php index 6c39a5b1..1a657572 100644 --- a/system/libraries/Sha1.php +++ b/system/libraries/Sha1.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -42,9 +42,9 @@ * @author ExpressionEngine Dev Team * @link http://codeigniter.com/user_guide/general/encryption.html */ -class CI_SHA { +class CI_SHA1 { - function CI_SHA() + public function __construct() { log_message('debug', "SHA1 Class Initialized"); } @@ -55,7 +55,7 @@ function CI_SHA() * @access public * @param string * @return string - */ + */ function generate($str) { $n = ((strlen($str) + 8) >> 6) + 1; @@ -88,7 +88,7 @@ function generate($str) $oldd = $d; $olde = $e; - for($j = 0; $j < 80; $j++) + for ($j = 0; $j < 80; $j++) { if ($j < 16) { @@ -117,7 +117,7 @@ function generate($str) return $this->_hex($a).$this->_hex($b).$this->_hex($c).$this->_hex($d).$this->_hex($e); } - + // -------------------------------------------------------------------- /** @@ -126,7 +126,7 @@ function generate($str) * @access private * @param string * @return string - */ + */ function _hex($str) { $str = dechex($str); @@ -138,7 +138,7 @@ function _hex($str) return $str; } - + // -------------------------------------------------------------------- /** @@ -146,7 +146,7 @@ function _hex($str) * * @access private * @return string - */ + */ function _ft($t, $b, $c, $d) { if ($t < 20) @@ -166,7 +166,7 @@ function _ft($t, $b, $c, $d) * * @access private * @return string - */ + */ function _kt($t) { if ($t < 20) @@ -186,7 +186,7 @@ function _kt($t) return -899497514; } } - + // -------------------------------------------------------------------- /** @@ -194,7 +194,7 @@ function _kt($t) * * @access private * @return string - */ + */ function _safe_add($x, $y) { $lsw = ($x & 0xFFFF) + ($y & 0xFFFF); @@ -202,7 +202,7 @@ function _safe_add($x, $y) return ($msw << 16) | ($lsw & 0xFFFF); } - + // -------------------------------------------------------------------- /** @@ -210,7 +210,7 @@ function _safe_add($x, $y) * * @access private * @return integer - */ + */ function _rol($num, $cnt) { return ($num << $cnt) | $this->_zero_fill($num, 32 - $cnt); @@ -223,7 +223,7 @@ function _rol($num, $cnt) * * @access private * @return string - */ + */ function _zero_fill($a, $b) { $bin = decbin($a); diff --git a/system/libraries/Table.php b/system/libraries/Table.php index 86d54217..def69677 100644 --- a/system/libraries/Table.php +++ b/system/libraries/Table.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.3.1 @@ -30,14 +30,14 @@ class CI_Table { var $rows = array(); var $heading = array(); - var $auto_heading = TRUE; - var $caption = NULL; - var $template = NULL; + var $auto_heading = TRUE; + var $caption = NULL; + var $template = NULL; var $newline = "\n"; var $empty_cells = ""; - - - function CI_Table() + var $function = FALSE; + + public function __construct() { log_message('debug', "Table Class Initialized"); } @@ -57,7 +57,7 @@ function set_template($template) { return FALSE; } - + $this->template = $template; } @@ -75,7 +75,7 @@ function set_template($template) function set_heading() { $args = func_get_args(); - $this->heading = (is_array($args[0])) ? $args[0] : $args; + $this->heading = $this->_prep_args($args); } // -------------------------------------------------------------------- @@ -97,21 +97,21 @@ function make_columns($array = array(), $col_limit = 0) { return FALSE; } - - // Turn off the auto-heading feature since it's doubtful we + + // Turn off the auto-heading feature since it's doubtful we // will want headings from a one-dimensional array $this->auto_heading = FALSE; - + if ($col_limit == 0) { return $array; } - + $new = array(); - while(count($array) > 0) - { + while (count($array) > 0) + { $temp = array_splice($array, 0, $col_limit); - + if (count($temp) < $col_limit) { for ($i = count($temp); $i < $col_limit; $i++) @@ -119,10 +119,10 @@ function make_columns($array = array(), $col_limit = 0) $temp[] = ' '; } } - + $new[] = $temp; } - + return $new; } @@ -141,7 +141,7 @@ function set_empty($value) { $this->empty_cells = $value; } - + // -------------------------------------------------------------------- /** @@ -156,7 +156,55 @@ function set_empty($value) function add_row() { $args = func_get_args(); - $this->rows[] = (is_array($args[0])) ? $args[0] : $args; + $this->rows[] = $this->_prep_args($args); + } + + // -------------------------------------------------------------------- + + /** + * Prep Args + * + * Ensures a standard associative array format for all cell data + * + * @access public + * @param type + * @return type + */ + function _prep_args($args) + { + // If there is no $args[0], skip this and treat as an associative array + // This can happen if there is only a single key, for example this is passed to table->generate + // array(array('foo'=>'bar')) + if (isset($args[0]) AND (count($args) == 1 && is_array($args[0]))) + { + // args sent as indexed array + if ( ! isset($args[0]['data'])) + { + foreach ($args[0] as $key => $val) + { + if (is_array($val) && isset($val['data'])) + { + $args[$key] = $val; + } + else + { + $args[$key] = array('data' => $val); + } + } + } + } + else + { + foreach ($args as $key => $val) + { + if ( ! is_array($val)) + { + $args[$key] = array('data' => $val); + } + } + } + + return $args; } // -------------------------------------------------------------------- @@ -171,7 +219,7 @@ function add_row() function set_caption($caption) { $this->caption = $caption; - } + } // -------------------------------------------------------------------- @@ -198,21 +246,23 @@ function generate($table_data = NULL) $this->_set_from_array($table_data, $set_heading); } } - + // Is there anything to display? No? Smite them! if (count($this->heading) == 0 AND count($this->rows) == 0) { return 'Undefined table data'; } - + // Compile and validate the template date $this->_compile_template(); - - + + // set a custom cell manipulation function to a locally scoped variable so its callable + $function = $this->function; + // Build the table! - + $out = $this->template['table_open']; - $out .= $this->newline; + $out .= $this->newline; // Add any caption here if ($this->caption) @@ -225,63 +275,104 @@ function generate($table_data = NULL) // Is there a table heading to display? if (count($this->heading) > 0) { + $out .= $this->template['thead_open']; + $out .= $this->newline; $out .= $this->template['heading_row_start']; - $out .= $this->newline; + $out .= $this->newline; - foreach($this->heading as $heading) + foreach ($this->heading as $heading) { - $out .= $this->template['heading_cell_start']; - $out .= $heading; + $temp = $this->template['heading_cell_start']; + + foreach ($heading as $key => $val) + { + if ($key != 'data') + { + $temp = str_replace('template['heading_cell_end']; } $out .= $this->template['heading_row_end']; - $out .= $this->newline; + $out .= $this->newline; + $out .= $this->template['thead_close']; + $out .= $this->newline; } // Build the table rows if (count($this->rows) > 0) { + $out .= $this->template['tbody_open']; + $out .= $this->newline; + $i = 1; - foreach($this->rows as $row) + foreach ($this->rows as $row) { if ( ! is_array($row)) { break; } - + // We use modulus to alternate the row colors $name = (fmod($i++, 2)) ? '' : 'alt_'; - + $out .= $this->template['row_'.$name.'start']; - $out .= $this->newline; - - foreach($row as $cell) + $out .= $this->newline; + + foreach ($row as $cell) { - $out .= $this->template['cell_'.$name.'start']; - - if ($cell === "") + $temp = $this->template['cell_'.$name.'start']; + + foreach ($cell as $key => $val) + { + if ($key != 'data') + { + $temp = str_replace('empty_cells; } else { - $out .= $cell; + if ($function !== FALSE && is_callable($function)) + { + $out .= call_user_func($function, $cell); + } + else + { + $out .= $cell; + } } - + $out .= $this->template['cell_'.$name.'end']; } - + $out .= $this->template['row_'.$name.'end']; - $out .= $this->newline; + $out .= $this->newline; } + + $out .= $this->template['tbody_close']; + $out .= $this->newline; } $out .= $this->template['table_close']; - + + // Clear table class properties before generating the table + $this->clear(); + return $out; } - + // -------------------------------------------------------------------- /** @@ -294,9 +385,9 @@ function clear() { $this->rows = array(); $this->heading = array(); - $this->auto_heading = TRUE; + $this->auto_heading = TRUE; } - + // -------------------------------------------------------------------- /** @@ -312,7 +403,7 @@ function _set_from_object($query) { return FALSE; } - + // First generate the headings from the table column names if (count($this->heading) == 0) { @@ -320,17 +411,17 @@ function _set_from_object($query) { return FALSE; } - - $this->heading = $query->list_fields(); + + $this->heading = $this->_prep_args($query->list_fields()); } - + // Next blast through the result array and build out the rows - + if ($query->num_rows() > 0) { foreach ($query->result_array() as $row) { - $this->rows[] = $row; + $this->rows[] = $this->_prep_args($row); } } } @@ -350,26 +441,20 @@ function _set_from_array($data, $set_heading = TRUE) { return FALSE; } - + $i = 0; foreach ($data as $row) { - if ( ! is_array($row)) - { - $this->rows[] = $data; - break; - } - // If a heading hasn't already been set we'll use the first row of the array as the heading if ($i == 0 AND count($data) > 1 AND count($this->heading) == 0 AND $set_heading == TRUE) { - $this->heading = $row; + $this->heading = $this->_prep_args($row); } else { - $this->rows[] = $row; + $this->rows[] = $this->_prep_args($row); } - + $i++; } } @@ -382,24 +467,24 @@ function _set_from_array($data, $set_heading = TRUE) * @access private * @return void */ - function _compile_template() - { - if ($this->template == NULL) - { - $this->template = $this->_default_template(); - return; - } - + function _compile_template() + { + if ($this->template == NULL) + { + $this->template = $this->_default_template(); + return; + } + $this->temp = $this->_default_template(); - foreach (array('table_open','heading_row_start', 'heading_row_end', 'heading_cell_start', 'heading_cell_end', 'row_start', 'row_end', 'cell_start', 'cell_end', 'row_alt_start', 'row_alt_end', 'cell_alt_start', 'cell_alt_end', 'table_close') as $val) + foreach (array('table_open', 'thead_open', 'thead_close', 'heading_row_start', 'heading_row_end', 'heading_cell_start', 'heading_cell_end', 'tbody_open', 'tbody_close', 'row_start', 'row_end', 'cell_start', 'cell_end', 'row_alt_start', 'row_alt_end', 'cell_alt_start', 'cell_alt_end', 'table_close') as $val) { if ( ! isset($this->template[$val])) { $this->template[$val] = $this->temp[$val]; } - } - } - + } + } + // -------------------------------------------------------------------- /** @@ -411,27 +496,33 @@ function _compile_template() function _default_template() { return array ( - 'table_open' => '', + 'table_open' => '
', + + 'thead_open' => '', + 'thead_close' => '', - 'heading_row_start' => '', - 'heading_row_end' => '', + 'heading_row_start' => '', + 'heading_row_end' => '', 'heading_cell_start' => '', - 'row_start' => '', - 'row_end' => '', + 'tbody_open' => '', + 'tbody_close' => '', + + 'row_start' => '', + 'row_end' => '', 'cell_start' => '', - 'row_alt_start' => '', - 'row_alt_end' => '', + 'row_alt_start' => '', + 'row_alt_end' => '', 'cell_alt_start' => '', - 'table_close' => '
', 'heading_cell_end' => '
', 'cell_end' => '
', 'cell_alt_end' => '
' - ); + 'table_close' => '' + ); } - + } diff --git a/system/libraries/Trackback.php b/system/libraries/Trackback.php index ab8f46a6..b0a76782 100644 --- a/system/libraries/Trackback.php +++ b/system/libraries/Trackback.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -27,7 +27,7 @@ * @link http://codeigniter.com/user_guide/libraries/trackback.html */ class CI_Trackback { - + var $time_format = 'local'; var $charset = 'UTF-8'; var $data = array('url' => '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => ''); @@ -40,28 +40,28 @@ class CI_Trackback { * * @access public */ - function CI_Trackback() + public function __construct() { log_message('debug', "Trackback Class Initialized"); } - + // -------------------------------------------------------------------- - + /** * Send Trackback * * @access public * @param array * @return bool - */ + */ function send($tb_data) - { + { if ( ! is_array($tb_data)) { $this->set_error('The send() method must be passed an array'); return FALSE; } - + // Pre-process the Trackback Data foreach (array('url', 'title', 'excerpt', 'blog_name', 'ping_url') as $item) { @@ -70,14 +70,14 @@ function send($tb_data) $this->set_error('Required item missing: '.$item); return FALSE; } - + switch ($item) { case 'ping_url' : $$item = $this->extract_urls($tb_data[$item]); break; case 'excerpt' : $$item = $this->limit_characters($this->convert_xml(strip_tags(stripslashes($tb_data[$item])))); break; - case 'url' : $$item = str_replace('-', '-', $this->convert_xml(strip_tags(stripslashes($tb_data[$item])))); + case 'url' : $$item = str_replace('-', '-', $this->convert_xml(strip_tags(stripslashes($tb_data[$item])))); break; default : $$item = $this->convert_xml(strip_tags(stripslashes($tb_data[$item]))); break; @@ -94,7 +94,7 @@ function send($tb_data) { $$item = $this->convert_ascii($$item); } - elseif($item == 'blog_name') + elseif ($item == 'blog_name') { $$item = $this->convert_ascii($$item); } @@ -103,9 +103,9 @@ function send($tb_data) // Build the Trackback data string $charset = ( ! isset($tb_data['charset'])) ? $this->charset : $tb_data['charset']; - + $data = "url=".rawurlencode($url)."&title=".rawurlencode($title)."&blog_name=".rawurlencode($blog_name)."&excerpt=".rawurlencode($excerpt)."&charset=".rawurlencode($charset); - + // Send Trackback(s) $return = TRUE; if (count($ping_url) > 0) @@ -116,27 +116,27 @@ function send($tb_data) { $return = FALSE; } - } + } } return $return; } - + // -------------------------------------------------------------------- - + /** * Receive Trackback Data * * This function simply validates the incoming TB data. - * It returns false on failure and true on success. + * It returns FALSE on failure and TRUE on success. * If the data is valid it is set to the $this->data array * so that it can be inserted into a database. * * @access public * @return bool - */ + */ function receive() - { + { foreach (array('url', 'title', 'blog_name', 'excerpt') as $val) { if ( ! isset($_POST[$val]) OR $_POST[$val] == '') @@ -144,29 +144,29 @@ function receive() $this->set_error('The following required POST variable is missing: '.$val); return FALSE; } - + $this->data['charset'] = ( ! isset($_POST['charset'])) ? 'auto' : strtoupper(trim($_POST['charset'])); - + if ($val != 'url' && function_exists('mb_convert_encoding')) { $_POST[$val] = mb_convert_encoding($_POST[$val], $this->charset, $this->data['charset']); } - + $_POST[$val] = ($val != 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]); - + if ($val == 'excerpt') { $_POST['excerpt'] = $this->limit_characters($_POST['excerpt']); } - + $this->data[$val] = $_POST[$val]; } return TRUE; - } - + } + // -------------------------------------------------------------------- - + /** * Send Trackback Error Message * @@ -177,15 +177,15 @@ function receive() * @access public * @param string * @return void - */ + */ function send_error($message = 'Incomplete Information') { echo "\n\n1\n".$message."\n"; exit; } - + // -------------------------------------------------------------------- - + /** * Send Trackback Success Message * @@ -194,44 +194,44 @@ function send_error($message = 'Incomplete Information') * * @access public * @return void - */ + */ function send_success() { echo "\n\n0\n"; exit; } - + // -------------------------------------------------------------------- - + /** * Fetch a particular item * * @access public * @param string * @return string - */ + */ function data($item) { return ( ! isset($this->data[$item])) ? '' : $this->data[$item]; } // -------------------------------------------------------------------- - + /** * Process Trackback * * Opens a socket connection and passes the data to - * the server. Returns true on success, false on failure + * the server. Returns TRUE on success, FALSE on failure * * @access public * @param string * @param string * @return bool - */ + */ function process($url, $data) { $target = parse_url($url); - + // Open the socket if ( ! $fp = @fsockopen($target['host'], 80)) { @@ -241,7 +241,7 @@ function process($url, $data) // Build the path $ppath = ( ! isset($target['path'])) ? $url : $target['path']; - + $path = (isset($target['query']) && $target['query'] != "") ? $ppath.'?'.$target['query'] : $ppath; // Add the Trackback ID to the data string @@ -260,31 +260,32 @@ function process($url, $data) // Was it successful? $this->response = ""; - - while( ! feof($fp)) + + while ( ! feof($fp)) { $this->response .= fgets($fp, 128); } @fclose($fp); - + + if (stristr($this->response, '0') === FALSE) { $message = 'An unknown error was encountered'; - + if (preg_match("/(.*?)<\/message>/is", $this->response, $match)) { $message = trim($match['1']); } - + $this->set_error($message); return FALSE; } return TRUE; } - + // -------------------------------------------------------------------- - + /** * Extract Trackback URLs * @@ -295,34 +296,34 @@ function process($url, $data) * @access public * @param string * @return string - */ + */ function extract_urls($urls) - { + { // Remove the pesky white space and replace with a comma. $urls = preg_replace("/\s*(\S+)\s*/", "\\1,", $urls); - + // If they use commas get rid of the doubles. $urls = str_replace(",,", ",", $urls); - + // Remove any comma that might be at the end if (substr($urls, -1) == ",") { $urls = substr($urls, 0, -1); } - + // Break into an array via commas $urls = preg_split('/[,]/', $urls); - + // Removes duplicates $urls = array_unique($urls); - + array_walk($urls, array($this, 'validate_url')); - + return $urls; } - + // -------------------------------------------------------------------- - + /** * Validate URL * @@ -331,7 +332,7 @@ function extract_urls($urls) * @access public * @param string * @return string - */ + */ function validate_url($url) { $url = trim($url); @@ -341,58 +342,58 @@ function validate_url($url) $url = "http://".$url; } } - + // -------------------------------------------------------------------- - + /** * Find the Trackback URL's ID * * @access public * @param string * @return string - */ + */ function get_id($url) - { + { $tb_id = ""; - - if (strstr($url, '?')) + + if (strpos($url, '?') !== FALSE) { $tb_array = explode('/', $url); $tb_end = $tb_array[count($tb_array)-1]; - + if ( ! is_numeric($tb_end)) { $tb_end = $tb_array[count($tb_array)-2]; } - + $tb_array = explode('=', $tb_end); $tb_id = $tb_array[count($tb_array)-1]; } else { $url = rtrim($url, '/'); - + $tb_array = explode('/', $url); $tb_id = $tb_array[count($tb_array)-1]; - + if ( ! is_numeric($tb_id)) { $tb_id = $tb_array[count($tb_array)-2]; } - } - + } + if ( ! preg_match ("/^([0-9]+)$/", $tb_id)) { - return false; + return FALSE; } else { return $tb_id; - } + } } - + // -------------------------------------------------------------------- - + /** * Convert Reserved XML characters to Entities * @@ -403,22 +404,22 @@ function get_id($url) function convert_xml($str) { $temp = '__TEMP_AMPERSANDS__'; - + $str = preg_replace("/&#(\d+);/", "$temp\\1;", $str); $str = preg_replace("/&(\w+);/", "$temp\\1;", $str); - + $str = str_replace(array("&","<",">","\"", "'", "-"), - array("&", "<", ">", """, "'", "-"), - $str); - + array("&", "<", ">", """, "'", "-"), + $str); + $str = preg_replace("/$temp(\d+);/","&#\\1;",$str); $str = preg_replace("/$temp(\w+);/","&\\1;", $str); - + return $str; - } - + } + // -------------------------------------------------------------------- - + /** * Character limiter * @@ -438,25 +439,25 @@ function limit_characters($str, $n = 500, $end_char = '…') } $str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str)); - + if (strlen($str) <= $n) { return $str; } - + $out = ""; foreach (explode(' ', trim($str)) as $val) { - $out .= $val.' '; + $out .= $val.' '; if (strlen($out) >= $n) { return trim($out).$end_char; - } + } } } - + // -------------------------------------------------------------------- - + /** * High ASCII to Entities * @@ -469,58 +470,58 @@ function limit_characters($str, $n = 500, $end_char = '…') */ function convert_ascii($str) { - $count = 1; - $out = ''; - $temp = array(); - - for ($i = 0, $s = strlen($str); $i < $s; $i++) - { - $ordinal = ord($str[$i]); - - if ($ordinal < 128) - { - $out .= $str[$i]; - } - else - { - if (count($temp) == 0) - { - $count = ($ordinal < 224) ? 2 : 3; - } - - $temp[] = $ordinal; - - if (count($temp) == $count) - { - $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64); - - $out .= '&#'.$number.';'; - $count = 1; - $temp = array(); - } - } - } - - return $out; + $count = 1; + $out = ''; + $temp = array(); + + for ($i = 0, $s = strlen($str); $i < $s; $i++) + { + $ordinal = ord($str[$i]); + + if ($ordinal < 128) + { + $out .= $str[$i]; + } + else + { + if (count($temp) == 0) + { + $count = ($ordinal < 224) ? 2 : 3; + } + + $temp[] = $ordinal; + + if (count($temp) == $count) + { + $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64); + + $out .= '&#'.$number.';'; + $count = 1; + $temp = array(); + } + } + } + + return $out; } - + // -------------------------------------------------------------------- - + /** * Set error message * * @access public * @param string * @return void - */ + */ function set_error($msg) { log_message('error', $msg); $this->error_msg[] = $msg; } - + // -------------------------------------------------------------------- - + /** * Show error messages * @@ -528,15 +529,15 @@ function set_error($msg) * @param string * @param string * @return string - */ + */ function display_errors($open = '

', $close = '

') - { + { $str = ''; foreach ($this->error_msg as $val) { $str .= $open.$val.$close; } - + return $str; } diff --git a/system/libraries/Typography.php b/system/libraries/Typography.php index 242ca3cb..734cec10 100644 --- a/system/libraries/Typography.php +++ b/system/libraries/Typography.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -28,39 +28,31 @@ class CI_Typography { // Block level elements that should not be wrapped inside

tags var $block_elements = 'address|blockquote|div|dl|fieldset|form|h\d|hr|noscript|object|ol|p|pre|script|table|ul'; - + // Elements that should not have

and
tags within them. var $skip_elements = 'p|pre|ol|ul|dl|object|table|h\d'; - + // Tags we want the parser to completely ignore when splitting the string. var $inline_elements = 'a|abbr|acronym|b|bdo|big|br|button|cite|code|del|dfn|em|i|img|ins|input|label|map|kbd|q|samp|select|small|span|strong|sub|sup|textarea|tt|var'; - + // array of block level elements that require inner content to be within another block level element var $inner_block_required = array('blockquote'); - + // the last block element parsed var $last_block_element = ''; - + // whether or not to protect quotes within { curly braces } var $protect_braced_quotes = FALSE; - - /** - * Nothing to do here... - * - */ - function CI_Typography() - { - } /** * Auto Typography * * This function converts text, making it typographically correct: - * - Converts double spaces into paragraphs. - * - Converts single line breaks into
tags - * - Converts single and double quotes into correctly facing curly quote entities. - * - Converts three dots into ellipsis. - * - Converts double dashes into em-dashes. + * - Converts double spaces into paragraphs. + * - Converts single line breaks into
tags + * - Converts single and double quotes into correctly facing curly quote entities. + * - Converts three dots into ellipsis. + * - Converts double dashes into em-dashes. * - Converts two spaces into entities * * @access public @@ -78,15 +70,15 @@ function auto_typography($str, $reduce_linebreaks = FALSE) // Standardize Newlines to make matching easier if (strpos($str, "\r") !== FALSE) { - $str = str_replace(array("\r\n", "\r"), "\n", $str); + $str = str_replace(array("\r\n", "\r"), "\n", $str); } - + // Reduce line breaks. If there are more than two consecutive linebreaks // we'll compress them down to a maximum of two since there's no benefit to more. if ($reduce_linebreaks === TRUE) { $str = preg_replace("/\n\n+/", "\n\n", $str); - } + } // HTML comment tags don't conform to patterns of normal tags, so pull them out separately, only if needed $html_comments = array(); @@ -101,50 +93,50 @@ function auto_typography($str, $reduce_linebreaks = FALSE) } } } - + // match and yank

 tags if they exist.  It's cheaper to do this separately since most content will
 		// not contain 
 tags, and it keeps the PCRE patterns below simpler and faster
 		if (strpos($str, '.*?
#si", array($this, '_protect_characters'), $str); } - + // Convert quotes within tags to temporary markers. $str = preg_replace_callback("#<.+?>#si", array($this, '_protect_characters'), $str); // Do the same with braces if necessary if ($this->protect_braced_quotes === TRUE) { - $str = preg_replace_callback("#\{.+?\}#si", array($this, '_protect_characters'), $str); + $str = preg_replace_callback("#\{.+?\}#si", array($this, '_protect_characters'), $str); } - - // Convert "ignore" tags to temporary marker. The parser splits out the string at every tag - // it encounters. Certain inline tags, like image tags, links, span tags, etc. will be + + // Convert "ignore" tags to temporary marker. The parser splits out the string at every tag + // it encounters. Certain inline tags, like image tags, links, span tags, etc. will be // adversely affected if they are split out so we'll convert the opening bracket < temporarily to: {@TAG} $str = preg_replace("#<(/*)(".$this->inline_elements.")([ >])#i", "{@TAG}\\1\\2\\3", $str); // Split the string at every tag. This expression creates an array with this prototype: - // - // [array] - // { - // [0] = - // [1] = Content... - // [2] = - // Etc... - // } + // + // [array] + // { + // [0] = + // [1] = Content... + // [2] = + // Etc... + // } $chunks = preg_split('/(<(?:[^<>]+(?:"[^"]*"|\'[^\']*\')?)+>)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); - - // Build our finalized string. We cycle through the array, skipping tags, and processing the contained text + + // Build our finalized string. We cycle through the array, skipping tags, and processing the contained text $str = ''; $process = TRUE; $paragraph = FALSE; $current_chunk = 0; $total_chunks = count($chunks); - + foreach ($chunks as $chunk) - { + { $current_chunk++; - + // Are we dealing with a tag? If so, we'll skip the processing for this cycle. // Well also set the "process" flag which allows us to skip
 tags and a few other things.
 			if (preg_match("#<(/*)(".$this->block_elements.").*?>#", $chunk, $match))
@@ -153,7 +145,7 @@ function auto_typography($str, $reduce_linebreaks = FALSE)
 				{
 					$process =  ($match[1] == '/') ? TRUE : FALSE;
 				}
-				
+
 				if ($match[1] == '')
 				{
 					$this->last_block_element = $match[2];
@@ -162,32 +154,32 @@ function auto_typography($str, $reduce_linebreaks = FALSE)
 				$str .= $chunk;
 				continue;
 			}
-			
+
 			if ($process == FALSE)
 			{
 				$str .= $chunk;
 				continue;
 			}
-			
+
 			//  Force a newline to make sure end tags get processed by _format_newlines()
 			if ($current_chunk == $total_chunks)
 			{
-				$chunk .= "\n";  
+				$chunk .= "\n";
 			}
-			
+
 			//  Convert Newlines into 

and
tags $str .= $this->_format_newlines($chunk); } - + // No opening block level tag? Add it if needed. if ( ! preg_match("/^\s*<(?:".$this->block_elements.")/i", $str)) { $str = preg_replace("/^(.*?)<(".$this->block_elements.")/i", '

$1

<$2', $str); } - + // Convert quotes, elipsis, em-dashes, non-breaking spaces, and ampersands $str = $this->format_characters($str); - + // restore HTML comments for ($i = 0, $total = count($html_comments); $i < $total; $i++) { @@ -196,18 +188,18 @@ function auto_typography($str, $reduce_linebreaks = FALSE) // if '

{@HC1}' then replace

{@HC1}

with the comment, else replace only {@HC1} with the comment $str = preg_replace('#(?(?=

\{@HC'.$i.'\})

\{@HC'.$i.'\}(\s*

)|\{@HC'.$i.'\})#s', $html_comments[$i], $str); } - + // Final clean up $table = array( - + // If the user submitted their own paragraph tags within the text // we will retain them instead of using our tags. - '/(*?]>)

/' => '$1', // *?]>)

/' => '$1', // )+#' => '

', '/(

\W*

)+/' => '

', - + // Clean up stray paragraph tags that appear before block level elements '#

<('.$this->block_elements.')#' => '<$1', @@ -219,10 +211,19 @@ function auto_typography($str, $reduce_linebreaks = FALSE) '/\{@DQ\}/' => '"', '/\{@SQ\}/' => "'", '/\{@DD\}/' => '--', - '/\{@NBS\}/' => ' ' + '/\{@NBS\}/' => ' ', + // An unintended consequence of the _format_newlines function is that + // some of the newlines get truncated, resulting in

tags + // starting immediately after tags on the same line. + // This forces a newline after such occurrences, which looks much nicer. + "/>

\n/" => ">\n

", + + // Similarly, there might be cases where a closing will follow + // a closing

tag, so we'll correct it by adding a newline in between + "#

"

\n

#'] = '

 

'; } - + return preg_replace(array_keys($table), $table, $str); } - + // -------------------------------------------------------------------- - + /** * Format Characters * @@ -255,10 +256,10 @@ function auto_typography($str, $reduce_linebreaks = FALSE) function format_characters($str) { static $table; - + if ( ! isset($table)) { - $table = array( + $table = array( // nested smart quotes, opening and closing // note that rules for grammar (English) allow only for two levels deep // and that single quotes are _supposed_ to always be on the outside @@ -304,7 +305,7 @@ function format_characters($str) return preg_replace(array_keys($table), $table, $str); } - + // -------------------------------------------------------------------- /** @@ -315,47 +316,50 @@ function format_characters($str) * @access public * @param string * @return string - */ + */ function _format_newlines($str) { if ($str == '') { return $str; } - + if (strpos($str, "\n") === FALSE && ! in_array($this->last_block_element, $this->inner_block_required)) { return $str; } - + // Convert two consecutive newlines to paragraphs $str = str_replace("\n\n", "

\n\n

", $str); - + // Convert single spaces to
tags $str = preg_replace("/([^\n])(\n)([^\n])/", "\\1
\\2\\3", $str); - + // Wrap the whole enchilada in enclosing paragraphs if ($str != "\n") { - $str = '

'.$str.'

'; + // We trim off the right-side new line so that the closing

tag + // will be positioned immediately following the string, matching + // the behavior of the opening

tag + $str = '

'.rtrim($str).'

'; } // Remove empty paragraphs if they are on the first line, as this // is a potential unintended consequence of the previous code $str = preg_replace("/

<\/p>(.*)/", "\\1", $str, 1); - + return $str; } - + // ------------------------------------------------------------------------ - + /** * Protect Characters * * Protects special characters from being formatted later * We don't want quotes converted within tags so we'll temporarily convert them to {@DQ} and {@SQ} - * and we don't want double dashes converted to emdash entities, so they are marked with {@DD} - * likewise double spaces are converted to {@NBS} to prevent entity conversion + * and we don't want double dashes converted to emdash entities, so they are marked with {@DD} + * likewise double spaces are converted to {@NBS} to prevent entity conversion * * @access public * @param array @@ -367,19 +371,19 @@ function _protect_characters($match) } // -------------------------------------------------------------------- - + /** * Convert newlines to HTML line breaks except within PRE tags * * @access public * @param string * @return string - */ + */ function nl2br_except_pre($str) { $ex = explode("pre>",$str); $ct = count($ex); - + $newstr = ""; for ($i = 0; $i < $ct; $i++) { @@ -391,14 +395,14 @@ function nl2br_except_pre($str) { $newstr .= $ex[$i]; } - + if ($ct - 1 != $i) $newstr .= "pre>"; } - + return $newstr; } - + } // END Typography Class diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php index d1db6297..5bd7e801 100644 --- a/system/libraries/Unit_test.php +++ b/system/libraries/Unit_test.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.3.1 @@ -28,19 +28,50 @@ */ class CI_Unit_test { - var $active = TRUE; - var $results = array(); - var $strict = FALSE; - var $_template = NULL; - var $_template_rows = NULL; + var $active = TRUE; + var $results = array(); + var $strict = FALSE; + var $_template = NULL; + var $_template_rows = NULL; + var $_test_items_visible = array(); - function CI_Unit_test() + public function __construct() { + // These are the default items visible when a test is run. + $this->_test_items_visible = array ( + 'test_name', + 'test_datatype', + 'res_datatype', + 'result', + 'file', + 'line', + 'notes' + ); + log_message('debug', "Unit Testing Class Initialized"); - } + } // -------------------------------------------------------------------- - + + /** + * Run the tests + * + * Runs the supplied tests + * + * @access public + * @param array + * @return void + */ + function set_test_items($items = array()) + { + if ( ! empty($items) AND is_array($items)) + { + $this->_test_items_visible = $items; + } + } + + // -------------------------------------------------------------------- + /** * Run the tests * @@ -51,48 +82,49 @@ function CI_Unit_test() * @param mixed * @param string * @return string - */ - function run($test, $expected = TRUE, $test_name = 'undefined') + */ + function run($test, $expected = TRUE, $test_name = 'undefined', $notes = '') { if ($this->active == FALSE) { return FALSE; } - - if (in_array($expected, array('is_string', 'is_bool', 'is_true', 'is_false', 'is_int', 'is_numeric', 'is_float', 'is_double', 'is_array', 'is_null'), TRUE)) + + if (in_array($expected, array('is_object', 'is_string', 'is_bool', 'is_true', 'is_false', 'is_int', 'is_numeric', 'is_float', 'is_double', 'is_array', 'is_null'), TRUE)) { $expected = str_replace('is_float', 'is_double', $expected); - $result = ($expected($test)) ? TRUE : FALSE; + $result = ($expected($test)) ? TRUE : FALSE; $extype = str_replace(array('true', 'false'), 'bool', str_replace('is_', '', $expected)); } else { if ($this->strict == TRUE) - $result = ($test === $expected) ? TRUE : FALSE; + $result = ($test === $expected) ? TRUE : FALSE; else - $result = ($test == $expected) ? TRUE : FALSE; - + $result = ($test == $expected) ? TRUE : FALSE; + $extype = gettype($expected); } - + $back = $this->_backtrace(); - + $report[] = array ( 'test_name' => $test_name, 'test_datatype' => gettype($test), 'res_datatype' => $extype, 'result' => ($result === TRUE) ? 'passed' : 'failed', 'file' => $back['file'], - 'line' => $back['line'] + 'line' => $back['line'], + 'notes' => $notes ); - $this->results[] = $report; - + $this->results[] = $report; + return($this->report($this->result($report))); } // -------------------------------------------------------------------- - + /** * Generate a report * @@ -120,7 +152,6 @@ function report($result = array()) foreach ($res as $key => $val) { - if ($key == $CI->lang->line('ut_result')) { if ($val == $CI->lang->line('ut_passed')) @@ -144,9 +175,9 @@ function report($result = array()) return $r; } - + // -------------------------------------------------------------------- - + /** * Use strict comparison * @@ -160,9 +191,9 @@ function use_strict($state = TRUE) { $this->strict = ($state == FALSE) ? FALSE : TRUE; } - + // -------------------------------------------------------------------- - + /** * Make Unit testing active * @@ -176,9 +207,9 @@ function active($state = TRUE) { $this->active = ($state == FALSE) ? FALSE : TRUE; } - + // -------------------------------------------------------------------- - + /** * Result Array * @@ -188,21 +219,26 @@ function active($state = TRUE) * @return array */ function result($results = array()) - { + { $CI =& get_instance(); $CI->load->language('unit_test'); - + if (count($results) == 0) { $results = $this->results; } - + $retval = array(); foreach ($results as $result) { $temp = array(); foreach ($result as $key => $val) { + if ( ! in_array($key, $this->_test_items_visible)) + { + continue; + } + if (is_array($val)) { foreach ($val as $k => $v) @@ -210,8 +246,8 @@ function result($results = array()) if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$v)))) { $v = $line; - } - $temp[$CI->lang->line('ut_'.$k)] = $v; + } + $temp[$CI->lang->line('ut_'.$k)] = $v; } } else @@ -219,19 +255,19 @@ function result($results = array()) if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$val)))) { $val = $line; - } + } $temp[$CI->lang->line('ut_'.$key)] = $val; } } - + $retval[] = $temp; } - + return $retval; } - + // -------------------------------------------------------------------- - + /** * Set the template * @@ -240,14 +276,14 @@ function result($results = array()) * @access public * @param string * @return void - */ + */ function set_template($template) { $this->_template = $template; } - + // -------------------------------------------------------------------- - + /** * Generate a backtrace * @@ -261,17 +297,17 @@ function _backtrace() if (function_exists('debug_backtrace')) { $back = debug_backtrace(); - + $file = ( ! isset($back['1']['file'])) ? '' : $back['1']['file']; $line = ( ! isset($back['1']['line'])) ? '' : $back['1']['line']; - + return array('file' => $file, 'line' => $line); } return array('file' => 'Unknown', 'line' => 'Unknown'); } // -------------------------------------------------------------------- - + /** * Get Default Template * @@ -279,17 +315,17 @@ function _backtrace() * @return string */ function _default_template() - { + { $this->_template = "\n".''; $this->_template .= '{rows}'; $this->_template .= "\n".'
'; - + $this->_template_rows = "\n\t".''; $this->_template_rows .= "\n\t\t".'{item}'; $this->_template_rows .= "\n\t\t".'{result}'; - $this->_template_rows .= "\n\t".''; + $this->_template_rows .= "\n\t".''; } - + // -------------------------------------------------------------------- /** @@ -300,29 +336,29 @@ function _default_template() * @access private * @return void */ - function _parse_template() - { - if ( ! is_null($this->_template_rows)) - { - return; - } - - if (is_null($this->_template)) - { - $this->_default_template(); - return; - } - + function _parse_template() + { + if ( ! is_null($this->_template_rows)) + { + return; + } + + if (is_null($this->_template)) + { + $this->_default_template(); + return; + } + if ( ! preg_match("/\{rows\}(.*?)\{\/rows\}/si", $this->_template, $match)) { - $this->_default_template(); - return; + $this->_default_template(); + return; } $this->_template_rows = $match['1']; - $this->_template = str_replace($match['0'], '{rows}', $this->_template); - } - + $this->_template = str_replace($match['0'], '{rows}', $this->_template); + } + } // END Unit_test Class diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php index 618c49be..0e5d73b1 100644 --- a/system/libraries/Upload.php +++ b/system/libraries/Upload.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -25,57 +25,59 @@ * @link http://codeigniter.com/user_guide/libraries/file_uploading.html */ class CI_Upload { - - var $max_size = 0; - var $max_width = 0; - var $max_height = 0; - var $max_filename = 0; - var $allowed_types = ""; - var $file_temp = ""; - var $file_name = ""; - var $orig_name = ""; - var $file_type = ""; - var $file_size = ""; - var $file_ext = ""; - var $upload_path = ""; - var $overwrite = FALSE; - var $encrypt_name = FALSE; - var $is_image = FALSE; - var $image_width = ''; - var $image_height = ''; - var $image_type = ''; - var $image_size_str = ''; - var $error_msg = array(); - var $mimes = array(); - var $remove_spaces = TRUE; - var $xss_clean = FALSE; - var $temp_prefix = "temp_file_"; - + + public $max_size = 0; + public $max_width = 0; + public $max_height = 0; + public $max_filename = 0; + public $allowed_types = ""; + public $file_temp = ""; + public $file_name = ""; + public $orig_name = ""; + public $file_type = ""; + public $file_size = ""; + public $file_ext = ""; + public $upload_path = ""; + public $overwrite = FALSE; + public $encrypt_name = FALSE; + public $is_image = FALSE; + public $image_width = ''; + public $image_height = ''; + public $image_type = ''; + public $image_size_str = ''; + public $error_msg = array(); + public $mimes = array(); + public $remove_spaces = TRUE; + public $xss_clean = FALSE; + public $temp_prefix = "temp_file_"; + public $client_name = ''; + + protected $_file_name_override = ''; + /** * Constructor * * @access public */ - function CI_Upload($props = array()) + public function __construct($props = array()) { if (count($props) > 0) { $this->initialize($props); } - + log_message('debug', "Upload Class Initialized"); } - + // -------------------------------------------------------------------- - + /** * Initialize preferences * - * @access public * @param array * @return void - */ - function initialize($config = array()) + */ + public function initialize($config = array()) { $defaults = array( 'max_size' => 0, @@ -101,10 +103,11 @@ function initialize($config = array()) 'mimes' => array(), 'remove_spaces' => TRUE, 'xss_clean' => FALSE, - 'temp_prefix' => "temp_file_" - ); - - + 'temp_prefix' => "temp_file_", + 'client_name' => '' + ); + + foreach ($defaults as $key => $val) { if (isset($config[$key])) @@ -117,32 +120,36 @@ function initialize($config = array()) else { $this->$key = $config[$key]; - } + } } else { $this->$key = $val; } } + + // if a file_name was provided in the config, use it instead of the user input + // supplied file name for all uploads until initialized again + $this->_file_name_override = $this->file_name; } - + // -------------------------------------------------------------------- - + /** * Perform the file upload * - * @access public * @return bool - */ - function do_upload($field = 'userfile') + */ + public function do_upload($field = 'userfile') { - // Is $_FILES[$field] set? If not, no reason to continue. + + // Is $_FILES[$field] set? If not, no reason to continue. if ( ! isset($_FILES[$field])) { $this->set_error('upload_no_file_selected'); return FALSE; } - + // Is the upload path valid? if ( ! $this->validate_upload_path()) { @@ -164,10 +171,10 @@ function do_upload($field = 'userfile') $this->set_error('upload_file_exceeds_form_limit'); break; case 3: // UPLOAD_ERR_PARTIAL - $this->set_error('upload_file_partial'); + $this->set_error('upload_file_partial'); break; case 4: // UPLOAD_ERR_NO_FILE - $this->set_error('upload_no_file_selected'); + $this->set_error('upload_no_file_selected'); break; case 6: // UPLOAD_ERR_NO_TMP_DIR $this->set_error('upload_no_temp_directory'); @@ -185,19 +192,16 @@ function do_upload($field = 'userfile') return FALSE; } + // Set the uploaded data as class variables - $this->file_temp = $_FILES[$field]['tmp_name']; + $this->file_temp = $_FILES[$field]['tmp_name']; + $this->file_size = $_FILES[$field]['size']; + $this->_file_mime_type($_FILES[$field]); + $this->file_type = preg_replace("/^(.+?);.*$/", "\\1", $this->file_type); + $this->file_type = strtolower(trim(stripslashes($this->file_type), '"')); $this->file_name = $this->_prep_filename($_FILES[$field]['name']); - $this->file_size = $_FILES[$field]['size']; - $this->file_type = preg_replace("/^(.+?);.*$/", "\\1", $_FILES[$field]['type']); - $this->file_type = strtolower($this->file_type); - $this->file_ext = $this->get_extension($_FILES[$field]['name']); - - // Convert the file size to kilobytes - if ($this->file_size > 0) - { - $this->file_size = round($this->file_size/1024, 2); - } + $this->file_ext = $this->get_extension($this->file_name); + $this->client_name = $this->file_name; // Is the file type allowed to be uploaded? if ( ! $this->is_allowed_filetype()) @@ -206,6 +210,36 @@ function do_upload($field = 'userfile') return FALSE; } + // if we're overriding, let's now make sure the new name and type is allowed + if ($this->_file_name_override != '') + { + $this->file_name = $this->_prep_filename($this->_file_name_override); + + // If no extension was provided in the file_name config item, use the uploaded one + if (strpos($this->_file_name_override, '.') === FALSE) + { + $this->file_name .= $this->file_ext; + } + + // An extension was provided, lets have it! + else + { + $this->file_ext = $this->get_extension($this->_file_name_override); + } + + if ( ! $this->is_allowed_filetype(TRUE)) + { + $this->set_error('upload_invalid_filetype'); + return FALSE; + } + } + + // Convert the file size to kilobytes + if ($this->file_size > 0) + { + $this->file_size = round($this->file_size/1024, 2); + } + // Is the file size within the allowed maximum? if ( ! $this->is_allowed_filesize()) { @@ -223,7 +257,7 @@ function do_upload($field = 'userfile') // Sanitize the file name for security $this->file_name = $this->clean_file_name($this->file_name); - + // Truncate the file name if it's too long if ($this->max_filename > 0) { @@ -247,13 +281,28 @@ function do_upload($field = 'userfile') if ($this->overwrite == FALSE) { $this->file_name = $this->set_filename($this->upload_path, $this->file_name); - + if ($this->file_name === FALSE) { return FALSE; } } + /* + * Run the file through the XSS hacking filter + * This helps prevent malicious code from being + * embedded within a file. Scripts can easily + * be disguised as images or other file types. + */ + if ($this->xss_clean) + { + if ($this->do_xss_clean() === FALSE) + { + $this->set_error('upload_unable_to_write_file'); + return FALSE; + } + } + /* * Move the file to the final destination * To deal with different server configurations @@ -265,21 +314,10 @@ function do_upload($field = 'userfile') { if ( ! @move_uploaded_file($this->file_temp, $this->upload_path.$this->file_name)) { - $this->set_error('upload_destination_error'); - return FALSE; + $this->set_error('upload_destination_error'); + return FALSE; } } - - /* - * Run the file through the XSS hacking filter - * This helps prevent malicious code from being - * embedded within a file. Scripts can easily - * be disguised as images or other file types. - */ - if ($this->xss_clean == TRUE) - { - $this->do_xss_clean(); - } /* * Set the finalized image dimensions @@ -291,19 +329,18 @@ function do_upload($field = 'userfile') return TRUE; } - + // -------------------------------------------------------------------- - + /** * Finalized Data Array - * + * * Returns an associative array containing all of the information * related to the upload, allowing the developer easy access in one array. * - * @access public * @return array - */ - function data() + */ + public function data() { return array ( 'file_name' => $this->file_name, @@ -312,6 +349,7 @@ function data() 'full_path' => $this->upload_path.$this->file_name, 'raw_name' => str_replace($this->file_ext, '', $this->file_name), 'orig_name' => $this->orig_name, + 'client_name' => $this->client_name, 'file_ext' => $this->file_ext, 'file_size' => $this->file_size, 'is_image' => $this->is_image(), @@ -321,24 +359,23 @@ function data() 'image_size_str' => $this->image_size_str, ); } - + // -------------------------------------------------------------------- - + /** * Set Upload Path * - * @access public * @param string * @return void - */ - function set_upload_path($path) + */ + public function set_upload_path($path) { // Make sure it has a trailing slash $this->upload_path = rtrim($path, '/').'/'; } - + // -------------------------------------------------------------------- - + /** * Set the file name * @@ -346,29 +383,28 @@ function set_upload_path($path) * existence of a file with the same name. If found, it will append a * number to the end of the filename to avoid overwriting a pre-existing file. * - * @access public * @param string * @param string * @return string - */ - function set_filename($path, $filename) + */ + public function set_filename($path, $filename) { if ($this->encrypt_name == TRUE) - { + { mt_srand(); - $filename = md5(uniqid(mt_rand())).$this->file_ext; + $filename = md5(uniqid(mt_rand())).$this->file_ext; } - + if ( ! file_exists($path.$filename)) { return $filename; } - + $filename = str_replace($this->file_ext, '', $filename); - + $new_filename = ''; for ($i = 1; $i < 100; $i++) - { + { if ( ! file_exists($path.$filename.$i.$this->file_ext)) { $new_filename = $filename.$i.$this->file_ext; @@ -386,89 +422,88 @@ function set_filename($path, $filename) return $new_filename; } } - + // -------------------------------------------------------------------- - + /** * Set Maximum File Size * - * @access public * @param integer * @return void - */ - function set_max_filesize($n) + */ + public function set_max_filesize($n) { $this->max_size = ((int) $n < 0) ? 0: (int) $n; } - + // -------------------------------------------------------------------- - + /** * Set Maximum File Name Length * - * @access public * @param integer * @return void - */ - function set_max_filename($n) + */ + public function set_max_filename($n) { $this->max_filename = ((int) $n < 0) ? 0: (int) $n; } // -------------------------------------------------------------------- - + /** * Set Maximum Image Width * - * @access public * @param integer * @return void - */ - function set_max_width($n) + */ + public function set_max_width($n) { $this->max_width = ((int) $n < 0) ? 0: (int) $n; } - + // -------------------------------------------------------------------- - + /** * Set Maximum Image Height * - * @access public * @param integer * @return void - */ - function set_max_height($n) + */ + public function set_max_height($n) { $this->max_height = ((int) $n < 0) ? 0: (int) $n; } - + // -------------------------------------------------------------------- - + /** * Set Allowed File Types * - * @access public * @param string * @return void - */ - function set_allowed_types($types) + */ + public function set_allowed_types($types) { + if ( ! is_array($types) && $types == '*') + { + $this->allowed_types = '*'; + return; + } $this->allowed_types = explode('|', $types); } - + // -------------------------------------------------------------------- - + /** * Set Image Properties * * Uses GD to determine the width/height/type of image * - * @access public * @param string * @return void - */ - function set_image_properties($path = '') + */ + public function set_image_properties($path = '') { if ( ! $this->is_image()) { @@ -478,7 +513,7 @@ function set_image_properties($path = '') if (function_exists('getimagesize')) { if (FALSE !== ($D = @getimagesize($path))) - { + { $types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png'); $this->image_width = $D['0']; @@ -488,45 +523,43 @@ function set_image_properties($path = '') } } } - + // -------------------------------------------------------------------- - + /** * Set XSS Clean * * Enables the XSS flag so that the file that was uploaded * will be run through the XSS filter. * - * @access public * @param bool * @return void */ - function set_xss_clean($flag = FALSE) + public function set_xss_clean($flag = FALSE) { $this->xss_clean = ($flag == TRUE) ? TRUE : FALSE; } - + // -------------------------------------------------------------------- - + /** * Validate the image * - * @access public * @return bool - */ - function is_image() + */ + public function is_image() { // IE will sometimes return odd mime-types during upload, so here we just standardize all // jpegs or pngs to the same file type. $png_mimes = array('image/x-png'); $jpeg_mimes = array('image/jpg', 'image/jpe', 'image/jpeg', 'image/pjpeg'); - + if (in_array($this->file_type, $png_mimes)) { $this->file_type = 'image/png'; } - + if (in_array($this->file_type, $jpeg_mimes)) { $this->file_type = 'image/jpeg'; @@ -536,70 +569,79 @@ function is_image() 'image/gif', 'image/jpeg', 'image/png', - ); + ); return (in_array($this->file_type, $img_mimes, TRUE)) ? TRUE : FALSE; } - + // -------------------------------------------------------------------- - + /** * Verify that the filetype is allowed * - * @access public * @return bool - */ - function is_allowed_filetype() + */ + public function is_allowed_filetype($ignore_mime = FALSE) { + if ($this->allowed_types == '*') + { + return TRUE; + } + if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types)) { $this->set_error('upload_no_file_types'); return FALSE; } - $image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe'); + $ext = strtolower(ltrim($this->file_ext, '.')); - foreach ($this->allowed_types as $val) + if ( ! in_array($ext, $this->allowed_types)) { - $mime = $this->mimes_types(strtolower($val)); + return FALSE; + } - // Images get some additional checks - if (in_array($val, $image_types)) + // Images get some additional checks + $image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe'); + + if (in_array($ext, $image_types)) + { + if (getimagesize($this->file_temp) === FALSE) { - if (getimagesize($this->file_temp) === FALSE) - { - return FALSE; - } + return FALSE; } + } + + if ($ignore_mime === TRUE) + { + return TRUE; + } - if (is_array($mime)) + $mime = $this->mimes_types($ext); + + if (is_array($mime)) + { + if (in_array($this->file_type, $mime, TRUE)) { - if (in_array($this->file_type, $mime, TRUE)) - { - return TRUE; - } + return TRUE; } - else - { - if ($mime == $this->file_type) - { - return TRUE; - } - } } - + elseif ($mime == $this->file_type) + { + return TRUE; + } + return FALSE; } - + // -------------------------------------------------------------------- - + /** * Verify that the file is within the allowed size * - * @access public * @return bool - */ - function is_allowed_filesize() + */ + public function is_allowed_filesize() { if ($this->max_size != 0 AND $this->file_size > $this->max_size) { @@ -610,16 +652,15 @@ function is_allowed_filesize() return TRUE; } } - + // -------------------------------------------------------------------- - + /** * Verify that the image is within the allowed width/height * - * @access public * @return bool - */ - function is_allowed_dimensions() + */ + public function is_allowed_dimensions() { if ( ! $this->is_image()) { @@ -645,26 +686,25 @@ function is_allowed_dimensions() return TRUE; } - + // -------------------------------------------------------------------- - + /** * Validate Upload Path * * Verifies that it is a valid upload path with proper permissions. * * - * @access public * @return bool - */ - function validate_upload_path() + */ + public function validate_upload_path() { if ($this->upload_path == '') { $this->set_error('upload_no_filepath'); return FALSE; } - + if (function_exists('realpath') AND @realpath($this->upload_path) !== FALSE) { $this->upload_path = str_replace("\\", "/", realpath($this->upload_path)); @@ -685,32 +725,30 @@ function validate_upload_path() $this->upload_path = preg_replace("/(.+?)\/*$/", "\\1/", $this->upload_path); return TRUE; } - + // -------------------------------------------------------------------- - + /** * Extract the file extension * - * @access public * @param string * @return string - */ - function get_extension($filename) + */ + public function get_extension($filename) { $x = explode('.', $filename); return '.'.end($x); - } - + } + // -------------------------------------------------------------------- - + /** * Clean the file name for security * - * @access public * @param string * @return string - */ - function clean_file_name($filename) + */ + public function clean_file_name($filename) { $bad = array( "\n"; } - + return $r; } - //------------------------------------- - // Executes the Method - //------------------------------------- - + // -------------------------------------------------------------------- + + /** + * Executes the Method + * + * @access protected + * @param object + * @return mixed + */ function _execute($m) { $methName = $m->method_name; - + // Check to see if it is a system call $system_call = (strncmp($methName, 'system', 5) == 0) ? TRUE : FALSE; - + + if ($this->xss_clean == FALSE) + { + $m->xss_clean = FALSE; + } + //------------------------------------- // Valid Method //------------------------------------- - + if ( ! isset($this->methods[$methName]['function'])) { return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); } - + //------------------------------------- // Check for Method (and Object) //------------------------------------- - + $method_parts = explode(".", $this->methods[$methName]['function']); $objectCall = (isset($method_parts['1']) && $method_parts['1'] != "") ? TRUE : FALSE; - + if ($system_call === TRUE) { if ( ! is_callable(array($this,$method_parts['1']))) @@ -281,30 +318,30 @@ function _execute($m) return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); } } - + //------------------------------------- // Checking Methods Signature //------------------------------------- - + if (isset($this->methods[$methName]['signature'])) { $sig = $this->methods[$methName]['signature']; - for($i=0; $iparams)+1) { - for($n=0; $n < count($m->params); $n++) + for ($n=0; $n < count($m->params); $n++) { $p = $m->params[$n]; $pt = ($p->kindOf() == 'scalar') ? $p->scalarval() : $p->kindOf(); - + if ($pt != $current_sig[$n+1]) { $pno = $n+1; $wanted = $current_sig[$n+1]; - + return new XML_RPC_Response(0, $this->xmlrpcerr['incorrect_params'], $this->xmlrpcstr['incorrect_params'] . @@ -345,22 +382,26 @@ function _execute($m) } } - - //------------------------------------- - // Server Function: List Methods - //------------------------------------- - + // -------------------------------------------------------------------- + + /** + * Server Function: List Methods + * + * @access public + * @param mixed + * @return object + */ function listMethods($m) { $v = new XML_RPC_Values(); $output = array(); - - foreach($this->methods as $key => $value) + + foreach ($this->methods as $key => $value) { $output[] = new XML_RPC_Values($key, 'string'); } - - foreach($this->system_methods as $key => $value) + + foreach ($this->system_methods as $key => $value) { $output[]= new XML_RPC_Values($key, 'string'); } @@ -369,27 +410,32 @@ function listMethods($m) return new XML_RPC_Response($v); } - //------------------------------------- - // Server Function: Return Signature for Method - //------------------------------------- - + // -------------------------------------------------------------------- + + /** + * Server Function: Return Signature for Method + * + * @access public + * @param mixed + * @return object + */ function methodSignature($m) { $parameters = $m->output_parameters(); $method_name = $parameters[0]; - + if (isset($this->methods[$method_name])) { if ($this->methods[$method_name]['signature']) { $sigs = array(); $signature = $this->methods[$method_name]['signature']; - - for($i=0; $i < count($signature); $i++) + + for ($i=0; $i < count($signature); $i++) { $cursig = array(); $inSig = $signature[$i]; - for($j=0; $joutput_parameters(); $method_name = $parameters[0]; - + if (isset($this->methods[$method_name])) { $docstring = isset($this->methods[$method_name]['docstring']) ? $this->methods[$method_name]['docstring'] : ''; - + return new XML_RPC_Response(new XML_RPC_Values($docstring, 'string')); } else @@ -429,16 +480,21 @@ function methodHelp($m) return new XML_RPC_Response(0, $this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']); } } - - //------------------------------------- - // Server Function: Multi-call - //------------------------------------- - + + // -------------------------------------------------------------------- + + /** + * Server Function: Multi-call + * + * @access public + * @param mixed + * @return object + */ function multicall($m) { // Disabled return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']); - + $parameters = $m->output_parameters(); $calls = $parameters[0]; @@ -447,15 +503,15 @@ function multicall($m) foreach ($calls as $value) { //$attempt = $this->_execute(new XML_RPC_Message($value[0], $value[1])); - + $m = new XML_RPC_Message($value[0]); $plist=''; - - for($i=0; $i < count($value[1]); $i++) + + for ($i=0; $i < count($value[1]); $i++) { $m->addParam(new XML_RPC_Values($value[1][$i], 'string')); } - + $attempt = $this->_execute($m); if ($attempt->faultCode() != 0) @@ -468,47 +524,67 @@ function multicall($m) return new XML_RPC_Response(new XML_RPC_Values($result, 'array')); } - - - //------------------------------------- - // Multi-call Function: Error Handling - //------------------------------------- + // -------------------------------------------------------------------- + + /** + * Multi-call Function: Error Handling + * + * @access public + * @param mixed + * @return object + */ function multicall_error($err) { $str = is_string($err) ? $this->xmlrpcstr["multicall_${err}"] : $err->faultString(); $code = is_string($err) ? $this->xmlrpcerr["multicall_${err}"] : $err->faultCode(); - + $struct['faultCode'] = new XML_RPC_Values($code, 'int'); $struct['faultString'] = new XML_RPC_Values($str, 'string'); - + return new XML_RPC_Values($struct, 'struct'); } - - - //------------------------------------- - // Multi-call Function: Processes method - //------------------------------------- - + + // -------------------------------------------------------------------- + + /** + * Multi-call Function: Processes method + * + * @access public + * @param mixed + * @return object + */ function do_multicall($call) { if ($call->kindOf() != 'struct') + { return $this->multicall_error('notstruct'); + } elseif ( ! $methName = $call->me['struct']['methodName']) + { return $this->multicall_error('nomethod'); - + } + list($scalar_type,$scalar_value)=each($methName->me); $scalar_type = $scalar_type == $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type; - + if ($methName->kindOf() != 'scalar' OR $scalar_type != 'string') + { return $this->multicall_error('notstring'); + } elseif ($scalar_value == 'system.multicall') + { return $this->multicall_error('recursion'); + } elseif ( ! $params = $call->me['struct']['params']) + { return $this->multicall_error('noparams'); + } elseif ($params->kindOf() != 'array') + { return $this->multicall_error('notarray'); - + } + list($a,$b)=each($params->me); $numParams = count($b); @@ -526,8 +602,8 @@ function do_multicall($call) } return new XML_RPC_Values(array($result->value()), 'array'); - } - + } + } // END XML_RPC_Server class diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php index f81da856..666327d5 100644 --- a/system/libraries/Zip.php +++ b/system/libraries/Zip.php @@ -2,11 +2,11 @@ /** * CodeIgniter * - * An open source application development framework for PHP 4.3.2 or newer + * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team - * @copyright Copyright (c) 2008 - 2009, EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 @@ -32,15 +32,21 @@ */ class CI_Zip { - var $zipdata = ''; - var $directory = ''; - var $entries = 0; - var $file_num = 0; + var $zipdata = ''; + var $directory = ''; + var $entries = 0; + var $file_num = 0; var $offset = 0; + var $now; - function CI_Zip() + /** + * Constructor + */ + public function __construct() { log_message('debug', "Zip Compression Class Initialized"); + + $this->now = time(); } // -------------------------------------------------------------------- @@ -63,12 +69,35 @@ function add_dir($directory) $dir .= '/'; } - $this->_add_dir($dir); + $dir_time = $this->_get_mod_time($dir); + + $this->_add_dir($dir, $dir_time['file_mtime'], $dir_time['file_mdate']); } } // -------------------------------------------------------------------- + /** + * Get file/directory modification time + * + * If this is a newly created file/dir, we will set the time to 'now' + * + * @param string path to file + * @return array filemtime/filemdate + */ + function _get_mod_time($dir) + { + // filemtime() will return false, but it does raise an error. + $date = (@filemtime($dir)) ? filemtime($dir) : getdate($this->now); + + $time['file_mtime'] = ($date['hours'] << 11) + ($date['minutes'] << 5) + $date['seconds'] / 2; + $time['file_mdate'] = (($date['year'] - 1980) << 9) + ($date['mon'] << 5) + $date['mday']; + + return $time; + } + + // -------------------------------------------------------------------- + /** * Add Directory * @@ -76,12 +105,14 @@ function add_dir($directory) * @param string the directory name * @return void */ - function _add_dir($dir) + function _add_dir($dir, $file_mtime, $file_mdate) { $dir = str_replace("\\", "/", $dir); $this->zipdata .= - "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) .pack('V', 0) // crc32 .pack('V', 0) // compressed filesize .pack('V', 0) // uncompressed filesize @@ -94,7 +125,9 @@ function _add_dir($dir) .pack('V', 0); // uncompressed filesize $this->directory .= - "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) .pack('V',0) // crc32 .pack('V',0) // compressed filesize .pack('V',0) // uncompressed filesize @@ -110,7 +143,7 @@ function _add_dir($dir) $this->offset = strlen($this->zipdata); $this->entries++; } - + // -------------------------------------------------------------------- /** @@ -124,19 +157,23 @@ function _add_dir($dir) * @param mixed * @param string * @return void - */ + */ function add_data($filepath, $data = NULL) { if (is_array($filepath)) { foreach ($filepath as $path => $data) { - $this->_add_data($path, $data); + $file_data = $this->_get_mod_time($path); + + $this->_add_data($path, $data, $file_data['file_mtime'], $file_data['file_mdate']); } } else { - $this->_add_data($filepath, $data); + $file_data = $this->_get_mod_time($filepath); + + $this->_add_data($filepath, $data, $file_data['file_mtime'], $file_data['file_mdate']); } } @@ -149,8 +186,8 @@ function add_data($filepath, $data = NULL) * @param string the file name/path * @param string the data to be encoded * @return void - */ - function _add_data($filepath, $data) + */ + function _add_data($filepath, $data, $file_mtime, $file_mdate) { $filepath = str_replace("\\", "/", $filepath); @@ -162,7 +199,9 @@ function _add_data($filepath, $data) $compressed_size = strlen($gzdata); $this->zipdata .= - "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00" + "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) .pack('V', $crc32) .pack('V', $compressed_size) .pack('V', $uncompressed_size) @@ -172,7 +211,9 @@ function _add_data($filepath, $data) .$gzdata; // "file data" segment $this->directory .= - "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00\x00\x00\x00\x00" + "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00" + .pack('v', $file_mtime) + .pack('v', $file_mdate) .pack('V', $crc32) .pack('V', $compressed_size) .pack('V', $uncompressed_size) @@ -189,7 +230,7 @@ function _add_data($filepath, $data) $this->entries++; $this->file_num++; } - + // -------------------------------------------------------------------- /** @@ -197,7 +238,7 @@ function _add_data($filepath, $data) * * @access public * @return bool - */ + */ function read_file($path, $preserve_filepath = FALSE) { if ( ! file_exists($path)) @@ -208,7 +249,7 @@ function read_file($path, $preserve_filepath = FALSE) if (FALSE !== ($data = file_get_contents($path))) { $name = str_replace("\\", "/", $path); - + if ($preserve_filepath === FALSE) { $name = preg_replace("|.*/(.+)|", "\\1", $name); @@ -221,7 +262,7 @@ function read_file($path, $preserve_filepath = FALSE) } // ------------------------------------------------------------------------ - + /** * Read a directory and add it to the zip. * @@ -232,27 +273,48 @@ function read_file($path, $preserve_filepath = FALSE) * @access public * @param string path to source * @return bool - */ - function read_dir($path) - { - if ($fp = @opendir($path)) + */ + function read_dir($path, $preserve_filepath = TRUE, $root_path = NULL) + { + if ( ! $fp = @opendir($path)) { - while (FALSE !== ($file = readdir($fp))) + return FALSE; + } + + // Set the original directory root for child dir's to use as relative + if ($root_path === NULL) + { + $root_path = dirname($path).'/'; + } + + while (FALSE !== ($file = readdir($fp))) + { + if (substr($file, 0, 1) == '.') { - if (@is_dir($path.$file) && substr($file, 0, 1) != '.') - { - $this->read_dir($path.$file."/"); - } - elseif (substr($file, 0, 1) != ".") + continue; + } + + if (@is_dir($path.$file)) + { + $this->read_dir($path.$file."/", $preserve_filepath, $root_path); + } + else + { + if (FALSE !== ($data = file_get_contents($path.$file))) { - if (FALSE !== ($data = file_get_contents($path.$file))) - { - $this->add_data(str_replace("\\", "/", $path).$file, $data); + $name = str_replace("\\", "/", $path); + + if ($preserve_filepath === FALSE) + { + $name = str_replace($root_path, '', $name); } + + $this->add_data($name.$file, $data); } } - return TRUE; } + + return TRUE; } // -------------------------------------------------------------------- @@ -262,7 +324,7 @@ function read_dir($path) * * @access public * @return binary string - */ + */ function get_zip() { // Is there any data to return? @@ -281,7 +343,7 @@ function get_zip() return $zip_data; } - + // -------------------------------------------------------------------- /** @@ -292,7 +354,7 @@ function get_zip() * @access public * @param string the file name * @return bool - */ + */ function archive($filepath) { if ( ! ($fp = @fopen($filepath, FOPEN_WRITE_CREATE_DESTRUCTIVE))) @@ -300,12 +362,12 @@ function archive($filepath) return FALSE; } - flock($fp, LOCK_EX); + flock($fp, LOCK_EX); fwrite($fp, $this->get_zip()); flock($fp, LOCK_UN); fclose($fp); - return TRUE; + return TRUE; } // -------------------------------------------------------------------- @@ -325,11 +387,13 @@ function download($filename = 'backup.zip') $filename .= '.zip'; } - $zip_content =& $this->get_zip(); - $CI =& get_instance(); $CI->load->helper('download'); + $get_zip = $this->get_zip(); + + $zip_content =& $get_zip; + force_download($filename, $zip_content); } @@ -343,7 +407,7 @@ function download($filename = 'backup.zip') * * @access public * @return void - */ + */ function clear_data() { $this->zipdata = ''; @@ -352,7 +416,7 @@ function clear_data() $this->file_num = 0; $this->offset = 0; } - + } /* End of file Zip.php */ diff --git a/system/libraries/javascript/Jquery.php b/system/libraries/javascript/Jquery.php new file mode 100644 index 00000000..baab83d2 --- /dev/null +++ b/system/libraries/javascript/Jquery.php @@ -0,0 +1,1071 @@ +CI =& get_instance(); + extract($params); + + if ($autoload === TRUE) + { + $this->script(); + } + + log_message('debug', "Jquery Class Initialized"); + } + + // -------------------------------------------------------------------- + // Event Code + // -------------------------------------------------------------------- + + /** + * Blur + * + * Outputs a jQuery blur event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _blur($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'blur'); + } + + // -------------------------------------------------------------------- + + /** + * Change + * + * Outputs a jQuery change event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _change($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'change'); + } + + // -------------------------------------------------------------------- + + /** + * Click + * + * Outputs a jQuery click event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @param boolean whether or not to return false + * @return string + */ + function _click($element = 'this', $js = '', $ret_false = TRUE) + { + if ( ! is_array($js)) + { + $js = array($js); + } + + if ($ret_false) + { + $js[] = "return false;"; + } + + return $this->_add_event($element, $js, 'click'); + } + + // -------------------------------------------------------------------- + + /** + * Double Click + * + * Outputs a jQuery dblclick event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _dblclick($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'dblclick'); + } + + // -------------------------------------------------------------------- + + /** + * Error + * + * Outputs a jQuery error event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _error($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'error'); + } + + // -------------------------------------------------------------------- + + /** + * Focus + * + * Outputs a jQuery focus event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _focus($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'focus'); + } + + // -------------------------------------------------------------------- + + /** + * Hover + * + * Outputs a jQuery hover event + * + * @access private + * @param string - element + * @param string - Javascript code for mouse over + * @param string - Javascript code for mouse out + * @return string + */ + function _hover($element = 'this', $over, $out) + { + $event = "\n\t$(" . $this->_prep_element($element) . ").hover(\n\t\tfunction()\n\t\t{\n\t\t\t{$over}\n\t\t}, \n\t\tfunction()\n\t\t{\n\t\t\t{$out}\n\t\t});\n"; + + $this->jquery_code_for_compile[] = $event; + + return $event; + } + + // -------------------------------------------------------------------- + + /** + * Keydown + * + * Outputs a jQuery keydown event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _keydown($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'keydown'); + } + + // -------------------------------------------------------------------- + + /** + * Keyup + * + * Outputs a jQuery keydown event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _keyup($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'keyup'); + } + + // -------------------------------------------------------------------- + + /** + * Load + * + * Outputs a jQuery load event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _load($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'load'); + } + + // -------------------------------------------------------------------- + + /** + * Mousedown + * + * Outputs a jQuery mousedown event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _mousedown($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'mousedown'); + } + + // -------------------------------------------------------------------- + + /** + * Mouse Out + * + * Outputs a jQuery mouseout event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _mouseout($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'mouseout'); + } + + // -------------------------------------------------------------------- + + /** + * Mouse Over + * + * Outputs a jQuery mouseover event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _mouseover($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'mouseover'); + } + + // -------------------------------------------------------------------- + + /** + * Mouseup + * + * Outputs a jQuery mouseup event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _mouseup($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'mouseup'); + } + + // -------------------------------------------------------------------- + + /** + * Output + * + * Outputs script directly + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _output($array_js = '') + { + if ( ! is_array($array_js)) + { + $array_js = array($array_js); + } + + foreach ($array_js as $js) + { + $this->jquery_code_for_compile[] = "\t$js\n"; + } + } + + // -------------------------------------------------------------------- + + /** + * Resize + * + * Outputs a jQuery resize event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _resize($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'resize'); + } + + // -------------------------------------------------------------------- + + /** + * Scroll + * + * Outputs a jQuery scroll event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _scroll($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'scroll'); + } + + // -------------------------------------------------------------------- + + /** + * Unload + * + * Outputs a jQuery unload event + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @return string + */ + function _unload($element = 'this', $js = '') + { + return $this->_add_event($element, $js, 'unload'); + } + + // -------------------------------------------------------------------- + // Effects + // -------------------------------------------------------------------- + + /** + * Add Class + * + * Outputs a jQuery addClass event + * + * @access private + * @param string - element + * @return string + */ + function _addClass($element = 'this', $class='') + { + $element = $this->_prep_element($element); + $str = "$({$element}).addClass(\"$class\");"; + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Animate + * + * Outputs a jQuery animate event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _animate($element = 'this', $params = array(), $speed = '', $extra = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + $animations = "\t\t\t"; + + foreach ($params as $param=>$value) + { + $animations .= $param.': \''.$value.'\', '; + } + + $animations = substr($animations, 0, -2); // remove the last ", " + + if ($speed != '') + { + $speed = ', '.$speed; + } + + if ($extra != '') + { + $extra = ', '.$extra; + } + + $str = "$({$element}).animate({\n$animations\n\t\t}".$speed.$extra.");"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Fade In + * + * Outputs a jQuery hide event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _fadeIn($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).fadeIn({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Fade Out + * + * Outputs a jQuery hide event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _fadeOut($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).fadeOut({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Hide + * + * Outputs a jQuery hide action + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _hide($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).hide({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Remove Class + * + * Outputs a jQuery remove class event + * + * @access private + * @param string - element + * @return string + */ + function _removeClass($element = 'this', $class='') + { + $element = $this->_prep_element($element); + $str = "$({$element}).removeClass(\"$class\");"; + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Slide Up + * + * Outputs a jQuery slideUp event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _slideUp($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).slideUp({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Slide Down + * + * Outputs a jQuery slideDown event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _slideDown($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).slideDown({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Slide Toggle + * + * Outputs a jQuery slideToggle event + * + * @access public + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _slideToggle($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).slideToggle({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Toggle + * + * Outputs a jQuery toggle event + * + * @access private + * @param string - element + * @return string + */ + function _toggle($element = 'this') + { + $element = $this->_prep_element($element); + $str = "$({$element}).toggle();"; + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Toggle Class + * + * Outputs a jQuery toggle class event + * + * @access private + * @param string - element + * @return string + */ + function _toggleClass($element = 'this', $class='') + { + $element = $this->_prep_element($element); + $str = "$({$element}).toggleClass(\"$class\");"; + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Show + * + * Outputs a jQuery show event + * + * @access private + * @param string - element + * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds + * @param string - Javascript callback function + * @return string + */ + function _show($element = 'this', $speed = '', $callback = '') + { + $element = $this->_prep_element($element); + $speed = $this->_validate_speed($speed); + + if ($callback != '') + { + $callback = ", function(){\n{$callback}\n}"; + } + + $str = "$({$element}).show({$speed}{$callback});"; + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Updater + * + * An Ajax call that populates the designated DOM node with + * returned content + * + * @access private + * @param string The element to attach the event to + * @param string the controller to run the call against + * @param string optional parameters + * @return string + */ + + function _updater($container = 'this', $controller, $options = '') + { + $container = $this->_prep_element($container); + + $controller = (strpos('://', $controller) === FALSE) ? $controller : $this->CI->config->site_url($controller); + + // ajaxStart and ajaxStop are better choices here... but this is a stop gap + if ($this->CI->config->item('javascript_ajax_img') == '') + { + $loading_notifier = "Loading..."; + } + else + { + $loading_notifier = 'CI->config->slash_item('base_url') . $this->CI->config->item('javascript_ajax_img') . '\' alt=\'Loading\' />'; + } + + $updater = "$($container).empty();\n"; // anything that was in... get it out + $updater .= "\t\t$($container).prepend(\"$loading_notifier\");\n"; // to replace with an image + + $request_options = ''; + if ($options != '') + { + $request_options .= ", {"; + $request_options .= (is_array($options)) ? "'".implode("', '", $options)."'" : "'".str_replace(":", "':'", $options)."'"; + $request_options .= "}"; + } + + $updater .= "\t\t$($container).load('$controller'$request_options);"; + return $updater; + } + + + // -------------------------------------------------------------------- + // Pre-written handy stuff + // -------------------------------------------------------------------- + + /** + * Zebra tables + * + * @access private + * @param string table name + * @param string plugin location + * @return string + */ + function _zebraTables($class = '', $odd = 'odd', $hover = '') + { + $class = ($class != '') ? '.'.$class : ''; + + $zebra = "\t\$(\"table{$class} tbody tr:nth-child(even)\").addClass(\"{$odd}\");"; + + $this->jquery_code_for_compile[] = $zebra; + + if ($hover != '') + { + $hover = $this->hover("table{$class} tbody tr", "$(this).addClass('hover');", "$(this).removeClass('hover');"); + } + + return $zebra; + } + + + + // -------------------------------------------------------------------- + // Plugins + // -------------------------------------------------------------------- + + /** + * Corner Plugin + * + * http://www.malsup.com/jquery/corner/ + * + * @access public + * @param string target + * @return string + */ + function corner($element = '', $corner_style = '') + { + // may want to make this configurable down the road + $corner_location = '/plugins/jquery.corner.js'; + + if ($corner_style != '') + { + $corner_style = '"'.$corner_style.'"'; + } + + return "$(" . $this->_prep_element($element) . ").corner(".$corner_style.");"; + } + + // -------------------------------------------------------------------- + + /** + * modal window + * + * Load a thickbox modal window + * + * @access public + * @return void + */ + function modal($src, $relative = FALSE) + { + $this->jquery_code_for_load[] = $this->external($src, $relative); + } + + // -------------------------------------------------------------------- + + /** + * Effect + * + * Load an Effect library + * + * @access public + * @return void + */ + function effect($src, $relative = FALSE) + { + $this->jquery_code_for_load[] = $this->external($src, $relative); + } + + // -------------------------------------------------------------------- + + /** + * Plugin + * + * Load a plugin library + * + * @access public + * @return void + */ + function plugin($src, $relative = FALSE) + { + $this->jquery_code_for_load[] = $this->external($src, $relative); + } + + // -------------------------------------------------------------------- + + /** + * UI + * + * Load a user interface library + * + * @access public + * @return void + */ + function ui($src, $relative = FALSE) + { + $this->jquery_code_for_load[] = $this->external($src, $relative); + } + // -------------------------------------------------------------------- + + /** + * Sortable + * + * Creates a jQuery sortable + * + * @access public + * @return void + */ + function sortable($element, $options = array()) + { + + if (count($options) > 0) + { + $sort_options = array(); + foreach ($options as $k=>$v) + { + $sort_options[] = "\n\t\t".$k.': '.$v.""; + } + $sort_options = implode(",", $sort_options); + } + else + { + $sort_options = ''; + } + + return "$(" . $this->_prep_element($element) . ").sortable({".$sort_options."\n\t});"; + } + + // -------------------------------------------------------------------- + + /** + * Table Sorter Plugin + * + * @access public + * @param string table name + * @param string plugin location + * @return string + */ + function tablesorter($table = '', $options = '') + { + $this->jquery_code_for_compile[] = "\t$(" . $this->_prep_element($table) . ").tablesorter($options);\n"; + } + + // -------------------------------------------------------------------- + // Class functions + // -------------------------------------------------------------------- + + /** + * Add Event + * + * Constructs the syntax for an event, and adds to into the array for compilation + * + * @access private + * @param string The element to attach the event to + * @param string The code to execute + * @param string The event to pass + * @return string + */ + function _add_event($element, $js, $event) + { + if (is_array($js)) + { + $js = implode("\n\t\t", $js); + + } + + $event = "\n\t$(" . $this->_prep_element($element) . ").{$event}(function(){\n\t\t{$js}\n\t});\n"; + $this->jquery_code_for_compile[] = $event; + return $event; + } + + // -------------------------------------------------------------------- + + /** + * Compile + * + * As events are specified, they are stored in an array + * This funciton compiles them all for output on a page + * + * @access private + * @return string + */ + function _compile($view_var = 'script_foot', $script_tags = TRUE) + { + // External references + $external_scripts = implode('', $this->jquery_code_for_load); + $this->CI->load->vars(array('library_src' => $external_scripts)); + + if (count($this->jquery_code_for_compile) == 0 ) + { + // no inline references, let's just return + return; + } + + // Inline references + $script = '$(document).ready(function() {' . "\n"; + $script .= implode('', $this->jquery_code_for_compile); + $script .= '});'; + + $output = ($script_tags === FALSE) ? $script : $this->inline($script); + + $this->CI->load->vars(array($view_var => $output)); + + } + + // -------------------------------------------------------------------- + + /** + * Clear Compile + * + * Clears the array of script events collected for output + * + * @access public + * @return void + */ + function _clear_compile() + { + $this->jquery_code_for_compile = array(); + } + + // -------------------------------------------------------------------- + + /** + * Document Ready + * + * A wrapper for writing document.ready() + * + * @access private + * @return string + */ + function _document_ready($js) + { + if ( ! is_array($js)) + { + $js = array ($js); + + } + + foreach ($js as $script) + { + $this->jquery_code_for_compile[] = $script; + } + } + + // -------------------------------------------------------------------- + + /** + * Script Tag + * + * Outputs the script tag that loads the jquery.js file into an HTML document + * + * @access public + * @param string + * @return string + */ + function script($library_src = '', $relative = FALSE) + { + $library_src = $this->external($library_src, $relative); + $this->jquery_code_for_load[] = $library_src; + return $library_src; + } + + // -------------------------------------------------------------------- + + /** + * Prep Element + * + * Puts HTML element in quotes for use in jQuery code + * unless the supplied element is the Javascript 'this' + * object, in which case no quotes are added + * + * @access public + * @param string + * @return string + */ + function _prep_element($element) + { + if ($element != 'this') + { + $element = '"'.$element.'"'; + } + + return $element; + } + + // -------------------------------------------------------------------- + + /** + * Validate Speed + * + * Ensures the speed parameter is valid for jQuery + * + * @access private + * @param string + * @return string + */ + function _validate_speed($speed) + { + if (in_array($speed, array('slow', 'normal', 'fast'))) + { + $speed = '"'.$speed.'"'; + } + elseif (preg_match("/[^0-9]/", $speed)) + { + $speed = ''; + } + + return $speed; + } + +} + +/* End of file Jquery.php */ +/* Location: ./system/libraries/Jquery.php */ \ No newline at end of file diff --git a/system/plugins/captcha_pi.php b/system/plugins/captcha_pi.php deleted file mode 100644 index 36a74c42..00000000 --- a/system/plugins/captcha_pi.php +++ /dev/null @@ -1,356 +0,0 @@ -load->plugin('captcha'); - -Once loaded you can generate a captcha like this: - - $vals = array( - 'word' => 'Random word', - 'img_path' => './captcha/', - 'img_url' => 'http://example.com/captcha/', - 'font_path' => './system/fonts/texb.ttf', - 'img_width' => '150', - 'img_height' => 30, - 'expiration' => 7200 - ); - - $cap = create_captcha($vals); - echo $cap['image']; - - -NOTES: - - The captcha function requires the GD image library. - - Only the img_path and img_url are required. - - If a "word" is not supplied, the function will generate a random - ASCII string. You might put together your own word library that - you can draw randomly from. - - If you do not specify a path to a TRUE TYPE font, the native ugly GD - font will be used. - - The "captcha" folder must be writable (666, or 777) - - The "expiration" (in seconds) signifies how long an image will - remain in the captcha folder before it will be deleted. The default - is two hours. - -RETURNED DATA - -The create_captcha() function returns an associative array with this data: - - [array] - ( - 'image' => IMAGE TAG - 'time' => TIMESTAMP (in microtime) - 'word' => CAPTCHA WORD - ) - -The "image" is the actual image tag: - - -The "time" is the micro timestamp used as the image name without the file -extension. It will be a number like this: 1139612155.3422 - -The "word" is the word that appears in the captcha image, which if not -supplied to the function, will be a random string. - - -ADDING A DATABASE - -In order for the captcha function to prevent someone from posting, you will need -to add the information returned from create_captcha() function to your database. -Then, when the data from the form is submitted by the user you will need to verify -that the data exists in the database and has not expired. - -Here is a table prototype: - - CREATE TABLE captcha ( - captcha_id bigint(13) unsigned NOT NULL auto_increment, - captcha_time int(10) unsigned NOT NULL, - ip_address varchar(16) default '0' NOT NULL, - word varchar(20) NOT NULL, - PRIMARY KEY `captcha_id` (`captcha_id`), - KEY `word` (`word`) - ) - - -Here is an example of usage with a DB. - -On the page where the captcha will be shown you'll have something like this: - - $this->load->plugin('captcha'); - $vals = array( - 'img_path' => './captcha/', - 'img_url' => 'http://example.com/captcha/' - ); - - $cap = create_captcha($vals); - - $data = array( - 'captcha_id' => '', - 'captcha_time' => $cap['time'], - 'ip_address' => $this->input->ip_address(), - 'word' => $cap['word'] - ); - - $query = $this->db->insert_string('captcha', $data); - $this->db->query($query); - - echo 'Submit the word you see below:'; - echo $cap['image']; - echo ''; - - -Then, on the page that accepts the submission you'll have something like this: - - // First, delete old captchas - $expiration = time()-7200; // Two hour limit - $DB->query("DELETE FROM captcha WHERE captcha_time < ".$expiration); - - // Then see if a captcha exists: - $sql = "SELECT COUNT(*) AS count FROM captcha WHERE word = ? AND ip_address = ? AND date > ?"; - $binds = array($_POST['captcha'], $this->input->ip_address(), $expiration); - $query = $this->db->query($sql, $binds); - $row = $query->row(); - - if ($row->count == 0) - { - echo "You must submit the word that appears in the image"; - } - -*/ - - - -/** -|========================================================== -| Create Captcha -|========================================================== -| -*/ -function create_captcha($data = '', $img_path = '', $img_url = '', $font_path = '') -{ - $defaults = array('word' => '', 'img_path' => '', 'img_url' => '', 'img_width' => '150', 'img_height' => '30', 'font_path' => '', 'expiration' => 7200); - - foreach ($defaults as $key => $val) - { - if ( ! is_array($data)) - { - if ( ! isset($$key) OR $$key == '') - { - $$key = $val; - } - } - else - { - $$key = ( ! isset($data[$key])) ? $val : $data[$key]; - } - } - - if ($img_path == '' OR $img_url == '') - { - return FALSE; - } - - if ( ! @is_dir($img_path)) - { - return FALSE; - } - - if ( ! is_really_writable($img_path)) - { - return FALSE; - } - - if ( ! extension_loaded('gd')) - { - return FALSE; - } - - // ----------------------------------- - // Remove old images - // ----------------------------------- - - list($usec, $sec) = explode(" ", microtime()); - $now = ((float)$usec + (float)$sec); - - $current_dir = @opendir($img_path); - - while($filename = @readdir($current_dir)) - { - if ($filename != "." and $filename != ".." and $filename != "index.html") - { - $name = str_replace(".jpg", "", $filename); - - if (($name + $expiration) < $now) - { - @unlink($img_path.$filename); - } - } - } - - @closedir($current_dir); - - // ----------------------------------- - // Do we have a "word" yet? - // ----------------------------------- - - if ($word == '') - { - $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - - $str = ''; - for ($i = 0; $i < 8; $i++) - { - $str .= substr($pool, mt_rand(0, strlen($pool) -1), 1); - } - - $word = $str; - } - - // ----------------------------------- - // Determine angle and position - // ----------------------------------- - - $length = strlen($word); - $angle = ($length >= 6) ? rand(-($length-6), ($length-6)) : 0; - $x_axis = rand(6, (360/$length)-16); - $y_axis = ($angle >= 0 ) ? rand($img_height, $img_width) : rand(6, $img_height); - - // ----------------------------------- - // Create image - // ----------------------------------- - - // PHP.net recommends imagecreatetruecolor(), but it isn't always available - if (function_exists('imagecreatetruecolor')) - { - $im = imagecreatetruecolor($img_width, $img_height); - } - else - { - $im = imagecreate($img_width, $img_height); - } - - // ----------------------------------- - // Assign colors - // ----------------------------------- - - $bg_color = imagecolorallocate ($im, 255, 255, 255); - $border_color = imagecolorallocate ($im, 153, 102, 102); - $text_color = imagecolorallocate ($im, 204, 153, 153); - $grid_color = imagecolorallocate($im, 255, 182, 182); - $shadow_color = imagecolorallocate($im, 255, 240, 240); - - // ----------------------------------- - // Create the rectangle - // ----------------------------------- - - ImageFilledRectangle($im, 0, 0, $img_width, $img_height, $bg_color); - - // ----------------------------------- - // Create the spiral pattern - // ----------------------------------- - - $theta = 1; - $thetac = 7; - $radius = 16; - $circles = 20; - $points = 32; - - for ($i = 0; $i < ($circles * $points) - 1; $i++) - { - $theta = $theta + $thetac; - $rad = $radius * ($i / $points ); - $x = ($rad * cos($theta)) + $x_axis; - $y = ($rad * sin($theta)) + $y_axis; - $theta = $theta + $thetac; - $rad1 = $radius * (($i + 1) / $points); - $x1 = ($rad1 * cos($theta)) + $x_axis; - $y1 = ($rad1 * sin($theta )) + $y_axis; - imageline($im, $x, $y, $x1, $y1, $grid_color); - $theta = $theta - $thetac; - } - - // ----------------------------------- - // Write the text - // ----------------------------------- - - $use_font = ($font_path != '' AND file_exists($font_path) AND function_exists('imagettftext')) ? TRUE : FALSE; - - if ($use_font == FALSE) - { - $font_size = 5; - $x = rand(0, $img_width/($length/3)); - $y = 0; - } - else - { - $font_size = 16; - $x = rand(0, $img_width/($length/1.5)); - $y = $font_size+2; - } - - for ($i = 0; $i < strlen($word); $i++) - { - if ($use_font == FALSE) - { - $y = rand(0 , $img_height/2); - imagestring($im, $font_size, $x, $y, substr($word, $i, 1), $text_color); - $x += ($font_size*2); - } - else - { - $y = rand($img_height/2, $img_height-3); - imagettftext($im, $font_size, $angle, $x, $y, $text_color, $font_path, substr($word, $i, 1)); - $x += $font_size; - } - } - - - // ----------------------------------- - // Create the border - // ----------------------------------- - - imagerectangle($im, 0, 0, $img_width-1, $img_height-1, $border_color); - - // ----------------------------------- - // Generate the image - // ----------------------------------- - - $img_name = $now.'.jpg'; - - ImageJPEG($im, $img_path.$img_name); - - $img = "\""; - - ImageDestroy($im); - - return array('word' => $word, 'time' => $now, 'image' => $img); -} - - -/* End of file captcha_pi.php */ -/* Location: ./system/plugins/captcha_pi.php */ \ No newline at end of file diff --git a/system/plugins/js_calendar_pi.php b/system/plugins/js_calendar_pi.php deleted file mode 100644 index 19d05681..00000000 --- a/system/plugins/js_calendar_pi.php +++ /dev/null @@ -1,629 +0,0 @@ -load->plugin('js_calendar'); - -Once loaded you'll add the calendar script to the of your page like this: - - - -The above function will be passed the name of your form. - -Then to show the actual calendar you'll do this: - - -

- -

Today

-
- - -Note: The first parameter is the name of the field containing your date, the second parameter contains the "now" time, -and the third tells the calendar whether to highlight the current day or not. - -Lastly, you'll need some CSS for your calendar: - -.calendar { - border: 1px #6975A3 solid; - background-color: transparent; -} -.calheading { - background-color: #7C8BC0; - color: #fff; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 11px; - font-weight: bold; - text-align: center; -} -.calnavleft { - background-color: #7C8BC0; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 10px; - font-weight: bold; - color: #fff; - padding: 4px; - cursor: pointer; -} -.calnavright { - background-color: #7C8BC0; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 10px; - font-weight: bold; - color: #fff; - text-align: right; - padding: 4px; - cursor: pointer; -} -.caldayheading { - background-color: #000; - color: #fff; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 10px; - text-align: center; - padding: 6px 2px 6px 2px; -} -.caldaycells{ - color: #000; - background-color: #D1D7E6; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 11px; - text-align: center; - padding: 4px; - border: 1px #E0E5F1 solid; - cursor: pointer; -} -.caldaycellhover{ - color: #fff; - background-color: #B3BCD4; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 11px; - text-align: center; - padding: 4px; - border: 1px #B3BCD4 solid; - cursor: pointer; -} -.caldayselected{ - background-color: #737FAC; - color: #fff; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 11px; - font-weight: bold; - text-align: center; - border: 1px #566188 solid; - padding: 3px; - cursor: pointer; -} -.calblanktop { - background-color: #fff; - padding: 4px; -} -.calblankbot { - background-color: #fff; - padding: 4px; -} - - -*/ - -function js_calendar_script($form_name = 'entryform') -{ -$CI =& get_instance(); -$CI->load->language('calendar'); -ob_start(); -?> - - - var '.$field_id.' = new calendar("'.$field_id.'", '.$time.', '.(($highlight == TRUE) ? 'true' : 'false').'); - document.write('.$field_id.'.write()); - '; -} - - -/* End of file js_calendar_pi.php */ -/* Location: ./system/plugins/js_calendar_pi.php */ \ No newline at end of file