Browse Source

Initial commit

Skamander 12 years ago
parent
commit
5d35cbc9bb
100 changed files with 22051 additions and 0 deletions
  1. 9 0
      php-codeigniter/.gitignore
  2. 36 0
      php-codeigniter/README.md
  3. 0 0
      php-codeigniter/__init__.py
  4. 1 0
      php-codeigniter/application/.htaccess
  5. 1 0
      php-codeigniter/application/cache/.htaccess
  6. 10 0
      php-codeigniter/application/cache/index.html
  7. 116 0
      php-codeigniter/application/config/autoload.php
  8. 362 0
      php-codeigniter/application/config/config.php
  9. 41 0
      php-codeigniter/application/config/constants.php
  10. 69 0
      php-codeigniter/application/config/database.php
  11. 15 0
      php-codeigniter/application/config/doctypes.php
  12. 64 0
      php-codeigniter/application/config/foreign_chars.php
  13. 16 0
      php-codeigniter/application/config/hooks.php
  14. 10 0
      php-codeigniter/application/config/index.html
  15. 41 0
      php-codeigniter/application/config/migration.php
  16. 106 0
      php-codeigniter/application/config/mimes.php
  17. 17 0
      php-codeigniter/application/config/profiler.php
  18. 46 0
      php-codeigniter/application/config/routes.php
  19. 66 0
      php-codeigniter/application/config/smileys.php
  20. 178 0
      php-codeigniter/application/config/user_agents.php
  21. 31 0
      php-codeigniter/application/controllers/bench.php
  22. 10 0
      php-codeigniter/application/controllers/index.html
  23. 27 0
      php-codeigniter/application/controllers/welcome.php
  24. 10 0
      php-codeigniter/application/core/index.html
  25. 62 0
      php-codeigniter/application/errors/error_404.php
  26. 62 0
      php-codeigniter/application/errors/error_db.php
  27. 62 0
      php-codeigniter/application/errors/error_general.php
  28. 10 0
      php-codeigniter/application/errors/error_php.php
  29. 10 0
      php-codeigniter/application/errors/index.html
  30. 10 0
      php-codeigniter/application/helpers/index.html
  31. 10 0
      php-codeigniter/application/hooks/index.html
  32. 10 0
      php-codeigniter/application/index.html
  33. 10 0
      php-codeigniter/application/language/english/index.html
  34. 10 0
      php-codeigniter/application/libraries/index.html
  35. 10 0
      php-codeigniter/application/logs/index.html
  36. 10 0
      php-codeigniter/application/models/index.html
  37. 10 0
      php-codeigniter/application/third_party/index.html
  38. 10 0
      php-codeigniter/application/views/index.html
  39. 88 0
      php-codeigniter/application/views/welcome_message.php
  40. 13 0
      php-codeigniter/benchmark_config
  41. 125 0
      php-codeigniter/deploy/nginx.conf
  42. 9 0
      php-codeigniter/deploy/php-codeigniter
  43. 205 0
      php-codeigniter/index.php
  44. 51 0
      php-codeigniter/license.txt
  45. 26 0
      php-codeigniter/setup.py
  46. 1 0
      php-codeigniter/system/.htaccess
  47. 118 0
      php-codeigniter/system/core/Benchmark.php
  48. 402 0
      php-codeigniter/system/core/CodeIgniter.php
  49. 564 0
      php-codeigniter/system/core/Common.php
  50. 379 0
      php-codeigniter/system/core/Config.php
  51. 64 0
      php-codeigniter/system/core/Controller.php
  52. 193 0
      php-codeigniter/system/core/Exceptions.php
  53. 248 0
      php-codeigniter/system/core/Hooks.php
  54. 849 0
      php-codeigniter/system/core/Input.php
  55. 160 0
      php-codeigniter/system/core/Lang.php
  56. 1248 0
      php-codeigniter/system/core/Loader.php
  57. 57 0
      php-codeigniter/system/core/Model.php
  58. 574 0
      php-codeigniter/system/core/Output.php
  59. 522 0
      php-codeigniter/system/core/Router.php
  60. 876 0
      php-codeigniter/system/core/Security.php
  61. 654 0
      php-codeigniter/system/core/URI.php
  62. 165 0
      php-codeigniter/system/core/Utf8.php
  63. 10 0
      php-codeigniter/system/core/index.html
  64. 162 0
      php-codeigniter/system/database/DB.php
  65. 2045 0
      php-codeigniter/system/database/DB_active_rec.php
  66. 195 0
      php-codeigniter/system/database/DB_cache.php
  67. 1410 0
      php-codeigniter/system/database/DB_driver.php
  68. 382 0
      php-codeigniter/system/database/DB_forge.php
  69. 410 0
      php-codeigniter/system/database/DB_result.php
  70. 414 0
      php-codeigniter/system/database/DB_utility.php
  71. 792 0
      php-codeigniter/system/database/drivers/cubrid/cubrid_driver.php
  72. 288 0
      php-codeigniter/system/database/drivers/cubrid/cubrid_forge.php
  73. 202 0
      php-codeigniter/system/database/drivers/cubrid/cubrid_result.php
  74. 108 0
      php-codeigniter/system/database/drivers/cubrid/cubrid_utility.php
  75. 10 0
      php-codeigniter/system/database/drivers/cubrid/index.html
  76. 10 0
      php-codeigniter/system/database/drivers/index.html
  77. 10 0
      php-codeigniter/system/database/drivers/mssql/index.html
  78. 667 0
      php-codeigniter/system/database/drivers/mssql/mssql_driver.php
  79. 248 0
      php-codeigniter/system/database/drivers/mssql/mssql_forge.php
  80. 169 0
      php-codeigniter/system/database/drivers/mssql/mssql_result.php
  81. 88 0
      php-codeigniter/system/database/drivers/mssql/mssql_utility.php
  82. 10 0
      php-codeigniter/system/database/drivers/mysql/index.html
  83. 779 0
      php-codeigniter/system/database/drivers/mysql/mysql_driver.php
  84. 273 0
      php-codeigniter/system/database/drivers/mysql/mysql_forge.php
  85. 174 0
      php-codeigniter/system/database/drivers/mysql/mysql_result.php
  86. 210 0
      php-codeigniter/system/database/drivers/mysql/mysql_utility.php
  87. 10 0
      php-codeigniter/system/database/drivers/mysqli/index.html
  88. 776 0
      php-codeigniter/system/database/drivers/mysqli/mysqli_driver.php
  89. 258 0
      php-codeigniter/system/database/drivers/mysqli/mysqli_forge.php
  90. 174 0
      php-codeigniter/system/database/drivers/mysqli/mysqli_result.php
  91. 87 0
      php-codeigniter/system/database/drivers/mysqli/mysqli_utility.php
  92. 10 0
      php-codeigniter/system/database/drivers/oci8/index.html
  93. 808 0
      php-codeigniter/system/database/drivers/oci8/oci8_driver.php
  94. 248 0
      php-codeigniter/system/database/drivers/oci8/oci8_forge.php
  95. 217 0
      php-codeigniter/system/database/drivers/oci8/oci8_result.php
  96. 87 0
      php-codeigniter/system/database/drivers/oci8/oci8_utility.php
  97. 10 0
      php-codeigniter/system/database/drivers/odbc/index.html
  98. 637 0
      php-codeigniter/system/database/drivers/odbc/odbc_driver.php
  99. 266 0
      php-codeigniter/system/database/drivers/odbc/odbc_forge.php
  100. 228 0
      php-codeigniter/system/database/drivers/odbc/odbc_result.php

+ 9 - 0
php-codeigniter/.gitignore

@@ -0,0 +1,9 @@
+/app/cache
+/app/logs
+/bin
+/vendors
+/build
+/dist
+.DS_Store
+/tags
+.idea

+ 36 - 0
php-codeigniter/README.md

@@ -0,0 +1,36 @@
+# Codeigniter PHP Benchmarking Test
+
+This is the Codeigniter PHP portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+Uses the PHP standard [JSON encoder](http://www.php.net/manual/en/function.json-encode.php).
+
+* [JSON test controller](application/controllers/bench.php)
+
+
+### Data-Store/Database Mapping Test
+Uses the db abstraction class from Codeigniter
+
+* [DB test controller](application/controllers/bench.php)
+
+
+## Infrastructure Software Versions
+The tests were run with:
+
+* [Codeigniter Version 2.1.3](http://ellislab.com/codeigniter)
+* [PHP Version 5.4.13](http://www.php.net/) with FPM and APC
+* [nginx 1.2.7](http://nginx.org/)
+* [MySQL 5.5.29](https://dev.mysql.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost/index.php/bench/json
+
+### Data-Store/Database Mapping Test
+
+http://localhost/index.php/bench/db
+
+### Variable Query Test
+    
+http://localhost/index.php/bench/db/2

+ 0 - 0
php-codeigniter/__init__.py


+ 1 - 0
php-codeigniter/application/.htaccess

@@ -0,0 +1 @@
+Deny from all

+ 1 - 0
php-codeigniter/application/cache/.htaccess

@@ -0,0 +1 @@
+deny from all

+ 10 - 0
php-codeigniter/application/cache/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 116 - 0
php-codeigniter/application/config/autoload.php

@@ -0,0 +1,116 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/*
+| -------------------------------------------------------------------
+| AUTO-LOADER
+| -------------------------------------------------------------------
+| This file specifies which systems should be loaded by default.
+|
+| 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
+| you globally define which systems you would like loaded with every
+| request.
+|
+| -------------------------------------------------------------------
+| Instructions
+| -------------------------------------------------------------------
+|
+| These are the things you can load automatically:
+|
+| 1. Packages
+| 2. Libraries
+| 3. Helper files
+| 4. Custom config files
+| 5. Language files
+| 6. Models
+|
+*/
+
+/*
+| -------------------------------------------------------------------
+|  Auto-load Packges
+| -------------------------------------------------------------------
+| Prototype:
+|
+|  $autoload['packages'] = array(APPPATH.'third_party', '/usr/local/shared');
+|
+*/
+
+$autoload['packages'] = array();
+
+
+/*
+| -------------------------------------------------------------------
+|  Auto-load Libraries
+| -------------------------------------------------------------------
+| These are the classes located in the system/libraries folder
+| or in your application/libraries folder.
+|
+| Prototype:
+|
+|	$autoload['libraries'] = array('database', 'session', 'xmlrpc');
+*/
+
+$autoload['libraries'] = array('database');
+
+
+/*
+| -------------------------------------------------------------------
+|  Auto-load Helper Files
+| -------------------------------------------------------------------
+| Prototype:
+|
+|	$autoload['helper'] = array('url', 'file');
+*/
+
+$autoload['helper'] = array();
+
+
+/*
+| -------------------------------------------------------------------
+|  Auto-load Config files
+| -------------------------------------------------------------------
+| Prototype:
+|
+|	$autoload['config'] = array('config1', 'config2');
+|
+| NOTE: This item is intended for use ONLY if you have created custom
+| config files.  Otherwise, leave it blank.
+|
+*/
+
+$autoload['config'] = array();
+
+
+/*
+| -------------------------------------------------------------------
+|  Auto-load Language files
+| -------------------------------------------------------------------
+| Prototype:
+|
+|	$autoload['language'] = array('lang1', 'lang2');
+|
+| NOTE: Do not include the "_lang" part of your file.  For example
+| "codeigniter_lang.php" would be referenced as array('codeigniter');
+|
+*/
+
+$autoload['language'] = array();
+
+
+/*
+| -------------------------------------------------------------------
+|  Auto-load Models
+| -------------------------------------------------------------------
+| Prototype:
+|
+|	$autoload['model'] = array('model1', 'model2');
+|
+*/
+
+$autoload['model'] = array();
+
+
+/* End of file autoload.php */
+/* Location: ./application/config/autoload.php */

+ 362 - 0
php-codeigniter/application/config/config.php

@@ -0,0 +1,362 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+
+/*
+|--------------------------------------------------------------------------
+| Base Site URL
+|--------------------------------------------------------------------------
+|
+| URL to your CodeIgniter root. Typically this will be your base URL,
+| WITH a trailing slash:
+|
+|	http://example.com/
+|
+| If this is not set then CodeIgniter will guess the protocol, domain and
+| path to your installation.
+|
+*/
+$config['base_url']	= '';
+
+/*
+|--------------------------------------------------------------------------
+| Index File
+|--------------------------------------------------------------------------
+|
+| Typically this will be your index.php file, unless you've renamed it to
+| something else. If you are using mod_rewrite to remove the page set this
+| variable so that it is blank.
+|
+*/
+$config['index_page'] = 'index.php';
+
+/*
+|--------------------------------------------------------------------------
+| URI PROTOCOL
+|--------------------------------------------------------------------------
+|
+| This item determines which server global should be used to retrieve the
+| URI string.  The default setting of 'AUTO' works for most servers.
+| If your links do not seem to work, try one of the other delicious flavors:
+|
+| 'AUTO'			Default - auto detects
+| 'PATH_INFO'		Uses the PATH_INFO
+| 'QUERY_STRING'	Uses the QUERY_STRING
+| 'REQUEST_URI'		Uses the REQUEST_URI
+| 'ORIG_PATH_INFO'	Uses the ORIG_PATH_INFO
+|
+*/
+$config['uri_protocol']	= 'AUTO';
+
+/*
+|--------------------------------------------------------------------------
+| URL suffix
+|--------------------------------------------------------------------------
+|
+| This option allows you to add a suffix to all URLs generated by CodeIgniter.
+| For more information please see the user guide:
+|
+| http://codeigniter.com/user_guide/general/urls.html
+*/
+
+$config['url_suffix'] = '';
+
+/*
+|--------------------------------------------------------------------------
+| Default Language
+|--------------------------------------------------------------------------
+|
+| This determines which set of language files should be used. Make sure
+| there is an available translation if you intend to use something other
+| than english.
+|
+*/
+$config['language']	= 'english';
+
+/*
+|--------------------------------------------------------------------------
+| Default Character Set
+|--------------------------------------------------------------------------
+|
+| This determines which character set is used by default in various methods
+| that require a character set to be provided.
+|
+*/
+$config['charset'] = 'UTF-8';
+
+/*
+|--------------------------------------------------------------------------
+| Enable/Disable System Hooks
+|--------------------------------------------------------------------------
+|
+| If you would like to use the 'hooks' feature you must enable it by
+| setting this variable to TRUE (boolean).  See the user guide for details.
+|
+*/
+$config['enable_hooks'] = FALSE;
+
+
+/*
+|--------------------------------------------------------------------------
+| Class Extension Prefix
+|--------------------------------------------------------------------------
+|
+| This item allows you to set the filename/classname prefix when extending
+| native libraries.  For more information please see the user guide:
+|
+| http://codeigniter.com/user_guide/general/core_classes.html
+| http://codeigniter.com/user_guide/general/creating_libraries.html
+|
+*/
+$config['subclass_prefix'] = 'MY_';
+
+
+/*
+|--------------------------------------------------------------------------
+| Allowed URL Characters
+|--------------------------------------------------------------------------
+|
+| This lets you specify with a regular expression which characters are permitted
+| within your URLs.  When someone tries to submit a URL with disallowed
+| characters they will get a warning message.
+|
+| As a security measure you are STRONGLY encouraged to restrict URLs to
+| as few characters as possible.  By default only these are allowed: a-z 0-9~%.:_-
+|
+| Leave blank to allow all characters -- but only if you are insane.
+|
+| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
+|
+*/
+$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';
+
+
+/*
+|--------------------------------------------------------------------------
+| Enable Query Strings
+|--------------------------------------------------------------------------
+|
+| By default CodeIgniter uses search-engine friendly segment based URLs:
+| example.com/who/what/where/
+|
+| By default CodeIgniter enables access to the $_GET array.  If for some
+| reason you would like to disable it, set 'allow_get_array' to FALSE.
+|
+| You can optionally enable standard query string based URLs:
+| example.com?who=me&what=something&where=here
+|
+| Options are: TRUE or FALSE (boolean)
+|
+| The other items let you set the query string 'words' that will
+| invoke your controllers and its functions:
+| example.com/index.php?c=controller&m=function
+|
+| Please note that some of the helpers won't work as expected when
+| this feature is enabled, since CodeIgniter is designed primarily to
+| use segment based URLs.
+|
+*/
+$config['allow_get_array']		= TRUE;
+$config['enable_query_strings'] = FALSE;
+$config['controller_trigger']	= 'c';
+$config['function_trigger']		= 'm';
+$config['directory_trigger']	= 'd'; // experimental not currently in use
+
+/*
+|--------------------------------------------------------------------------
+| Error Logging Threshold
+|--------------------------------------------------------------------------
+|
+| If you have enabled error logging, you can set an error threshold to
+| determine what gets logged. Threshold options are:
+| You can enable error logging by setting a threshold over zero. The
+| threshold determines what gets logged. Threshold options are:
+|
+|	0 = Disables logging, Error logging TURNED OFF
+|	1 = Error Messages (including PHP errors)
+|	2 = Debug Messages
+|	3 = Informational Messages
+|	4 = All Messages
+|
+| For a live site you'll usually only enable Errors (1) to be logged otherwise
+| your log files will fill up very fast.
+|
+*/
+$config['log_threshold'] = 0;
+
+/*
+|--------------------------------------------------------------------------
+| Error Logging Directory Path
+|--------------------------------------------------------------------------
+|
+| Leave this BLANK unless you would like to set something other than the default
+| application/logs/ folder. Use a full server path with trailing slash.
+|
+*/
+$config['log_path'] = '';
+
+/*
+|--------------------------------------------------------------------------
+| Date Format for Logs
+|--------------------------------------------------------------------------
+|
+| Each item that is logged has an associated date. You can use PHP date
+| codes to set your own date formatting
+|
+*/
+$config['log_date_format'] = 'Y-m-d H:i:s';
+
+/*
+|--------------------------------------------------------------------------
+| Cache Directory Path
+|--------------------------------------------------------------------------
+|
+| Leave this BLANK unless you would like to set something other than the default
+| system/cache/ folder.  Use a full server path with trailing slash.
+|
+*/
+$config['cache_path'] = '';
+
+/*
+|--------------------------------------------------------------------------
+| Encryption Key
+|--------------------------------------------------------------------------
+|
+| If you use the Encryption class or the Session class you
+| MUST set an encryption key.  See the user guide for info.
+|
+*/
+$config['encryption_key'] = '';
+
+/*
+|--------------------------------------------------------------------------
+| Session Variables
+|--------------------------------------------------------------------------
+|
+| 'sess_cookie_name'		= the name you want for the cookie
+| 'sess_expiration'			= the number of SECONDS you want the session to last.
+|   by default sessions last 7200 seconds (two hours).  Set to zero for no expiration.
+| 'sess_expire_on_close'	= Whether to cause the session to expire automatically
+|   when the browser window is closed
+| 'sess_encrypt_cookie'		= Whether to encrypt the cookie
+| 'sess_use_database'		= Whether to save the session data to a database
+| 'sess_table_name'			= The name of the session database table
+| 'sess_match_ip'			= Whether to match the user's IP address when reading the session data
+| 'sess_match_useragent'	= Whether to match the User Agent when reading the session data
+| 'sess_time_to_update'		= how many seconds between CI refreshing Session Information
+|
+*/
+$config['sess_cookie_name']		= 'ci_session';
+$config['sess_expiration']		= 7200;
+$config['sess_expire_on_close']	= FALSE;
+$config['sess_encrypt_cookie']	= FALSE;
+$config['sess_use_database']	= FALSE;
+$config['sess_table_name']		= 'ci_sessions';
+$config['sess_match_ip']		= FALSE;
+$config['sess_match_useragent']	= TRUE;
+$config['sess_time_to_update']	= 300;
+
+/*
+|--------------------------------------------------------------------------
+| Cookie Related Variables
+|--------------------------------------------------------------------------
+|
+| 'cookie_prefix' = Set a prefix if you need to avoid collisions
+| 'cookie_domain' = Set to .your-domain.com for site-wide cookies
+| 'cookie_path'   =  Typically will be a forward slash
+| 'cookie_secure' =  Cookies will only be set if a secure HTTPS connection exists.
+|
+*/
+$config['cookie_prefix']	= "";
+$config['cookie_domain']	= "";
+$config['cookie_path']		= "/";
+$config['cookie_secure']	= FALSE;
+
+/*
+|--------------------------------------------------------------------------
+| Global XSS Filtering
+|--------------------------------------------------------------------------
+|
+| Determines whether the XSS filter is always active when GET, POST or
+| COOKIE data is encountered
+|
+*/
+$config['global_xss_filtering'] = FALSE;
+
+/*
+|--------------------------------------------------------------------------
+| Cross Site Request Forgery
+|--------------------------------------------------------------------------
+| Enables a CSRF cookie token to be set. When set to TRUE, token will be
+| checked on a submitted form. If you are accepting user data, it is strongly
+| recommended CSRF protection be enabled.
+|
+| 'csrf_token_name' = The token name
+| 'csrf_cookie_name' = The cookie name
+| 'csrf_expire' = The number in seconds the token should expire.
+*/
+$config['csrf_protection'] = FALSE;
+$config['csrf_token_name'] = 'csrf_test_name';
+$config['csrf_cookie_name'] = 'csrf_cookie_name';
+$config['csrf_expire'] = 7200;
+
+/*
+|--------------------------------------------------------------------------
+| Output Compression
+|--------------------------------------------------------------------------
+|
+| Enables Gzip output compression for faster page loads.  When enabled,
+| the output class will test whether your server supports Gzip.
+| Even if it does, however, not all browsers support compression
+| so enable only if you are reasonably sure your visitors can handle it.
+|
+| VERY IMPORTANT:  If you are getting a blank page when compression is enabled it
+| means you are prematurely outputting something to your browser. It could
+| even be a line of whitespace at the end of one of your scripts.  For
+| compression to work, nothing can be sent before the output buffer is called
+| by the output class.  Do not 'echo' any values with compression enabled.
+|
+*/
+$config['compress_output'] = FALSE;
+
+/*
+|--------------------------------------------------------------------------
+| Master Time Reference
+|--------------------------------------------------------------------------
+|
+| Options are 'local' or 'gmt'.  This pref tells the system whether to use
+| your server's local time as the master 'now' reference, or convert it to
+| GMT.  See the 'date helper' page of the user guide for information
+| regarding date handling.
+|
+*/
+$config['time_reference'] = 'local';
+
+
+/*
+|--------------------------------------------------------------------------
+| Rewrite PHP Short Tags
+|--------------------------------------------------------------------------
+|
+| If your PHP installation does not have short tag support enabled CI
+| can rewrite the tags on-the-fly, enabling you to utilize that syntax
+| in your view files.  Options are TRUE or FALSE (boolean)
+|
+*/
+$config['rewrite_short_tags'] = FALSE;
+
+
+/*
+|--------------------------------------------------------------------------
+| Reverse Proxy IPs
+|--------------------------------------------------------------------------
+|
+| If your server is behind a reverse proxy, you must whitelist the proxy IP
+| addresses from which CodeIgniter should trust the HTTP_X_FORWARDED_FOR
+| header in order to properly identify the visitor's IP address.
+| Comma-delimited, e.g. '10.0.1.200,10.0.1.201'
+|
+*/
+$config['proxy_ips'] = '';
+
+
+/* End of file config.php */
+/* Location: ./application/config/config.php */

+ 41 - 0
php-codeigniter/application/config/constants.php

@@ -0,0 +1,41 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+
+/*
+|--------------------------------------------------------------------------
+| File and Directory Modes
+|--------------------------------------------------------------------------
+|
+| These prefs are used when checking and setting modes when working
+| with the file system.  The defaults are fine on servers with proper
+| security, but you may wish (or even need) to change the values in
+| certain environments (Apache running a separate process for each
+| user, PHP under CGI with Apache suEXEC, etc.).  Octal values should
+| always be used to set the mode correctly.
+|
+*/
+define('FILE_READ_MODE', 0644);
+define('FILE_WRITE_MODE', 0666);
+define('DIR_READ_MODE', 0755);
+define('DIR_WRITE_MODE', 0777);
+
+/*
+|--------------------------------------------------------------------------
+| File Stream Modes
+|--------------------------------------------------------------------------
+|
+| These modes are used when working with fopen()/popen()
+|
+*/
+
+define('FOPEN_READ',							'rb');
+define('FOPEN_READ_WRITE',						'r+b');
+define('FOPEN_WRITE_CREATE_DESTRUCTIVE',		'wb'); // truncates existing file data, use with care
+define('FOPEN_READ_WRITE_CREATE_DESTRUCTIVE',	'w+b'); // truncates existing file data, use with care
+define('FOPEN_WRITE_CREATE',					'ab');
+define('FOPEN_READ_WRITE_CREATE',				'a+b');
+define('FOPEN_WRITE_CREATE_STRICT',				'xb');
+define('FOPEN_READ_WRITE_CREATE_STRICT',		'x+b');
+
+
+/* End of file constants.php */
+/* Location: ./application/config/constants.php */

+ 69 - 0
php-codeigniter/application/config/database.php

@@ -0,0 +1,69 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/*
+| -------------------------------------------------------------------
+| DATABASE CONNECTIVITY SETTINGS
+| -------------------------------------------------------------------
+| This file will contain the settings needed to access your database.
+|
+| For complete instructions please consult the 'Database Connection'
+| page of the User Guide.
+|
+| -------------------------------------------------------------------
+| EXPLANATION OF VARIABLES
+| -------------------------------------------------------------------
+|
+|	['hostname'] The hostname of your database server.
+|	['username'] The username used to connect to the database
+|	['password'] The password used to connect to the database
+|	['database'] The name of the database you want to connect to
+|	['dbdriver'] The database type. ie: mysql.  Currently supported:
+				 mysql, mysqli, postgre, odbc, mssql, sqlite, oci8
+|	['dbprefix'] You can add an optional prefix, which will be added
+|				 to the table name when using the  Active Record class
+|	['pconnect'] TRUE/FALSE - Whether to use a persistent connection
+|	['db_debug'] TRUE/FALSE - Whether database errors should be displayed.
+|	['cache_on'] TRUE/FALSE - Enables/disables query caching
+|	['cachedir'] The path to the folder where cache files should be stored
+|	['char_set'] The character set used in communicating with the database
+|	['dbcollat'] The character collation used in communicating with the database
+|				 NOTE: For MySQL and MySQLi databases, this setting is only used
+| 				 as a backup if your server is running PHP < 5.2.3 or MySQL < 5.0.7
+|				 (and in table creation queries made with DB Forge).
+| 				 There is an incompatibility in PHP with mysql_real_escape_string() which
+| 				 can make your site vulnerable to SQL injection if you are using a
+| 				 multi-byte character set and are running versions lower than these.
+| 				 Sites using Latin-1 or UTF-8 database character set and collation are unaffected.
+|	['swap_pre'] A default table prefix that should be swapped with the dbprefix
+|	['autoinit'] Whether or not to automatically initialize the database.
+|	['stricton'] TRUE/FALSE - forces 'Strict Mode' connections
+|							- good for ensuring strict SQL while developing
+|
+| The $active_group variable lets you choose which connection group to
+| make active.  By default there is only one group (the 'default' group).
+|
+| The $active_record variables lets you determine whether or not to load
+| the active record class
+*/
+
+$active_group = 'default';
+$active_record = TRUE;
+
+$db['default']['hostname'] = 'localhost';
+$db['default']['username'] = 'benchmarkdbuser';
+$db['default']['password'] = 'benchmarkdbpass';
+$db['default']['database'] = 'hello_world';
+$db['default']['dbdriver'] = 'mysql';
+$db['default']['dbprefix'] = '';
+$db['default']['pconnect'] = TRUE;
+$db['default']['db_debug'] = TRUE;
+$db['default']['cache_on'] = FALSE;
+$db['default']['cachedir'] = '';
+$db['default']['char_set'] = 'utf8';
+$db['default']['dbcollat'] = 'utf8_general_ci';
+$db['default']['swap_pre'] = '';
+$db['default']['autoinit'] = TRUE;
+$db['default']['stricton'] = FALSE;
+
+
+/* End of file database.php */
+/* Location: ./application/config/database.php */

+ 15 - 0
php-codeigniter/application/config/doctypes.php

@@ -0,0 +1,15 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+
+$_doctypes = array(
+					'xhtml11'		=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
+					'xhtml1-strict'	=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
+					'xhtml1-trans'	=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
+					'xhtml1-frame'	=> '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
+					'html5'			=> '<!DOCTYPE html>',
+					'html4-strict'	=> '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
+					'html4-trans'	=> '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
+					'html4-frame'	=> '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
+					);
+
+/* End of file doctypes.php */
+/* Location: ./application/config/doctypes.php */

+ 64 - 0
php-codeigniter/application/config/foreign_chars.php

@@ -0,0 +1,64 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/*
+| -------------------------------------------------------------------
+| Foreign Characters
+| -------------------------------------------------------------------
+| This file contains an array of foreign characters for transliteration
+| conversion used by the Text helper
+|
+*/
+$foreign_characters = array(
+	'/ä|æ|ǽ/' => '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 */

+ 16 - 0
php-codeigniter/application/config/hooks.php

@@ -0,0 +1,16 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/*
+| -------------------------------------------------------------------------
+| Hooks
+| -------------------------------------------------------------------------
+| This file lets you define "hooks" to extend CI without hacking the core
+| files.  Please see the user guide for info:
+|
+|	http://codeigniter.com/user_guide/general/hooks.html
+|
+*/
+
+
+
+/* End of file hooks.php */
+/* Location: ./application/config/hooks.php */

+ 10 - 0
php-codeigniter/application/config/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 41 - 0
php-codeigniter/application/config/migration.php

@@ -0,0 +1,41 @@
+<?php defined('BASEPATH') OR exit('No direct script access allowed');
+/*
+|--------------------------------------------------------------------------
+| Enable/Disable Migrations
+|--------------------------------------------------------------------------
+|
+| Migrations are disabled by default but should be enabled 
+| whenever you intend to do a schema migration.
+|
+*/
+$config['migration_enabled'] = FALSE;
+
+
+/*
+|--------------------------------------------------------------------------
+| Migrations version
+|--------------------------------------------------------------------------
+|
+| This is used to set migration version that the file system should be on.
+| If you run $this->migration->latest() this is the version that schema will
+| be upgraded / downgraded to.
+|
+*/
+$config['migration_version'] = 0;
+
+
+/*
+|--------------------------------------------------------------------------
+| Migrations Path
+|--------------------------------------------------------------------------
+|
+| Path to your migrations folder.
+| Typically, it will be within your application path.
+| Also, writing permission is required within the migrations path.
+|
+*/
+$config['migration_path'] = APPPATH . 'migrations/';
+
+
+/* End of file migration.php */
+/* Location: ./application/config/migration.php */

+ 106 - 0
php-codeigniter/application/config/mimes.php

@@ -0,0 +1,106 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/*
+| -------------------------------------------------------------------
+| MIME TYPES
+| -------------------------------------------------------------------
+| This file contains an array of mime types.  It is used by the
+| Upload class to help identify allowed file types.
+|
+*/
+
+$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', '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'	=>	array('application/octet-stream', 'application/x-msdownload'),
+				'class'	=>	'application/octet-stream',
+				'psd'	=>	'application/x-photoshop',
+				'so'	=>	'application/octet-stream',
+				'sea'	=>	'application/octet-stream',
+				'dll'	=>	'application/octet-stream',
+				'oda'	=>	'application/oda',
+				'pdf'	=>	array('application/pdf', 'application/x-download'),
+				'ai'	=>	'application/postscript',
+				'eps'	=>	'application/postscript',
+				'ps'	=>	'application/postscript',
+				'smi'	=>	'application/smil',
+				'smil'	=>	'application/smil',
+				'mif'	=>	'application/vnd.mif',
+				'xls'	=>	array('application/excel', 'application/vnd.ms-excel', 'application/msexcel'),
+				'ppt'	=>	array('application/powerpoint', 'application/vnd.ms-powerpoint'),
+				'wbxml'	=>	'application/wbxml',
+				'wmlc'	=>	'application/wmlc',
+				'dcr'	=>	'application/x-director',
+				'dir'	=>	'application/x-director',
+				'dxr'	=>	'application/x-director',
+				'dvi'	=>	'application/x-dvi',
+				'gtar'	=>	'application/x-gtar',
+				'gz'	=>	'application/x-gzip',
+				'php'	=>	'application/x-httpd-php',
+				'php4'	=>	'application/x-httpd-php',
+				'php3'	=>	'application/x-httpd-php',
+				'phtml'	=>	'application/x-httpd-php',
+				'phps'	=>	'application/x-httpd-php-source',
+				'js'	=>	'application/x-javascript',
+				'swf'	=>	'application/x-shockwave-flash',
+				'sit'	=>	'application/x-stuffit',
+				'tar'	=>	'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'),
+				'mid'	=>	'audio/midi',
+				'midi'	=>	'audio/midi',
+				'mpga'	=>	'audio/mpeg',
+				'mp2'	=>	'audio/mpeg',
+				'mp3'	=>	array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'),
+				'aif'	=>	'audio/x-aiff',
+				'aiff'	=>	'audio/x-aiff',
+				'aifc'	=>	'audio/x-aiff',
+				'ram'	=>	'audio/x-pn-realaudio',
+				'rm'	=>	'audio/x-pn-realaudio',
+				'rpm'	=>	'audio/x-pn-realaudio-plugin',
+				'ra'	=>	'audio/x-realaudio',
+				'rv'	=>	'video/vnd.rn-realvideo',
+				'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'),
+				'jpe'	=>	array('image/jpeg', 'image/pjpeg'),
+				'png'	=>	array('image/png',  'image/x-png'),
+				'tiff'	=>	'image/tiff',
+				'tif'	=>	'image/tiff',
+				'css'	=>	'text/css',
+				'html'	=>	'text/html',
+				'htm'	=>	'text/html',
+				'shtml'	=>	'text/html',
+				'txt'	=>	'text/plain',
+				'text'	=>	'text/plain',
+				'log'	=>	array('text/plain', 'text/x-log'),
+				'rtx'	=>	'text/richtext',
+				'rtf'	=>	'text/rtf',
+				'xml'	=>	'text/xml',
+				'xsl'	=>	'text/xml',
+				'mpeg'	=>	'video/mpeg',
+				'mpg'	=>	'video/mpeg',
+				'mpe'	=>	'video/mpeg',
+				'qt'	=>	'video/quicktime',
+				'mov'	=>	'video/quicktime',
+				'avi'	=>	'video/x-msvideo',
+				'movie'	=>	'video/x-sgi-movie',
+				'doc'	=>	'application/msword',
+				'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',
+				'json' => array('application/json', 'text/json')
+			);
+
+
+/* End of file mimes.php */
+/* Location: ./application/config/mimes.php */

+ 17 - 0
php-codeigniter/application/config/profiler.php

@@ -0,0 +1,17 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/*
+| -------------------------------------------------------------------------
+| Profiler Sections
+| -------------------------------------------------------------------------
+| This file lets you determine whether or not various sections of Profiler
+| data are displayed when the Profiler is enabled.
+| Please see the user guide for info:
+|
+|	http://codeigniter.com/user_guide/general/profiling.html
+|
+*/
+
+
+
+/* End of file profiler.php */
+/* Location: ./application/config/profiler.php */

+ 46 - 0
php-codeigniter/application/config/routes.php

@@ -0,0 +1,46 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/*
+| -------------------------------------------------------------------------
+| URI ROUTING
+| -------------------------------------------------------------------------
+| This file lets you re-map URI requests to specific controller functions.
+|
+| Typically there is a one-to-one relationship between a URL string
+| and its corresponding controller class/method. The segments in a
+| URL normally follow this pattern:
+|
+|	example.com/class/method/id/
+|
+| In some instances, however, you may want to remap this relationship
+| so that a different class/function is called than the one
+| corresponding to the URL.
+|
+| Please see the user guide for complete details:
+|
+|	http://codeigniter.com/user_guide/general/routing.html
+|
+| -------------------------------------------------------------------------
+| RESERVED ROUTES
+| -------------------------------------------------------------------------
+|
+| There area two reserved routes:
+|
+|	$route['default_controller'] = 'welcome';
+|
+| This route indicates which controller class should be loaded if the
+| URI contains no data. In the above example, the "welcome" class
+| would be loaded.
+|
+|	$route['404_override'] = 'errors/page_missing';
+|
+| This route will tell the Router what URI segments to use if those provided
+| in the URL cannot be matched to a valid route.
+|
+*/
+
+$route['default_controller'] = "welcome";
+$route['404_override'] = '';
+
+
+/* End of file routes.php */
+/* Location: ./application/config/routes.php */

+ 66 - 0
php-codeigniter/application/config/smileys.php

@@ -0,0 +1,66 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/*
+| -------------------------------------------------------------------
+| SMILEYS
+| -------------------------------------------------------------------
+| This file contains an array of smileys for use with the emoticon helper.
+| Individual images can be used to replace multiple simileys.  For example:
+| :-) and :) use the same image replacement.
+|
+| Please see user guide for more info:
+| http://codeigniter.com/user_guide/helpers/smiley_helper.html
+|
+*/
+
+$smileys = array(
+
+//	smiley			image name						width	height	alt
+
+	':-)'			=>	array('grin.gif',			'19',	'19',	'grin'),
+	':lol:'			=>	array('lol.gif',			'19',	'19',	'LOL'),
+	':cheese:'		=>	array('cheese.gif',			'19',	'19',	'cheese'),
+	':)'			=>	array('smile.gif',			'19',	'19',	'smile'),
+	';-)'			=>	array('wink.gif',			'19',	'19',	'wink'),
+	';)'			=>	array('wink.gif',			'19',	'19',	'wink'),
+	':smirk:'		=>	array('smirk.gif',			'19',	'19',	'smirk'),
+	':roll:'		=>	array('rolleyes.gif',		'19',	'19',	'rolleyes'),
+	':-S'			=>	array('confused.gif',		'19',	'19',	'confused'),
+	':wow:'			=>	array('surprise.gif',		'19',	'19',	'surprised'),
+	':bug:'			=>	array('bigsurprise.gif',	'19',	'19',	'big surprise'),
+	':-P'			=>	array('tongue_laugh.gif',	'19',	'19',	'tongue laugh'),
+	'%-P'			=>	array('tongue_rolleye.gif',	'19',	'19',	'tongue rolleye'),
+	';-P'			=>	array('tongue_wink.gif',	'19',	'19',	'tongue wink'),
+	':P'			=>	array('raspberry.gif',		'19',	'19',	'raspberry'),
+	':blank:'		=>	array('blank.gif',			'19',	'19',	'blank stare'),
+	':long:'		=>	array('longface.gif',		'19',	'19',	'long face'),
+	':ohh:'			=>	array('ohh.gif',			'19',	'19',	'ohh'),
+	':grrr:'		=>	array('grrr.gif',			'19',	'19',	'grrr'),
+	':gulp:'		=>	array('gulp.gif',			'19',	'19',	'gulp'),
+	'8-/'			=>	array('ohoh.gif',			'19',	'19',	'oh oh'),
+	':down:'		=>	array('downer.gif',			'19',	'19',	'downer'),
+	':red:'			=>	array('embarrassed.gif',	'19',	'19',	'red face'),
+	':sick:'		=>	array('sick.gif',			'19',	'19',	'sick'),
+	':shut:'		=>	array('shuteye.gif',		'19',	'19',	'shut eye'),
+	':-/'			=>	array('hmm.gif',			'19',	'19',	'hmmm'),
+	'>:('			=>	array('mad.gif',			'19',	'19',	'mad'),
+	':mad:'			=>	array('mad.gif',			'19',	'19',	'mad'),
+	'>:-('			=>	array('angry.gif',			'19',	'19',	'angry'),
+	':angry:'		=>	array('angry.gif',			'19',	'19',	'angry'),
+	':zip:'			=>	array('zip.gif',			'19',	'19',	'zipper'),
+	':kiss:'		=>	array('kiss.gif',			'19',	'19',	'kiss'),
+	':ahhh:'		=>	array('shock.gif',			'19',	'19',	'shock'),
+	':coolsmile:'	=>	array('shade_smile.gif',	'19',	'19',	'cool smile'),
+	':coolsmirk:'	=>	array('shade_smirk.gif',	'19',	'19',	'cool smirk'),
+	':coolgrin:'	=>	array('shade_grin.gif',		'19',	'19',	'cool grin'),
+	':coolhmm:'		=>	array('shade_hmm.gif',		'19',	'19',	'cool hmm'),
+	':coolmad:'		=>	array('shade_mad.gif',		'19',	'19',	'cool mad'),
+	':coolcheese:'	=>	array('shade_cheese.gif',	'19',	'19',	'cool cheese'),
+	':vampire:'		=>	array('vampire.gif',		'19',	'19',	'vampire'),
+	':snake:'		=>	array('snake.gif',			'19',	'19',	'snake'),
+	':exclaim:'		=>	array('exclaim.gif',		'19',	'19',	'excaim'),
+	':question:'	=>	array('question.gif',		'19',	'19',	'question') // no comma after last item
+
+		);
+
+/* End of file smileys.php */
+/* Location: ./application/config/smileys.php */

+ 178 - 0
php-codeigniter/application/config/user_agents.php

@@ -0,0 +1,178 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/*
+| -------------------------------------------------------------------
+| USER AGENT TYPES
+| -------------------------------------------------------------------
+| This file contains four arrays of user agent data.  It is used by the
+| User Agent Class to help identify browser, platform, robot, and
+| mobile device data.  The array keys are used to identify the device
+| and the array values are used to set the actual name of the item.
+|
+*/
+
+$platforms = array (
+					'windows nt 6.0'	=> 'Windows Longhorn',
+					'windows nt 5.2'	=> 'Windows 2003',
+					'windows nt 5.0'	=> 'Windows 2000',
+					'windows nt 5.1'	=> 'Windows XP',
+					'windows nt 4.0'	=> 'Windows NT 4.0',
+					'winnt4.0'			=> 'Windows NT 4.0',
+					'winnt 4.0'			=> 'Windows NT',
+					'winnt'				=> 'Windows NT',
+					'windows 98'		=> 'Windows 98',
+					'win98'				=> 'Windows 98',
+					'windows 95'		=> 'Windows 95',
+					'win95'				=> 'Windows 95',
+					'windows'			=> 'Unknown Windows OS',
+					'os x'				=> 'Mac OS X',
+					'ppc mac'			=> 'Power PC Mac',
+					'freebsd'			=> 'FreeBSD',
+					'ppc'				=> 'Macintosh',
+					'linux'				=> 'Linux',
+					'debian'			=> 'Debian',
+					'sunos'				=> 'Sun Solaris',
+					'beos'				=> 'BeOS',
+					'apachebench'		=> 'ApacheBench',
+					'aix'				=> 'AIX',
+					'irix'				=> 'Irix',
+					'osf'				=> 'DEC OSF',
+					'hp-ux'				=> 'HP-UX',
+					'netbsd'			=> 'NetBSD',
+					'bsdi'				=> 'BSDi',
+					'openbsd'			=> 'OpenBSD',
+					'gnu'				=> 'GNU/Linux',
+					'unix'				=> 'Unknown Unix OS'
+				);
+
+
+// The order of this array should NOT be changed. Many browsers return
+// multiple browser types so we want to identify the sub-type first.
+$browsers = array(
+					'Flock'				=> 'Flock',
+					'Chrome'			=> 'Chrome',
+					'Opera'				=> 'Opera',
+					'MSIE'				=> 'Internet Explorer',
+					'Internet Explorer'	=> 'Internet Explorer',
+					'Shiira'			=> 'Shiira',
+					'Firefox'			=> 'Firefox',
+					'Chimera'			=> 'Chimera',
+					'Phoenix'			=> 'Phoenix',
+					'Firebird'			=> 'Firebird',
+					'Camino'			=> 'Camino',
+					'Netscape'			=> 'Netscape',
+					'OmniWeb'			=> 'OmniWeb',
+					'Safari'			=> 'Safari',
+					'Mozilla'			=> 'Mozilla',
+					'Konqueror'			=> 'Konqueror',
+					'icab'				=> 'iCab',
+					'Lynx'				=> 'Lynx',
+					'Links'				=> 'Links',
+					'hotjava'			=> 'HotJava',
+					'amaya'				=> 'Amaya',
+					'IBrowse'			=> 'IBrowse'
+				);
+
+$mobiles = array(
+					// legacy array, old values commented out
+					'mobileexplorer'	=> 'Mobile Explorer',
+//					'openwave'			=> 'Open Wave',
+//					'opera mini'		=> 'Opera Mini',
+//					'operamini'			=> 'Opera Mini',
+//					'elaine'			=> 'Palm',
+					'palmsource'		=> 'Palm',
+//					'digital paths'		=> 'Palm',
+//					'avantgo'			=> 'Avantgo',
+//					'xiino'				=> 'Xiino',
+					'palmscape'			=> 'Palmscape',
+//					'nokia'				=> 'Nokia',
+//					'ericsson'			=> 'Ericsson',
+//					'blackberry'		=> 'BlackBerry',
+//					'motorola'			=> 'Motorola'
+
+					// Phones and Manufacturers
+					'motorola'			=> "Motorola",
+					'nokia'				=> "Nokia",
+					'palm'				=> "Palm",
+					'iphone'			=> "Apple iPhone",
+					'ipad'				=> "iPad",
+					'ipod'				=> "Apple iPod Touch",
+					'sony'				=> "Sony Ericsson",
+					'ericsson'			=> "Sony Ericsson",
+					'blackberry'		=> "BlackBerry",
+					'cocoon'			=> "O2 Cocoon",
+					'blazer'			=> "Treo",
+					'lg'				=> "LG",
+					'amoi'				=> "Amoi",
+					'xda'				=> "XDA",
+					'mda'				=> "MDA",
+					'vario'				=> "Vario",
+					'htc'				=> "HTC",
+					'samsung'			=> "Samsung",
+					'sharp'				=> "Sharp",
+					'sie-'				=> "Siemens",
+					'alcatel'			=> "Alcatel",
+					'benq'				=> "BenQ",
+					'ipaq'				=> "HP iPaq",
+					'mot-'				=> "Motorola",
+					'playstation portable'	=> "PlayStation Portable",
+					'hiptop'			=> "Danger Hiptop",
+					'nec-'				=> "NEC",
+					'panasonic'			=> "Panasonic",
+					'philips'			=> "Philips",
+					'sagem'				=> "Sagem",
+					'sanyo'				=> "Sanyo",
+					'spv'				=> "SPV",
+					'zte'				=> "ZTE",
+					'sendo'				=> "Sendo",
+
+					// Operating Systems
+					'symbian'				=> "Symbian",
+					'SymbianOS'				=> "SymbianOS",
+					'elaine'				=> "Palm",
+					'palm'					=> "Palm",
+					'series60'				=> "Symbian S60",
+					'windows ce'			=> "Windows CE",
+
+					// Browsers
+					'obigo'					=> "Obigo",
+					'netfront'				=> "Netfront Browser",
+					'openwave'				=> "Openwave Browser",
+					'mobilexplorer'			=> "Mobile Explorer",
+					'operamini'				=> "Opera Mini",
+					'opera mini'			=> "Opera Mini",
+
+					// Other
+					'digital paths'			=> "Digital Paths",
+					'avantgo'				=> "AvantGo",
+					'xiino'					=> "Xiino",
+					'novarra'				=> "Novarra Transcoder",
+					'vodafone'				=> "Vodafone",
+					'docomo'				=> "NTT DoCoMo",
+					'o2'					=> "O2",
+
+					// Fallback
+					'mobile'				=> "Generic Mobile",
+					'wireless'				=> "Generic Mobile",
+					'j2me'					=> "Generic Mobile",
+					'midp'					=> "Generic Mobile",
+					'cldc'					=> "Generic Mobile",
+					'up.link'				=> "Generic Mobile",
+					'up.browser'			=> "Generic Mobile",
+					'smartphone'			=> "Generic Mobile",
+					'cellphone'				=> "Generic Mobile"
+				);
+
+// There are hundreds of bots but these are the most common.
+$robots = array(
+					'googlebot'			=> 'Googlebot',
+					'msnbot'			=> 'MSNBot',
+					'slurp'				=> 'Inktomi Slurp',
+					'yahoo'				=> 'Yahoo',
+					'askjeeves'			=> 'AskJeeves',
+					'fastcrawler'		=> 'FastCrawler',
+					'infoseek'			=> 'InfoSeek Robot 1.0',
+					'lycos'				=> 'Lycos'
+				);
+
+/* End of file user_agents.php */
+/* Location: ./application/config/user_agents.php */

+ 31 - 0
php-codeigniter/application/controllers/bench.php

@@ -0,0 +1,31 @@
+<?php
+/**
+ * Created by JetBrains PhpStorm.
+ * User: Skamander
+ * Date: 11.04.13
+ * Time: 17:33
+ * To change this template use File | Settings | File Templates.
+ */
+
+class Bench extends CI_Controller {
+
+    public function json() {
+        $this->output
+            ->set_content_type('application/json')
+            ->set_output(json_encode(array('message' => 'Hello World!')));
+    }
+
+    public function db($queries = 1) {
+        $worlds = array();
+
+        for ($i = 0; $i < $queries; ++$i) {
+            $worlds[] = $this->db
+                ->query('SELECT * FROM World WHERE id = ?', array(mt_rand(1, 10000)))
+                ->row();
+        }
+
+        $this->output
+            ->set_content_type('application/json')
+            ->set_output(json_encode($worlds));
+    }
+}

+ 10 - 0
php-codeigniter/application/controllers/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 27 - 0
php-codeigniter/application/controllers/welcome.php

@@ -0,0 +1,27 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+
+class Welcome extends CI_Controller {
+
+	/**
+	 * Index Page for this controller.
+	 *
+	 * Maps to the following URL
+	 * 		http://example.com/index.php/welcome
+	 *	- or -  
+	 * 		http://example.com/index.php/welcome/index
+	 *	- or -
+	 * Since this controller is set as the default controller in 
+	 * config/routes.php, it's displayed at http://example.com/
+	 *
+	 * So any other public methods not prefixed with an underscore will
+	 * map to /index.php/welcome/<method_name>
+	 * @see http://codeigniter.com/user_guide/general/urls.html
+	 */
+	public function index()
+	{
+		$this->load->view('welcome_message');
+	}
+}
+
+/* End of file welcome.php */
+/* Location: ./application/controllers/welcome.php */

+ 10 - 0
php-codeigniter/application/core/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 62 - 0
php-codeigniter/application/errors/error_404.php

@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>404 Page Not Found</title>
+<style type="text/css">
+
+::selection{ background-color: #E13300; color: white; }
+::moz-selection{ background-color: #E13300; color: white; }
+::webkit-selection{ background-color: #E13300; color: white; }
+
+body {
+	background-color: #fff;
+	margin: 40px;
+	font: 13px/20px normal Helvetica, Arial, sans-serif;
+	color: #4F5155;
+}
+
+a {
+	color: #003399;
+	background-color: transparent;
+	font-weight: normal;
+}
+
+h1 {
+	color: #444;
+	background-color: transparent;
+	border-bottom: 1px solid #D0D0D0;
+	font-size: 19px;
+	font-weight: normal;
+	margin: 0 0 14px 0;
+	padding: 14px 15px 10px 15px;
+}
+
+code {
+	font-family: Consolas, Monaco, Courier New, Courier, monospace;
+	font-size: 12px;
+	background-color: #f9f9f9;
+	border: 1px solid #D0D0D0;
+	color: #002166;
+	display: block;
+	margin: 14px 0 14px 0;
+	padding: 12px 10px 12px 10px;
+}
+
+#container {
+	margin: 10px;
+	border: 1px solid #D0D0D0;
+	-webkit-box-shadow: 0 0 8px #D0D0D0;
+}
+
+p {
+	margin: 12px 15px 12px 15px;
+}
+</style>
+</head>
+<body>
+	<div id="container">
+		<h1><?php echo $heading; ?></h1>
+		<?php echo $message; ?>
+	</div>
+</body>
+</html>

+ 62 - 0
php-codeigniter/application/errors/error_db.php

@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Database Error</title>
+<style type="text/css">
+
+::selection{ background-color: #E13300; color: white; }
+::moz-selection{ background-color: #E13300; color: white; }
+::webkit-selection{ background-color: #E13300; color: white; }
+
+body {
+	background-color: #fff;
+	margin: 40px;
+	font: 13px/20px normal Helvetica, Arial, sans-serif;
+	color: #4F5155;
+}
+
+a {
+	color: #003399;
+	background-color: transparent;
+	font-weight: normal;
+}
+
+h1 {
+	color: #444;
+	background-color: transparent;
+	border-bottom: 1px solid #D0D0D0;
+	font-size: 19px;
+	font-weight: normal;
+	margin: 0 0 14px 0;
+	padding: 14px 15px 10px 15px;
+}
+
+code {
+	font-family: Consolas, Monaco, Courier New, Courier, monospace;
+	font-size: 12px;
+	background-color: #f9f9f9;
+	border: 1px solid #D0D0D0;
+	color: #002166;
+	display: block;
+	margin: 14px 0 14px 0;
+	padding: 12px 10px 12px 10px;
+}
+
+#container {
+	margin: 10px;
+	border: 1px solid #D0D0D0;
+	-webkit-box-shadow: 0 0 8px #D0D0D0;
+}
+
+p {
+	margin: 12px 15px 12px 15px;
+}
+</style>
+</head>
+<body>
+	<div id="container">
+		<h1><?php echo $heading; ?></h1>
+		<?php echo $message; ?>
+	</div>
+</body>
+</html>

+ 62 - 0
php-codeigniter/application/errors/error_general.php

@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Error</title>
+<style type="text/css">
+
+::selection{ background-color: #E13300; color: white; }
+::moz-selection{ background-color: #E13300; color: white; }
+::webkit-selection{ background-color: #E13300; color: white; }
+
+body {
+	background-color: #fff;
+	margin: 40px;
+	font: 13px/20px normal Helvetica, Arial, sans-serif;
+	color: #4F5155;
+}
+
+a {
+	color: #003399;
+	background-color: transparent;
+	font-weight: normal;
+}
+
+h1 {
+	color: #444;
+	background-color: transparent;
+	border-bottom: 1px solid #D0D0D0;
+	font-size: 19px;
+	font-weight: normal;
+	margin: 0 0 14px 0;
+	padding: 14px 15px 10px 15px;
+}
+
+code {
+	font-family: Consolas, Monaco, Courier New, Courier, monospace;
+	font-size: 12px;
+	background-color: #f9f9f9;
+	border: 1px solid #D0D0D0;
+	color: #002166;
+	display: block;
+	margin: 14px 0 14px 0;
+	padding: 12px 10px 12px 10px;
+}
+
+#container {
+	margin: 10px;
+	border: 1px solid #D0D0D0;
+	-webkit-box-shadow: 0 0 8px #D0D0D0;
+}
+
+p {
+	margin: 12px 15px 12px 15px;
+}
+</style>
+</head>
+<body>
+	<div id="container">
+		<h1><?php echo $heading; ?></h1>
+		<?php echo $message; ?>
+	</div>
+</body>
+</html>

+ 10 - 0
php-codeigniter/application/errors/error_php.php

@@ -0,0 +1,10 @@
+<div style="border:1px solid #990000;padding-left:20px;margin:0 0 10px 0;">
+
+<h4>A PHP Error was encountered</h4>
+
+<p>Severity: <?php echo $severity; ?></p>
+<p>Message:  <?php echo $message; ?></p>
+<p>Filename: <?php echo $filepath; ?></p>
+<p>Line Number: <?php echo $line; ?></p>
+
+</div>

+ 10 - 0
php-codeigniter/application/errors/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 10 - 0
php-codeigniter/application/helpers/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 10 - 0
php-codeigniter/application/hooks/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 10 - 0
php-codeigniter/application/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 10 - 0
php-codeigniter/application/language/english/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 10 - 0
php-codeigniter/application/libraries/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 10 - 0
php-codeigniter/application/logs/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 10 - 0
php-codeigniter/application/models/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 10 - 0
php-codeigniter/application/third_party/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 10 - 0
php-codeigniter/application/views/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 88 - 0
php-codeigniter/application/views/welcome_message.php

@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+	<meta charset="utf-8">
+	<title>Welcome to CodeIgniter</title>
+
+	<style type="text/css">
+
+	::selection{ background-color: #E13300; color: white; }
+	::moz-selection{ background-color: #E13300; color: white; }
+	::webkit-selection{ background-color: #E13300; color: white; }
+
+	body {
+		background-color: #fff;
+		margin: 40px;
+		font: 13px/20px normal Helvetica, Arial, sans-serif;
+		color: #4F5155;
+	}
+
+	a {
+		color: #003399;
+		background-color: transparent;
+		font-weight: normal;
+	}
+
+	h1 {
+		color: #444;
+		background-color: transparent;
+		border-bottom: 1px solid #D0D0D0;
+		font-size: 19px;
+		font-weight: normal;
+		margin: 0 0 14px 0;
+		padding: 14px 15px 10px 15px;
+	}
+
+	code {
+		font-family: Consolas, Monaco, Courier New, Courier, monospace;
+		font-size: 12px;
+		background-color: #f9f9f9;
+		border: 1px solid #D0D0D0;
+		color: #002166;
+		display: block;
+		margin: 14px 0 14px 0;
+		padding: 12px 10px 12px 10px;
+	}
+
+	#body{
+		margin: 0 15px 0 15px;
+	}
+	
+	p.footer{
+		text-align: right;
+		font-size: 11px;
+		border-top: 1px solid #D0D0D0;
+		line-height: 32px;
+		padding: 0 10px 0 10px;
+		margin: 20px 0 0 0;
+	}
+	
+	#container{
+		margin: 10px;
+		border: 1px solid #D0D0D0;
+		-webkit-box-shadow: 0 0 8px #D0D0D0;
+	}
+	</style>
+</head>
+<body>
+
+<div id="container">
+	<h1>Welcome to CodeIgniter!</h1>
+
+	<div id="body">
+		<p>The page you are looking at is being generated dynamically by CodeIgniter.</p>
+
+		<p>If you would like to edit this page you'll find it located at:</p>
+		<code>application/views/welcome_message.php</code>
+
+		<p>The corresponding controller for this page is found at:</p>
+		<code>application/controllers/welcome.php</code>
+
+		<p>If you are exploring CodeIgniter for the very first time, you should start by reading the <a href="user_guide/">User Guide</a>.</p>
+	</div>
+
+	<p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds</p>
+</div>
+
+</body>
+</html>

+ 13 - 0
php-codeigniter/benchmark_config

@@ -0,0 +1,13 @@
+{
+  "framework": "php-codeigniter",
+  "tests": [{
+    "default": {
+      "setup_file": "setup",
+      "json_url": "/index.php/bench/json",
+      "db_url": "/index.php/bench/db",
+      "query_url": "/index.php/bench/db/",
+      "port": 8080,
+      "sort": 52
+    }
+  }]
+}

+ 125 - 0
php-codeigniter/deploy/nginx.conf

@@ -0,0 +1,125 @@
+#user  nobody;
+worker_processes  8;
+
+#error_log  logs/error.log;
+#error_log  logs/error.log  notice;
+#error_log  logs/error.log  info;
+
+#pid        logs/nginx.pid;
+
+
+events {
+    worker_connections  1024;
+}
+
+
+http {
+    include       /usr/local/nginx/conf/mime.types;
+    default_type  application/octet-stream;
+
+    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
+    #                  '$status $body_bytes_sent "$http_referer" '
+    #                  '"$http_user_agent" "$http_x_forwarded_for"';
+
+    #access_log  logs/access.log  main;
+
+    sendfile        on;
+    #tcp_nopush     on;
+
+    #keepalive_timeout  0;
+    keepalive_timeout  65;
+
+    #gzip  on;
+
+    server {
+        listen       8080;
+        server_name  localhost;
+
+        #charset koi8-r;
+
+        #access_log  logs/host.access.log  main;
+
+        #location / {
+        #    root   html;
+        #    index  index.html index.htm;
+        #}
+
+        #error_page  404              /404.html;
+
+        # redirect server error pages to the static page /50x.html
+        #
+        #error_page   500 502 503 504  /50x.html;
+        #location = /50x.html {
+        #    root   html;
+        #}
+
+        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
+        #
+        #location ~ \.php$ {
+        #    proxy_pass   http://127.0.0.1;
+        #}
+
+        root /home/ubuntu/FrameworkBenchmarks/php-codeigniter/;
+        index  index.php;
+
+        location / {
+            try_files $uri $uri/ /index.php?$uri&$args;
+        }
+
+        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
+        #
+        location ~ \.php$ {
+            try_files $uri =404;
+            fastcgi_pass   127.0.0.1:9001;
+            fastcgi_index  index.php;
+#            fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
+            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
+            include        /usr/local/nginx/conf/fastcgi_params;
+        }
+
+        # deny access to .htaccess files, if Apache's document root
+        # concurs with nginx's one
+        #
+        #location ~ /\.ht {
+        #    deny  all;
+        #}
+    }
+
+
+    # another virtual host using mix of IP-, name-, and port-based configuration
+    #
+    #server {
+    #    listen       8000;
+    #    listen       somename:8080;
+    #    server_name  somename  alias  another.alias;
+
+    #    location / {
+    #        root   html;
+    #        index  index.html index.htm;
+    #    }
+    #}
+
+
+    # HTTPS server
+    #
+    #server {
+    #    listen       443;
+    #    server_name  localhost;
+
+    #    ssl                  on;
+    #    ssl_certificate      cert.pem;
+    #    ssl_certificate_key  cert.key;
+
+    #    ssl_session_timeout  5m;
+
+    #    ssl_protocols  SSLv2 SSLv3 TLSv1;
+    #    ssl_ciphers  HIGH:!aNULL:!MD5;
+    #    ssl_prefer_server_ciphers   on;
+
+    #    location / {
+    #        root   html;
+    #        index  index.html index.htm;
+    #    }
+    #}
+
+}

+ 9 - 0
php-codeigniter/deploy/php-codeigniter

@@ -0,0 +1,9 @@
+<VirtualHost *:8080>
+  Alias /php-codeigniter/ "/home/ubuntu/FrameworkBenchmarks/php-codeigniter/"
+  <Directory /home/ubuntu/FrameworkBenchmarks/php-codeigniter>
+          Options Indexes FollowSymLinks MultiViews
+          #AllowOverride None
+          Order allow,deny
+          allow from all
+  </Directory>
+</VirtualHost>

+ 205 - 0
php-codeigniter/index.php

@@ -0,0 +1,205 @@
+<?php
+
+/*
+ *---------------------------------------------------------------
+ * APPLICATION ENVIRONMENT
+ *---------------------------------------------------------------
+ *
+ * You can load different configurations depending on your
+ * current environment. Setting the environment also influences
+ * things like logging and error reporting.
+ *
+ * This can be set to anything, but default usage is:
+ *
+ *     development
+ *     testing
+ *     production
+ *
+ * NOTE: If you change these, also change the error_reporting() code below
+ *
+ */
+	define('ENVIRONMENT', 'development');
+/*
+ *---------------------------------------------------------------
+ * ERROR REPORTING
+ *---------------------------------------------------------------
+ *
+ * Different environments will require different levels of error reporting.
+ * By default development will show errors but testing and live will hide them.
+ */
+
+if (defined('ENVIRONMENT'))
+{
+	switch (ENVIRONMENT)
+	{
+		case 'development':
+			error_reporting(E_ALL);
+		break;
+	
+		case 'testing':
+		case 'production':
+			error_reporting(0);
+		break;
+
+		default:
+			exit('The application environment is not set correctly.');
+	}
+}
+
+/*
+ *---------------------------------------------------------------
+ * SYSTEM FOLDER NAME
+ *---------------------------------------------------------------
+ *
+ * This variable must contain the name of your "system" folder.
+ * Include the path if the folder is not in the same  directory
+ * as this file.
+ *
+ */
+	$system_path = 'system';
+
+/*
+ *---------------------------------------------------------------
+ * APPLICATION FOLDER NAME
+ *---------------------------------------------------------------
+ *
+ * If you want this front controller to use a different "application"
+ * folder then the default one you can set its name here. The folder
+ * can also be renamed or relocated anywhere on your server.  If
+ * you do, use a full server path. For more info please see the user guide:
+ * http://codeigniter.com/user_guide/general/managing_apps.html
+ *
+ * NO TRAILING SLASH!
+ *
+ */
+	$application_folder = 'application';
+
+/*
+ * --------------------------------------------------------------------
+ * DEFAULT CONTROLLER
+ * --------------------------------------------------------------------
+ *
+ * Normally you will set your default controller in the routes.php file.
+ * You can, however, force a custom routing by hard-coding a
+ * specific controller class/function here.  For most applications, you
+ * WILL NOT set your routing here, but it's an option for those
+ * special instances where you might want to override the standard
+ * routing in a specific front controller that shares a common CI installation.
+ *
+ * IMPORTANT:  If you set the routing here, NO OTHER controller will be
+ * callable. In essence, this preference limits your application to ONE
+ * specific controller.  Leave the function name blank if you need
+ * to call functions dynamically via the URI.
+ *
+ * Un-comment the $routing array below to use this feature
+ *
+ */
+	// The directory name, relative to the "controllers" folder.  Leave blank
+	// if your controller is not in a sub-folder within the "controllers" folder
+	// $routing['directory'] = '';
+
+	// The controller class file name.  Example:  Mycontroller
+	// $routing['controller'] = '';
+
+	// The controller function you wish to be called.
+	// $routing['function']	= '';
+
+
+/*
+ * -------------------------------------------------------------------
+ *  CUSTOM CONFIG VALUES
+ * -------------------------------------------------------------------
+ *
+ * The $assign_to_config array below will be passed dynamically to the
+ * config class when initialized. This allows you to set custom config
+ * items or override any default config values found in the config.php file.
+ * This can be handy as it permits you to share one application between
+ * multiple front controller files, with each file containing different
+ * config values.
+ *
+ * Un-comment the $assign_to_config array below to use this feature
+ *
+ */
+	// $assign_to_config['name_of_config_item'] = 'value of config item';
+
+
+
+// --------------------------------------------------------------------
+// END OF USER CONFIGURABLE SETTINGS.  DO NOT EDIT BELOW THIS LINE
+// --------------------------------------------------------------------
+
+/*
+ * ---------------------------------------------------------------
+ *  Resolve the system path for increased reliability
+ * ---------------------------------------------------------------
+ */
+
+	// Set the current directory correctly for CLI requests
+	if (defined('STDIN'))
+	{
+		chdir(dirname(__FILE__));
+	}
+
+	if (realpath($system_path) !== FALSE)
+	{
+		$system_path = realpath($system_path).'/';
+	}
+
+	// ensure there's a trailing slash
+	$system_path = rtrim($system_path, '/').'/';
+
+	// Is the system path correct?
+	if ( ! is_dir($system_path))
+	{
+		exit("Your system folder path does not appear to be set correctly. Please open the following file and correct this: ".pathinfo(__FILE__, PATHINFO_BASENAME));
+	}
+
+/*
+ * -------------------------------------------------------------------
+ *  Now that we know the path, set the main path constants
+ * -------------------------------------------------------------------
+ */
+	// The name of THIS file
+	define('SELF', pathinfo(__FILE__, PATHINFO_BASENAME));
+
+	// The PHP file extension
+	// this global constant is deprecated.
+	define('EXT', '.php');
+
+	// Path to the system folder
+	define('BASEPATH', str_replace("\\", "/", $system_path));
+
+	// Path to the front controller (this file)
+	define('FCPATH', str_replace(SELF, '', __FILE__));
+
+	// Name of the "system folder"
+	define('SYSDIR', trim(strrchr(trim(BASEPATH, '/'), '/'), '/'));
+
+
+	// The path to the "application" folder
+	if (is_dir($application_folder))
+	{
+		define('APPPATH', $application_folder.'/');
+	}
+	else
+	{
+		if ( ! is_dir(BASEPATH.$application_folder.'/'))
+		{
+			exit("Your application folder path does not appear to be set correctly. Please open the following file and correct this: ".SELF);
+		}
+
+		define('APPPATH', BASEPATH.$application_folder.'/');
+	}
+
+/*
+ * --------------------------------------------------------------------
+ * LOAD THE BOOTSTRAP FILE
+ * --------------------------------------------------------------------
+ *
+ * And away we go...
+ *
+ */
+require_once BASEPATH.'core/CodeIgniter.php';
+
+/* End of file index.php */
+/* Location: ./index.php */

+ 51 - 0
php-codeigniter/license.txt

@@ -0,0 +1,51 @@
+Copyright (c) 2008 - 2011, EllisLab, Inc.
+All rights reserved.
+
+This license is a legal agreement between you and EllisLab Inc. for the use
+of CodeIgniter Software (the "Software").  By obtaining the Software you
+agree to comply with the terms and conditions of this license.
+
+PERMITTED USE
+You are permitted to use, copy, modify, and distribute the Software and its
+documentation, with or without modification, for any purpose, provided that
+the following conditions are met:
+
+1. A copy of this license agreement must be included with the distribution.
+
+2. Redistributions of source code must retain the above copyright notice in
+   all source code files.
+
+3. Redistributions in binary form must reproduce the above copyright notice
+   in the documentation and/or other materials provided with the distribution.
+
+4. Any files that have been modified must carry notices stating the nature
+   of the change and the names of those who changed them.
+
+5. Products derived from the Software must include an acknowledgment that
+   they are derived from CodeIgniter in their documentation and/or other
+   materials provided with the distribution.
+
+6. Products derived from the Software may not be called "CodeIgniter",
+   nor may "CodeIgniter" appear in their name, without prior written
+   permission from EllisLab, Inc.
+
+INDEMNITY
+You agree to indemnify and hold harmless the authors of the Software and
+any contributors for any direct, indirect, incidental, or consequential
+third-party claims, actions or suits, as well as any related expenses,
+liabilities, damages, settlements or fees arising from your use or misuse
+of the Software, or a violation of any terms of this license.
+
+DISCLAIMER OF WARRANTY
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR
+IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF QUALITY, PERFORMANCE,
+NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
+
+LIMITATIONS OF LIABILITY
+YOU ASSUME ALL RISK ASSOCIATED WITH THE INSTALLATION AND USE OF THE SOFTWARE.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS OF THE SOFTWARE BE LIABLE
+FOR CLAIMS, DAMAGES OR OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION
+WITH THE SOFTWARE. LICENSE HOLDERS ARE SOLELY RESPONSIBLE FOR DETERMINING THE
+APPROPRIATENESS OF USE AND ASSUME ALL RISKS ASSOCIATED WITH ITS USE, INCLUDING
+BUT NOT LIMITED TO THE RISKS OF PROGRAM ERRORS, DAMAGE TO EQUIPMENT, LOSS OF
+DATA OR SOFTWARE PROGRAMS, OR UNAVAILABILITY OR INTERRUPTION OF OPERATIONS.

+ 26 - 0
php-codeigniter/setup.py

@@ -0,0 +1,26 @@
+import subprocess
+import sys
+import setup_util
+from os.path import expanduser
+
+home = expanduser("~")
+
+def start(args):
+  setup_util.replace_text("php-codeigniter/application/config/database.php", "localhost", ""+ args.database_host +"")
+  setup_util.replace_text("php-codeigniter/deploy/nginx.conf", "root .*\/FrameworkBenchmarks", "root " + home + "/FrameworkBenchmarks")
+
+  try:
+    subprocess.check_call("sudo chown -R www-data:www-data php-codeigniter", shell=True)
+    subprocess.check_call("sudo php-fpm --fpm-config config/php-fpm.conf -g " + home + "/FrameworkBenchmarks/php-codeigniter/deploy/php-fpm.pid", shell=True)
+    subprocess.check_call("sudo /usr/local/nginx/sbin/nginx -c " + home + "/FrameworkBenchmarks/php-codeigniter/deploy/nginx.conf", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+def stop():
+  try:
+    subprocess.call("sudo /usr/local/nginx/sbin/nginx -s stop", shell=True)
+    subprocess.call("sudo kill -QUIT $( cat php-codeigniter/deploy/php-fpm.pid )", shell=True)
+    subprocess.check_call("sudo chown -R $USER:$USER php-codeigniter", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1

+ 1 - 0
php-codeigniter/system/.htaccess

@@ -0,0 +1 @@
+Deny from all

+ 118 - 0
php-codeigniter/system/core/Benchmark.php

@@ -0,0 +1,118 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * CodeIgniter Benchmark Class
+ *
+ * This class enables you to mark points and calculate the time difference
+ * between them.  Memory consumption can also be displayed.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/benchmark.html
+ */
+class CI_Benchmark {
+
+	/**
+	 * List of all benchmark markers and when they were added
+	 *
+	 * @var array
+	 */
+	var $marker = array();
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set a benchmark marker
+	 *
+	 * Multiple calls to this function can be made so that several
+	 * execution points can be timed
+	 *
+	 * @access	public
+	 * @param	string	$name	name of the marker
+	 * @return	void
+	 */
+	function mark($name)
+	{
+		$this->marker[$name] = microtime();
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Calculates the time difference between two marked points.
+	 *
+	 * If the first parameter is empty this function instead returns the
+	 * {elapsed_time} pseudo-variable. This permits the full system
+	 * execution time to be shown in a template. The output class will
+	 * swap the real value for this variable.
+	 *
+	 * @access	public
+	 * @param	string	a particular marked point
+	 * @param	string	a particular marked point
+	 * @param	integer	the number of decimal places
+	 * @return	mixed
+	 */
+	function elapsed_time($point1 = '', $point2 = '', $decimals = 4)
+	{
+		if ($point1 == '')
+		{
+			return '{elapsed_time}';
+		}
+
+		if ( ! isset($this->marker[$point1]))
+		{
+			return '';
+		}
+
+		if ( ! isset($this->marker[$point2]))
+		{
+			$this->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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Memory Usage
+	 *
+	 * This function returns the {memory_usage} pseudo-variable.
+	 * This permits it to be put it anywhere in a template
+	 * without the memory being calculated until the end.
+	 * The output class will swap the real value for this variable.
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function memory_usage()
+	{
+		return '{memory_usage}';
+	}
+
+}
+
+// END CI_Benchmark class
+
+/* End of file Benchmark.php */
+/* Location: ./system/core/Benchmark.php */

+ 402 - 0
php-codeigniter/system/core/CodeIgniter.php

@@ -0,0 +1,402 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * System Initialization File
+ *
+ * Loads the base classes and executes the request.
+ *
+ * @package		CodeIgniter
+ * @subpackage	codeigniter
+ * @category	Front-controller
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/
+ */
+
+/**
+ * CodeIgniter Version
+ *
+ * @var string
+ *
+ */
+	define('CI_VERSION', '2.1.3');
+
+/**
+ * CodeIgniter Branch (Core = TRUE, Reactor = FALSE)
+ *
+ * @var boolean
+ *
+ */
+	define('CI_CORE', FALSE);
+
+/*
+ * ------------------------------------------------------
+ *  Load the global functions
+ * ------------------------------------------------------
+ */
+	require(BASEPATH.'core/Common.php');
+
+/*
+ * ------------------------------------------------------
+ *  Load the framework constants
+ * ------------------------------------------------------
+ */
+	if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/constants.php'))
+	{
+		require(APPPATH.'config/'.ENVIRONMENT.'/constants.php');
+	}
+	else
+	{
+		require(APPPATH.'config/constants.php');
+	}
+
+/*
+ * ------------------------------------------------------
+ *  Define a custom error handler so we can log PHP errors
+ * ------------------------------------------------------
+ */
+	set_error_handler('_exception_handler');
+
+	if ( ! is_php('5.3'))
+	{
+		@set_magic_quotes_runtime(0); // Kill magic quotes
+	}
+
+/*
+ * ------------------------------------------------------
+ *  Set the subclass_prefix
+ * ------------------------------------------------------
+ *
+ * Normally the "subclass_prefix" is set in the config file.
+ * The subclass prefix allows CI to know if a core class is
+ * being extended via a library in the local application
+ * "libraries" folder. Since CI allows config items to be
+ * overriden via data set in the main index. php file,
+ * before proceeding we need to know if a subclass_prefix
+ * override exists.  If so, we will set this value now,
+ * before any classes are loaded
+ * Note: Since the config file data is cached it doesn't
+ * hurt to load it here.
+ */
+	if (isset($assign_to_config['subclass_prefix']) AND $assign_to_config['subclass_prefix'] != '')
+	{
+		get_config(array('subclass_prefix' => $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 */

+ 564 - 0
php-codeigniter/system/core/Common.php

@@ -0,0 +1,564 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Common Functions
+ *
+ * Loads the base classes and executes the request.
+ *
+ * @package		CodeIgniter
+ * @subpackage	codeigniter
+ * @category	Common Functions
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+* Determines if the current version of PHP is greater then the supplied value
+*
+* Since there are a few places where we conditionally test for PHP > 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 */

+ 379 - 0
php-codeigniter/system/core/Config.php

@@ -0,0 +1,379 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * CodeIgniter Config Class
+ *
+ * This class contains functions that enable config files to be managed
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/config.html
+ */
+class CI_Config {
+
+	/**
+	 * List of all loaded config values
+	 *
+	 * @var array
+	 */
+	var $config = array();
+	/**
+	 * List of all loaded config files
+	 *
+	 * @var array
+	 */
+	var $is_loaded = array();
+	/**
+	 * List of paths to search when trying to load a config file
+	 *
+	 * @var array
+	 */
+	var $_config_paths = array(APPPATH);
+
+	/**
+	 * Constructor
+	 *
+	 * Sets the $config data from the primary config.php file as a class variable
+	 *
+	 * @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 successfully loaded or not
+	 */
+	function __construct()
+	{
+		$this->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 */

+ 64 - 0
php-codeigniter/system/core/Controller.php

@@ -0,0 +1,64 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * CodeIgniter Application Controller Class
+ *
+ * This class object is the super class that every library in
+ * CodeIgniter will be assigned to.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/general/controllers.html
+ */
+class CI_Controller {
+
+	private static $instance;
+
+	/**
+	 * Constructor
+	 */
+	public function __construct()
+	{
+		self::$instance =& $this;
+		
+		// Assign all the class objects that were instantiated by the
+		// bootstrap file (CodeIgniter.php) to local class variables
+		// so that CI can run as one big super object.
+		foreach (is_loaded() as $var => $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 */

+ 193 - 0
php-codeigniter/system/core/Exceptions.php

@@ -0,0 +1,193 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Exceptions Class
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Exceptions
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/exceptions.html
+ */
+class CI_Exceptions {
+	var $action;
+	var $severity;
+	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',
+						E_PARSE				=>	'Parsing Error',
+						E_NOTICE			=>	'Notice',
+						E_CORE_ERROR		=>	'Core Error',
+						E_CORE_WARNING		=>	'Core Warning',
+						E_COMPILE_ERROR		=>	'Compile Error',
+						E_COMPILE_WARNING	=>	'Compile Warning',
+						E_USER_ERROR		=>	'User Error',
+						E_USER_WARNING		=>	'User Warning',
+						E_USER_NOTICE		=>	'User Notice',
+						E_STRICT			=>	'Runtime Notice'
+					);
+
+
+	/**
+	 * Constructor
+	 */
+	public function __construct()
+	{
+		$this->ob_level = ob_get_level();
+		// Note:  Do not log messages from this constructor.
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Exception Logger
+	 *
+	 * This function logs PHP generated error messages
+	 *
+	 * @access	private
+	 * @param	string	the error severity
+	 * @param	string	the error string
+	 * @param	string	the error filepath
+	 * @param	string	the error line number
+	 * @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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 404 Page Not Found Handler
+	 *
+	 * @access	private
+	 * @param	string	the page
+	 * @param 	bool	log error yes/no
+	 * @return	string
+	 */
+	function show_404($page = '', $log_error = TRUE)
+	{
+		$heading = "404 Page Not Found";
+		$message = "The page you requested was not found.";
+
+		// 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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * General Error Page
+	 *
+	 * This function takes an error message as input
+	 * (either as a string or an array) and displays
+	 * it using the specified template.
+	 *
+	 * @access	private
+	 * @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 = '<p>'.implode('</p><p>', ( ! is_array($message)) ? array($message) : $message).'</p>';
+
+		if (ob_get_level() > $this->ob_level + 1)
+		{
+			ob_end_flush();
+		}
+		ob_start();
+		include(APPPATH.'errors/'.$template.'.php');
+		$buffer = ob_get_contents();
+		ob_end_clean();
+		return $buffer;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Native PHP error handler
+	 *
+	 * @access	private
+	 * @param	string	the error severity
+	 * @param	string	the error string
+	 * @param	string	the error filepath
+	 * @param	string	the error line number
+	 * @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_start();
+		include(APPPATH.'errors/error_php.php');
+		$buffer = ob_get_contents();
+		ob_end_clean();
+		echo $buffer;
+	}
+
+
+}
+// END Exceptions Class
+
+/* End of file Exceptions.php */
+/* Location: ./system/core/Exceptions.php */

+ 248 - 0
php-codeigniter/system/core/Hooks.php

@@ -0,0 +1,248 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * CodeIgniter Hooks Class
+ *
+ * Provides a mechanism to extend the base system without hacking.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/encryption.html
+ */
+class CI_Hooks {
+
+	/**
+	 * 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 __construct()
+	{
+		$this->_initialize();
+		log_message('debug', "Hooks Class Initialized");
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Initialize the Hooks Preferences
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _initialize()
+	{
+		$CFG =& load_class('Config', 'core');
+
+		// If hooks are not enabled in the config file
+		// there is nothing else to do
+
+		if ($CFG->item('enable_hooks') == FALSE)
+		{
+			return;
+		}
+
+		// Grab the "hooks" definition file.
+		// If there are no hooks, we're done.
+
+		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))
+		{
+			return;
+		}
+
+		$this->hooks =& $hook;
+		$this->enabled = TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Call Hook
+	 *
+	 * Calls a particular hook
+	 *
+	 * @access	private
+	 * @param	string	the hook name
+	 * @return	mixed
+	 */
+	function _call_hook($which = '')
+	{
+		if ( ! $this->enabled OR ! isset($this->hooks[$which]))
+		{
+			return FALSE;
+		}
+
+		if (isset($this->hooks[$which][0]) AND is_array($this->hooks[$which][0]))
+		{
+			foreach ($this->hooks[$which] as $val)
+			{
+				$this->_run_hook($val);
+			}
+		}
+		else
+		{
+			$this->_run_hook($this->hooks[$which]);
+		}
+
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Run Hook
+	 *
+	 * Runs a particular hook
+	 *
+	 * @access	private
+	 * @param	array	the hook details
+	 * @return	bool
+	 */
+	function _run_hook($data)
+	{
+		if ( ! is_array($data))
+		{
+			return FALSE;
+		}
+
+		// -----------------------------------
+		// Safety - Prevents run-away loops
+		// -----------------------------------
+
+		// If the script being called happens to have the same
+		// hook call within it a loop can happen
+
+		if ($this->in_progress == TRUE)
+		{
+			return;
+		}
+
+		// -----------------------------------
+		// Set file path
+		// -----------------------------------
+
+		if ( ! isset($data['filepath']) OR ! isset($data['filename']))
+		{
+			return FALSE;
+		}
+
+		$filepath = APPPATH.$data['filepath'].'/'.$data['filename'];
+
+		if ( ! file_exists($filepath))
+		{
+			return FALSE;
+		}
+
+		// -----------------------------------
+		// Set class/function name
+		// -----------------------------------
+
+		$class		= FALSE;
+		$function	= FALSE;
+		$params		= '';
+
+		if (isset($data['class']) AND $data['class'] != '')
+		{
+			$class = $data['class'];
+		}
+
+		if (isset($data['function']))
+		{
+			$function = $data['function'];
+		}
+
+		if (isset($data['params']))
+		{
+			$params = $data['params'];
+		}
+
+		if ($class === FALSE AND $function === FALSE)
+		{
+			return FALSE;
+		}
+
+		// -----------------------------------
+		// Set the in_progress flag
+		// -----------------------------------
+
+		$this->in_progress = TRUE;
+
+		// -----------------------------------
+		// Call the requested class and/or function
+		// -----------------------------------
+
+		if ($class !== FALSE)
+		{
+			if ( ! class_exists($class))
+			{
+				require($filepath);
+			}
+
+			$HOOK = new $class;
+			$HOOK->$function($params);
+		}
+		else
+		{
+			if ( ! function_exists($function))
+			{
+				require($filepath);
+			}
+
+			$function($params);
+		}
+
+		$this->in_progress = FALSE;
+		return TRUE;
+	}
+
+}
+
+// END CI_Hooks class
+
+/* End of file Hooks.php */
+/* Location: ./system/core/Hooks.php */

+ 849 - 0
php-codeigniter/system/core/Input.php

@@ -0,0 +1,849 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Input Class
+ *
+ * Pre-processes global input data for security
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Input
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/input.html
+ */
+class CI_Input {
+
+	/**
+	 * IP address of the current user
+	 *
+	 * @var string
+	 */
+	var $ip_address				= FALSE;
+	/**
+	 * user agent (web browser) being used by the current user
+	 *
+	 * @var string
+	 */
+	var $user_agent				= FALSE;
+	/**
+	 * If FALSE, then $_GET will be set to an empty array
+	 *
+	 * @var bool
+	 */
+	var $_allow_get_array		= TRUE;
+	/**
+	 * If TRUE, then newlines are standardized
+	 *
+	 * @var bool
+	 */
+	var $_standardize_newlines	= TRUE;
+	/**
+	 * Determines whether the XSS filter is always active when GET, POST or COOKIE data is encountered
+	 * Set automatically based on config setting
+	 *
+	 * @var bool
+	 */
+	var $_enable_xss			= FALSE;
+	/**
+	 * Enables a CSRF cookie token to be set.
+	 * Set automatically based on config setting
+	 *
+	 * @var bool
+	 */
+	var $_enable_csrf			= FALSE;
+	/**
+	 * List of all HTTP request headers
+	 *
+	 * @var array
+	 */
+	protected $headers			= array();
+
+	/**
+	 * Constructor
+	 *
+	 * Sets whether to globally enable the XSS processing
+	 * and whether to allow the $_GET array
+	 *
+	 * @return	void
+	 */
+	public function __construct()
+	{
+		log_message('debug', "Input Class Initialized");
+
+		$this->_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 */

+ 160 - 0
php-codeigniter/system/core/Lang.php

@@ -0,0 +1,160 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Language Class
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Language
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/language.html
+ */
+class CI_Lang {
+
+	/**
+	 * List of translations
+	 *
+	 * @var array
+	 */
+	var $language	= array();
+	/**
+	 * List of loaded language files
+	 *
+	 * @var array
+	 */
+	var $is_loaded	= array();
+
+	/**
+	 * Constructor
+	 *
+	 * @access	public
+	 */
+	function __construct()
+	{
+		log_message('debug', "Language Class Initialized");
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Load a language file
+	 *
+	 * @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, $add_suffix = TRUE, $alt_path = '')
+	{
+		$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 == '')
+		{
+			$deft_lang = ( ! isset($config['language'])) ? 'english' : $config['language'];
+			$idiom = ($deft_lang == '') ? 'english' : $deft_lang;
+		}
+
+		// Determine where the language file is and load it
+		if ($alt_path != '' && file_exists($alt_path.'language/'.$idiom.'/'.$langfile))
+		{
+			include($alt_path.'language/'.$idiom.'/'.$langfile);
+		}
+		else
+		{
+			$found = FALSE;
+
+			foreach (get_instance()->load->get_package_paths(TRUE) as $package_path)
+			{
+				if (file_exists($package_path.'language/'.$idiom.'/'.$langfile))
+				{
+					include($package_path.'language/'.$idiom.'/'.$langfile);
+					$found = TRUE;
+					break;
+				}
+			}
+
+			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);
+			return;
+		}
+
+		if ($return == TRUE)
+		{
+			return $lang;
+		}
+
+		$this->is_loaded[] = $langfile;
+		$this->language = array_merge($this->language, $lang);
+		unset($lang);
+
+		log_message('debug', 'Language file loaded: language/'.$idiom.'/'.$langfile);
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch a single line of text from the language array
+	 *
+	 * @access	public
+	 * @param	string	$line	the language line
+	 * @return	string
+	 */
+	function line($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 Lang.php */
+/* Location: ./system/core/Lang.php */

+ 1248 - 0
php-codeigniter/system/core/Loader.php

@@ -0,0 +1,1248 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Loader Class
+ *
+ * Loads views and files
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @author		ExpressionEngine Dev Team
+ * @category	Loader
+ * @link		http://codeigniter.com/user_guide/libraries/loader.html
+ */
+class CI_Loader {
+
+	// All these are set automatically. Don't mess with them.
+	/**
+	 * 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
+	 */
+	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.
+	 *
+	 * @param	string	the name of the class
+	 * @param	mixed	the optional parameters
+	 * @param	string	an optional object name
+	 * @return	void
+	 */
+	public function library($library = '', $params = NULL, $object_name = NULL)
+	{
+		if (is_array($library))
+		{
+			foreach ($library as $class)
+			{
+				$this->library($class, $params);
+			}
+
+			return;
+		}
+
+		if ($library == '' OR isset($this->_base_classes[$library]))
+		{
+			return FALSE;
+		}
+
+		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.
+	 *
+	 * @param	string	the name of the class
+	 * @param	string	name for the model
+	 * @param	bool	database connection
+	 * @return	void
+	 */
+	public function model($model, $name = '', $db_conn = FALSE)
+	{
+		if (is_array($model))
+		{
+			foreach ($model as $babe)
+			{
+				$this->model($babe);
+			}
+			return;
+		}
+
+		if ($model == '')
+		{
+			return;
+		}
+
+		$path = '';
+
+		// Is the model in a sub-folder? If so, parse out the filename and path.
+		if (($last_slash = strrpos($model, '/')) !== FALSE)
+		{
+			// 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);
+
+		foreach ($this->_ci_model_paths as $mod_path)
+		{
+			if ( ! file_exists($mod_path.'models/'.$path.$model.'.php'))
+			{
+				continue;
+			}
+
+			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('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
+	 *
+	 * @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
+	 */
+	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 == NULL AND isset($CI->db) AND is_object($CI->db))
+		{
+			return FALSE;
+		}
+
+		require_once(BASEPATH.'database/DB.php');
+
+		if ($return === TRUE)
+		{
+			return DB($params, $active_record);
+		}
+
+		// Initialize the db variable.  Needed to prevent
+		// reference errors with some configurations
+		$CI->db = '';
+
+		// Load the DB class
+		$CI->db =& DB($params, $active_record);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Load the Utilities Class
+	 *
+	 * @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.php');
+		require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_utility.php');
+		$class = 'CI_DB_'.$CI->db->dbdriver.'_utility';
+
+		$CI->dbutil = new $class();
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Load the Database Forge Class
+	 *
+	 * @return	string
+	 */
+	public function dbforge()
+	{
+		if ( ! class_exists('CI_DB'))
+		{
+			$this->database();
+		}
+
+		$CI =& get_instance();
+
+		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();
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Load View
+	 *
+	 * This function is used to load a "view" file.  It has three parameters:
+	 *
+	 * 1. The name of the "view" file to be included.
+	 * 2. An associative array of data to be extracted for use in the view.
+	 * 3. TRUE/FALSE - whether to return the data or load it.  In
+	 * some cases it's advantageous to be able to return data so that
+	 * a developer can process it in some way.
+	 *
+	 * @param	string
+	 * @param	array
+	 * @param	bool
+	 * @return	void
+	 */
+	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
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @return	string
+	 */
+	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.
+	 *
+	 * @param	array
+	 * @param 	string
+	 * @return	void
+	 */
+	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)
+			{
+				$this->_ci_cached_vars[$key] = $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.
+	 *
+	 * @param	mixed
+	 * @return	void
+	 */
+	public function helper($helpers = array())
+	{
+		foreach ($this->_ci_prep_filename($helpers, '_helper') as $helper)
+		{
+			if (isset($this->_ci_helpers[$helper]))
+			{
+				continue;
+			}
+
+			$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.'.php';
+
+				if ( ! file_exists($base_helper))
+				{
+					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;
+			}
+
+			// Try to load the helper
+			foreach ($this->_ci_helper_paths as $path)
+			{
+				if (file_exists($path.'helpers/'.$helper.'.php'))
+				{
+					include_once($path.'helpers/'.$helper.'.php');
+
+					$this->_ci_helpers[$helper] = TRUE;
+					log_message('debug', 'Helper loaded: '.$helper);
+					break;
+				}
+			}
+
+			// 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.
+	 *
+	 * @param	array
+	 * @return	void
+	 */
+	public function helpers($helpers = array())
+	{
+		$this->helper($helpers);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Loads a language file
+	 *
+	 * @param	array
+	 * @param	string
+	 * @return	void
+	 */
+	public function language($file = array(), $lang = '')
+	{
+		$CI =& get_instance();
+
+		if ( ! is_array($file))
+		{
+			$file = array($file);
+		}
+
+		foreach ($file as $langfile)
+		{
+			$CI->lang->load($langfile, $lang);
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Loads a config file
+	 *
+	 * @param	string
+	 * @param	bool
+	 * @param 	bool
+	 * @return	void
+	 */
+	public function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)
+	{
+		$CI =& get_instance();
+		$CI->config->load($file, $use_sections, $fail_gracefully);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Driver
+	 *
+	 * Loads a driver library
+	 *
+	 * @param	string	the name of the class
+	 * @param	mixed	the optional parameters
+	 * @param	string	an optional object name
+	 * @return	void
+	 */
+	public function driver($library = '', $params = NULL, $object_name = NULL)
+	{
+		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 ($library == '')
+		{
+			return FALSE;
+		}
+
+		// 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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Add Package Path
+	 *
+	 * Prepends a parent path to the library, model, helper, and config path arrays
+	 *
+	 * @param	string
+	 * @param 	boolean
+	 * @return	void
+	 */
+	public function add_package_path($path, $view_cascade=TRUE)
+	{
+		$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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get Package Paths
+	 *
+	 * Return a list of all package paths, by default it will ignore BASEPATH.
+	 *
+	 * @param	string
+	 * @return	void
+	 */
+	public function get_package_paths($include_base = FALSE)
+	{
+		return $include_base === TRUE ? $this->_ci_library_paths : $this->_ci_model_paths;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Remove Package Path
+	 *
+	 * 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.
+	 *
+	 * @param	type
+	 * @param 	bool
+	 * @return	type
+	 */
+	public function remove_package_path($path = '', $remove_config_path = TRUE)
+	{
+		$config =& $this->_ci_get_component('config');
+
+		if ($path == '')
+		{
+			$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);
+		}
+		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
+	 *
+	 * This function is used to load views and files.
+	 * Variables are prefixed with _ci_ to avoid symbol collision with
+	 * variables made available to view files
+	 *
+	 * @param	array
+	 * @return	void
+	 */
+	protected function _ci_load($_ci_data)
+	{
+		// Set the default data variables
+		foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val)
+		{
+			$$_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 != '')
+		{
+			$_ci_x = explode('/', $_ci_path);
+			$_ci_file = end($_ci_x);
+		}
+		else
+		{
+			$_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 && ! 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.
+
+		$_ci_CI =& get_instance();
+		foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var)
+		{
+			if ( ! isset($this->$_ci_key))
+			{
+				$this->$_ci_key =& $_ci_CI->$_ci_key;
+			}
+		}
+
+		/*
+		 * Extract and cache variables
+		 *
+		 * You can either set variables using the dedicated $this->load_vars()
+		 * 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
+		 *
+		 * We buffer the output for two reasons:
+		 * 1. Speed. You get a significant speed boost.
+		 * 2. So that the final rendered template can be
+		 * post-processed by the output class.  Why do we
+		 * need post processing?  For one thing, in order to
+		 * show the elapsed page load time.  Unless we
+		 * can intercept the content right before it's sent to
+		 * 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('<?=', '<?php echo ', file_get_contents($_ci_path))));
+		}
+		else
+		{
+			include($_ci_path); // include() vs include_once() allows for multiple views with the same name
+		}
+
+		log_message('debug', 'File loaded: '.$_ci_path);
+
+		// Return the file data if requested
+		if ($_ci_return === TRUE)
+		{
+			$buffer = ob_get_contents();
+			@ob_end_clean();
+			return $buffer;
+		}
+
+		/*
+		 * Flush the buffer... or buff the flusher?
+		 *
+		 * In order to permit views to be nested within
+		 * other views, we need to flush the content back out whenever
+		 * we are beyond the first level of output buffering so that
+		 * it can be seen and included properly by the first included
+		 * template and any subsequent ones. Oy!
+		 *
+		 */
+		if (ob_get_level() > $this->_ci_ob_level + 1)
+		{
+			ob_end_flush();
+		}
+		else
+		{
+			$_ci_CI->output->append_output(ob_get_contents());
+			@ob_end_clean();
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Load class
+	 *
+	 * This function loads the requested class.
+	 *
+	 * @param	string	the item that is being loaded
+	 * @param	mixed	any additional parameters
+	 * @param	string	an optional object name
+	 * @return	void
+	 */
+	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('.php', '', trim($class, '/'));
+
+		// Was the path included with the class name?
+		// We look for a slash to determine this
+		$subdir = '';
+		if (($last_slash = strrpos($class, '/')) !== FALSE)
+		{
+			// 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.'.php';
+
+			// Is this a class extension request?
+			if (file_exists($subclass))
+			{
+				$baseclass = BASEPATH.'libraries/'.ucfirst($class).'.php';
+
+				if ( ! file_exists($baseclass))
+				{
+					log_message('error', "Unable to load the requested class: ".$class);
+					show_error("Unable to load the requested class: ".$class);
+				}
+
+				// Safety:  Was the class already loaded by a previous call?
+				if (in_array($subclass, $this->_ci_loaded_files))
+				{
+					// Before we deem this to be a duplicate request, let's see
+					// if a custom object name is being supplied.  If so, we'll
+					// return a new instance of the object
+					if ( ! is_null($object_name))
+					{
+						$CI =& get_instance();
+						if ( ! isset($CI->$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($subclass);
+				$this->_ci_loaded_files[] = $subclass;
+
+				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;
+			foreach ($this->_ci_library_paths as $path)
+			{
+				$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))
+				{
+					// Before we deem this to be a duplicate request, let's see
+					// if a custom object name is being supplied.  If so, we'll
+					// return a new instance of the object
+					if ( ! is_null($object_name))
+					{
+						$CI =& get_instance();
+						if ( ! isset($CI->$object_name))
+						{
+							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?
+		if ($subdir == '')
+		{
+			$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)
+		{
+			log_message('error', "Unable to load the requested class: ".$class);
+			show_error("Unable to load the requested class: ".$class);
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Instantiates a class
+	 *
+	 * @param	string
+	 * @param	string
+	 * @param	bool
+	 * @param	string	an optional object name
+	 * @return	null
+	 */
+	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)
+		{
+			// Fetch the config paths containing any package paths
+			$config_component = $this->_ci_get_component('config');
+
+			if (is_array($config_component->_config_paths))
+			{
+				// 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))
+			{
+				$name = 'CI_'.$class;
+			}
+			elseif (class_exists(config_item('subclass_prefix').$class))
+			{
+				$name = config_item('subclass_prefix').$class;
+			}
+			else
+			{
+				$name = $class;
+			}
+		}
+		else
+		{
+			$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];
+		}
+		else
+		{
+			$classvar = $object_name;
+		}
+
+		// Save the class name and object name
+		$this->_ci_classes[$class] = $classvar;
+
+		// 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, and helpers to be loaded automatically.
+	 *
+	 * @param	array
+	 * @return	void
+	 */
+	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 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']) AND isset($autoload['core']))
+		{
+			$autoload['libraries'] = $autoload['core'];
+		}
+
+		// Load libraries
+		if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)
+		{
+			// Load the database driver.
+			if (in_array('database', $autoload['libraries']))
+			{
+				$this->database();
+				$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));
+			}
+
+			// Load all other libraries
+			foreach ($autoload['libraries'] as $item)
+			{
+				$this->library($item);
+			}
+		}
+
+		// Autoload models
+		if (isset($autoload['model']))
+		{
+			$this->model($autoload['model']);
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Object to Array
+	 *
+	 * Takes an object as input and converts the class variables to array key/vals
+	 *
+	 * @param	object
+	 * @return	array
+	 */
+	protected function _ci_object_to_array($object)
+	{
+		return (is_object($object)) ? get_object_vars($object) : $object;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get a reference to a specific library or model
+	 *
+	 * @param 	string
+	 * @return	bool
+	 */
+	protected function &_ci_get_component($component)
+	{
+		$CI =& get_instance();
+		return $CI->$component;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Prep filename
+	 *
+	 * This function preps the name of various items to make loading them more reliable.
+	 *
+	 * @param	mixed
+	 * @param 	string
+	 * @return	array
+	 */
+	protected function _ci_prep_filename($filename, $extension)
+	{
+		if ( ! is_array($filename))
+		{
+			return array(strtolower(str_replace('.php', '', str_replace($extension, '', $filename)).$extension));
+		}
+		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/core/Loader.php */

+ 57 - 0
php-codeigniter/system/core/Model.php

@@ -0,0 +1,57 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * CodeIgniter Model Class
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Libraries
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/config.html
+ */
+class CI_Model {
+
+	/**
+	 * Constructor
+	 *
+	 * @access public
+	 */
+	function __construct()
+	{
+		log_message('debug', "Model Class Initialized");
+	}
+
+	/**
+	 * __get
+	 *
+	 * Allows models to access CI's loaded classes using the same
+	 * syntax as controllers.
+	 *
+	 * @param	string
+	 * @access private
+	 */
+	function __get($key)
+	{
+		$CI =& get_instance();
+		return $CI->$key;
+	}
+}
+// END Model Class
+
+/* End of file Model.php */
+/* Location: ./system/core/Model.php */

+ 574 - 0
php-codeigniter/system/core/Output.php

@@ -0,0 +1,574 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Output Class
+ *
+ * Responsible for sending final output to browser
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Output
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/output.html
+ */
+class CI_Output {
+
+	/**
+	 * 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;
+
+	/**
+	 * 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
+	 *
+	 * Returns the current output string
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function get_output()
+	{
+		return $this->final_output;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Output
+	 *
+	 * Sets the output string
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */
+	function set_output($output)
+	{
+		$this->final_output = $output;
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Append Output
+	 *
+	 * Appends data onto the output string
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */
+	function append_output($output)
+	{
+		if ($this->final_output == '')
+		{
+			$this->final_output = $output;
+		}
+		else
+		{
+			$this->final_output .= $output;
+		}
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Header
+	 *
+	 * Lets you set a server header which will be outputted with the final display.
+	 *
+	 * Note:  If a file is cached, headers will not be sent.  We need to figure out
+	 * how to permit header data to be saved with the cache data...
+	 *
+	 * @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
+	 * @return	void
+	 */
+	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
+	 *
+	 * All "view" data is automatically put into this variable by the controller class:
+	 *
+	 * $this->final_output
+	 *
+	 * This function sends the finalized output data to the browser along
+	 * with any server headers and profile data.  It also stops the
+	 * 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 == '')
+		{
+			$output =& $this->final_output;
+		}
+
+		// --------------------------------------------------------------------
+
+		// 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');
+
+		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 && $this->_zlib_oc == FALSE)
+		{
+			if (extension_loaded('zlib'))
+			{
+				if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) AND strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
+				{
+					ob_start('ob_gzhandler');
+				}
+			}
+		}
+
+		// --------------------------------------------------------------------
+
+		// Are there any server headers to send?
+		if (count($this->headers) > 0)
+		{
+			foreach ($this->headers as $header)
+			{
+				@header($header[0], $header[1]);
+			}
+		}
+
+		// --------------------------------------------------------------------
+
+		// 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 ( ! isset($CI))
+		{
+			echo $output;
+			log_message('debug', "Final output sent to browser");
+			log_message('debug', "Total execution time: ".$elapsed);
+			return TRUE;
+		}
+
+		// --------------------------------------------------------------------
+
+		// 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');
+
+			if ( ! empty($this->_profiler_sections))
+			{
+				$CI->profiler->set_sections($this->_profiler_sections);
+			}
+
+			// If the output data contains closing </body> and </html> tags
+			// we will remove them and add them back after we insert the profile data
+			if (preg_match("|</body>.*?</html>|is", $output))
+			{
+				$output  = preg_replace("|</body>.*?</html>|is", '', $output);
+				$output .= $CI->profiler->run();
+				$output .= '</body></html>';
+			}
+			else
+			{
+				$output .= $CI->profiler->run();
+			}
+		}
+
+		// --------------------------------------------------------------------
+
+		// Does the controller contain a function named _output()?
+		// If so send the output there.  Otherwise, echo it.
+		if (method_exists($CI, '_output'))
+		{
+			$CI->_output($output);
+		}
+		else
+		{
+			echo $output;  // Send it to the browser!
+		}
+
+		log_message('debug', "Final output sent to browser");
+		log_message('debug', "Total execution time: ".$elapsed);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Write a Cache File
+	 *
+	 * @access	public
+	 * @param 	string
+	 * @return	void
+	 */
+	function _write_cache($output)
+	{
+		$CI =& get_instance();
+		$path = $CI->config->item('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))
+		{
+			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);
+			flock($fp, LOCK_UN);
+		}
+		else
+		{
+			log_message('error', "Unable to secure a file lock for file at: ".$cache_path);
+			return;
+		}
+		fclose($fp);
+		@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') == '') ? 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
+		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'])))
+		{
+			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.");
+		return TRUE;
+	}
+
+
+}
+// END Output Class
+
+/* End of file Output.php */
+/* Location: ./system/core/Output.php */

+ 522 - 0
php-codeigniter/system/core/Router.php

@@ -0,0 +1,522 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Router Class
+ *
+ * Parses URIs and determines routing
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @author		ExpressionEngine Dev Team
+ * @category	Libraries
+ * @link		http://codeigniter.com/user_guide/general/routing.html
+ */
+class CI_Router {
+
+	/**
+	 * 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		= '';
+	/**
+	 * Default controller (and method if specific)
+	 *
+	 * @var string
+	 * @access public
+	 */
+	var $default_controller;
+
+	/**
+	 * Constructor
+	 *
+	 * Runs the route mapping function.
+	 */
+	function __construct()
+	{
+		$this->config =& load_class('Config', 'core');
+		$this->uri =& load_class('URI', 'core');
+		log_message('debug', "Router Class Initialized");
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set the route mapping
+	 *
+	 * This function determines what should be served based on the URI request,
+	 * as well as any "routes" that have been set in the routing config file.
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _set_routing()
+	{
+		// 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')]))
+		{
+			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();
+			}
+		}
+
+		// Load the routes.php file.
+		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']);
+
+		// 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 == '')
+		{
+			return $this->_set_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();
+
+		// 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
+	 *
+	 * This function takes an array of URI segments as
+	 * input, and sets the current class/method
+	 *
+	 * @access	private
+	 * @param	array
+	 * @param	bool
+	 * @return	void
+	 */
+	function _set_request($segments = array())
+	{
+		$segments = $this->_validate_request($segments);
+
+		if (count($segments) == 0)
+		{
+			return $this->_set_default_controller();
+		}
+
+		$this->set_class($segments[0]);
+
+		if (isset($segments[1]))
+		{
+			// A standard method request
+			$this->set_method($segments[1]);
+		}
+		else
+		{
+			// This lets the "routed" segment array identify that the default
+			// 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.
+	 *
+	 * @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].'.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].'.php'))
+				{
+					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
+			{
+				// 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.'.php'))
+				{
+					$this->directory = '';
+					return array();
+				}
+
+			}
+
+			return $segments;
+		}
+
+
+		// 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]);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 *  Parse Routes
+	 *
+	 * This function matches any routes that may exist in
+	 * the config/routes.php file against the URI to
+	 * determine if the class/method need to be remapped.
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _parse_routes()
+	{
+		// 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]))
+		{
+			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);
+				}
+
+				return $this->_set_request(explode('/', $val));
+			}
+		}
+
+		// 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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set the class name
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */
+	function set_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())
+		{
+			return 'index';
+		}
+
+		return $this->method;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 *  Set the directory name
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	void
+	 */
+	function set_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/core/Router.php */

+ 876 - 0
php-codeigniter/system/core/Security.php

@@ -0,0 +1,876 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Security Class
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	Security
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/security.html
+ */
+class CI_Security {
+
+	/**
+	 * Random Hash for protecting URLs
+	 *
+	 * @var string
+	 * @access protected
+	 */
+	protected $_xss_hash			= '';
+	/**
+	 * Random Hash for Cross Site Request Forgery Protection Cookie
+	 *
+	 * @var string
+	 * @access protected
+	 */
+	protected $_csrf_hash			= '';
+	/**
+	 * Expiration time for Cross Site Request Forgery Protection Cookie
+	 * Defaults to two hours (in seconds)
+	 *
+	 * @var int
+	 * @access protected
+	 */
+	protected $_csrf_expire			= 7200;
+	/**
+	 * Token name for Cross Site Request Forgery Protection Cookie
+	 *
+	 * @var string
+	 * @access protected
+	 */
+	protected $_csrf_token_name		= 'ci_csrf_token';
+	/**
+	 * Cookie name for Cross Site Request Forgery Protection Cookie
+	 *
+	 * @var string
+	 * @access protected
+	 */
+	protected $_csrf_cookie_name	= 'ci_csrf_token';
+	/**
+	 * List of never allowed strings
+	 *
+	 * @var array
+	 * @access protected
+	 */
+	protected $_never_allowed_str = array(
+		'document.cookie'	=> '[removed]',
+		'document.write'	=> '[removed]',
+		'.parentNode'		=> '[removed]',
+		'.innerHTML'		=> '[removed]',
+		'window.location'	=> '[removed]',
+		'-moz-binding'		=> '[removed]',
+		'<!--'				=> '&lt;!--',
+		'-->'				=> '--&gt;',
+		'<![CDATA['			=> '&lt;![CDATA[',
+		'<comment>'			=> '&lt;comment&gt;'
+	);
+
+	/* 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:
+		 *
+		 * <a href="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>
+		 *
+		 * 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:
+		 *
+		 * <?xml
+		 *
+		 * But it doesn't seem to pose a problem.
+		 */
+		if ($is_image === TRUE)
+		{
+			// Images have a tendency to have the PHP short opening and
+			// closing tags every so often so we skip those and only
+			// do the long opening tags.
+			$str = preg_replace('/<\?(php)/i', "&lt;?\\1", $str);
+		}
+		else
+		{
+			$str = str_replace(array('<?', '?'.'>'),  array('&lt;?', '?&gt;'), $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("/<a/i", $str))
+			{
+				$str = preg_replace_callback("#<a\s+([^>]*?)(>|$)#si", array($this, '_js_link_removal'), $str);
+			}
+
+			if (preg_match("/<img/i", $str))
+			{
+				$str = preg_replace_callback("#<img\s+([^>]*?)(\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: <blink>
+		 * Becomes: &lt;blink&gt;
+		 */
+		$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&#40;'some code'&#41;
+		 */
+		$str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2&#40;\\3&#41;", $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:
+	 *		<a |style=document.write('hello');alert('world');| class=link>
+	 * 	- Everything inside the quotes
+	 *		For example, everything between the pipes:
+	 *		<a |style="document.write('hello'); alert('world');"| class="link">
+	 *
+	 * @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 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], '/');
+			}
+
+			// 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], '/');
+			}
+
+			// 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 $3$5$6$7', $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 = '&lt;'.$matches[1].$matches[2].$matches[3];
+
+		// encode captured opening or closing brace to prevent recursive vectors
+		$str .= str_replace(array('>', '<'), array('&gt;', '&lt;'),
+							$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|<script|<xss|data\s*:)#si',
+				'',
+				$this->_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|<script|<xss|base64\s*,)#si',
+				'',
+				$this->_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('&gt;', '&lt;', '\\\\'), $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 */

+ 654 - 0
php-codeigniter/system/core/URI.php

@@ -0,0 +1,654 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * URI Class
+ *
+ * Parses URIs and determines routing
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	URI
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/uri.html
+ */
+class CI_URI {
+
+	/**
+	 * 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();
+
+	/**
+	 * Constructor
+	 *
+	 * Simply globalizes the $RTR object.  The front
+	 * loads the Router class early on so it's not available
+	 * normally as other classes are.
+	 *
+	 * @access	public
+	 */
+	function __construct()
+	{
+		$this->config =& load_class('Config', 'core');
+		log_message('debug', "URI Class Initialized");
+	}
+
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get the URI String
+	 *
+	 * @access	private
+	 * @return	string
+	 */
+	function _fetch_uri_string()
+	{
+		if (strtoupper($this->config->item('uri_protocol')) == 'AUTO')
+		{
+			// Is the request coming from the command line?
+			if (php_sapi_name() == 'cli' or defined('STDIN'))
+			{
+				$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;
+			}
+
+			// Is there a PATH_INFO variable?
+			// Note: some servers seem to have trouble with getenv() so we'll test it two ways
+			$path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
+			if (trim($path, '/') != '' && $path != "/".SELF)
+			{
+				$this->_set_uri_string($path);
+				return;
+			}
+
+			// No PATH_INFO?... What about QUERY_STRING?
+			$path =  (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
+			if (trim($path, '/') != '')
+			{
+				$this->_set_uri_string($path);
+				return;
+			}
+
+			// As a last ditch effort lets try using the $_GET array
+			if (is_array($_GET) && count($_GET) == 1 && trim(key($_GET), '/') != '')
+			{
+				$this->_set_uri_string(key($_GET));
+				return;
+			}
+
+			// We've exhausted all our options...
+			$this->uri_string = '';
+			return;
+		}
+
+		$uri = strtoupper($this->config->item('uri_protocol'));
+
+		if ($uri == 'REQUEST_URI')
+		{
+			$this->_set_uri_string($this->_detect_uri());
+			return;
+		}
+		elseif ($uri == 'CLI')
+		{
+			$this->_set_uri_string($this->_parse_cli_args());
+			return;
+		}
+
+		$path = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
+		$this->_set_uri_string($path);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set the URI String
+	 *
+	 * @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
+	 */
+	private function _detect_uri()
+	{
+		if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME']))
+		{
+			return '';
+		}
+
+		$uri = $_SERVER['REQUEST_URI'];
+		if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
+		{
+			$uri = substr($uri, strlen($_SERVER['SCRIPT_NAME']));
+		}
+		elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
+		{
+			$uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
+		}
+
+		// 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)
+		{
+			$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();
+		}
+
+		if ($uri == '/' || empty($uri))
+		{
+			return '/';
+		}
+
+		$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) : '';
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Filter segments for malicious characters
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	string
+	 */
+	function _filter_uri($str)
+	{
+		if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)
+		{
+			// preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards
+			// compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern
+			if ( ! preg_match("|^[".str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-'))."]+$|i", $str))
+			{
+				show_error('The URI you submitted has disallowed characters.', 400);
+			}
+		}
+
+		// Convert programatic characters to entities
+		$bad	= array('$',		'(',		')',		'%28',		'%29');
+		$good	= array('&#36;',	'&#40;',	'&#41;',	'&#40;',	'&#41;');
+
+		return str_replace($bad, $good, $str);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Remove the suffix from the URL if needed
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _remove_url_suffix()
+	{
+		if  ($this->config->item('url_suffix') != "")
+		{
+			$this->uri_string = preg_replace("|".preg_quote($this->config->item('url_suffix'))."$|", "", $this->uri_string);
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Explode the URI Segments. The individual segments will
+	 * be stored in the $this->segments array.
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _explode_segments()
+	{
+		foreach (explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val)
+		{
+			// Filter segments for security
+			$val = trim($this->_filter_uri($val));
+
+			if ($val != '')
+			{
+				$this->segments[] = $val;
+			}
+		}
+	}
+
+	// --------------------------------------------------------------------
+	/**
+	 * Re-index Segments
+	 *
+	 * This function re-indexes the $this->segment array so that it
+	 * starts at 1 rather than 0.  Doing so makes it simpler to
+	 * use functions like $this->uri->segment(n) since there is
+	 * a 1:1 relationship between the segment array and the actual segments.
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _reindex_segments()
+	{
+		array_unshift($this->segments, NULL);
+		array_unshift($this->rsegments, NULL);
+		unset($this->segments[0]);
+		unset($this->rsegments[0]);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch a URI Segment
+	 *
+	 * This function returns the URI segment based on the number provided.
+	 *
+	 * @access	public
+	 * @param	integer
+	 * @param	bool
+	 * @return	string
+	 */
+	function segment($n, $no_result = FALSE)
+	{
+		return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch a URI "routed" Segment
+	 *
+	 * This function returns the re-routed URI segment (assuming routing rules are used)
+	 * based on the number provided.  If there is no routing this function returns the
+	 * same result as $this->segment()
+	 *
+	 * @access	public
+	 * @param	integer
+	 * @param	bool
+	 * @return	string
+	 */
+	function rsegment($n, $no_result = FALSE)
+	{
+		return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Generate a key value pair from the URI string
+	 *
+	 * This function generates and associative array of URI data starting
+	 * at the supplied segment. For example, if this is your URI:
+	 *
+	 *	example.com/user/search/name/joe/location/UK/gender/male
+	 *
+	 * You can use this function to generate an array with this prototype:
+	 *
+	 * array (
+	 *			name => joe
+	 *			location => UK
+	 *			gender => male
+	 *		 )
+	 *
+	 * @access	public
+	 * @param	integer	the starting segment number
+	 * @param	array	an array of default values
+	 * @return	array
+	 */
+	function uri_to_assoc($n = 3, $default = array())
+	{
+		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');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Generate a key value pair from the URI string or Re-routed URI string
+	 *
+	 * @access	private
+	 * @param	integer	the starting segment number
+	 * @param	array	an array of default values
+	 * @param	string	which array we should use
+	 * @return	array
+	 */
+	function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
+	{
+		if ($which == 'segment')
+		{
+			$total_segments = 'total_segments';
+			$segment_array = 'segment_array';
+		}
+		else
+		{
+			$total_segments = 'total_rsegments';
+			$segment_array = 'rsegment_array';
+		}
+
+		if ( ! is_numeric($n))
+		{
+			return $default;
+		}
+
+		if (isset($this->keyval[$n]))
+		{
+			return $this->keyval[$n];
+		}
+
+		if ($this->$total_segments() < $n)
+		{
+			if (count($default) == 0)
+			{
+				return array();
+			}
+
+			$retval = array();
+			foreach ($default as $val)
+			{
+				$retval[$val] = FALSE;
+			}
+			return $retval;
+		}
+
+		$segments = array_slice($this->$segment_array(), ($n - 1));
+
+		$i = 0;
+		$lastval = '';
+		$retval  = array();
+		foreach ($segments as $seg)
+		{
+			if ($i % 2)
+			{
+				$retval[$lastval] = $seg;
+			}
+			else
+			{
+				$retval[$seg] = FALSE;
+				$lastval = $seg;
+			}
+
+			$i++;
+		}
+
+		if (count($default) > 0)
+		{
+			foreach ($default as $val)
+			{
+				if ( ! array_key_exists($val, $retval))
+				{
+					$retval[$val] = FALSE;
+				}
+			}
+		}
+
+		// Cache the array for reuse
+		$this->keyval[$n] = $retval;
+		return $retval;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Generate a URI string from an associative array
+	 *
+	 *
+	 * @access	public
+	 * @param	array	an associative array of key/values
+	 * @return	array
+	 */
+	function assoc_to_uri($array)
+	{
+		$temp = array();
+		foreach ((array)$array as $key => $val)
+		{
+			$temp[] = $key;
+			$temp[] = $val;
+		}
+
+		return implode('/', $temp);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch a URI Segment and add a trailing slash
+	 *
+	 * @access	public
+	 * @param	integer
+	 * @param	string
+	 * @return	string
+	 */
+	function slash_segment($n, $where = 'trailing')
+	{
+		return $this->_slash_segment($n, $where, 'segment');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch a URI Segment and add a trailing slash
+	 *
+	 * @access	public
+	 * @param	integer
+	 * @param	string
+	 * @return	string
+	 */
+	function slash_rsegment($n, $where = 'trailing')
+	{
+		return $this->_slash_segment($n, $where, 'rsegment');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch a URI Segment and add a trailing slash - helper function
+	 *
+	 * @access	private
+	 * @param	integer
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
+	function _slash_segment($n, $where = 'trailing', $which = 'segment')
+	{
+		$leading	= '/';
+		$trailing	= '/';
+
+		if ($where == 'trailing')
+		{
+			$leading	= '';
+		}
+		elseif ($where == 'leading')
+		{
+			$trailing	= '';
+		}
+
+		return $leading.$this->$which($n).$trailing;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Segment Array
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	function segment_array()
+	{
+		return $this->segments;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Routed Segment Array
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	function rsegment_array()
+	{
+		return $this->rsegments;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Total number of segments
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function total_segments()
+	{
+		return count($this->segments);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Total number of routed segments
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function total_rsegments()
+	{
+		return count($this->rsegments);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch the entire URI string
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function uri_string()
+	{
+		return $this->uri_string;
+	}
+
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch the entire Re-routed URI string
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function ruri_string()
+	{
+		return '/'.implode('/', $this->rsegment_array());
+	}
+
+}
+// END URI Class
+
+/* End of file URI.php */
+/* Location: ./system/core/URI.php */

+ 165 - 0
php-codeigniter/system/core/Utf8.php

@@ -0,0 +1,165 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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 2.0
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Utf8 Class
+ *
+ * Provides support for UTF-8 environments
+ *
+ * @package		CodeIgniter
+ * @subpackage	Libraries
+ * @category	UTF-8
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/libraries/utf8.html
+ */
+class CI_Utf8 {
+
+	/**
+	 * Constructor
+	 *
+	 * Determines if UTF-8 support is to be enabled
+	 *
+	 */
+	function __construct()
+	{
+		log_message('debug', "Utf8 Class Initialized");
+
+		global $CFG;
+
+		if (
+			preg_match('/./u', 'é') === 1					// PCRE must support UTF-8
+			AND function_exists('iconv')					// iconv must be installed
+			AND ini_get('mbstring.func_overload') != 1		// Multibyte string function overloading cannot be enabled
+			AND $CFG->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 */

+ 10 - 0
php-codeigniter/system/core/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 162 - 0
php-codeigniter/system/database/DB.php

@@ -0,0 +1,162 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Initialize the database
+ *
+ * @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 = NULL)
+{
+	// Load the DB config file if a DSN string wasn't passed
+	if (is_string($params) AND strpos($params, '://') === FALSE)
+	{
+		// 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';
+		 */
+
+		if (($dns = @parse_url($params)) === FALSE)
+		{
+			show_error('Invalid DB Connection String');
+		}
+
+		$params = array(
+							'dbdriver'	=> $dns['scheme'],
+							'hostname'	=> (isset($dns['host'])) ? rawurldecode($dns['host']) : '',
+							'username'	=> (isset($dns['user'])) ? rawurldecode($dns['user']) : '',
+							'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)
+			{
+				// booleans please
+				if (strtoupper($val) == "TRUE")
+				{
+					$val = TRUE;
+				}
+				elseif (strtoupper($val) == "FALSE")
+				{
+					$val = FALSE;
+				}
+
+				$params[$key] = $val;
+			}
+		}
+	}
+
+	// No DB specified yet?  Beat them senseless...
+	if ( ! isset($params['dbdriver']) OR $params['dbdriver'] == '')
+	{
+		show_error('You have not selected a database type to connect to.');
+	}
+
+	// Load the DB classes.  Note: Since the active record class is optional
+	// 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 !== NULL)
+	{
+		$active_record = $active_record_override;
+	}
+
+	require_once(BASEPATH.'database/DB_driver.php');
+
+	if ( ! isset($active_record) OR $active_record == TRUE)
+	{
+		require_once(BASEPATH.'database/DB_active_rec.php');
+
+		if ( ! class_exists('CI_DB'))
+		{
+			eval('class CI_DB extends CI_DB_active_record { }');
+		}
+	}
+	else
+	{
+		if ( ! class_exists('CI_DB'))
+		{
+			eval('class CI_DB extends CI_DB_driver { }');
+		}
+	}
+
+	require_once(BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php');
+
+	// Instantiate the DB adapter
+	$driver = 'CI_DB_'.$params['dbdriver'].'_driver';
+	$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;
+}
+
+
+
+/* End of file DB.php */
+/* Location: ./system/database/DB.php */

+ 2045 - 0
php-codeigniter/system/database/DB_active_rec.php

@@ -0,0 +1,2045 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Active Record Class
+ *
+ * This is the platform-independent base Active Record implementation class.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Drivers
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_active_record extends CI_DB_driver {
+
+	var $ar_select				= array();
+	var $ar_distinct			= FALSE;
+	var $ar_from				= array();
+	var $ar_join				= array();
+	var $ar_where				= array();
+	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_wherein				= array();
+	var $ar_aliased_tables		= array();
+	var $ar_store_array			= array();
+
+	// Active Record Caching variables
+	var $ar_caching				= FALSE;
+	var $ar_cache_exists		= array();
+	var $ar_cache_select		= array();
+	var $ar_cache_from			= array();
+	var $ar_cache_join			= array();
+	var $ar_cache_where			= array();
+	var $ar_cache_like			= array();
+	var $ar_cache_groupby		= array();
+	var $ar_cache_having		= array();
+	var $ar_cache_orderby		= array();
+	var $ar_cache_set			= array();
+	
+	var $ar_no_escape 			= array();
+	var $ar_cache_no_escape     = array();
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Select
+	 *
+	 * Generates the SELECT portion of the query
+	 *
+	 * @param	string
+	 * @return	object
+	 */
+	public function select($select = '*', $escape = NULL)
+	{
+		if (is_string($select))
+		{
+			$select = explode(',', $select);
+		}
+
+		foreach ($select as $val)
+		{
+			$val = trim($val);
+
+			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;
+				}
+			}
+		}
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Select Max
+	 *
+	 * Generates a SELECT MAX(field) portion of a query
+	 *
+	 * @param	string	the field
+	 * @param	string	an alias
+	 * @return	object
+	 */
+	public function select_max($select = '', $alias = '')
+	{
+		return $this->_max_min_avg_sum($select, $alias, 'MAX');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Select Min
+	 *
+	 * Generates a SELECT MIN(field) portion of a query
+	 *
+	 * @param	string	the field
+	 * @param	string	an alias
+	 * @return	object
+	 */
+	public function select_min($select = '', $alias = '')
+	{
+		return $this->_max_min_avg_sum($select, $alias, 'MIN');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Select Average
+	 *
+	 * Generates a SELECT AVG(field) portion of a query
+	 *
+	 * @param	string	the field
+	 * @param	string	an alias
+	 * @return	object
+	 */
+	public function select_avg($select = '', $alias = '')
+	{
+		return $this->_max_min_avg_sum($select, $alias, 'AVG');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Select Sum
+	 *
+	 * Generates a SELECT SUM(field) portion of a query
+	 *
+	 * @param	string	the field
+	 * @param	string	an alias
+	 * @return	object
+	 */
+	public function select_sum($select = '', $alias = '')
+	{
+		return $this->_max_min_avg_sum($select, $alias, 'SUM');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Processing Function for the four functions above:
+	 *
+	 *	select_max()
+	 *	select_min()
+	 *	select_avg()
+	 *  select_sum()
+	 *
+	 * @param	string	the field
+	 * @param	string	an alias
+	 * @return	object
+	 */
+	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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Determines the alias name based on the table
+	 *
+	 * @param	string
+	 * @return	string
+	 */
+	protected function _create_alias_from_table($item)
+	{
+		if (strpos($item, '.') !== FALSE)
+		{
+			return end(explode('.', $item));
+		}
+
+		return $item;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * DISTINCT
+	 *
+	 * Sets a flag which tells the query string compiler to add DISTINCT
+	 *
+	 * @param	bool
+	 * @return	object
+	 */
+	public function distinct($val = TRUE)
+	{
+		$this->ar_distinct = (is_bool($val)) ? $val : TRUE;
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * From
+	 *
+	 * Generates the FROM portion of the query
+	 *
+	 * @param	mixed	can be a string or array
+	 * @return	object
+	 */
+	public function from($from)
+	{
+		foreach ((array) $from as $val)
+		{
+			if (strpos($val, ',') !== FALSE)
+			{
+				foreach (explode(',', $val) as $v)
+				{
+					$v = trim($v);
+					$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';
+					}
+				}
+
+			}
+			else
+			{
+				$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
+				$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);
+					$this->ar_cache_exists[] = 'from';
+				}
+			}
+		}
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Join
+	 *
+	 * Generates the JOIN portion of the query
+	 *
+	 * @param	string
+	 * @param	string	the join condition
+	 * @param	string	the type of join
+	 * @return	object
+	 */
+	public function join($table, $cond, $type = '')
+	{
+		if ($type != '')
+		{
+			$type = strtoupper(trim($type));
+
+			if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER')))
+			{
+				$type = '';
+			}
+			else
+			{
+				$type .= ' ';
+			}
+		}
+
+		// Extract any aliases that might exist.  We use this information
+		// in the _protect_identifiers to know whether to add a table prefix
+		$this->_track_aliases($table);
+
+		// Strip apart the condition and protect the identifiers
+		if (preg_match('/([\w\.]+)([\W\s]+)(.+)/', $cond, $match))
+		{
+			$match[1] = $this->_protect_identifiers($match[1]);
+			$match[3] = $this->_protect_identifiers($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;
+
+		$this->ar_join[] = $join;
+		if ($this->ar_caching === TRUE)
+		{
+			$this->ar_cache_join[] = $join;
+			$this->ar_cache_exists[] = 'join';
+		}
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Where
+	 *
+	 * Generates the WHERE portion of the query. Separates
+	 * multiple calls with AND
+	 *
+	 * @param	mixed
+	 * @param	mixed
+	 * @return	object
+	 */
+	public function where($key, $value = NULL, $escape = TRUE)
+	{
+		return $this->_where($key, $value, 'AND ', $escape);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * OR Where
+	 *
+	 * Generates the WHERE portion of the query. Separates
+	 * multiple calls with OR
+	 *
+	 * @param	mixed
+	 * @param	mixed
+	 * @return	object
+	 */
+	public function or_where($key, $value = NULL, $escape = TRUE)
+	{
+		return $this->_where($key, $value, 'OR ', $escape);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Where
+	 *
+	 * Called by where() or or_where()
+	 *
+	 * @param	mixed
+	 * @param	mixed
+	 * @param	string
+	 * @return	object
+	 */
+	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))
+		{
+			$escape = $this->_protect_identifiers;
+		}
+
+		foreach ($key as $k => $v)
+		{
+			$prefix = (count($this->ar_where) == 0 AND count($this->ar_cache_where) == 0) ? '' : $type;
+
+			if (is_null($v) && ! $this->_has_operator($k))
+			{
+				// 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 .= ' = ';
+				}
+			}
+			else
+			{
+				$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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Where_in
+	 *
+	 * Generates a WHERE field IN ('item', 'item') SQL query joined with
+	 * AND if appropriate
+	 *
+	 * @param	string	The field to search
+	 * @param	array	The values searched on
+	 * @return	object
+	 */
+	public function where_in($key = NULL, $values = NULL)
+	{
+		return $this->_where_in($key, $values);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Where_in_or
+	 *
+	 * Generates a WHERE field IN ('item', 'item') SQL query joined with
+	 * OR if appropriate
+	 *
+	 * @param	string	The field to search
+	 * @param	array	The values searched on
+	 * @return	object
+	 */
+	public function or_where_in($key = NULL, $values = NULL)
+	{
+		return $this->_where_in($key, $values, FALSE, 'OR ');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Where_not_in
+	 *
+	 * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
+	 * with AND if appropriate
+	 *
+	 * @param	string	The field to search
+	 * @param	array	The values searched on
+	 * @return	object
+	 */
+	public function where_not_in($key = NULL, $values = NULL)
+	{
+		return $this->_where_in($key, $values, TRUE);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Where_not_in_or
+	 *
+	 * Generates a WHERE field NOT IN ('item', 'item') SQL query joined
+	 * with OR if appropriate
+	 *
+	 * @param	string	The field to search
+	 * @param	array	The values searched on
+	 * @return	object
+	 */
+	public function or_where_not_in($key = NULL, $values = NULL)
+	{
+		return $this->_where_in($key, $values, TRUE, 'OR ');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Where_in
+	 *
+	 * Called by where_in, where_in_or, where_not_in, where_not_in_or
+	 *
+	 * @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
+	 * @return	object
+	 */
+	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)
+		{
+			$this->ar_wherein[] = $this->escape($value);
+		}
+
+		$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;
+		if ($this->ar_caching === TRUE)
+		{
+			$this->ar_cache_where[] = $where_in;
+			$this->ar_cache_exists[] = 'where';
+		}
+
+		// reset the array for multiple calls
+		$this->ar_wherein = array();
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Like
+	 *
+	 * Generates a %LIKE% portion of the query. Separates
+	 * multiple calls with AND
+	 *
+	 * @param	mixed
+	 * @param	mixed
+	 * @return	object
+	 */
+	public function like($field, $match = '', $side = 'both')
+	{
+		return $this->_like($field, $match, 'AND ', $side);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Not Like
+	 *
+	 * Generates a NOT LIKE portion of the query. Separates
+	 * multiple calls with AND
+	 *
+	 * @param	mixed
+	 * @param	mixed
+	 * @return	object
+	 */
+	public function not_like($field, $match = '', $side = 'both')
+	{
+		return $this->_like($field, $match, 'AND ', $side, 'NOT');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * OR Like
+	 *
+	 * Generates a %LIKE% portion of the query. Separates
+	 * multiple calls with OR
+	 *
+	 * @param	mixed
+	 * @param	mixed
+	 * @return	object
+	 */
+	public function or_like($field, $match = '', $side = 'both')
+	{
+		return $this->_like($field, $match, 'OR ', $side);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * OR Not Like
+	 *
+	 * Generates a NOT LIKE portion of the query. Separates
+	 * multiple calls with OR
+	 *
+	 * @param	mixed
+	 * @param	mixed
+	 * @return	object
+	 */
+	public function or_not_like($field, $match = '', $side = 'both')
+	{
+		return $this->_like($field, $match, 'OR ', $side, 'NOT');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Like
+	 *
+	 * Called by like() or orlike()
+	 *
+	 * @param	mixed
+	 * @param	mixed
+	 * @param	string
+	 * @return	object
+	 */
+	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);
+
+			$prefix = (count($this->ar_like) == 0) ? '' : $type;
+
+			$v = $this->escape_like_str($v);
+			
+			if ($side == 'none')
+			{
+				$like_statement = $prefix." $k $not LIKE '{$v}'";
+			}
+			elseif ($side == 'before')
+			{
+				$like_statement = $prefix." $k $not LIKE '%{$v}'";
+			}
+			elseif ($side == 'after')
+			{
+				$like_statement = $prefix." $k $not LIKE '{$v}%'";
+			}
+			else
+			{
+				$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_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
+	 *
+	 * @param	string
+	 * @return	object
+	 */
+	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);
+					$this->ar_cache_exists[] = 'groupby';
+				}
+			}
+		}
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Sets the HAVING value
+	 *
+	 * Separates multiple calls with AND
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	object
+	 */
+	public function having($key, $value = '', $escape = TRUE)
+	{
+		return $this->_having($key, $value, 'AND ', $escape);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Sets the OR HAVING value
+	 *
+	 * Separates multiple calls with OR
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	object
+	 */
+	public function or_having($key, $value = '', $escape = TRUE)
+	{
+		return $this->_having($key, $value, 'OR ', $escape);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Sets the HAVING values
+	 *
+	 * Called by having() or or_having()
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	object
+	 */
+	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;
+
+			if ($escape === TRUE)
+			{
+				$k = $this->_protect_identifiers($k);
+			}
+
+			if ( ! $this->_has_operator($k))
+			{
+				$k .= ' = ';
+			}
+
+			if ($v != '')
+			{
+				$v = ' '.$this->escape($v);
+			}
+
+			$this->ar_having[] = $prefix.$k.$v;
+			if ($this->ar_caching === TRUE)
+			{
+				$this->ar_cache_having[] = $prefix.$k.$v;
+				$this->ar_cache_exists[] = 'having';
+			}
+		}
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Sets the ORDER BY value
+	 *
+	 * @param	string
+	 * @param	string	direction: asc or desc
+	 * @return	object
+	 */
+	public function order_by($orderby, $direction = '')
+	{
+		if (strtolower($direction) == 'random')
+		{
+			$orderby = ''; // Random results want or don't need a field name
+			$direction = $this->_random_keyword;
+		}
+		elseif (trim($direction) != '')
+		{
+			$direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC';
+		}
+
+
+		if (strpos($orderby, ',') !== FALSE)
+		{
+			$temp = array();
+			foreach (explode(',', $orderby) as $part)
+			{
+				$part = trim($part);
+				if ( ! in_array($part, $this->ar_aliased_tables))
+				{
+					$part = $this->_protect_identifiers(trim($part));
+				}
+
+				$temp[] = $part;
+			}
+
+			$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)
+		{
+			$this->ar_cache_orderby[] = $orderby_statement;
+			$this->ar_cache_exists[] = 'orderby';
+		}
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Sets the LIMIT value
+	 *
+	 * @param	integer	the limit value
+	 * @param	integer	the offset value
+	 * @return	object
+	 */
+	public function limit($value, $offset = '')
+	{
+		$this->ar_limit = (int) $value;
+
+		if ($offset != '')
+		{
+			$this->ar_offset = (int) $offset;
+		}
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Sets the OFFSET value
+	 *
+	 * @param	integer	the offset value
+	 * @return	object
+	 */
+	public function offset($offset)
+	{
+		$this->ar_offset = $offset;
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The "set" function.  Allows key/value pairs to be set for inserting or updating
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	boolean
+	 * @return	object
+	 */
+	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)
+		{
+			if ($escape === FALSE)
+			{
+				$this->ar_set[$this->_protect_identifiers($k)] = $v;
+			}
+			else
+			{
+				$this->ar_set[$this->_protect_identifiers($k, FALSE, TRUE)] = $this->escape($v);
+			}
+		}
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get
+	 *
+	 * Compiles the select statement based on the other functions called
+	 * and runs the query
+	 *
+	 * @param	string	the table
+	 * @param	string	the limit clause
+	 * @param	string	the offset clause
+	 * @return	object
+	 */
+	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);
+		$this->_reset_select();
+		return $result;
+	}
+
+	/**
+	 * "Count All Results" query
+	 *
+	 * Generates a platform-specific query string that counts all records
+	 * returned by an Active Record query.
+	 *
+	 * @param	string
+	 * @return	string
+	 */
+	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;
+		}
+
+		$row = $query->row();
+		return (int) $row->numrows;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Get_Where
+	 *
+	 * Allows the where clause, limit and offset to be added directly
+	 *
+	 * @param	string	the where clause
+	 * @param	string	the limit clause
+	 * @param	string	the offset clause
+	 * @return	object
+	 */
+	public function get_where($table = '', $where = null, $limit = null, $offset = null)
+	{
+		if ($table != '')
+		{
+			$this->from($table);
+		}
+
+		if ( ! is_null($where))
+		{
+			$this->where($where);
+		}
+
+		if ( ! is_null($limit))
+		{
+			$this->limit($limit, $offset);
+		}
+
+		$sql = $this->_compile_select();
+
+		$result = $this->query($sql);
+		$this->_reset_select();
+		return $result;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Insert_Batch
+	 *
+	 * Compiles batch insert strings and runs the queries
+	 *
+	 * @param	string	the table to retrieve the results from
+	 * @param	array	an associative array of insert values
+	 * @return	object
+	 */
+	public function insert_batch($table = '', $set = NULL)
+	{
+		if ( ! is_null($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;
+		}
+
+		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->_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 TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The "set_insert_batch" function.  Allows key/value pairs to be set for batch inserts
+	 *
+	 * @param	mixed
+	 * @param	string
+	 * @param	boolean
+	 * @return	object
+	 */
+	public function set_insert_batch($key, $value = '', $escape = TRUE)
+	{
+		$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)
+			{
+				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->_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);
+		}
+
+		if ($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[] = $k.'-'.$v;
+				}
+
+				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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Empty Table
+	 *
+	 * Compiles a delete string and runs "DELETE FROM table"
+	 *
+	 * @param	string	the table to empty
+	 * @return	object
+	 */
+	public function empty_table($table = '')
+	{
+		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];
+		}
+		else
+		{
+			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+		}
+
+		$sql = $this->_delete($table);
+
+		$this->_reset_write();
+
+		return $this->query($sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Truncate
+	 *
+	 * Compiles a truncate string and runs the query
+	 * If the database does not support the truncate() command
+	 * This function maps to "DELETE FROM table"
+	 *
+	 * @param	string	the table to truncate
+	 * @return	object
+	 */
+	public function truncate($table = '')
+	{
+		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];
+		}
+		else
+		{
+			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+		}
+
+		$sql = $this->_truncate($table);
+
+		$this->_reset_write();
+
+		return $this->query($sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Delete
+	 *
+	 * Compiles a delete string and runs the query
+	 *
+	 * @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
+	 */
+	public function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE)
+	{
+		// Combine any cached components with the current statements
+		$this->_merge_cache();
+
+		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];
+		}
+		elseif (is_array($table))
+		{
+			foreach ($table as $single_table)
+			{
+				$this->delete($single_table, $where, $limit, FALSE);
+			}
+
+			$this->_reset_write();
+			return;
+		}
+		else
+		{
+			$table = $this->_protect_identifiers($table, TRUE, NULL, FALSE);
+		}
+
+		if ($where != '')
+		{
+			$this->where($where);
+		}
+
+		if ($limit != NULL)
+		{
+			$this->limit($limit);
+		}
+
+		if (count($this->ar_where) == 0 && count($this->ar_wherein) == 0 && count($this->ar_like) == 0)
+		{
+			if ($this->db_debug)
+			{
+				return $this->display_error('db_del_must_use_where');
+			}
+
+			return FALSE;
+		}
+
+		$sql = $this->_delete($table, $this->ar_where, $this->ar_like, $this->ar_limit);
+
+		if ($reset_data)
+		{
+			$this->_reset_write();
+		}
+
+		return $this->query($sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * DB Prefix
+	 *
+	 * Prepends a database prefix if one exists in configuration
+	 *
+	 * @param	string	the table
+	 * @return	string
+	 */
+	public function dbprefix($table = '')
+	{
+		if ($table == '')
+		{
+			$this->display_error('db_table_name_required');
+		}
+
+		return $this->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.
+	 *
+	 * @param	string	The table to inspect
+	 * @return	string
+	 */
+	protected function _track_aliases($table)
+	{
+		if (is_array($table))
+		{
+			foreach ($table as $t)
+			{
+				$this->_track_aliases($t);
+			}
+			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('/\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))
+			{
+				$this->ar_aliased_tables[] = $table;
+			}
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Compile the SELECT statement
+	 *
+	 * Generates a query string based on which functions were used.
+	 * Should not be called directly.  The get() function calls it.
+	 *
+	 * @return	string
+	 */
+	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)
+		{
+			$sql = $select_override;
+		}
+		else
+		{
+			$sql = ( ! $this->ar_distinct) ? 'SELECT ' : 'SELECT DISTINCT ';
+
+			if (count($this->ar_select) == 0)
+			{
+				$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)
+				{
+					$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)
+		{
+			$sql .= "\nFROM ";
+
+			$sql .= $this->_from_tables($this->ar_from);
+		}
+
+		// ----------------------------------------------------------------
+
+		// Write the "JOIN" portion of the query
+
+		if (count($this->ar_join) > 0)
+		{
+			$sql .= "\n";
+
+			$sql .= implode("\n", $this->ar_join);
+		}
+
+		// ----------------------------------------------------------------
+
+		// Write the "WHERE" portion of the query
+
+		if (count($this->ar_where) > 0 OR count($this->ar_like) > 0)
+		{
+			$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)
+			{
+				$sql .= "\nAND ";
+			}
+
+			$sql .= implode("\n", $this->ar_like);
+		}
+
+		// ----------------------------------------------------------------
+
+		// 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 ";
+			$sql .= implode("\n", $this->ar_having);
+		}
+
+		// ----------------------------------------------------------------
+
+		// 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";
+			$sql = $this->_limit($sql, $this->ar_limit, $this->ar_offset);
+		}
+
+		return $sql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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($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')
+			{
+				$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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Start Cache
+	 *
+	 * Starts AR caching
+	 *
+	 * @return	void
+	 */
+	public function start_cache()
+	{
+		$this->ar_caching = TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Stop Cache
+	 *
+	 * Stops AR caching
+	 *
+	 * @return	void
+	 */
+	public function stop_cache()
+	{
+		$this->ar_caching = FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Flush Cache
+	 *
+	 * Empties the AR cache
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	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()
+		));
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Merge Cache
+	 *
+	 * When called, this function merges any cached AR arrays with
+	 * locally called ones.
+	 *
+	 * @return	void
+	 */
+	protected function _merge_cache()
+	{
+		if (count($this->ar_cache_exists) == 0)
+		{
+			return;
+		}
+
+		foreach ($this->ar_cache_exists as $val)
+		{
+			$ar_variable	= 'ar_'.$val;
+			$ar_cache_var	= 'ar_cache_'.$val;
+
+			if (count($this->$ar_cache_var) == 0)
+			{
+				continue;
+			}
+
+			$this->$ar_variable = array_unique(array_merge($this->$ar_cache_var, $this->$ar_variable));
+		}
+
+		// If we are "protecting identifiers" we need to examine the "from"
+		// portion of the query to determine if there are any aliases
+		if ($this->_protect_identifiers === TRUE AND count($this->ar_cache_from) > 0)
+		{
+			$this->_track_aliases($this->ar_from);
+		}
+
+		$this->ar_no_escape = $this->ar_cache_no_escape;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Resets the active record values.  Called by the get() function
+	 *
+	 * @param	array	An array of fields to reset
+	 * @return	void
+	 */
+	protected function _reset_run($ar_reset_items)
+	{
+		foreach ($ar_reset_items as $item => $default_value)
+		{
+			if ( ! in_array($item, $this->ar_store_array))
+			{
+				$this->$item = $default_value;
+			}
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Resets the active record values.  Called by the get() function
+	 *
+	 * @return	void
+	 */
+	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_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() insert_batch() update_batch() and delete() functions
+	 *
+	 * @return	void
+	 */
+	protected function _reset_write()
+	{
+		$ar_reset_items = array(
+			'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 */
+/* Location: ./system/database/DB_active_rec.php */

+ 195 - 0
php-codeigniter/system/database/DB_cache.php

@@ -0,0 +1,195 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Database Cache Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_Cache {
+
+	var $CI;
+	var $db;	// allows passing of db object so that multiple database connections and returned db objects can be supported
+
+	/**
+	 * Constructor
+	 *
+	 * Grabs the CI super object instance so we can access it.
+	 *
+	 */
+	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');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Cache Directory Path
+	 *
+	 * @access	public
+	 * @param	string	the path to the cache directory
+	 * @return	bool
+	 */
+	function check_path($path = '')
+	{
+		if ($path == '')
+		{
+			if ($this->db->cachedir == '')
+			{
+				return $this->db->cache_off();
+			}
+
+			$path = $this->db->cachedir;
+		}
+
+		// Add a trailing slash to the path if needed
+		$path = preg_replace("/(.+?)\/*$/", "\\1/",  $path);
+
+		if ( ! is_dir($path) OR ! is_really_writable($path))
+		{
+			// If the path is wrong we'll turn off caching
+			return $this->db->cache_off();
+		}
+
+		$this->db->cachedir = $path;
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Retrieve a cached query
+	 *
+	 * The URI being requested will become the name of the cache sub-folder.
+	 * An MD5 hash of the SQL statement will become the cache file name
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function read($sql)
+	{
+		if ( ! $this->check_path())
+		{
+			return $this->db->cache_off();
+		}
+
+		$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);
+
+		if (FALSE === ($cachedata = read_file($filepath)))
+		{
+			return FALSE;
+		}
+
+		return unserialize($cachedata);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Write a query to a cache file
+	 *
+	 * @access	public
+	 * @return	bool
+	 */
+	function write($sql, $object)
+	{
+		if ( ! $this->check_path())
+		{
+			return $this->db->cache_off();
+		}
+
+		$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);
+		}
+
+		if (write_file($dir_path.$filename, serialize($object)) === FALSE)
+		{
+			return FALSE;
+		}
+
+		@chmod($dir_path.$filename, FILE_WRITE_MODE);
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Delete cache files within a particular directory
+	 *
+	 * @access	public
+	 * @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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Delete all existing cache files
+	 *
+	 * @access	public
+	 * @return	bool
+	 */
+	function delete_all()
+	{
+		delete_files($this->db->cachedir, TRUE);
+	}
+
+}
+
+
+/* End of file DB_cache.php */
+/* Location: ./system/database/DB_cache.php */

+ 1410 - 0
php-codeigniter/system/database/DB_driver.php

@@ -0,0 +1,1410 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Database Driver Class
+ *
+ * This is the platform-independent base DB implementation class.
+ * This class will not be called directly. Rather, the adapter
+ * class for the specific database will extend and instantiate it.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Drivers
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_driver {
+
+	var $username;
+	var $password;
+	var $hostname;
+	var $database;
+	var $dbdriver		= 'mysql';
+	var $dbprefix		= '';
+	var $char_set		= 'utf8';
+	var $dbcollat		= 'utf8_general_ci';
+	var $autoinit		= TRUE; // Whether to automatically initialize the DB
+	var $swap_pre		= '';
+	var $port			= '';
+	var $pconnect		= FALSE;
+	var $conn_id		= FALSE;
+	var $result_id		= FALSE;
+	var $db_debug		= FALSE;
+	var $benchmark		= 0;
+	var $query_count	= 0;
+	var $bind_marker	= '?';
+	var $save_queries	= TRUE;
+	var $queries		= array();
+	var $query_times	= array();
+	var $data_cache		= array();
+	var $trans_enabled	= TRUE;
+	var $trans_strict	= TRUE;
+	var $_trans_depth	= 0;
+	var $_trans_status	= TRUE; // Used with transactions to determine if a rollback should occur
+	var $cache_on		= FALSE;
+	var $cachedir		= '';
+	var $cache_autodel	= FALSE;
+	var $CACHE; // The cache class object
+
+	// Private variables
+	var $_protect_identifiers	= TRUE;
+	var $_reserved_identifiers	= array('*'); // Identifiers that should NOT be escaped
+
+	// These are use with Oracle
+	var $stmt_id;
+	var $curs_id;
+	var $limit_used;
+
+
+
+	/**
+	 * Constructor.  Accepts one parameter containing the database
+	 * connection settings.
+	 *
+	 * @param array
+	 */
+	function __construct($params)
+	{
+		if (is_array($params))
+		{
+			foreach ($params as $key => $val)
+			{
+				$this->$key = $val;
+			}
+		}
+
+		log_message('debug', 'Database Driver Class Initialized');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Initialize Database Settings
+	 *
+	 * @access	private Called by the constructor
+	 * @param	mixed
+	 * @return	void
+	 */
+	function initialize()
+	{
+		// If an existing connection resource is available
+		// there is no need to connect and select the database
+		if (is_resource($this->conn_id) OR is_object($this->conn_id))
+		{
+			return TRUE;
+		}
+
+		// ----------------------------------------------------------------
+
+		// Connect to the database and set the connection ID
+		$this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect();
+
+		// No connection resource?  Throw an error
+		if ( ! $this->conn_id)
+		{
+			log_message('error', 'Unable to connect to the database');
+
+			if ($this->db_debug)
+			{
+				$this->display_error('db_unable_to_connect');
+			}
+			return FALSE;
+		}
+
+		// ----------------------------------------------------------------
+
+		// Select the DB... assuming a database name is specified in the config file
+		if ($this->database != '')
+		{
+			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;
+			}
+			else
+			{
+				// We've selected the DB. Now we set the character set
+				if ( ! $this->db_set_charset($this->char_set, $this->dbcollat))
+				{
+					return FALSE;
+				}
+
+				return TRUE;
+			}
+		}
+
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set client character set
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	resource
+	 */
+	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
+	 */
+	function platform()
+	{
+		return $this->dbdriver;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Database Version Number.  Returns a string containing the
+	 * version of the database being used
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function version()
+	{
+		if (FALSE === ($sql = $this->_version()))
+		{
+			if ($this->db_debug)
+			{
+				return $this->display_error('db_unsupported_function');
+			}
+			return FALSE;
+		}
+
+		// 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;
+		}
+		else
+		{
+			$query = $this->query($sql);
+			return $query->row('ver');
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Execute the query
+	 *
+	 * Accepts an SQL string as input and returns a result object upon
+	 * successful execution of a "read" type query.  Returns boolean TRUE
+	 * upon successful execution of a "write" type query. Returns boolean
+	 * FALSE upon failure, and if the $db_debug variable is set to TRUE
+	 * will raise an error.
+	 *
+	 * @access	public
+	 * @param	string	An SQL query string
+	 * @param	array	An array of binding data
+	 * @return	mixed
+	 */
+	function query($sql, $binds = FALSE, $return_object = TRUE)
+	{
+		if ($sql == '')
+		{
+			if ($this->db_debug)
+			{
+				log_message('error', 'Invalid query: '.$sql);
+				return $this->display_error('db_invalid_query');
+			}
+			return FALSE;
+		}
+
+		// 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
+		if ($this->cache_on == TRUE AND stristr($sql, 'SELECT'))
+		{
+			if ($this->_cache_init())
+			{
+				$this->load_rdriver();
+				if (FALSE !== ($cache = $this->CACHE->read($sql)))
+				{
+					return $cache;
+				}
+			}
+		}
+
+		// 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)))
+		{
+			if ($this->save_queries == TRUE)
+			{
+				$this->query_times[] = 0;
+			}
+
+			// This will trigger a rollback if transactions are being used
+			$this->_trans_status = FALSE;
+
+			if ($this->db_debug)
+			{
+				// grab the error number and message now, as we might run some
+				// 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
+				// transactions to remain in limbo.
+				$this->trans_complete();
+
+				// Log and display errors
+				log_message('error', 'Query error: '.$error_msg);
+				return $this->display_error(
+										array(
+												'Error Number: '.$error_no,
+												$error_msg,
+												$sql
+											)
+										);
+			}
+
+			return FALSE;
+		}
+
+		// Stop and aggregate the query time results
+		$time_end = list($em, $es) = explode(' ', microtime());
+		$this->benchmark += ($em + $es) - ($sm + $ss);
+
+		if ($this->save_queries == 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)
+		{
+			// If caching is enabled we'll auto-cleanup any
+			// existing files related to this particular URI
+			if ($this->cache_on == TRUE AND $this->cache_autodel == TRUE AND $this->_cache_init())
+			{
+				$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
+		if ($return_object !== TRUE)
+		{
+			return TRUE;
+		}
+
+		// 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;
+
+		if ($this->dbdriver == 'oci8')
+		{
+			$RES->stmt_id		= $this->stmt_id;
+			$RES->curs_id		= NULL;
+			$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())
+		{
+			// We'll create a new instance of the result object
+			// only without the platform specific driver since
+			// we can't use it with cached data (the query result
+			// resource ID won't be any good once we've cached the
+			// 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->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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Load the result drivers
+	 *
+	 * @access	public
+	 * @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.php');
+			include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result.php');
+		}
+
+		return $driver;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Simple Query
+	 * This is a simplified version of the query() function.  Internally
+	 * we only use it when running transaction commands since they do
+	 * not require all the features of the main query() function.
+	 *
+	 * @access	public
+	 * @param	string	the sql query
+	 * @return	mixed
+	 */
+	function simple_query($sql)
+	{
+		if ( ! $this->conn_id)
+		{
+			$this->initialize();
+		}
+
+		return $this->_execute($sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Disable Transactions
+	 * This permits transactions to be disabled at run-time.
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function trans_off()
+	{
+		$this->trans_enabled = FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Enable/disable Transaction Strict Mode
+	 * When strict mode is enabled, if you are running multiple groups of
+	 * transactions, if one group fails all groups will be rolled back.
+	 * If strict mode is disabled, each group is treated autonomously, meaning
+	 * a failure of one group will not affect any others
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function trans_strict($mode = TRUE)
+	{
+		$this->trans_strict = is_bool($mode) ? $mode : TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Start Transaction
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function trans_start($test_mode = FALSE)
+	{
+		if ( ! $this->trans_enabled)
+		{
+			return FALSE;
+		}
+
+		// When transactions are nested we only begin/commit/rollback the outermost ones
+		if ($this->_trans_depth > 0)
+		{
+			$this->_trans_depth += 1;
+			return;
+		}
+
+		$this->trans_begin($test_mode);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Complete Transaction
+	 *
+	 * @access	public
+	 * @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.
+			if ($this->trans_strict === FALSE)
+			{
+				$this->_trans_status = TRUE;
+			}
+
+			log_message('debug', 'DB Transaction Failure');
+			return FALSE;
+		}
+
+		$this->trans_commit();
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Lets you retrieve the transaction flag to determine if it has failed
+	 *
+	 * @access	public
+	 * @return	bool
+	 */
+	function trans_status()
+	{
+		return $this->_trans_status;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Compile Bindings
+	 *
+	 * @access	public
+	 * @param	string	the sql statement
+	 * @param	array	an array of bind data
+	 * @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);
+
+		// The count of bind should be 1 less then the count of segments
+		// If there are more bind arguments trim it down
+		if (count($binds) >= count($segments)) {
+			$binds = array_slice($binds, 0, count($segments)-1);
+		}
+
+		// Construct the binded query
+		$result = $segments[0];
+		$i = 0;
+		foreach ($binds as $bind)
+		{
+			$result .= $this->escape($bind);
+			$result .= $segments[++$i];
+		}
+
+		return $result;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Determines if a query is a "write" type.
+	 *
+	 * @access	public
+	 * @param	string	An SQL query string
+	 * @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))
+		{
+			return FALSE;
+		}
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Calculate the aggregate query elapsed time
+	 *
+	 * @access	public
+	 * @param	integer	The number of decimal places
+	 * @return	integer
+	 */
+	function elapsed_time($decimals = 6)
+	{
+		return number_format($this->benchmark, $decimals);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Returns the total number of queries
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function total_queries()
+	{
+		return $this->query_count;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Returns the last query that was executed
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function last_query()
+	{
+		return end($this->queries);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * "Smart" Escape String
+	 *
+	 * Escapes data based on type
+	 * Sets boolean and null types
+	 *
+	 * @access	public
+	 * @param	string
+	 * @return	mixed
+	 */
+	function escape($str)
+	{
+		if (is_string($str))
+		{
+			$str = "'".$this->escape_str($str)."'";
+		}
+		elseif (is_bool($str))
+		{
+			$str = ($str === FALSE) ? 0 : 1;
+		}
+		elseif (is_null($str))
+		{
+			$str = 'NULL';
+		}
+
+		return $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)
+	{
+		return $this->escape_str($str, TRUE);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Primary
+	 *
+	 * Retrieves the primary key.  It assumes that the row in the first
+	 * position is the primary key
+	 *
+	 * @access	public
+	 * @param	string	the table name
+	 * @return	string
+	 */
+	function primary($table = '')
+	{
+		$fields = $this->list_fields($table);
+
+		if ( ! is_array($fields))
+		{
+			return FALSE;
+		}
+
+		return current($fields);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Returns an array of table names
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	function list_tables($constrain_by_prefix = FALSE)
+	{
+		// Is there a cached result?
+		if (isset($this->data_cache['table_names']))
+		{
+			return $this->data_cache['table_names'];
+		}
+
+		if (FALSE === ($sql = $this->_list_tables($constrain_by_prefix)))
+		{
+			if ($this->db_debug)
+			{
+				return $this->display_error('db_unsupported_function');
+			}
+			return FALSE;
+		}
+
+		$retval = array();
+		$query = $this->query($sql);
+
+		if ($query->num_rows() > 0)
+		{
+			foreach ($query->result_array() as $row)
+			{
+				if (isset($row['TABLE_NAME']))
+				{
+					$retval[] = $row['TABLE_NAME'];
+				}
+				else
+				{
+					$retval[] = array_shift($row);
+				}
+			}
+		}
+
+		$this->data_cache['table_names'] = $retval;
+		return $this->data_cache['table_names'];
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Determine if a particular table exists
+	 * @access	public
+	 * @return	boolean
+	 */
+	function table_exists($table_name)
+	{
+		return ( ! in_array($this->_protect_identifiers($table_name, TRUE, FALSE, FALSE), $this->list_tables())) ? FALSE : TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch MySQL Field Names
+	 *
+	 * @access	public
+	 * @param	string	the table name
+	 * @return	array
+	 */
+	function list_fields($table = '')
+	{
+		// Is there a cached result?
+		if (isset($this->data_cache['field_names'][$table]))
+		{
+			return $this->data_cache['field_names'][$table];
+		}
+
+		if ($table == '')
+		{
+			if ($this->db_debug)
+			{
+				return $this->display_error('db_field_param_missing');
+			}
+			return FALSE;
+		}
+
+		if (FALSE === ($sql = $this->_list_columns($table)))
+		{
+			if ($this->db_debug)
+			{
+				return $this->display_error('db_unsupported_function');
+			}
+			return FALSE;
+		}
+
+		$query = $this->query($sql);
+
+		$retval = array();
+		foreach ($query->result_array() as $row)
+		{
+			if (isset($row['COLUMN_NAME']))
+			{
+				$retval[] = $row['COLUMN_NAME'];
+			}
+			else
+			{
+				$retval[] = current($row);
+			}
+		}
+
+		$this->data_cache['field_names'][$table] = $retval;
+		return $this->data_cache['field_names'][$table];
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Determine if a particular field exists
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	boolean
+	 */
+	function field_exists($field_name, $table_name)
+	{
+		return ( ! in_array($field_name, $this->list_fields($table_name))) ? FALSE : TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Returns an object with field data
+	 *
+	 * @access	public
+	 * @param	string	the table name
+	 * @return	object
+	 */
+	function field_data($table = '')
+	{
+		if ($table == '')
+		{
+			if ($this->db_debug)
+			{
+				return $this->display_error('db_field_param_missing');
+			}
+			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
+	 */
+	function insert_string($table, $data)
+	{
+		$fields = array();
+		$values = array();
+
+		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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Generate an update string
+	 *
+	 * @access	public
+	 * @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
+	 */
+	function update_string($table, $data, $where)
+	{
+		if ($where == '')
+		{
+			return false;
+		}
+
+		$fields = array();
+		foreach ($data as $key => $val)
+		{
+			$fields[$this->_protect_identifiers($key)] = $this->escape($val);
+		}
+
+		if ( ! is_array($where))
+		{
+			$dest = array($where);
+		}
+		else
+		{
+			$dest = array();
+			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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Tests whether the string has an SQL operator
+	 *
+	 * @access	private
+	 * @param	string
+	 * @return	bool
+	 */
+	function _has_operator($str)
+	{
+		$str = trim($str);
+		if ( ! preg_match("/(\s|<|>|!|=|is null|is not null)/i", $str))
+		{
+			return FALSE;
+		}
+
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Enables a native PHP function to be run, using a platform agnostic wrapper.
+	 *
+	 * @access	public
+	 * @param	string	the function name
+	 * @param	mixed	any parameters needed by the function
+	 * @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)
+			{
+				return $this->display_error('db_unsupported_function');
+			}
+			return FALSE;
+		}
+		else
+		{
+			$args = (func_num_args() > 1) ? array_splice(func_get_args(), 1) : null;
+			if (is_null($args))
+			{
+				return call_user_func($function);
+			}
+			else
+			{
+				return call_user_func_array($function, $args);
+			}
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set Cache Directory Path
+	 *
+	 * @access	public
+	 * @param	string	the path to the cache directory
+	 * @return	void
+	 */
+	function cache_set_path($path = '')
+	{
+		$this->cachedir = $path;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Enable Query Caching
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function cache_on()
+	{
+		$this->cache_on = TRUE;
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Disable Query Caching
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function cache_off()
+	{
+		$this->cache_on = FALSE;
+		return FALSE;
+	}
+
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Delete the cache files associated with a particular URI
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function cache_delete($segment_one = '', $segment_two = '')
+	{
+		if ( ! $this->_cache_init())
+		{
+			return FALSE;
+		}
+		return $this->CACHE->delete($segment_one, $segment_two);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Delete All cache files
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function cache_delete_all()
+	{
+		if ( ! $this->_cache_init())
+		{
+			return FALSE;
+		}
+
+		return $this->CACHE->delete_all();
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Initialize the Cache Class
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _cache_init()
+	{
+		if (is_object($this->CACHE) AND class_exists('CI_DB_Cache'))
+		{
+			return TRUE;
+		}
+
+		if ( ! class_exists('CI_DB_Cache'))
+		{
+			if ( ! @include(BASEPATH.'database/DB_cache.php'))
+			{
+				return $this->cache_off();
+			}
+		}
+
+		$this->CACHE = new CI_DB_Cache($this); // pass db object to support multiple db connections and returned db objects
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Close DB Connection
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function close()
+	{
+		if (is_resource($this->conn_id) OR is_object($this->conn_id))
+		{
+			$this->_close($this->conn_id);
+		}
+		$this->conn_id = FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Display an error message
+	 *
+	 * @access	public
+	 * @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
+	 */
+	function display_error($error = '', $swap = '', $native = FALSE)
+	{
+		$LANG =& load_class('Lang', 'core');
+		$LANG->load('db');
+
+		$heading = $LANG->line('db_error_heading');
+
+		if ($native == TRUE)
+		{
+			$message = $error;
+		}
+		else
+		{
+			$message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error;
+		}
+
+		// 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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Protect Identifiers
+	 *
+	 * This function adds backticks if appropriate based on db type
+	 *
+	 * @access	private
+	 * @param	mixed	the item to escape
+	 * @return	mixed	the item with backticks
+	 */
+	function protect_identifiers($item, $prefix_single = FALSE)
+	{
+		return $this->_protect_identifiers($item, $prefix_single);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Protect Identifiers
+	 *
+	 * This function is used extensively by the Active Record class, and by
+	 * 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:
+	 *
+	 * SELECT * FROM hostname.database.table.column AS c FROM hostname.database.table
+	 *
+	 * Or a query with aliasing:
+	 *
+	 * SELECT m.member_id, m.member_name FROM members AS m
+	 *
+	 * Since the column name can include up to four segments (host, DB, table, column)
+	 * or also have an alias prefix, we need to do a bit of work to figure this out and
+	 * insert the table prefix (if it exists) in the proper position, and escape only
+	 * the correct identifiers.
+	 *
+	 * @access	private
+	 * @param	string
+	 * @param	bool
+	 * @param	mixed
+	 * @param	bool
+	 * @return	string
+	 */
+	function _protect_identifiers($item, $prefix_single = FALSE, $protect_identifiers = NULL, $field_exists = TRUE)
+	{
+		if ( ! is_bool($protect_identifiers))
+		{
+			$protect_identifiers = $this->_protect_identifiers;
+		}
+
+		if (is_array($item))
+		{
+			$escaped_array = array();
+
+			foreach ($item as $k => $v)
+			{
+				$escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v);
+			}
+
+			return $escaped_array;
+		}
+
+		// 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
+		if (strpos($item, ' ') !== FALSE)
+		{
+			$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
+		// 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)
+		{
+			return $item.$alias;
+		}
+
+		// Break the string apart if it contains periods, then insert the table prefix
+		// in the correct location, assuming the period doesn't indicate that we're dealing
+		// with an alias. While we're at it, we will escape the components
+		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
+			if (in_array($parts[0], $this->ar_aliased_tables))
+			{
+				if ($protect_identifiers === TRUE)
+				{
+					foreach ($parts as $key => $val)
+					{
+						if ( ! in_array($val, $this->_reserved_identifiers))
+						{
+							$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 != '')
+			{
+				// We now add the table prefix based on some logic.
+				// Do we have 4 segments (hostname.database.table.column)?
+				// If so, we add the table prefix to the column name in the 3rd segment.
+				if (isset($parts[3]))
+				{
+					$i = 2;
+				}
+				// Do we have 3 segments (database.table.column)?
+				// If so, we add the table prefix to the column name in 2nd position
+				elseif (isset($parts[2]))
+				{
+					$i = 1;
+				}
+				// Do we have 2 segments (table.column)?
+				// If so, we add the table prefix to the column name in 1st segment
+				else
+				{
+					$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)
+				{
+					$i++;
+				}
+
+				// Verify table prefix and replace if necessary
+				if ($this->swap_pre != '' && strncmp($parts[$i], $this->swap_pre, strlen($this->swap_pre)) === 0)
+				{
+					$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;
+		}
+
+		// Is there a table prefix?  If not, no need to insert it
+		if ($this->dbprefix != '')
+		{
+			// Verify table prefix and replace if necessary
+			if ($this->swap_pre != '' && strncmp($item, $this->swap_pre, strlen($this->swap_pre)) === 0)
+			{
+				$item = preg_replace("/^".$this->swap_pre."(\S+?)/", $this->dbprefix."\\1", $item);
+			}
+
+			// Do we prefix an item with no segments?
+			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 */

+ 382 - 0
php-codeigniter/system/database/DB_forge.php

@@ -0,0 +1,382 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Database Utility Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_forge {
+
+	var $fields			= array();
+	var $keys			= array();
+	var $primary_keys	= array();
+	var $db_char_set	=	'';
+
+	/**
+	 * Constructor
+	 *
+	 * Grabs the CI super object instance so we can access it.
+	 *
+	 */
+	function __construct()
+	{
+		// Assign the main database object to $this->db
+		$CI =& get_instance();
+		$this->db =& $CI->db;
+		log_message('debug', "Database Forge Class Initialized");
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Create database
+	 *
+	 * @access	public
+	 * @param	string	the database name
+	 * @return	bool
+	 */
+	function create_database($db_name)
+	{
+		$sql = $this->_create_database($db_name);
+
+		if (is_bool($sql))
+		{
+			return $sql;
+		}
+
+		return $this->db->query($sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Drop database
+	 *
+	 * @access	public
+	 * @param	string	the database name
+	 * @return	bool
+	 */
+	function drop_database($db_name)
+	{
+		$sql = $this->_drop_database($db_name);
+
+		if (is_bool($sql))
+		{
+			return $sql;
+		}
+
+		return $this->db->query($sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Add Key
+	 *
+	 * @access	public
+	 * @param	string	key
+	 * @param	string	type
+	 * @return	void
+	 */
+	function add_key($key = '', $primary = FALSE)
+	{
+		if (is_array($key))
+		{
+			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;
+		}
+		else
+		{
+			$this->keys[] = $key;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Add Field
+	 *
+	 * @access	public
+	 * @param	string	collation
+	 * @return	void
+	 */
+	function add_field($field = '')
+	{
+		if ($field == '')
+		{
+			show_error('Field information is required.');
+		}
+
+		if (is_string($field))
+		{
+			if ($field == 'id')
+			{
+				$this->add_field(array(
+										'id' => array(
+													'type' => 'INT',
+													'constraint' => 9,
+													'auto_increment' => TRUE
+													)
+								));
+				$this->add_key('id', TRUE);
+			}
+			else
+			{
+				if (strpos($field, ' ') === FALSE)
+				{
+					show_error('Field information is required for that operation.');
+				}
+
+				$this->fields[] = $field;
+			}
+		}
+
+		if (is_array($field))
+		{
+			$this->fields = array_merge($this->fields, $field);
+		}
+
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Create Table
+	 *
+	 * @access	public
+	 * @param	string	the table name
+	 * @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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Drop Table
+	 *
+	 * @access	public
+	 * @param	string	the table name
+	 * @return	bool
+	 */
+	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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Rename Table
+	 *
+	 * @access	public
+	 * @param	string	the old table name
+	 * @param	string	the new table name
+	 * @return	bool
+	 */
+	function rename_table($table_name, $new_table_name)
+	{
+		if ($table_name == '' OR $new_table_name == '')
+		{
+			show_error('A table name is required for that operation.');
+		}
+
+		$sql = $this->_rename_table($this->db->dbprefix.$table_name, $this->db->dbprefix.$new_table_name);
+		return $this->db->query($sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Column Add
+	 *
+	 * @access	public
+	 * @param	string	the table name
+	 * @param	string	the column name
+	 * @param	string	the column definition
+	 * @return	bool
+	 */
+	function add_column($table = '', $field = array(), $after_field = '')
+	{
+		if ($table == '')
+		{
+			show_error('A table name is required for that operation.');
+		}
+
+		// add field info into field array, but we can only do one at a time
+		// so we cycle through
+
+		foreach ($field as $k => $v)
+		{
+			$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;
+
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Column Drop
+	 *
+	 * @access	public
+	 * @param	string	the table name
+	 * @param	string	the column name
+	 * @return	bool
+	 */
+	function drop_column($table = '', $column_name = '')
+	{
+
+		if ($table == '')
+		{
+			show_error('A table name is required for that operation.');
+		}
+
+		if ($column_name == '')
+		{
+			show_error('A column name is required for that operation.');
+		}
+
+		$sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name);
+
+		return $this->db->query($sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Column Modify
+	 *
+	 * @access	public
+	 * @param	string	the table name
+	 * @param	string	the column name
+	 * @param	string	the column definition
+	 * @return	bool
+	 */
+	function modify_column($table = '', $field = array())
+	{
+		if ($table == '')
+		{
+			show_error('A table name is required for that operation.');
+		}
+
+		// add field info into field array, but we can only do one at a time
+		// so we cycle through
+
+		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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Reset
+	 *
+	 * Resets table creation vars
+	 *
+	 * @access	private
+	 * @return	void
+	 */
+	function _reset()
+	{
+		$this->fields		= array();
+		$this->keys			= array();
+		$this->primary_keys	= array();
+	}
+
+}
+
+/* End of file DB_forge.php */
+/* Location: ./system/database/DB_forge.php */

+ 410 - 0
php-codeigniter/system/database/DB_result.php

@@ -0,0 +1,410 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Database Result Class
+ *
+ * This is the platform-independent result class.
+ * This class will not be called directly. Rather, the adapter
+ * class for the specific database will extend and instantiate it.
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_result {
+
+	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;
+
+
+	/**
+	 * Query result.  Acts as a wrapper function for the following functions.
+	 *
+	 * @access	public
+	 * @param	string	can be "object" or "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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result.  "object" version.
+	 *
+	 * @access	public
+	 * @return	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
+		// we'll simply return an empty array.
+		if ($this->result_id === FALSE OR $this->num_rows() == 0)
+		{
+			return array();
+		}
+
+		$this->_data_seek(0);
+		while ($row = $this->_fetch_object())
+		{
+			$this->result_object[] = $row;
+		}
+
+		return $this->result_object;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result.  "array" version.
+	 *
+	 * @access	public
+	 * @return	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
+		// we'll simply return an empty array.
+		if ($this->result_id === FALSE OR $this->num_rows() == 0)
+		{
+			return array();
+		}
+
+		$this->_data_seek(0);
+		while ($row = $this->_fetch_assoc())
+		{
+			$this->result_array[] = $row;
+		}
+
+		return $this->result_array;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result.  Acts as a wrapper function for the following functions.
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string	can be "object" or "array"
+	 * @return	mixed	either a result object or array
+	 */
+	public function row($n = 0, $type = 'object')
+	{
+		if ( ! is_numeric($n))
+		{
+			// We cache the row data for subsequent uses
+			if ( ! is_array($this->row_data))
+			{
+				$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
+			$n = 0;
+		}
+
+		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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Assigns an item into a particular column slot
+	 *
+	 * @access	public
+	 * @return	object
+	 */
+	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;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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
+	 */
+	public function row_object($n = 0)
+	{
+		$result = $this->result_object();
+
+		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 - array version
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	public function row_array($n = 0)
+	{
+		$result = $this->result_array();
+
+		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 the "first" row
+	 *
+	 * @access	public
+	 * @return	object
+	 */
+	public function first_row($type = 'object')
+	{
+		$result = $this->result($type);
+
+		if (count($result) == 0)
+		{
+			return $result;
+		}
+		return $result[0];
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Returns the "last" row
+	 *
+	 * @access	public
+	 * @return	object
+	 */
+	public function last_row($type = 'object')
+	{
+		$result = $this->result($type);
+
+		if (count($result) == 0)
+		{
+			return $result;
+		}
+		return $result[count($result) -1];
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Returns the "next" row
+	 *
+	 * @access	public
+	 * @return	object
+	 */
+	public function next_row($type = 'object')
+	{
+		$result = $this->result($type);
+
+		if (count($result) == 0)
+		{
+			return $result;
+		}
+
+		if (isset($result[$this->current_row + 1]))
+		{
+			++$this->current_row;
+		}
+
+		return $result[$this->current_row];
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Returns the "previous" row
+	 *
+	 * @access	public
+	 * @return	object
+	 */
+	public function previous_row($type = 'object')
+	{
+		$result = $this->result($type);
+
+		if (count($result) == 0)
+		{
+			return $result;
+		}
+
+		if (isset($result[$this->current_row - 1]))
+		{
+			--$this->current_row;
+		}
+		return $result[$this->current_row];
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The following functions are normally overloaded by the identically named
+	 * methods in the platform-specific driver -- except when query caching
+	 * is used.  When caching is enabled we do not load the other driver.
+	 * These functions are primarily here to prevent undefined function errors
+	 * when a cached result object is in use.  They are not otherwise fully
+	 * operational due to the unavailability of the database resource IDs with
+	 * cached results.
+	 */
+	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 */

+ 414 - 0
php-codeigniter/system/database/DB_utility.php

@@ -0,0 +1,414 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * Code Igniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Database Utility Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_utility extends CI_DB_forge {
+
+	var $db;
+	var $data_cache		= array();
+
+	/**
+	 * Constructor
+	 *
+	 * Grabs the CI super object instance so we can access it.
+	 *
+	 */
+	function __construct()
+	{
+		// Assign the main database object to $this->db
+		$CI =& get_instance();
+		$this->db =& $CI->db;
+
+		log_message('debug', "Database Utility Class Initialized");
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * List databases
+	 *
+	 * @access	public
+	 * @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)
+		{
+			foreach ($query->result_array() as $row)
+			{
+				$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;
+		}
+	}
+
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Optimize Table
+	 *
+	 * @access	public
+	 * @param	string	the table name
+	 * @return	bool
+	 */
+	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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Optimize Database
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	function optimize_database()
+	{
+		$result = array();
+		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
+			$res = $query->result_array();
+			$res = current($res);
+			$key = str_replace($this->db->database.'.', '', current($res));
+			$keys = array_keys($res);
+			unset($res[$keys[0]]);
+
+			$result[$key] = $res;
+		}
+
+		return $result;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Repair Table
+	 *
+	 * @access	public
+	 * @param	string	the table name
+	 * @return	bool
+	 */
+	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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Generate CSV from a query result object
+	 *
+	 * @access	public
+	 * @param	object	The query result object
+	 * @param	string	The delimiter - comma by default
+	 * @param	string	The newline character - \n by default
+	 * @param	string	The enclosure - double quote by default
+	 * @return	string
+	 */
+	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 = rtrim($out);
+			$out .= $newline;
+		}
+
+		return $out;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Generate XML data from a query result object
+	 *
+	 * @access	public
+	 * @param	object	The query result object
+	 * @param	array	Any preferences
+	 * @return	string
+	 */
+	function xml_from_result($query, $params = array())
+	{
+		if ( ! is_object($query) OR ! method_exists($query, 'list_fields'))
+		{
+			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)
+		{
+			if ( ! isset($params[$key]))
+			{
+				$params[$key] = $val;
+			}
+		}
+
+		// Create variables for convenience
+		extract($params);
+
+		// Load the xml helper
+		$CI =& get_instance();
+		$CI->load->helper('xml');
+
+		// Generate the result
+		$xml = "<{$root}>".$newline;
+		foreach ($query->result_array() as $row)
+		{
+			$xml .= $tab."<{$element}>".$newline;
+
+			foreach ($row as $key => $val)
+			{
+				$xml .= $tab.$tab."<{$key}>".xml_convert($val)."</{$key}>".$newline;
+			}
+			$xml .= $tab."</{$element}>".$newline;
+		}
+		$xml .= "</$root>".$newline;
+
+		return $xml;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Database Backup
+	 *
+	 * @access	public
+	 * @return	void
+	 */
+	function backup($params = array())
+	{
+		// If the parameters have not been submitted as an
+		// array then we know that it is simply the table
+		// name, which is a valid short cut.
+		if (is_string($params))
+		{
+			$params = array('tables' => $params);
+		}
+
+		// ------------------------------------------------------
+
+		// Set up our default preferences
+		$prefs = array(
+							'tables'		=> array(),
+							'ignore'		=> array(),
+							'filename'		=> '',
+							'format'		=> 'gzip', // gzip, zip, txt
+							'add_drop'		=> TRUE,
+							'add_insert'	=> TRUE,
+							'newline'		=> "\n"
+						);
+
+		// Did the user submit any preferences? If so set them....
+		if (count($params) > 0)
+		{
+			foreach ($prefs as $key => $val)
+			{
+				if (isset($params[$key]))
+				{
+					$prefs[$key] = $params[$key];
+				}
+			}
+		}
+
+		// ------------------------------------------------------
+
+		// 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
+		if ( ! in_array($prefs['format'], array('gzip', 'zip', 'txt'), TRUE))
+		{
+			$prefs['format'] = 'txt';
+		}
+
+		// ------------------------------------------------------
+
+		// 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')))
+		{
+			if ($this->db->db_debug)
+			{
+				return $this->db->display_error('db_unsuported_compression');
+			}
+
+			$prefs['format'] = 'txt';
+		}
+
+		// ------------------------------------------------------
+
+		// Set the filename if not provided - Only needed with Zip files
+		if ($prefs['filename'] == '' AND $prefs['format'] == 'zip')
+		{
+			$prefs['filename'] = (count($prefs['tables']) == 1) ? $prefs['tables'] : $this->db->database;
+			$prefs['filename'] .= '_'.date('Y-m-d_H-i', time());
+		}
+
+		// ------------------------------------------------------
+
+		// Was a Gzip file requested?
+		if ($prefs['format'] == 'gzip')
+		{
+			return gzencode($this->_backup($prefs));
+		}
+
+		// ------------------------------------------------------
+
+		// Was a text file requested?
+		if ($prefs['format'] == 'txt')
+		{
+			return $this->_backup($prefs);
+		}
+
+		// ------------------------------------------------------
+
+		// Was a Zip file requested?
+		if ($prefs['format'] == 'zip')
+		{
+			// If they included the .zip file extension we'll remove it
+			if (preg_match("|.+?\.zip$|", $prefs['filename']))
+			{
+				$prefs['filename'] = str_replace('.zip', '', $prefs['filename']);
+			}
+
+			// Tack on the ".sql" file extension if needed
+			if ( ! preg_match("|.+?\.sql$|", $prefs['filename']))
+			{
+				$prefs['filename'] .= '.sql';
+			}
+
+			// Load the Zip class and output it
+
+			$CI =& get_instance();
+			$CI->load->library('zip');
+			$CI->zip->add_data($prefs['filename'], $this->_backup($prefs));
+			return $CI->zip->get_zip();
+		}
+
+	}
+
+}
+
+
+/* End of file DB_utility.php */
+/* Location: ./system/database/DB_utility.php */

+ 792 - 0
php-codeigniter/system/database/drivers/cubrid/cubrid_driver.php

@@ -0,0 +1,792 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Esen Sagynov
+ * @copyright	Copyright (c) 2008 - 2011, EllisLab, Inc.
+ * @license		http://codeigniter.com/user_guide/license.html
+ * @link		http://codeigniter.com
+ * @since		Version 2.0.2
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * CUBRID Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the active record
+ * class is being used or not.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Drivers
+ * @category	Database
+ * @author		Esen Sagynov
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_cubrid_driver extends CI_DB {
+
+	// Default CUBRID Broker port. Will be used unless user
+	// explicitly specifies another one.
+	const DEFAULT_PORT = 33000;
+
+	var $dbdriver = 'cubrid';
+
+	// The character used for escaping - no need in CUBRID
+	var	$_escape_char = '';
+
+	// clause and character used for LIKE escape sequences - not used in CUBRID
+	var $_like_escape_str = '';
+	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
+	 * used for the count_all() and count_all_results() functions.
+	 */
+	var $_count_string = 'SELECT COUNT(*) AS ';
+	var $_random_keyword = ' RAND()'; // database specific random keyword
+
+	/**
+	 * Non-persistent database connection
+	 *
+	 * @access	private called by the base class
+	 * @return	resource
+	 */
+	function db_connect()
+	{
+		// If no port is defined by the user, use the default value
+		if ($this->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 */

+ 288 - 0
php-codeigniter/system/database/drivers/cubrid/cubrid_forge.php

@@ -0,0 +1,288 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Esen Sagynov
+ * @copyright	Copyright (c) 2008 - 2011, EllisLab, Inc.
+ * @license		http://codeigniter.com/user_guide/license.html
+ * @link		http://codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * CUBRID Forge Class
+ *
+ * @category	Database
+ * @author		Esen Sagynov
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_cubrid_forge extends CI_DB_forge {
+
+	/**
+	 * Create database
+	 *
+	 * @access	private
+	 * @param	string	the database name
+	 * @return	bool
+	 */
+	function _create_database($name)
+	{
+		// CUBRID does not allow to create a database in SQL. The GUI tools
+		// have to be used for this purpose.
+		return FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Drop database
+	 *
+	 * @access	private
+	 * @param	string	the database name
+	 * @return	bool
+	 */
+	function _drop_database($name)
+	{
+		// CUBRID does not allow to drop a database in SQL. The GUI tools
+		// have to be used for this purpose.
+		return FALSE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Process Fields
+	 *
+	 * @access	private
+	 * @param	mixed	the fields
+	 * @return	string
+	 */
+	function _process_fields($fields)
+	{
+		$current_field_count = 0;
+		$sql = '';
+
+		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) . "\"";
+
+				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 */

+ 202 - 0
php-codeigniter/system/database/drivers/cubrid/cubrid_result.php

@@ -0,0 +1,202 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Esen Sagynov
+ * @copyright	Copyright (c) 2008 - 2011, EllisLab, Inc.
+ * @license		http://codeigniter.com/user_guide/license.html
+ * @link		http://codeigniter.com
+ * @since		Version 2.0.2
+ * @filesource
+ */
+
+// --------------------------------------------------------------------
+
+/**
+ * CUBRID Result Class
+ *
+ * This class extends the parent result class: CI_DB_result
+ *
+ * @category	Database
+ * @author		Esen Sagynov
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_cubrid_result extends CI_DB_result {
+
+	/**
+	 * Number of rows in the result set
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function num_rows()
+	{
+		return @cubrid_num_rows($this->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 */

+ 108 - 0
php-codeigniter/system/database/drivers/cubrid/cubrid_utility.php

@@ -0,0 +1,108 @@
+<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @package		CodeIgniter
+ * @author		Esen Sagynov
+ * @copyright	Copyright (c) 2008 - 2011, EllisLab, Inc.
+ * @license		http://codeigniter.com/user_guide/license.html
+ * @link		http://codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * CUBRID Utility Class
+ *
+ * @category	Database
+ * @author		Esen Sagynov
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_cubrid_utility extends CI_DB_utility {
+
+	/**
+	 * List databases
+	 *
+	 * @access	private
+	 * @return	array
+	 */
+	function _list_databases()
+	{
+		// CUBRID does not allow to see the list of all databases on the
+		// server. It is the way its architecture is designed. Every
+		// database is independent and isolated.
+		// For this reason we can return only the name of the currect
+		// connected database.
+		if ($this->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 */

+ 10 - 0
php-codeigniter/system/database/drivers/cubrid/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 10 - 0
php-codeigniter/system/database/drivers/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 10 - 0
php-codeigniter/system/database/drivers/mssql/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 667 - 0
php-codeigniter/system/database/drivers/mssql/mssql_driver.php

@@ -0,0 +1,667 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * MS SQL Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the active record
+ * class is being used or not.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Drivers
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+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
+	 * used for the count_all() and count_all_results() functions.
+	 */
+	var $_count_string = "SELECT COUNT(*) AS ";
+	var $_random_keyword = ' ASC'; // not currently supported
+
+	/**
+	 * Non-persistent database connection
+	 *
+	 * @access	private called by the base class
+	 * @return	resource
+	 */
+	function db_connect()
+	{
+		if ($this->port != '')
+		{
+			$this->hostname .= ','.$this->port;
+		}
+
+		return @mssql_connect($this->hostname, $this->username, $this->password);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Persistent database connection
+	 *
+	 * @access	private called by the base class
+	 * @return	resource
+	 */
+	function db_pconnect()
+	{
+		if ($this->port != '')
+		{
+			$this->hostname .= ','.$this->port;
+		}
+
+		return @mssql_pconnect($this->hostname, $this->username, $this->password);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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()
+	{
+		// Note: The brackets are required in the event that the DB name
+		// contains reserved characters
+		return @mssql_select_db('['.$this->database.']', $this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 @mssql_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)
+	{
+		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;
+
+		$this->simple_query('BEGIN TRAN');
+		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;
+		}
+
+		$this->simple_query('COMMIT TRAN');
+		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;
+		}
+
+		$this->simple_query('ROLLBACK TRAN');
+		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;
+		}
+
+		// Escape single quotes
+		$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
+			);
+		}
+
+		return $str;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Affected Rows
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function affected_rows()
+	{
+		return @mssql_rows_affected($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	* Insert ID
+	*
+	* Returns the last id created in the Identity column.
+	*
+	* @access public
+	* @return integer
+	*/
+	function insert_id()
+	{
+		$ver = self::_parse_major_version($this->version());
+		$sql = ($ver >= 8 ? "SELECT SCOPE_IDENTITY() AS last_id" : "SELECT @@IDENTITY AS last_id");
+		$query = $this->query($sql);
+		$row = $query->row();
+		return $row->last_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()
+	{
+		return "SELECT @@VERSION AS ver";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * "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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 = "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_chr);
+			return FALSE; // not currently supported
+		}
+
+		return $sql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 = '".$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()
+	{
+		return mssql_get_last_message();
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The error message number
+	 *
+	 * @access	private
+	 * @return	integer
+	 */
+	function _error_number()
+	{
+		// Are error numbers supported?
+		return '';
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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).")";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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;
+	}
+
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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)
+	{
+		$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)
+	{
+		@mssql_close($conn_id);
+	}
+
+}
+
+
+
+/* End of file mssql_driver.php */
+/* Location: ./system/database/drivers/mssql/mssql_driver.php */

+ 248 - 0
php-codeigniter/system/database/drivers/mssql/mssql_forge.php

@@ -0,0 +1,248 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * MS SQL Forge Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_mssql_forge extends CI_DB_forge {
+
+	/**
+	 * 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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Drop Table
+	 *
+	 * @access	private
+	 * @return	bool
+	 */
+	function _drop_table($table)
+	{
+		return "DROP TABLE ".$this->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 */

+ 169 - 0
php-codeigniter/system/database/drivers/mssql/mssql_result.php

@@ -0,0 +1,169 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * MS SQL Result Class
+ *
+ * This class extends the parent result class: CI_DB_result
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_mssql_result extends CI_DB_result {
+
+	/**
+	 * Number of rows in the result set
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function num_rows()
+	{
+		return @mssql_num_rows($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Number of fields in the result set
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function num_fields()
+	{
+		return @mssql_num_fields($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch Field Names
+	 *
+	 * Generates an array of column names
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	function list_fields()
+	{
+		$field_names = array();
+		while ($field = mssql_fetch_field($this->result_id))
+		{
+			$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();
+		while ($field = mssql_fetch_field($this->result_id))
+		{
+			$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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Free the result
+	 *
+	 * @return	null
+	 */
+	function free_result()
+	{
+		if (is_resource($this->result_id))
+		{
+			mssql_free_result($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 mssql_data_seek($this->result_id, $n);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - associative array
+	 *
+	 * Returns the result set as an array
+	 *
+	 * @access	private
+	 * @return	array
+	 */
+	function _fetch_assoc()
+	{
+		return mssql_fetch_assoc($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - object
+	 *
+	 * Returns the result set as an object
+	 *
+	 * @access	private
+	 * @return	object
+	 */
+	function _fetch_object()
+	{
+		return mssql_fetch_object($this->result_id);
+	}
+
+}
+
+
+/* End of file mssql_result.php */
+/* Location: ./system/database/drivers/mssql/mssql_result.php */

+ 88 - 0
php-codeigniter/system/database/drivers/mssql/mssql_utility.php

@@ -0,0 +1,88 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * MS SQL Utility Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_mssql_utility extends CI_DB_utility {
+
+	/**
+	 * List databases
+	 *
+	 * @access	private
+	 * @return	bool
+	 */
+	function _list_databases()
+	{
+		return "EXEC sp_helpdb"; // Can also be: EXEC sp_databases
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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)
+	{
+		return FALSE; // Is this supported in MS SQL?
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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)
+	{
+		return FALSE; // Is this supported in MS SQL?
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * MSSQL 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 mssql_utility.php */
+/* Location: ./system/database/drivers/mssql/mssql_utility.php */

+ 10 - 0
php-codeigniter/system/database/drivers/mysql/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 779 - 0
php-codeigniter/system/database/drivers/mysql/mysql_driver.php

@@ -0,0 +1,779 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * MySQL Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the active record
+ * class is being used or not.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Drivers
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_mysql_driver extends CI_DB {
+
+	var $dbdriver = 'mysql';
+
+	// The character used for escaping
+	var	$_escape_char = '`';
+
+	// clause and character used for LIKE escape sequences - not used in MySQL
+	var $_like_escape_str = '';
+	var $_like_escape_chr = '';
+
+	/**
+	 * 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
+	 * used for the count_all() and count_all_results() functions.
+	 */
+	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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Persistent database connection
+	 *
+	 * @access	private called by the base class
+	 * @return	resource
+	 */
+	function db_pconnect()
+	{
+		if ($this->port != '')
+		{
+			$this->hostname .= ':'.$this->port;
+		}
+
+		return @mysql_pconnect($this->hostname, $this->username, $this->password);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 (mysql_ping($this->conn_id) === FALSE)
+		{
+			$this->conn_id = FALSE;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Select the database
+	 *
+	 * @access	private called by the base class
+	 * @return	resource
+	 */
+	function db_select()
+	{
+		return @mysql_select_db($this->database, $this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set client character set
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	resource
+	 */
+	function db_set_charset($charset, $collation)
+	{
+		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
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function _version()
+	{
+		return "SELECT version() AS ver";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 @mysql_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)
+	{
+		// "DELETE FROM TABLE" returns 0 affected rows This hack modifies
+		// the query so that it returns the number of affected rows
+		if ($this->delete_hack === TRUE)
+		{
+			if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql))
+			{
+				$sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $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;
+
+		$this->simple_query('SET AUTOCOMMIT=0');
+		$this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
+		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;
+		}
+
+		$this->simple_query('COMMIT');
+		$this->simple_query('SET AUTOCOMMIT=1');
+		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;
+		}
+
+		$this->simple_query('ROLLBACK');
+		$this->simple_query('SET AUTOCOMMIT=1');
+		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('mysql_real_escape_string') AND is_resource($this->conn_id))
+		{
+			$str = mysql_real_escape_string($str, $this->conn_id);
+		}
+		elseif (function_exists('mysql_escape_string'))
+		{
+			$str = mysql_escape_string($str);
+		}
+		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 @mysql_affected_rows($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Insert ID
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function insert_id()
+	{
+		return @mysql_insert_id($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * "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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 "DESCRIBE ".$table;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The error message string
+	 *
+	 * @access	private
+	 * @return	string
+	 */
+	function _error_message()
+	{
+		return mysql_error($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The error message number
+	 *
+	 * @access	private
+	 * @return	integer
+	 */
+	function _error_number()
+	{
+		return mysql_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[] = $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)
+	{
+		@mysql_close($conn_id);
+	}
+
+}
+
+
+/* End of file mysql_driver.php */
+/* Location: ./system/database/drivers/mysql/mysql_driver.php */

+ 273 - 0
php-codeigniter/system/database/drivers/mysql/mysql_forge.php

@@ -0,0 +1,273 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * MySQL Forge Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_mysql_forge extends CI_DB_forge {
+
+	/**
+	 * 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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Process Fields
+	 *
+	 * @access	private
+	 * @param	mixed	the fields
+	 * @return	string
+	 */
+	function _process_fields($fields)
+	{
+		$current_field_count = 0;
+		$sql = '';
+
+		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);
+
+				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('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 .= ',';
+			}
+		}
+
+		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 ';
+		}
+
+		$sql .= $this->db->_escape_identifiers($table)." (";
+
+		$sql .= $this->_process_fields($fields);
+
+		if (count($primary_keys) > 0)
+		{
+			$key_name = $this->db->_protect_identifiers(implode('_', $primary_keys));
+			$primary_keys = $this->db->_protect_identifiers($primary_keys);
+			$sql .= ",\n\tPRIMARY KEY ".$key_name." (" . 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) DEFAULT CHARACTER SET {$this->db->char_set} COLLATE {$this->db->dbcollat};";
+
+		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 = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
+		return $sql;
+	}
+
+}
+
+/* End of file mysql_forge.php */
+/* Location: ./system/database/drivers/mysql/mysql_forge.php */

+ 174 - 0
php-codeigniter/system/database/drivers/mysql/mysql_result.php

@@ -0,0 +1,174 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// --------------------------------------------------------------------
+
+/**
+ * MySQL Result Class
+ *
+ * This class extends the parent result class: CI_DB_result
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_mysql_result extends CI_DB_result {
+
+	/**
+	 * Number of rows in the result set
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function num_rows()
+	{
+		return @mysql_num_rows($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Number of fields in the result set
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function num_fields()
+	{
+		return @mysql_num_fields($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch Field Names
+	 *
+	 * Generates an array of column names
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	function list_fields()
+	{
+		$field_names = array();
+		while ($field = mysql_fetch_field($this->result_id))
+		{
+			$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();
+		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->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))
+		{
+			mysql_free_result($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 mysql_data_seek($this->result_id, $n);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - associative array
+	 *
+	 * Returns the result set as an array
+	 *
+	 * @access	private
+	 * @return	array
+	 */
+	function _fetch_assoc()
+	{
+		return mysql_fetch_assoc($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - object
+	 *
+	 * Returns the result set as an object
+	 *
+	 * @access	private
+	 * @return	object
+	 */
+	function _fetch_object()
+	{
+		return mysql_fetch_object($this->result_id);
+	}
+
+}
+
+
+/* End of file mysql_result.php */
+/* Location: ./system/database/drivers/mysql/mysql_result.php */

+ 210 - 0
php-codeigniter/system/database/drivers/mysql/mysql_utility.php

@@ -0,0 +1,210 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * MySQL Utility Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_mysql_utility extends CI_DB_utility {
+
+	/**
+	 * List databases
+	 *
+	 * @access	private
+	 * @return	bool
+	 */
+	function _list_databases()
+	{
+		return "SHOW DATABASES";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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)
+	{
+		return "OPTIMIZE TABLE ".$this->db->_escape_identifiers($table);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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)
+	{
+		return "REPAIR TABLE ".$this->db->_escape_identifiers($table);
+	}
+
+	// --------------------------------------------------------------------
+	/**
+	 * MySQL Export
+	 *
+	 * @access	private
+	 * @param	array	Preferences
+	 * @return	mixed
+	 */
+	function _backup($params = array())
+	{
+		if (count($params) == 0)
+		{
+			return FALSE;
+		}
+
+		// Extract the prefs for simplicity
+		extract($params);
+
+		// Build the output
+		$output = '';
+		foreach ((array)$tables as $table)
+		{
+			// Is the table in the "ignore" list?
+			if (in_array($table, (array)$ignore, TRUE))
+			{
+				continue;
+			}
+
+			// Get the table schema
+			$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)
+			{
+				$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)
+			{
+				continue;
+			}
+
+			// 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();
+			while ($field = mysql_fetch_field($query->result_id))
+			{
+				// 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'),
+										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)
+				{
+					// Is the value NULL?
+					if ($v === NULL)
+					{
+						$val_str .= 'NULL';
+					}
+					else
+					{
+						// Escape the data if it's not an integer
+						if ($is_int[$i] == FALSE)
+						{
+							$val_str .= $this->db->escape($v);
+						}
+						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;
+	}
+}
+
+/* End of file mysql_utility.php */
+/* Location: ./system/database/drivers/mysql/mysql_utility.php */

+ 10 - 0
php-codeigniter/system/database/drivers/mysqli/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 776 - 0
php-codeigniter/system/database/drivers/mysqli/mysqli_driver.php

@@ -0,0 +1,776 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * MySQLi Database Adapter Class - MySQLi only works with PHP 5
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the active record
+ * class is being used or not.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Drivers
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_mysqli_driver extends CI_DB {
+
+	var $dbdriver = 'mysqli';
+
+	// The character used for escaping
+	var $_escape_char = '`';
+
+	// clause and character used for LIKE escape sequences - not used in MySQL
+	var $_like_escape_str = '';
+	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
+	 * used for the count_all() and count_all_results() functions.
+	 */
+	var $_count_string = "SELECT COUNT(*) AS ";
+	var $_random_keyword = ' RAND()'; // database specific random keyword
+
+	/**
+	 * 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;
+	
+	// --------------------------------------------------------------------
+
+	/**
+	 * Non-persistent database connection
+	 *
+	 * @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);
+		}
+		else
+		{
+			return @mysqli_connect($this->hostname, $this->username, $this->password, $this->database);
+		}
+
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Persistent database connection
+	 *
+	 * @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 (mysqli_ping($this->conn_id) === FALSE)
+		{
+			$this->conn_id = FALSE;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Select the database
+	 *
+	 * @access	private called by the base class
+	 * @return	resource
+	 */
+	function db_select()
+	{
+		return @mysqli_select_db($this->conn_id, $this->database);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set client character set
+	 *
+	 * @access	private
+	 * @param	string
+	 * @param	string
+	 * @return	resource
+	 */
+	function _db_set_charset($charset, $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
+	 *
+	 * @access	public
+	 * @return	string
+	 */
+	function _version()
+	{
+		return "SELECT version() AS ver";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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);
+		$result = @mysqli_query($this->conn_id, $sql);
+		return $result;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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)
+	{
+		// "DELETE FROM TABLE" returns 0 affected rows This hack modifies
+		// the query so that it returns the number of affected rows
+		if ($this->delete_hack === TRUE)
+		{
+			if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $sql))
+			{
+				$sql = preg_replace("/^\s*DELETE\s+FROM\s+(\S+)\s*$/", "DELETE FROM \\1 WHERE 1=1", $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;
+
+		$this->simple_query('SET AUTOCOMMIT=0');
+		$this->simple_query('START TRANSACTION'); // can also be BEGIN or BEGIN WORK
+		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;
+		}
+
+		$this->simple_query('COMMIT');
+		$this->simple_query('SET AUTOCOMMIT=1');
+		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;
+		}
+
+		$this->simple_query('ROLLBACK');
+		$this->simple_query('SET AUTOCOMMIT=1');
+		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('mysqli_real_escape_string') AND is_object($this->conn_id))
+		{
+			$str = mysqli_real_escape_string($this->conn_id, $str);
+		}
+		elseif (function_exists('mysql_escape_string'))
+		{
+			$str = mysql_escape_string($str);
+		}
+		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 @mysqli_affected_rows($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Insert ID
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function insert_id()
+	{
+		return @mysqli_insert_id($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * "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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 "DESCRIBE ".$table;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The error message string
+	 *
+	 * @access	private
+	 * @return	string
+	 */
+	function _error_message()
+	{
+		return mysqli_error($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The error message number
+	 *
+	 * @access	private
+	 * @return	integer
+	 */
+	function _error_number()
+	{
+		return mysqli_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).")";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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).")";
+	}
+	
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 "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)
+	{
+		$sql .= "LIMIT ".$limit;
+
+		if ($offset > 0)
+		{
+			$sql .= " OFFSET ".$offset;
+		}
+
+		return $sql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Close DB Connection
+	 *
+	 * @access	public
+	 * @param	resource
+	 * @return	void
+	 */
+	function _close($conn_id)
+	{
+		@mysqli_close($conn_id);
+	}
+
+
+}
+
+
+/* End of file mysqli_driver.php */
+/* Location: ./system/database/drivers/mysqli/mysqli_driver.php */

+ 258 - 0
php-codeigniter/system/database/drivers/mysqli/mysqli_forge.php

@@ -0,0 +1,258 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * MySQLi Forge Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_mysqli_forge extends CI_DB_forge {
+
+	/**
+	 * 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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Process Fields
+	 *
+	 * @access	private
+	 * @param	mixed	the fields
+	 * @return	string
+	 */
+	function _process_fields($fields)
+	{
+		$current_field_count = 0;
+		$sql = '';
+
+		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);
+
+				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) && $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 .= ',';
+			}
+		}
+
+		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 ';
+		}
+
+		$sql .= $this->db->_escape_identifiers($table)." (";
+
+		$sql .= $this->_process_fields($fields);
+
+		if (count($primary_keys) > 0)
+		{
+			$key_name = $this->db->_protect_identifiers(implode('_', $primary_keys));
+			$primary_keys = $this->db->_protect_identifiers($primary_keys);
+			$sql .= ",\n\tPRIMARY KEY ".$key_name." (" . 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) DEFAULT CHARACTER SET {$this->db->char_set} COLLATE {$this->db->dbcollat};";
+
+		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 = 'ALTER TABLE '.$this->db->_protect_identifiers($table_name)." RENAME TO ".$this->db->_protect_identifiers($new_table_name);
+		return $sql;
+	}
+
+}
+
+/* End of file mysqli_forge.php */
+/* Location: ./system/database/drivers/mysqli/mysqli_forge.php */

+ 174 - 0
php-codeigniter/system/database/drivers/mysqli/mysqli_result.php

@@ -0,0 +1,174 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * MySQLi Result Class
+ *
+ * This class extends the parent result class: CI_DB_result
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_mysqli_result extends CI_DB_result {
+
+	/**
+	 * Number of rows in the result set
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function num_rows()
+	{
+		return @mysqli_num_rows($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Number of fields in the result set
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function num_fields()
+	{
+		return @mysqli_num_fields($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch Field Names
+	 *
+	 * Generates an array of column names
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	function list_fields()
+	{
+		$field_names = array();
+		while ($field = mysqli_fetch_field($this->result_id))
+		{
+			$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();
+		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))
+		{
+			mysqli_free_result($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 mysqli_data_seek($this->result_id, $n);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - associative array
+	 *
+	 * Returns the result set as an array
+	 *
+	 * @access	private
+	 * @return	array
+	 */
+	function _fetch_assoc()
+	{
+		return mysqli_fetch_assoc($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - object
+	 *
+	 * Returns the result set as an object
+	 *
+	 * @access	private
+	 * @return	object
+	 */
+	function _fetch_object()
+	{
+		return mysqli_fetch_object($this->result_id);
+	}
+
+}
+
+
+/* End of file mysqli_result.php */
+/* Location: ./system/database/drivers/mysqli/mysqli_result.php */

+ 87 - 0
php-codeigniter/system/database/drivers/mysqli/mysqli_utility.php

@@ -0,0 +1,87 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * MySQLi Utility Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_mysqli_utility extends CI_DB_utility {
+
+	/**
+	 * List databases
+	 *
+	 * @access	private
+	 * @return	bool
+	 */
+	function _list_databases()
+	{
+		return "SHOW DATABASES";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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)
+	{
+		return "OPTIMIZE TABLE ".$this->db->_escape_identifiers($table);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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)
+	{
+		return "REPAIR TABLE ".$this->db->_escape_identifiers($table);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * MySQLi 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 mysqli_utility.php */
+/* Location: ./system/database/drivers/mysqli/mysqli_utility.php */

+ 10 - 0
php-codeigniter/system/database/drivers/oci8/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 808 - 0
php-codeigniter/system/database/drivers/oci8/oci8_driver.php

@@ -0,0 +1,808 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * oci8 Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the active record
+ * class is being used or not.
+ *
+ * @package		CodeIgniter
+ * @subpackage  Drivers
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+
+/**
+ * oci8 Database Adapter Class
+ *
+ * This is a modification of the DB_driver class to
+ * permit access to oracle databases
+ *
+ * @author	  Kelly McArdle
+ *
+ */
+
+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
+	 * used for the count_all() and count_all_results() functions.
+	 */
+	var $_count_string = "SELECT COUNT(1) AS ";
+	var $_random_keyword = ' ASC'; // not currently supported
+
+	// Set "auto commit" by default
+	var $_commit = OCI_COMMIT_ON_SUCCESS;
+
+	// need to track statement id and cursor id
+	var $stmt_id;
+	var $curs_id;
+
+	// if we use a limit, we will add a field that will
+	// throw off num_fields later
+	var $limit_used;
+
+	/**
+	 * Non-persistent database connection
+	 *
+	 * @access  private called by the base class
+	 * @return  resource
+	 */
+	public function db_connect()
+	{
+		return @oci_connect($this->username, $this->password, $this->hostname, $this->char_set);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Persistent database connection
+	 *
+	 * @access  private called by the base class
+	 * @return  resource
+	 */
+	public function db_pconnect()
+	{
+		return @oci_pconnect($this->username, $this->password, $this->hostname, $this->char_set);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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
+	 */
+	public function reconnect()
+	{
+		// not implemented in oracle
+		return;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Select the database
+	 *
+	 * @access  private called by the base class
+	 * @return  resource
+	 */
+	public function db_select()
+	{
+		// Not in Oracle - schemas are actually usernames
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set client character set
+	 *
+	 * @access	public
+	 * @param	string
+	 * @param	string
+	 * @return	resource
+	 */
+	public function db_set_charset($charset, $collation)
+	{
+		// @todo - add support if needed
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Version number query string
+	 *
+	 * @access  protected
+	 * @return  string
+	 */
+	protected function _version()
+	{
+		return oci_server_version($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Execute the query
+	 *
+	 * @access  protected  called by the base class
+	 * @param   string  an SQL query
+	 * @return  resource
+	 */
+	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);
+		oci_set_prefetch($this->stmt_id, 1000);
+		return @oci_execute($this->stmt_id, $this->_commit);
+	}
+
+	/**
+	 * Generate a statement ID
+	 *
+	 * @access  private
+	 * @param   string  an SQL query
+	 * @return  none
+	 */
+	private function _set_stmt_id($sql)
+	{
+		if ( ! is_resource($this->stmt_id))
+		{
+			$this->stmt_id = oci_parse($this->conn_id, $this->_prep_query($sql));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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
+	 */
+	private function _prep_query($sql)
+	{
+		return $sql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * getCursor.  Returns a cursor from the datbase
+	 *
+	 * @access  public
+	 * @return  cursor id
+	 */
+	public function get_cursor()
+	{
+		$this->curs_id = oci_new_cursor($this->conn_id);
+		return $this->curs_id;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Stored Procedure.  Executes a stored procedure
+	 *
+	 * @access  public
+	 * @param   package	 package stored procedure is in
+	 * @param   procedure   stored procedure to execute
+	 * @param   params	  array of parameters
+	 * @return  array
+	 *
+	 * params array keys
+	 *
+	 * KEY	  OPTIONAL	NOTES
+	 * name		no		the name of the parameter should be in :<param_name> format
+	 * value	no		the value of the parameter.  If this is an OUT or IN OUT parameter,
+	 *					this should be a reference to a variable
+	 * type		yes		the type of the parameter
+	 * length	yes		the max size of the parameter
+	 */
+	public function stored_procedure($package, $procedure, $params)
+	{
+		if ($package == '' OR $procedure == '' OR ! is_array($params))
+		{
+			if ($this->db_debug)
+			{
+				log_message('error', 'Invalid query: '.$package.'.'.$procedure);
+				return $this->display_error('db_invalid_query');
+			}
+			return FALSE;
+		}
+
+		// build the query string
+		$sql = "begin $package.$procedure(";
+
+		$have_cursor = FALSE;
+		foreach ($params as $param)
+		{
+			$sql .= $param['name'] . ",";
+
+			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);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Bind parameters
+	 *
+	 * @access  private
+	 * @return  none
+	 */
+	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)
+			{
+				if ( ! isset($param[$val]))
+				{
+					$param[$val] = '';
+				}
+			}
+
+			oci_bind_by_name($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']);
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Begin Transaction
+	 *
+	 * @access	public
+	 * @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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Commit Transaction
+	 *
+	 * @access	public
+	 * @return	bool
+	 */
+	public 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 = oci_commit($this->conn_id);
+		$this->_commit = OCI_COMMIT_ON_SUCCESS;
+		return $ret;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Rollback Transaction
+	 *
+	 * @access	public
+	 * @return	bool
+	 */
+	public 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 = oci_rollback($this->conn_id);
+		$this->_commit = OCI_COMMIT_ON_SUCCESS;
+		return $ret;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Escape String
+	 *
+	 * @access  public
+	 * @param   string
+	 * @param	bool	whether or not the string will be used in a LIKE condition
+	 * @return  string
+	 */
+	public function escape_str($str, $like = FALSE)
+	{
+		if (is_array($str))
+		{
+			foreach ($str as $key => $val)
+			{
+				$str[$key] = $this->escape_str($val, $like);
+			}
+
+			return $str;
+		}
+
+		$str = 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);
+		}
+
+		return $str;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Affected Rows
+	 *
+	 * @access  public
+	 * @return  integer
+	 */
+	public function affected_rows()
+	{
+		return @oci_num_rows($this->stmt_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Insert ID
+	 *
+	 * @access  public
+	 * @return  integer
+	 */
+	public function insert_id()
+	{
+		// not supported in oracle
+		return $this->display_error('db_unsupported_function');
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * "Count All" query
+	 *
+	 * Generates a platform-specific query string that counts all records in
+	 * the specified database
+	 *
+	 * @access  public
+	 * @param   string
+	 * @return  string
+	 */
+	public 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 == FALSE)
+		{
+			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	protected
+	 * @param	boolean
+	 * @return	string
+	 */
+	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_chr);
+		}
+
+		return $sql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Show column query
+	 *
+	 * Generates a platform-specific query string so that the column names can be fetched
+	 *
+	 * @access  protected
+	 * @param   string  the table name
+	 * @return  string
+	 */
+	protected function _list_columns($table = '')
+	{
+		return "SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = '$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
+	 */
+	protected function _field_data($table)
+	{
+		return "SELECT * FROM ".$table." where rownum = 1";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The error message string
+	 *
+	 * @access  protected
+	 * @return  string
+	 */
+	protected function _error_message()
+	{
+		// 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'];
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The error message number
+	 *
+	 * @access  protected
+	 * @return  integer
+	 */
+	protected function _error_number()
+	{
+		// Same as _error_message()
+		$error = is_resource($this->conn_id) ? oci_error($this->conn_id) : oci_error();
+		return $error['code'];
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Escape the SQL Identifiers
+	 *
+	 * This function escapes column and table names
+	 *
+	 * @access	protected
+	 * @param	string
+	 * @return	string
+	 */
+	protected 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	protected
+	 * @param	type
+	 * @return	type
+	 */
+	protected 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
+	 */
+	protected 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      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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Update statement
+	 *
+	 * Generates a platform-specific update string from the supplied data
+	 *
+	 * @access	protected
+	 * @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
+	 */
+	protected 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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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	protected
+	 * @param	string	the table name
+	 * @return	string
+	 */
+	protected function _truncate($table)
+	{
+		return "TRUNCATE TABLE ".$table;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Delete statement
+	 *
+	 * Generates a platform-specific delete string from the supplied data
+	 *
+	 * @access	protected
+	 * @param	string	the table name
+	 * @param	array	the where clause
+	 * @param	string	the limit clause
+	 * @return	string
+	 */
+	protected 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  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
+	 */
+	protected function _limit($sql, $limit, $offset)
+	{
+		$limit = $offset + $limit;
+		$newsql = "SELECT * FROM (select inner_query.*, rownum rnum FROM ($sql) inner_query WHERE rownum < $limit)";
+
+		if ($offset != 0)
+		{
+			$newsql .= " WHERE rnum >= $offset";
+		}
+
+		// remember that we used limits
+		$this->limit_used = TRUE;
+
+		return $newsql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Close DB Connection
+	 *
+	 * @access  protected
+	 * @param   resource
+	 * @return  void
+	 */
+	protected function _close($conn_id)
+	{
+		@oci_close($conn_id);
+	}
+
+
+}
+
+
+
+/* End of file oci8_driver.php */
+/* Location: ./system/database/drivers/oci8/oci8_driver.php */

+ 248 - 0
php-codeigniter/system/database/drivers/oci8/oci8_forge.php

@@ -0,0 +1,248 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Oracle Forge Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_oci8_forge extends CI_DB_forge {
+
+	/**
+	 * 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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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\tUNIQUE COLUMNS (" . implode(', ', $key) . ")";
+			}
+		}
+
+		$sql .= "\n)";
+
+		return $sql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Drop Table
+	 *
+	 * @access	private
+	 * @return	bool
+	 */
+	function _drop_table($table)
+	{
+		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 oci8_forge.php */
+/* Location: ./system/database/drivers/oci8/oci8_forge.php */

+ 217 - 0
php-codeigniter/system/database/drivers/oci8/oci8_result.php

@@ -0,0 +1,217 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * oci8 Result Class
+ *
+ * This class extends the parent result class: CI_DB_result
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_oci8_result extends CI_DB_result {
+
+	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.
+	 *
+	 * @return  integer
+	 */
+	public function num_rows()
+	{
+		if ($this->num_rows === 0 && count($this->result_array()) > 0)
+		{
+			$this->num_rows = count($this->result_array());
+			@oci_execute($this->stmt_id);
+
+			if ($this->curs_id)
+			{
+				@oci_execute($this->curs_id);
+			}
+		}
+
+		return $this->num_rows;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Number of fields in the result set
+	 *
+	 * @access  public
+	 * @return  integer
+	 */
+	public function num_fields()
+	{
+		$count = @oci_num_fields($this->stmt_id);
+
+		// if we used a limit we subtract it
+		if ($this->limit_used)
+		{
+			$count = $count - 1;
+		}
+
+		return $count;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch Field Names
+	 *
+	 * Generates an array of column names
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	public function list_fields()
+	{
+		$field_names = array();
+		for ($c = 1, $fieldCount = $this->num_fields(); $c <= $fieldCount; $c++)
+		{
+			$field_names[] = oci_field_name($this->stmt_id, $c);
+		}
+		return $field_names;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Field data
+	 *
+	 * Generates an array of objects containing field meta-data
+	 *
+	 * @access  public
+	 * @return  array
+	 */
+	public function field_data()
+	{
+		$retval = array();
+		for ($c = 1, $fieldCount = $this->num_fields(); $c <= $fieldCount; $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;
+		}
+
+		return $retval;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Free the result
+	 *
+	 * @return	null
+	 */
+	public function free_result()
+	{
+		if (is_resource($this->result_id))
+		{
+			oci_free_statement($this->result_id);
+			$this->result_id = FALSE;
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - associative array
+	 *
+	 * Returns the result set as an array
+	 *
+	 * @access  protected
+	 * @return  array
+	 */
+	protected function _fetch_assoc()
+	{
+		$id = ($this->curs_id) ? $this->curs_id : $this->stmt_id;
+		return oci_fetch_assoc($id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - object
+	 *
+	 * Returns the result set as an object
+	 *
+	 * @access  protected
+	 * @return  object
+	 */
+	protected function _fetch_object()
+	{
+		$id = ($this->curs_id) ? $this->curs_id : $this->stmt_id;
+		return @oci_fetch_object($id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Query result.  "array" version.
+	 *
+	 * @access  public
+	 * @return  array
+	 */
+	public function result_array()
+	{
+		if (count($this->result_array) > 0)
+		{
+			return $this->result_array;
+		}
+
+		$row = NULL;
+		while ($row = $this->_fetch_assoc())
+		{
+			$this->result_array[] = $row;
+		}
+
+		return $this->result_array;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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	protected
+	 * @return	array
+	 */
+	protected function _data_seek($n = 0)
+	{
+		return FALSE; // Not needed
+	}
+
+}
+
+
+/* End of file oci8_result.php */
+/* Location: ./system/database/drivers/oci8/oci8_result.php */

+ 87 - 0
php-codeigniter/system/database/drivers/oci8/oci8_utility.php

@@ -0,0 +1,87 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * Oracle Utility Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_oci8_utility extends CI_DB_utility {
+
+	/**
+	 * List databases
+	 *
+	 * @access	private
+	 * @return	bool
+	 */
+	function _list_databases()
+	{
+		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)
+	{
+		return FALSE; // Is this supported in Oracle?
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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)
+	{
+		return FALSE; // Is this supported in Oracle?
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Oracle 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 oci8_utility.php */
+/* Location: ./system/database/drivers/oci8/oci8_utility.php */

+ 10 - 0
php-codeigniter/system/database/drivers/odbc/index.html

@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>

+ 637 - 0
php-codeigniter/system/database/drivers/odbc/odbc_driver.php

@@ -0,0 +1,637 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * ODBC Database Adapter Class
+ *
+ * Note: _DB is an extender class that the app controller
+ * creates dynamically based on whether the active record
+ * class is being used or not.
+ *
+ * @package		CodeIgniter
+ * @subpackage	Drivers
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+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
+	 * used for the count_all() and count_all_results() functions.
+	 */
+	var $_count_string = "SELECT COUNT(*) AS ";
+	var $_random_keyword;
+
+
+	function __construct($params)
+	{
+		parent::__construct($params);
+
+		$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()
+	{
+		return @odbc_connect($this->hostname, $this->username, $this->password);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Persistent database connection
+	 *
+	 * @access	private called by the base class
+	 * @return	resource
+	 */
+	function db_pconnect()
+	{
+		return @odbc_pconnect($this->hostname, $this->username, $this->password);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 odbc
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Select the database
+	 *
+	 * @access	private called by the base class
+	 * @return	resource
+	 */
+	function db_select()
+	{
+		// Not needed for ODBC
+		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 "SELECT version() AS ver";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 @odbc_exec($this->conn_id, $sql);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 odbc_autocommit($this->conn_id, FALSE);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 = odbc_commit($this->conn_id);
+		odbc_autocommit($this->conn_id, TRUE);
+		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 = odbc_rollback($this->conn_id);
+		odbc_autocommit($this->conn_id, TRUE);
+		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;
+		}
+
+		// ODBC doesn't require escaping
+		$str = 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);
+		}
+
+		return $str;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Affected Rows
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function affected_rows()
+	{
+		return @odbc_num_rows($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Insert ID
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function insert_id()
+	{
+		return @odbc_insert_id($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * "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()
+	{
+		return odbc_errormsg($this->conn_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * The error message number
+	 *
+	 * @access	private
+	 * @return	integer
+	 */
+	function _error_number()
+	{
+		return odbc_error($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).")";
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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;
+	}
+
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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)
+	{
+		// Does ODBC doesn't use the LIMIT clause?
+		return $sql;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Close DB Connection
+	 *
+	 * @access	public
+	 * @param	resource
+	 * @return	void
+	 */
+	function _close($conn_id)
+	{
+		@odbc_close($conn_id);
+	}
+
+
+}
+
+
+
+/* End of file odbc_driver.php */
+/* Location: ./system/database/drivers/odbc/odbc_driver.php */

+ 266 - 0
php-codeigniter/system/database/drivers/odbc/odbc_forge.php

@@ -0,0 +1,266 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * ODBC Forge Class
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/database/
+ */
+class CI_DB_odbc_forge extends CI_DB_forge {
+
+	/**
+	 * 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;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * 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 ODBC 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 odbc_forge.php */
+/* Location: ./system/database/drivers/odbc/odbc_forge.php */

+ 228 - 0
php-codeigniter/system/database/drivers/odbc/odbc_result.php

@@ -0,0 +1,228 @@
+<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.1.6 or newer
+ *
+ * @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
+ * @filesource
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * ODBC Result Class
+ *
+ * This class extends the parent result class: CI_DB_result
+ *
+ * @category	Database
+ * @author		ExpressionEngine Dev Team
+ * @link		http://codeigniter.com/user_guide/database/
+ */
+class CI_DB_odbc_result extends CI_DB_result {
+
+	/**
+	 * Number of rows in the result set
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function num_rows()
+	{
+		return @odbc_num_rows($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Number of fields in the result set
+	 *
+	 * @access	public
+	 * @return	integer
+	 */
+	function num_fields()
+	{
+		return @odbc_num_fields($this->result_id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Fetch Field Names
+	 *
+	 * Generates an array of column names
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	function list_fields()
+	{
+		$field_names = array();
+		for ($i = 0; $i < $this->num_fields(); $i++)
+		{
+			$field_names[]	= odbc_field_name($this->result_id, $i);
+		}
+
+		return $field_names;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Field data
+	 *
+	 * Generates an array of objects containing field meta-data
+	 *
+	 * @access	public
+	 * @return	array
+	 */
+	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->max_length	= odbc_field_len($this->result_id, $i);
+			$F->primary_key = 0;
+			$F->default		= '';
+
+			$retval[] = $F;
+		}
+
+		return $retval;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Free the result
+	 *
+	 * @return	null
+	 */
+	function free_result()
+	{
+		if (is_resource($this->result_id))
+		{
+			odbc_free_result($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()
+	{
+		if (function_exists('odbc_fetch_object'))
+		{
+			return odbc_fetch_array($this->result_id);
+		}
+		else
+		{
+			return $this->_odbc_fetch_array($this->result_id);
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Result - object
+	 *
+	 * Returns the result set as an object
+	 *
+	 * @access	private
+	 * @return	object
+	 */
+	function _fetch_object()
+	{
+		if (function_exists('odbc_fetch_object'))
+		{
+			return odbc_fetch_object($this->result_id);
+		}
+		else
+		{
+			return $this->_odbc_fetch_object($this->result_id);
+		}
+	}
+
+
+	/**
+	 * Result - object
+	 *
+	 * subsititutes the odbc_fetch_object function when
+	 * not available (odbc_fetch_object requires unixODBC)
+	 *
+	 * @access	private
+	 * @return	object
+	 */
+	function _odbc_fetch_object(& $odbc_result) {
+		$rs = array();
+		$rs_obj = FALSE;
+		if (odbc_fetch_into($odbc_result, $rs)) {
+			foreach ($rs as $k=>$v) {
+				$field_name= odbc_field_name($odbc_result, $k+1);
+				$rs_obj->$field_name = $v;
+			}
+		}
+		return $rs_obj;
+	}
+
+
+	/**
+	 * Result - array
+	 *
+	 * subsititutes the odbc_fetch_array function when
+	 * not available (odbc_fetch_array requires unixODBC)
+	 *
+	 * @access	private
+	 * @return	array
+	 */
+	function _odbc_fetch_array(& $odbc_result) {
+		$rs = array();
+		$rs_assoc = FALSE;
+		if (odbc_fetch_into($odbc_result, $rs)) {
+			$rs_assoc=array();
+			foreach ($rs as $k=>$v) {
+				$field_name= odbc_field_name($odbc_result, $k+1);
+				$rs_assoc[$field_name] = $v;
+			}
+		}
+		return $rs_assoc;
+	}
+
+}
+
+
+/* End of file odbc_result.php */
+/* Location: ./system/database/drivers/odbc/odbc_result.php */

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