diff options
400 files changed, 31735 insertions, 15739 deletions
diff --git a/.gitignore b/.gitignore index 11fb6d67c..a035c2b27 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ application/logs/* user_guide_src/build/* user_guide_src/cilexer/build/* user_guide_src/cilexer/dist/* -user_guide_src/cilexer/pycilexer.egg-info/*
\ No newline at end of file +user_guide_src/cilexer/pycilexer.egg-info/* +/vendor/
\ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 84029b964..a1635eaa8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,23 +3,25 @@ language: php php: - 5.3 - 5.4 - + env: - DB=mysql - DB=pgsql - DB=sqlite + - DB=pdo/mysql + - DB=pdo/pgsql + - DB=pdo/sqlite before_script: - - pyrus channel-discover pear.php-tools.net - - pyrus install http://pear.php-tools.net/get/vfsStream-0.11.2.tgz - - phpenv rehash - - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS ci_test;' -U postgres; fi" - - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'create database ci_test;' -U postgres; fi" - - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'create database IF NOT EXISTS ci_test;'; fi" + - curl -s http://getcomposer.org/installer | php + - php composer.phar install + - sh -c "if [ '$DB' = 'pgsql' ] || [ '$DB' = 'pdo/pgsql' ]; then psql -c 'DROP DATABASE IF EXISTS ci_test;' -U postgres; fi" + - sh -c "if [ '$DB' = 'pgsql' ] || [ '$DB' = 'pdo/pgsql' ]; then psql -c 'create database ci_test;' -U postgres; fi" + - sh -c "if [ '$DB' = 'mysql' ] || [ '$DB' = 'pdo/mysql' ]; then mysql -e 'create database IF NOT EXISTS ci_test;'; fi" -script: phpunit --configuration tests/travis/$DB.phpunit.xml +script: phpunit --coverage-text --configuration tests/travis/$DB.phpunit.xml branches: only: - develop - - master
\ No newline at end of file + - /^feature\/.+$/
\ No newline at end of file diff --git a/DCO.txt b/DCO.txt new file mode 100644 index 000000000..a404c0d38 --- /dev/null +++ b/DCO.txt @@ -0,0 +1,25 @@ +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(1) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(2) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(3) The contribution was provided directly to me by some other + person who certified (1), (2) or (3) and I have not modified + it. + +(4) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/application/.htaccess b/application/.htaccess index 14249c50b..6c63ed4c4 100644 --- a/application/.htaccess +++ b/application/.htaccess @@ -1 +1,6 @@ -Deny from all
\ No newline at end of file +<IfModule authz_core_module> + Require all denied +</IfModule> +<IfModule !authz_core_module> + Deny from all +</IfModule>
\ No newline at end of file diff --git a/application/cache/.htaccess b/application/cache/.htaccess index 3418e55a6..6c63ed4c4 100644 --- a/application/cache/.htaccess +++ b/application/cache/.htaccess @@ -1 +1,6 @@ -deny from all
\ No newline at end of file +<IfModule authz_core_module> + Require all denied +</IfModule> +<IfModule !authz_core_module> + Deny from all +</IfModule>
\ No newline at end of file diff --git a/application/config/autoload.php b/application/config/autoload.php index b3e63cbf6..ff153fb48 100644 --- a/application/config/autoload.php +++ b/application/config/autoload.php @@ -46,10 +46,11 @@ | | 1. Packages | 2. Libraries -| 3. Helper files -| 4. Custom config files -| 5. Language files -| 6. Models +| 3. Drivers +| 4. Helper files +| 5. Custom config files +| 6. Language files +| 7. Models | */ @@ -75,7 +76,7 @@ $autoload['packages'] = array(); | | Prototype: | -| $autoload['libraries'] = array('database', 'session', 'xmlrpc'); +| $autoload['libraries'] = array('database', 'email', 'xmlrpc'); */ $autoload['libraries'] = array(); @@ -83,6 +84,22 @@ $autoload['libraries'] = array(); /* | ------------------------------------------------------------------- +| Auto-load Drivers +| ------------------------------------------------------------------- +| These classes are located in the system/libraries folder or in your +| application/libraries folder within their own subdirectory. They +| offer multiple interchangeable driver options. +| +| Prototype: +| +| $autoload['drivers'] = array('session', 'cache'); +*/ + +$autoload['drivers'] = array(); + + +/* +| ------------------------------------------------------------------- | Auto-load Helper Files | ------------------------------------------------------------------- | Prototype: @@ -139,4 +156,4 @@ $autoload['model'] = array(); /* End of file autoload.php */ -/* Location: ./application/config/autoload.php */
\ No newline at end of file +/* Location: ./application/config/autoload.php */ diff --git a/application/config/config.php b/application/config/config.php index 2628885f0..0562953b0 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -62,11 +62,11 @@ $config['index_page'] = 'index.php'; | 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 +| 'AUTO' Default - auto detects +| 'CLI' or 'argv' Uses $_SERVER['argv'] (for php-cli only) +| 'PATH_INFO' Uses $_SERVER['PATH_INFO'] +| 'REQUEST_URI' Uses $_SERVER['REQUEST_URI'] +| 'QUERY_STRING' Uses $_SERVER['QUERY_STRING'] | */ $config['uri_protocol'] = 'AUTO'; @@ -204,7 +204,7 @@ $config['directory_trigger'] = 'd'; // experimental not currently in use | 4 = All Messages | | You can also pass in a array with threshold levels to show individual error types -| +| | array(2) = Debug Messages, without Error Messages | | For a live site you'll usually only enable Errors (1) to be logged otherwise @@ -253,7 +253,7 @@ $config['cache_path'] = ''; | | If you use the Encryption class or the Session class you | MUST set an encryption key. See the user guide for info. -| +| | http://codeigniter.com/user_guide/libraries/encryption.html | http://codeigniter.com/user_guide/libraries/sessions.html | @@ -265,6 +265,9 @@ $config['encryption_key'] = ''; | Session Variables |-------------------------------------------------------------------------- | +| 'sess_driver' = the driver to load: cookie (Classic), native (PHP sessions), +| or your custom driver name +| 'sess_valid_drivers' = additional valid drivers which may be loaded | '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. @@ -278,6 +281,8 @@ $config['encryption_key'] = ''; | 'sess_time_to_update' = how many seconds between CI refreshing Session Information | */ +$config['sess_driver'] = 'cookie'; +$config['sess_valid_drivers'] = array(); $config['sess_cookie_name'] = 'ci_session'; $config['sess_expiration'] = 7200; $config['sess_expire_on_close'] = FALSE; @@ -297,12 +302,12 @@ $config['sess_time_to_update'] = 300; | '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. -| 'cookie_httponly' = Cookie will only be accessible via HTTP(S) (no javascript) +| 'cookie_httponly' = Cookie will only be accessible via HTTP(S) (no javascript) | */ -$config['cookie_prefix'] = ""; -$config['cookie_domain'] = ""; -$config['cookie_path'] = "/"; +$config['cookie_prefix'] = ''; +$config['cookie_domain'] = ''; +$config['cookie_path'] = '/'; $config['cookie_secure'] = FALSE; $config['cookie_httponly'] = FALSE; @@ -359,13 +364,25 @@ $config['compress_output'] = FALSE; /* |-------------------------------------------------------------------------- +| Minify +|-------------------------------------------------------------------------- +| +| Removes extra characters (usually unnecessary spaces) from your +| output for faster page load speeds. Makes your outputted HTML source +| code less readable. +| +*/ +$config['minify_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. +| Options are 'local' or any PHP supported timezone. This preference tells +| the system whether to use your server's local time as the master 'now' +| reference, or convert it to the configured one timezone. See the 'date +| helper' page of the user guide for information regarding date handling. | */ $config['time_reference'] = 'local'; @@ -389,14 +406,19 @@ $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' +| If your server is behind a reverse proxy, you must whitelist the proxy +| IP addresses from which CodeIgniter should trust headers such as +| HTTP_X_FORWARDED_FOR and HTTP_CLIENT_IP in order to properly identify +| the visitor's IP address. +| +| You can use both an array or a comma-separated list of proxy addresses, +| as well as specifying whole subnets. Here are a few examples: | +| Comma-separated: '10.0.1.200,192.168.5.0/24' +| Array: array('10.0.1.200', '192.168.5.0/24') */ $config['proxy_ips'] = ''; /* End of file config.php */ -/* Location: ./application/config/config.php */ +/* Location: ./application/config/config.php */
\ No newline at end of file diff --git a/application/config/constants.php b/application/config/constants.php index d22d2963e..62a18e761 100644 --- a/application/config/constants.php +++ b/application/config/constants.php @@ -52,14 +52,14 @@ define('DIR_WRITE_MODE', 0777); | */ -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'); +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'); /* |-------------------------------------------------------------------------- diff --git a/application/config/database.php b/application/config/database.php index 8c06dd2e6..32340263b 100644 --- a/application/config/database.php +++ b/application/config/database.php @@ -42,10 +42,12 @@ | ['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. e.g.: mysql. Currently supported: - mysql, mysqli, pdo, postgre, odbc, mssql, sqlite, oci8 +| ['dbdriver'] The database driver. e.g.: mysqli. +| Currently supported: +| cubrid, ibase, mssql, mysql, mysqli, oci8, +| odbc, pdo, postgre, sqlite, sqlite3, sqlsrv | ['dbprefix'] You can add an optional prefix, which will be added -| to the table name when using the Active Record class +| to the table name when using the Query Builder 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 @@ -61,6 +63,8 @@ | 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. +| ['encrypt'] Whether or not to use an encrypted connection. +| ['compress'] Whether or not to use client compression (MySQL only) | ['stricton'] TRUE/FALSE - forces 'Strict Mode' connections | - good for ensuring strict SQL while developing | ['failover'] array - A array with 0 or more data for connections if the main should fail. @@ -68,12 +72,12 @@ | 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 +| The $query_builder variables lets you determine whether or not to load +| the query builder class. */ $active_group = 'default'; -$active_record = TRUE; +$query_builder = TRUE; $db['default'] = array( 'dsn' => '', @@ -83,7 +87,7 @@ $db['default'] = array( 'database' => '', 'dbdriver' => 'mysqli', 'dbprefix' => '', - 'pconnect' => FALSE, + 'pconnect' => TRUE, 'db_debug' => TRUE, 'cache_on' => FALSE, 'cachedir' => '', @@ -91,6 +95,8 @@ $db['default'] = array( 'dbcollat' => 'utf8_general_ci', 'swap_pre' => '', 'autoinit' => TRUE, + 'encrypt' => FALSE, + 'compress' => FALSE, 'stricton' => FALSE, 'failover' => array() ); diff --git a/application/config/foreign_chars.php b/application/config/foreign_chars.php index e2d3f236e..5a2bb0cf7 100644 --- a/application/config/foreign_chars.php +++ b/application/config/foreign_chars.php @@ -40,50 +40,83 @@ $foreign_characters = array( '/Ä/' => 'Ae', '/Ü/' => 'Ue', '/Ö/' => 'Oe', - '/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ/' => 'A', - '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª/' => 'a', + '/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ|Α|Ά|Ả|Ạ|Ầ|Ẫ|Ẩ|Ậ|Ằ|Ắ|Ẵ|Ẳ|Ặ|А/' => 'A', + '/à|á|â|ã|å|ǻ|ā|ă|ą|ǎ|ª|α|ά|ả|ạ|ầ|ấ|ẫ|ẩ|ậ|ằ|ắ|ẵ|ẳ|ặ|а/' => 'a', + '/Б/' => 'B', + '/б/' => 'b', '/Ç|Ć|Ĉ|Ċ|Č/' => 'C', '/ç|ć|ĉ|ċ|č/' => 'c', - '/Ð|Ď|Đ/' => 'Dj', - '/ð|ď|đ/' => 'dj', - '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě/' => 'E', - '/è|é|ê|ë|ē|ĕ|ė|ę|ě/' => 'e', - '/Ĝ|Ğ|Ġ|Ģ/' => 'G', - '/ĝ|ğ|ġ|ģ/' => 'g', + '/Д/' => 'D', + '/д/' => 'd', + '/Ð|Ď|Đ|Δ/' => 'Dj', + '/ð|ď|đ|δ/' => 'dj', + '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Ε|Έ|Ẽ|Ẻ|Ẹ|Ề|Ế|Ễ|Ể|Ệ|Е|Ё|Э/' => 'E', + '/è|é|ê|ë|ē|ĕ|ė|ę|ě|έ|ε|ẽ|ẻ|ẹ|ề|ế|ễ|ể|ệ|е|ё|э/' => 'e', + '/Ф/' => 'F', + '/ф/' => 'f', + '/Ĝ|Ğ|Ġ|Ģ|Γ|Г/' => 'G', + '/ĝ|ğ|ġ|ģ|γ|г/' => 'g', '/Ĥ|Ħ/' => 'H', '/ĥ|ħ/' => 'h', - '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ/' => 'I', - '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı/' => 'i', + '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|Η|Ή|Ί|Ι|Ϊ|Ỉ|Ị|И|Й/' => 'I', + '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|η|ή|ί|ι|ϊ|ỉ|ị|и|й/' => 'i', '/Ĵ/' => 'J', '/ĵ/' => 'j', - '/Ķ/' => 'K', - '/ķ/' => 'k', - '/Ĺ|Ļ|Ľ|Ŀ|Ł/' => 'L', - '/ĺ|ļ|ľ|ŀ|ł/' => 'l', - '/Ñ|Ń|Ņ|Ň/' => 'N', - '/ñ|ń|ņ|ň|ʼn/' => 'n', - '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ/' => 'O', - '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º/' => 'o', - '/Ŕ|Ŗ|Ř/' => 'R', - '/ŕ|ŗ|ř/' => 'r', - '/Ś|Ŝ|Ş|Š/' => 'S', - '/ś|ŝ|ş|š|ſ/' => 's', - '/Ţ|Ť|Ŧ/' => 'T', - '/ţ|ť|ŧ/' => 't', - '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ/' => 'U', - '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ/' => 'u', - '/Ý|Ÿ|Ŷ/' => 'Y', - '/ý|ÿ|ŷ/' => 'y', + '/Ķ|Κ|К/' => 'K', + '/ķ|κ|к/' => 'k', + '/Ĺ|Ļ|Ľ|Ŀ|Ł|Λ|Л/' => 'L', + '/ĺ|ļ|ľ|ŀ|ł|λ|л/' => 'l', + '/М/' => 'M', + '/м/' => 'm', + '/Ñ|Ń|Ņ|Ň|Ν|Н/' => 'N', + '/ñ|ń|ņ|ň|ʼn|ν|н/' => 'n', + '/Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|Ο|Ό|Ω|Ώ|Ỏ|Ọ|Ồ|Ố|Ỗ|Ổ|Ộ|Ờ|Ớ|Ỡ|Ở|Ợ|О/' => 'O', + '/ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|ο|ό|ω|ώ|ỏ|ọ|ồ|ố|ỗ|ổ|ộ|ờ|ớ|ỡ|ở|ợ|о/' => 'o', + '/П/' => 'P', + '/п/' => 'p', + '/Ŕ|Ŗ|Ř|Ρ|Р/' => 'R', + '/ŕ|ŗ|ř|ρ|р/' => 'r', + '/Ś|Ŝ|Ş|Ș|Š|Σ|С/' => 'S', + '/ś|ŝ|ş|ș|š|ſ|σ|ς|с/' => 's', + '/Ț|Ţ|Ť|Ŧ|τ|Т/' => 'T', + '/ț|ţ|ť|ŧ|т/' => 't', + '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|Ũ|Ủ|Ụ|Ừ|Ứ|Ữ|Ử|Ự|У/' => 'U', + '/ù|ú|û|ũ|ū|ŭ|ů|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|υ|ύ|ϋ|ủ|ụ|ừ|ứ|ữ|ử|ự|у/' => 'u', + '/Ý|Ÿ|Ŷ|Υ|Ύ|Ϋ|Ỳ|Ỹ|Ỷ|Ỵ/' => 'Y', + '/ý|ÿ|ŷ|ỳ|ỹ|ỷ|ỵ/' => 'y', + '/В/' => 'V', + '/в/' => 'v', '/Ŵ/' => 'W', '/ŵ/' => 'w', - '/Ź|Ż|Ž/' => 'Z', - '/ź|ż|ž/' => 'z', + '/Ź|Ż|Ž|Ζ|З/' => 'Z', + '/ź|ż|ž|ζ|з/' => 'z', '/Æ|Ǽ/' => 'AE', '/ß/'=> 'ss', '/IJ/' => 'IJ', '/ij/' => 'ij', '/Œ/' => 'OE', - '/ƒ/' => 'f' + '/ƒ/' => 'f', + '/ξ/' => 'ks', + '/π/' => 'p', + '/β/' => 'v', + '/μ/' => 'm', + '/ψ/' => 'ps', + '/Ж/'=>'Zh', + '/ж/'=>'zh', + '/Х/'=>'Kh', + '/х/'=>'kh', + '/Ц/'=>'Tc', + '/ц/'=>'tc', + '/Ч/'=>'Ch', + '/ч/'=>'ch', + '/Ш/'=>'Sh', + '/ш/'=>'sh', + '/Щ/'=>'Shch', + '/щ/'=>'shch', + '/Ю/'=>'Iu', + '/ю/'=>'iu', + '/Я/'=>'Ia', + '/я/'=>'ia' ); /* End of file foreign_chars.php */ diff --git a/application/config/migration.php b/application/config/migration.php index 88e398243..3ea3ef93c 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -39,12 +39,30 @@ $config['migration_enabled'] = FALSE; /* |-------------------------------------------------------------------------- +| Migration Type +|-------------------------------------------------------------------------- +| +| Migration file names may be based on a sequential identifier or on +| a timestamp. Options are: +| +| 'sequential' = Default migration naming (001_add_blog.php) +| 'timestamp' = Timestamp migration naming (20121031104401_add_blog.php) +| Use timestamp format YYYYMMDDHHIISS. +| +| If this configuration value is missing the Migration library defaults +| to 'sequential' for backward compatibility. +| +*/ +$config['migration_type'] = 'timestamp'; + +/* +|-------------------------------------------------------------------------- | Migrations table |-------------------------------------------------------------------------- | | This is the name of the table that will store the current migrations state. | When migrations runs it will store in a database table which migration -| level the system is at. It then compares the migration level in the this +| level the system is at. It then compares the migration level in this | table to the $config['migration_version'] if they are not the same it | will migrate up. This must be set. | diff --git a/application/config/mimes.php b/application/config/mimes.php index 02e12c011..ffbc2ee72 100644 --- a/application/config/mimes.php +++ b/application/config/mimes.php @@ -34,136 +34,145 @@ | */ -$mimes = array( - 'hqx' => array('application/mac-binhex40', 'application/mac-binhex', 'application/x-binhex40', 'application/x-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' => array('application/macbinary', 'application/mac-binary', 'application/octet-stream', 'application/x-binary', 'application/x-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'), - 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - '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', - 'gzip' => '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' => array('audio/x-aiff', 'audio/aiff'), - 'aiff' => array('audio/x-aiff', 'audio/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' => array('application/xml', 'text/xml'), - 'xsl' => array('application/xml', 'text/xsl', 'text/xml'), - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mpe' => 'video/mpeg', - 'qt' => 'video/quicktime', - 'mov' => 'video/quicktime', - 'avi' => array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'), - 'movie' => 'video/x-sgi-movie', - 'doc' => array('application/msword', 'application/vnd.ms-office'), - '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'), - 'pem' => array('application/x-x509-user-cert', 'application/x-pem-file', 'application/octet-stream'), - 'p10' => array('application/x-pkcs10', 'application/pkcs10'), - 'p12' => 'application/x-pkcs12', - 'p7a' => 'application/x-pkcs7-signature', - 'p7c' => array('application/pkcs7-mime', 'application/x-pkcs7-mime'), - 'p7m' => array('application/pkcs7-mime', 'application/x-pkcs7-mime'), - 'p7r' => 'application/x-pkcs7-certreqresp', - 'p7s' => 'application/pkcs7-signature', - 'crt' => array('application/x-x509-ca-cert', 'application/x-x509-user-cert', 'application/pkix-cert'), - 'crl' => array('application/pkix-crl', 'application/pkcs-crl'), - 'der' => 'application/x-x509-ca-cert', - 'kdb' => 'application/octet-stream', - 'pgp' => 'application/pgp', - 'gpg' => 'application/gpg-keys', - 'sst' => 'application/octet-stream', - 'csr' => 'application/octet-stream', - 'rsa' => 'application/x-pkcs7', - 'cer' => array('application/pkix-cert', 'application/x-x509-ca-cert'), - '3g2' => 'video/3gpp2', - '3gp' => 'video/3gp', - 'mp4' => 'video/mp4', - 'm4a' => 'audio/x-m4a', - 'f4v' => 'video/mp4', - 'aac' => 'audio/x-acc', - 'm4u' => 'application/vnd.mpegurl', - 'm3u' => 'text/plain', - 'xspf' => 'application/xspf+xml', - 'vlc' => 'application/videolan', - 'wmv' => 'video/x-ms-wmv', - 'au' => 'audio/x-au', - 'ac3' => 'audio/ac3', - 'flac' => 'audio/x-flac', - 'ogg' => 'audio/ogg', - 'kmz' => array('application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'), - 'kml' => array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml') - ); +return array( + 'hqx' => array('application/mac-binhex40', 'application/mac-binhex', 'application/x-binhex40', 'application/x-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', 'text/plain'), + 'bin' => array('application/macbinary', 'application/mac-binary', 'application/octet-stream', 'application/x-binary', 'application/x-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', 'binary/octet-stream'), + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => array('application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'application/x-ms-excel', 'application/x-excel', 'application/x-dos_ms_excel', 'application/xls', 'application/x-xls', 'application/excel', 'application/download', 'application/vnd.ms-office', 'application/msword'), + 'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint'), + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + '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', + 'gzip' => 'application/x-gzip', + 'php' => array('application/x-httpd-php', 'application/php', 'application/x-php', 'text/php', 'text/x-php', 'application/x-httpd-php-source'), + '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', 'application/s-compressed', 'multipart/x-zip'), + 'rar' => array('application/x-rar', 'application/rar', 'application/x-rar-compressed'), + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mpga' => 'audio/mpeg', + 'mp2' => 'audio/mpeg', + 'mp3' => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'), + 'aif' => array('audio/x-aiff', 'audio/aiff'), + 'aiff' => array('audio/x-aiff', 'audio/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' => array('application/xml', 'text/xml'), + 'xsl' => array('application/xml', 'text/xsl', 'text/xml'), + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'avi' => array('video/x-msvideo', 'video/msvideo', 'video/avi', 'application/x-troff-msvideo'), + 'movie' => 'video/x-sgi-movie', + 'doc' => array('application/msword', 'application/vnd.ms-office'), + 'docx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword'), + 'dot' => array('application/msword', 'application/vnd.ms-office'), + 'dotx' => array('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', 'application/msword'), + 'xlsx' => array('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/zip', 'application/vnd.ms-excel', 'application/msword'), + 'word' => array('application/msword', 'application/octet-stream'), + 'xl' => 'application/excel', + 'eml' => 'message/rfc822', + 'json' => array('application/json', 'text/json'), + 'pem' => array('application/x-x509-user-cert', 'application/x-pem-file', 'application/octet-stream'), + 'p10' => array('application/x-pkcs10', 'application/pkcs10'), + 'p12' => 'application/x-pkcs12', + 'p7a' => 'application/x-pkcs7-signature', + 'p7c' => array('application/pkcs7-mime', 'application/x-pkcs7-mime'), + 'p7m' => array('application/pkcs7-mime', 'application/x-pkcs7-mime'), + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'crt' => array('application/x-x509-ca-cert', 'application/x-x509-user-cert', 'application/pkix-cert'), + 'crl' => array('application/pkix-crl', 'application/pkcs-crl'), + 'der' => 'application/x-x509-ca-cert', + 'kdb' => 'application/octet-stream', + 'pgp' => 'application/pgp', + 'gpg' => 'application/gpg-keys', + 'sst' => 'application/octet-stream', + 'csr' => 'application/octet-stream', + 'rsa' => 'application/x-pkcs7', + 'cer' => array('application/pkix-cert', 'application/x-x509-ca-cert'), + '3g2' => 'video/3gpp2', + '3gp' => 'video/3gp', + 'mp4' => 'video/mp4', + 'm4a' => 'audio/x-m4a', + 'f4v' => 'video/mp4', + 'aac' => 'audio/x-acc', + 'm4u' => 'application/vnd.mpegurl', + 'm3u' => 'text/plain', + 'xspf' => 'application/xspf+xml', + 'vlc' => 'application/videolan', + 'wmv' => 'video/x-ms-wmv', + 'au' => 'audio/x-au', + 'ac3' => 'audio/ac3', + 'flac' => 'audio/x-flac', + 'ogg' => 'audio/ogg', + 'kmz' => array('application/vnd.google-earth.kmz', 'application/zip', 'application/x-zip'), + 'kml' => array('application/vnd.google-earth.kml+xml', 'application/xml', 'text/xml'), + 'ics' => 'text/calendar', + 'zsh' => 'text/x-scriptzsh', + '7zip' => array('application/x-compressed', 'application/x-zip-compressed', 'application/zip', 'multipart/x-zip'), + 'cdr' => array('application/cdr', 'application/coreldraw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'), + 'wma' => array('audio/x-ms-wma', 'video/x-ms-asf'), + 'jar' => array('application/java-archive', 'application/x-java-application', 'application/x-jar', 'application/x-compressed') +); /* End of file mimes.php */ /* Location: ./application/config/mimes.php */
\ No newline at end of file diff --git a/application/config/routes.php b/application/config/routes.php index 474bda969..d1a4419b7 100644 --- a/application/config/routes.php +++ b/application/config/routes.php @@ -59,12 +59,12 @@ | | $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. +| This route will tell the Router which controller/method to use if those +| provided in the URL cannot be matched to a valid route. | */ -$route['default_controller'] = "welcome"; +$route['default_controller'] = 'welcome'; $route['404_override'] = ''; /* End of file routes.php */ diff --git a/application/config/user_agents.php b/application/config/user_agents.php index 60f256e01..78e4c8c7d 100644 --- a/application/config/user_agents.php +++ b/application/config/user_agents.php @@ -29,14 +29,14 @@ | ------------------------------------------------------------------- | USER AGENT TYPES | ------------------------------------------------------------------- -| This file contains four arrays of user agent data. It is used by the +| 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 +| 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 ( +$platforms = array( + 'windows nt 6.2' => 'Windows 8', 'windows nt 6.1' => 'Windows 7', 'windows nt 6.0' => 'Windows Vista', 'windows nt 5.2' => 'Windows 2003', @@ -51,6 +51,11 @@ $platforms = array ( 'windows 95' => 'Windows 95', 'win95' => 'Windows 95', 'windows' => 'Unknown Windows OS', + 'android' => 'Android', + 'blackberry' => 'BlackBerry', + 'iphone' => 'iOS', + 'ipad' => 'iOS', + 'ipod' => 'iOS', 'os x' => 'Mac OS X', 'ppc mac' => 'Power PC Mac', 'freebsd' => 'FreeBSD', @@ -117,84 +122,85 @@ $mobiles = array( // '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", - 'dsi' => "Nintendo DSi", - 'ds' => "Nintendo DS", - 'wii' => "Nintendo Wii", - '3ds' => "Nintendo 3DS", - 'open web' => "Open Web", - 'openweb' => "OpenWeb", + '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', + 'playstation 3' => 'PlayStation 3', + 'hiptop' => 'Danger Hiptop', + 'nec-' => 'NEC', + 'panasonic' => 'Panasonic', + 'philips' => 'Philips', + 'sagem' => 'Sagem', + 'sanyo' => 'Sanyo', + 'spv' => 'SPV', + 'zte' => 'ZTE', + 'sendo' => 'Sendo', + 'nintendo dsi' => 'Nintendo DSi', + 'nintendo ds' => 'Nintendo DS', + 'nintendo 3ds' => 'Nintendo 3DS', + 'wii' => 'Nintendo Wii', + 'open web' => 'Open Web', + 'openweb' => 'OpenWeb', // Operating Systems - 'android' => "Android", - 'symbian' => "Symbian", - 'SymbianOS' => "SymbianOS", - 'elaine' => "Palm", - 'palm' => "Palm", - 'series60' => "Symbian S60", - 'windows ce' => "Windows CE", + 'android' => 'Android', + 'symbian' => 'Symbian', + 'SymbianOS' => 'SymbianOS', + 'elaine' => '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", - 'opera mobi' => "Opera Mobile", + 'obigo' => 'Obigo', + 'netfront' => 'Netfront Browser', + 'openwave' => 'Openwave Browser', + 'mobilexplorer' => 'Mobile Explorer', + 'operamini' => 'Opera Mini', + 'opera mini' => 'Opera Mini', + 'opera mobi' => 'Opera Mobile', + 'fennec' => 'Firefox Mobile', // Other - 'digital paths' => "Digital Paths", - 'avantgo' => "AvantGo", - 'xiino' => "Xiino", - 'novarra' => "Novarra Transcoder", - 'vodafone' => "Vodafone", - 'docomo' => "NTT DoCoMo", - 'o2' => "O2", + '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" + '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. diff --git a/application/controllers/welcome.php b/application/controllers/welcome.php index 1ed82d2a7..f70dd78ad 100644 --- a/application/controllers/welcome.php +++ b/application/controllers/welcome.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); class Welcome extends CI_Controller { diff --git a/application/errors/error_404.php b/application/views/errors/error_404.php index 746032956..4a8823dee 100644 --- a/application/errors/error_404.php +++ b/application/views/errors/error_404.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); ?><!DOCTYPE html> <html lang="en"> <head> @@ -31,9 +32,9 @@ <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; } +::selection { background-color: #E13300; color: white; } +::-moz-selection { background-color: #E13300; color: white; } +::-webkit-selection { background-color: #E13300; color: white; } body { background-color: #fff; @@ -72,6 +73,8 @@ code { #container { margin: 10px; border: 1px solid #D0D0D0; + box-shadow: 0 0 8px #D0D0D0; + -moz-box-shadow: 0 0 8px #D0D0D0; -webkit-box-shadow: 0 0 8px #D0D0D0; } diff --git a/application/errors/error_db.php b/application/views/errors/error_db.php index eb3a75260..21d5d86ef 100644 --- a/application/errors/error_db.php +++ b/application/views/errors/error_db.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); ?><!DOCTYPE html> <html lang="en"> <head> @@ -31,9 +32,9 @@ <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; } +::selection { background-color: #E13300; color: white; } +::-moz-selection { background-color: #E13300; color: white; } +::-webkit-selection { background-color: #E13300; color: white; } body { background-color: #fff; @@ -72,6 +73,8 @@ code { #container { margin: 10px; border: 1px solid #D0D0D0; + box-shadow: 0 0 8px #D0D0D0; + -moz-box-shadow: 0 0 8px #D0D0D0; -webkit-box-shadow: 0 0 8px #D0D0D0; } diff --git a/application/errors/error_general.php b/application/views/errors/error_general.php index 59896e1ea..5bf361113 100644 --- a/application/errors/error_general.php +++ b/application/views/errors/error_general.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); ?><!DOCTYPE html> <html lang="en"> <head> @@ -31,9 +32,9 @@ <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; } +::selection { background-color: #E13300; color: white; } +::-moz-selection { background-color: #E13300; color: white; } +::-webkit-selection { background-color: #E13300; color: white; } body { background-color: #fff; @@ -72,6 +73,8 @@ code { #container { margin: 10px; border: 1px solid #D0D0D0; + box-shadow: 0 0 8px #D0D0D0; + -moz-box-shadow: 0 0 8px #D0D0D0; -webkit-box-shadow: 0 0 8px #D0D0D0; } diff --git a/application/errors/error_php.php b/application/views/errors/error_php.php index 3855720de..c0c4bd622 100644 --- a/application/errors/error_php.php +++ b/application/views/errors/error_php.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); ?> <div style="border:1px solid #990000;padding-left:20px;margin:0 0 10px 0;"> @@ -40,12 +41,15 @@ <p>Backtrace: </p> <?php foreach(debug_backtrace() as $error): ?> - <?php if(isset($error['file']) && ! stristr($error['file'], SYSDIR)): ?> + <?php if(isset($error['file']) && + strpos($error['file'], realpath(BASEPATH)) !== 0): ?> + <p style="margin-left:10px"> File: <?php echo $error['file'] ?><br /> Line: <?php echo $error['line'] ?><br /> Function: <?php echo $error['function'] ?> </p> + <?php endif ?> <?php endforeach ?></p> diff --git a/application/errors/index.html b/application/views/errors/index.html index c942a79ce..c942a79ce 100644 --- a/application/errors/index.html +++ b/application/views/errors/index.html diff --git a/application/views/welcome_message.php b/application/views/welcome_message.php index 45360da60..27332f456 100644 --- a/application/views/welcome_message.php +++ b/application/views/welcome_message.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); ?><!DOCTYPE html> <html lang="en"> <head> @@ -32,9 +33,9 @@ <style type="text/css"> - ::selection{ background-color: #E13300; color: white; } - ::moz-selection{ background-color: #E13300; color: white; } - ::webkit-selection{ background-color: #E13300; color: white; } + ::selection { background-color: #E13300; color: white; } + ::-moz-selection { background-color: #E13300; color: white; } + ::-webkit-selection { background-color: #E13300; color: white; } body { background-color: #fff; @@ -70,11 +71,11 @@ padding: 12px 10px 12px 10px; } - #body{ + #body { margin: 0 15px 0 15px; } - p.footer{ + p.footer { text-align: right; font-size: 11px; border-top: 1px solid #D0D0D0; @@ -83,9 +84,10 @@ margin: 20px 0 0 0; } - #container{ + #container { margin: 10px; border: 1px solid #D0D0D0; + -moz-box-shadow: 0 0 8px #D0D0D0; -webkit-box-shadow: 0 0 8px #D0D0D0; } </style> @@ -107,7 +109,7 @@ <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. <?php echo (ENVIRONMENT == 'development') ? 'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p> + <p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo (ENVIRONMENT === 'development') ? 'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p> </div> </body> diff --git a/composer.json b/composer.json new file mode 100644 index 000000000..7d60020c3 --- /dev/null +++ b/composer.json @@ -0,0 +1,8 @@ +{ + "require": { + "mikey179/vfsStream": "*" + }, + "require-dev": { + "phpunit/phpunit": "*" + } +}
\ No newline at end of file diff --git a/contributing.md b/contributing.md new file mode 100644 index 000000000..b6d486d00 --- /dev/null +++ b/contributing.md @@ -0,0 +1,92 @@ +# Contributing to CodeIgniter + + +CodeIgniter is a community driven project and accepts contributions of code and documentation from the community. These contributions are made in the form of Issues or [Pull Requests](http://help.github.com/send-pull-requests/) on the [EllisLab CodeIgniter repository](https://github.com/EllisLab/CodeIgniter>) on GitHub. + +Issues are a quick way to point out a bug. If you find a bug or documentation error in CodeIgniter then please check a few things first: + +1. There is not already an open Issue +2. The issue has already been fixed (check the develop branch, or look for closed Issues) +3. Is it something really obvious that you can fix yourself? + +Reporting issues is helpful but an even better approach is to send a Pull Request, which is done by "Forking" the main repository and committing to your own copy. This will require you to use the version control system called Git. + +## Guidelines + +Before we look into how, here are the guidelines. If your Pull Requests fail +to pass these guidelines it will be declined and you will need to re-submit +when you’ve made the changes. This might sound a bit tough, but it is required +for us to maintain quality of the code-base. + +### PHP Style + +All code must meet the [Style Guide](http://codeigniter.com/user_guide/general/styleguide.html), which is +essentially the [Allman indent style](http://en.wikipedia.org/wiki/Indent_style#Allman_style), underscores and readable operators. This makes certain that all code is the same format as the existing code and means it will be as readable as possible. + +### Documentation + +If you change anything that requires a change to documentation then you will need to add it. New classes, methods, parameters, changing default values, etc are all things that will require a change to documentation. The change-log must also be updated for every change. Also PHPDoc blocks must be maintained. + +### Compatibility + +CodeIgniter is compatible with PHP 5.2.4 so all code supplied must stick to +this requirement. If PHP 5.3 or 5.4 functions or features are used then there +must be a fallback for PHP 5.2.4. + +### Branching + +CodeIgniter uses the [Git-Flow](http://nvie.com/posts/a-successful-git-branching-model/) branching model which requires all pull requests to be sent to the "develop" branch. This is +where the next planned version will be developed. The "master" branch will always contain the latest stable version and is kept clean so a "hotfix" (e.g: an emergency security patch) can be applied to master to create a new version, without worrying about other features holding it up. For this reason all commits need to be made to "develop" and any sent to "master" will be closed automatically. If you have multiple changes to submit, please place all changes into their own branch on your fork. + +One thing at a time: A pull request should only contain one change. That does not mean only one commit, but one change - however many commits it took. The reason for this is that if you change X and Y but send a pull request for both at the same time, we might really want X but disagree with Y, meaning we cannot merge the request. Using the Git-Flow branching model you can create new branches for both of these features and send two requests. + +### Signing + +You must sign your work, certifying that you either wrote the work or otherwise have the right to pass it on to an open source project. git makes this trivial as you merely have to use `--signoff` on your commits to your CodeIgniter fork. + +`git commit --signoff` + +or simply + +`git commit -s` + +This will sign your commits with the information setup in your git config, e.g. + +`Signed-off-by: John Q Public <john.public@example.com>` + +If you are using [Tower](http://www.git-tower.com/) there is a "Sign-Off" checkbox in the commit window. You could even alias git commit to use the `-s` flag so you don’t have to think about it. + +By signing your work in this manner, you certify to a "Developer's Certificate of Origin". The current version of this certificate is in the `DCO.txt` file in the root of this repository. + + +## How-to Guide + +There are two ways to make changes, the easy way and the hard way. Either way you will need to [create a GitHub account](https://github.com/signup/free). + +Easy way GitHub allows in-line editing of files for making simple typo changes and quick-fixes. This is not the best way as you are unable to test the code works. If you do this you could be introducing syntax errors, etc, but for a Git-phobic user this is good for a quick-fix. + +Hard way The best way to contribute is to "clone" your fork of CodeIgniter to your development area. That sounds like some jargon, but "forking" on GitHub means "making a copy of that repo to your account" and "cloning" means "copying that code to your environment so you can work on it". + +1. Set up Git (Windows, Mac & Linux) +2. Go to the CodeIgniter repo +3. Fork it +4. Clone your CodeIgniter repo: git@github.com:<your-name>/CodeIgniter.git +5. Checkout the "develop" branch At this point you are ready to start making changes. +6. Fix existing bugs on the Issue tracker after taking a look to see nobody else is working on them. +7. Commit the files +8. Push your develop branch to your fork +9. Send a pull request [http://help.github.com/send-pull-requests/](http://help.github.com/send-pull-requests/) + +The Reactor Engineers will now be alerted about the change and at least one of the team will respond. If your change fails to meet the guidelines it will be bounced, or feedback will be provided to help you improve it. + +Once the Reactor Engineer handling your pull request is happy with it they will post it to the internal EllisLab discussion area to be double checked by the other Engineers and EllisLab developers. If nobody has a problem with the change then it will be merged into develop and will be part of the next release. Keeping your fork up-to-date + +Unlike systems like Subversion, Git can have multiple remotes. A remote is the name for a URL of a Git repository. By default your fork will have a remote named "origin" which points to your fork, but you can add another remote named "codeigniter" which points to `git://github.com/EllisLab/CodeIgniter.git`. This is a read-only remote but you can pull from this develop branch to update your own. + +If you are using command-line you can do the following: + +1. `git remote add codeigniter git://github.com/EllisLab/CodeIgniter.git` +2. `git pull codeigniter develop` +3. `git push origin develop` + +Now your fork is up to date. This should be done regularly, or before you send a pull request at least.
\ No newline at end of file @@ -42,7 +42,8 @@ * * NOTE: If you change these, also change the error_reporting() code below */ - define('ENVIRONMENT', 'development'); + define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development'); + /* *--------------------------------------------------------------- * ERROR REPORTING @@ -51,21 +52,22 @@ * 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) { - switch (ENVIRONMENT) - { - case 'development': - error_reporting(-1); - break; - case 'testing': - case 'production': - error_reporting(0); - break; - default: - exit('The application environment is not set correctly.'); - } + case 'development': + error_reporting(-1); + ini_set('display_errors', 1); + break; + + case 'testing': + case 'production': + error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED ^ E_STRICT); + ini_set('display_errors', 0); + break; + + default: + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); + exit('The application environment is not set correctly.'); } /* @@ -133,7 +135,7 @@ if (defined('ENVIRONMENT')) // if your controller is not in a sub-folder within the "controllers" folder // $routing['directory'] = ''; - // The controller class file name. Example: Mycontroller + // The controller class file name. Example: mycontroller // $routing['controller'] = ''; // The controller function you wish to be called. @@ -174,17 +176,20 @@ if (defined('ENVIRONMENT')) chdir(dirname(__FILE__)); } - if (realpath($system_path) !== FALSE) + if (($_temp = realpath($system_path)) !== FALSE) { - $system_path = realpath($system_path).'/'; + $system_path = $_temp.'/'; + } + else + { + // Ensure there's a trailing slash + $system_path = rtrim($system_path, '/').'/'; } - - // ensure there's a trailing slash - $system_path = rtrim($system_path, '/').'/'; // Is the system path correct? if ( ! is_dir($system_path)) { + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); exit('Your system folder path does not appear to be set correctly. Please open the following file and correct this: '.pathinfo(__FILE__, PATHINFO_BASENAME)); } @@ -196,10 +201,6 @@ if (defined('ENVIRONMENT')) // 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)); @@ -212,13 +213,18 @@ if (defined('ENVIRONMENT')) // The path to the "application" folder if (is_dir($application_folder)) { + if (($_temp = realpath($application_folder)) !== FALSE) + { + $application_folder = $_temp; + } + define('APPPATH', $application_folder.'/'); } else { if ( ! is_dir(BASEPATH.$application_folder.'/')) { - header('HTTP/1.1 503 Service Unavailable.', TRUE, '503'); + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); exit('Your application folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF); } @@ -226,21 +232,34 @@ if (defined('ENVIRONMENT')) } // The path to the "views" folder - if (is_dir($view_folder)) + if ( ! is_dir($view_folder)) { - define ('VIEWPATH', $view_folder .'/'); - } - else - { - if ( ! is_dir(APPPATH.'views/')) + if ( ! empty($view_folder) && is_dir(APPPATH.$view_folder.'/')) { - header('HTTP/1.1 503 Service Unavailable.', TRUE, '503'); + $view_folder = APPPATH.$view_folder; + } + elseif ( ! is_dir(APPPATH.'views/')) + { + header('HTTP/1.1 503 Service Unavailable.', TRUE, 503); exit('Your view folder path does not appear to be set correctly. Please open the following file and correct this: '.SELF); } + else + { + $view_folder = APPPATH.'views'; + } + } - define ('VIEWPATH', APPPATH.'views/' ); + if (($_temp = realpath($view_folder)) !== FALSE) + { + $view_folder = realpath($view_folder).'/'; + } + else + { + $view_folder = rtrim($view_folder, '/').'/'; } + define('VIEWPATH', $view_folder); + /* * -------------------------------------------------------------------- * LOAD THE BOOTSTRAP FILE diff --git a/phpdoc.dist.xml b/phpdoc.dist.xml new file mode 100644 index 000000000..6dc58c259 --- /dev/null +++ b/phpdoc.dist.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<phpdoc> + <title>CodeIgniter v3.0.0 API</title> + <parser> + <target>./api/</target> + </parser> + <transformer> + <target>./api/</target> + </transformer> + <files> + <directory>./system</directory> + </files> + + <logging> + <level>warn</level> + <paths> + <default>./api/log/{DATE}.log</default> + <errors>./api/{DATE}.errors.log</errors> + </paths> + </logging> +</phpdoc>
\ No newline at end of file diff --git a/readme.rst b/readme.rst index 4707847c7..8628645c6 100644 --- a/readme.rst +++ b/readme.rst @@ -38,138 +38,6 @@ Installation Please see the `installation section <http://codeigniter.com/user_guide/installation/index.html>`_ of the CodeIgniter User Guide. -************ -Contributing -************ - -CodeIgniter is a community driven project and accepts contributions of code -and documentation from the community. These contributions are made in the form -of Issues or `Pull Requests <http://help.github.com/send-pull-requests/>`_ on -the `EllisLab CodeIgniter repository -<https://github.com/EllisLab/CodeIgniter>`_ on GitHub. - -Issues are a quick way to point out a bug. If you find a bug or documentation -error in CodeIgniter then please check a few things first: - -- There is not already an open Issue -- The issue has already been fixed (check the develop branch, or look for - closed Issues) -- Is it something really obvious that you fix it yourself? - -Reporting issues is helpful but an even better approach is to send a Pull -Request, which is done by "Forking" the main repository and committing to your -own copy. This will require you to use the version control system called Git. - -********** -Guidelines -********** - -Before we look into how, here are the guidelines. If your Pull Requests fail -to pass these guidelines it will be declined and you will need to re-submit -when you’ve made the changes. This might sound a bit tough, but it is required -for us to maintain quality of the code-base. - -PHP Style -========= - -All code must meet the `Style Guide -<http://codeigniter.com/user_guide/general/styleguide.html>`_, which is -essentially the `Allman indent style -<http://en.wikipedia.org/wiki/Indent_style#Allman_style>`_, underscores and -readable operators. This makes certain that all code is the same format as the -existing code and means it will be as readable as possible. - -Documentation -============= - -If you change anything that requires a change to documentation then you will -need to add it. New classes, methods, parameters, changing default values, etc -are all things that will require a change to documentation. The change-log -must also be updated for every change. Also PHPDoc blocks must be maintained. - -Compatibility -============= - -CodeIgniter is compatible with PHP 5.2.4 so all code supplied must stick to -this requirement. If PHP 5.3 or 5.4 functions or features are used then there -must be a fallback for PHP 5.2.4. - -Branching -========= - -CodeIgniter uses the `Git-Flow -<http://nvie.com/posts/a-successful-git-branching-model/>`_ branching model -which requires all pull requests to be sent to the "develop" branch. This is -where the next planned version will be developed. The "master" branch will -always contain the latest stable version and is kept clean so a "hotfix" (e.g: -an emergency security patch) can be applied to master to create a new version, -without worrying about other features holding it up. For this reason all -commits need to be made to "develop" and any sent to "master" will be closed -automatically. If you have multiple changes to submit, please place all -changes into their own branch on your fork. - -One thing at a time: A pull request should only contain one change. That does -not mean only one commit, but one change - however many commits it took. The -reason for this is that if you change X and Y but send a pull request for both -at the same time, we might really want X but disagree with Y, meaning we -cannot merge the request. Using the Git-Flow branching model you can create -new branches for both of these features and send two requests. - -************ -How-to Guide -************ - -There are two ways to make changes, the easy way and the hard way. Either way -you will need to `create a GitHub account <https://github.com/signup/free>`_. - -Easy way GitHub allows in-line editing of files for making simple typo changes -and quick-fixes. This is not the best way as you are unable to test the code -works. If you do this you could be introducing syntax errors, etc, but for a -Git-phobic user this is good for a quick-fix. - -Hard way The best way to contribute is to "clone" your fork of CodeIgniter to -your development area. That sounds like some jargon, but "forking" on GitHub -means "making a copy of that repo to your account" and "cloning" means -"copying that code to your environment so you can work on it". - -#. Set up Git (Windows, Mac & Linux) -#. Go to the CodeIgniter repo -#. Fork it -#. Clone your CodeIgniter repo: git@github.com:<your-name>/CodeIgniter.git -#. Checkout the "develop" branch At this point you are ready to start making - changes. -#. Fix existing bugs on the Issue tracker after taking a look to see nobody - else is working on them. -#. Commit the files -#. Push your develop branch to your fork -#. Send a pull request http://help.github.com/send-pull-requests/ - -The Reactor Engineers will now be alerted about the change and at least one of -the team will respond. If your change fails to meet the guidelines it will be -bounced, or feedback will be provided to help you improve it. - -Once the Reactor Engineer handling your pull request is happy with it they -will post it to the internal EllisLab discussion area to be double checked by -the other Engineers and EllisLab developers. If nobody has a problem with the -change then it will be merged into develop and will be part of the next -release. Keeping your fork up-to-date - -Unlike systems like Subversion, Git can have multiple remotes. A remote is the -name for a URL of a Git repository. By default your fork will have a remote -named "origin" which points to your fork, but you can add another remote named -"codeigniter" which points to git://github.com/EllisLab/CodeIgniter.git. This -is a read-only remote but you can pull from this develop branch to update your -own. - -If you are using command-line you can do the following: - -#. git remote add codeigniter git://github.com/EllisLab/CodeIgniter.git -#. git pull codeigniter develop -#. git push origin develop - -Now your fork is up to date. This should be done regularly, or before you send -a pull request at least. - ******* License ******* @@ -183,8 +51,6 @@ Resources - `User Guide <http://codeigniter.com/user_guide/>`_ - `Community Forums <http://codeigniter.com/forums/>`_ -- `User - Voice <http://codeigniter.uservoice.com/forums/40508-codeigniter-reactor>`_ - `Community Wiki <http://codeigniter.com/wiki/>`_ - `Community IRC <http://codeigniter.com/irc/>`_ diff --git a/system/.htaccess b/system/.htaccess index 14249c50b..6c63ed4c4 100644 --- a/system/.htaccess +++ b/system/.htaccess @@ -1 +1,6 @@ -Deny from all
\ No newline at end of file +<IfModule authz_core_module> + Require all denied +</IfModule> +<IfModule !authz_core_module> + Deny from all +</IfModule>
\ No newline at end of file diff --git a/system/core/Benchmark.php b/system/core/Benchmark.php index f6b634deb..e80ee54dd 100755..100644 --- a/system/core/Benchmark.php +++ b/system/core/Benchmark.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,14 +24,13 @@ * @since Version 1.0 * @filesource */ - -// ------------------------------------------------------------------------ +defined('BASEPATH') OR exit('No direct script access allowed'); /** - * CodeIgniter Benchmark Class + * Benchmark Class * * This class enables you to mark points and calculate the time difference - * between them. Memory consumption can also be displayed. + * between them. Memory consumption can also be displayed. * * @package CodeIgniter * @subpackage Libraries @@ -42,31 +41,31 @@ class CI_Benchmark { /** - * List of all benchmark markers and when they were added + * List of all benchmark markers * - * @var array + * @var array */ public $marker = array(); - // -------------------------------------------------------------------- - /** * Set a benchmark marker * * Multiple calls to this function can be made so that several - * execution points can be timed + * execution points can be timed. * - * @param string $name name of the marker + * @param string $name Marker name * @return void */ public function mark($name) { - $this->marker[$name] = microtime(); + $this->marker[$name] = microtime(TRUE); } // -------------------------------------------------------------------- /** + * Elapsed time + * * Calculates the time difference between two marked points. * * If the first parameter is empty this function instead returns the @@ -74,14 +73,17 @@ class CI_Benchmark { * execution time to be shown in a template. The output class will * swap the real value for this variable. * - * @param string a particular marked point - * @param string a particular marked point - * @param integer the number of decimal places - * @return mixed + * @param string $point1 A particular marked point + * @param string $point2 A particular marked point + * @param int $decimals Number of decimal places + * + * @return string Calculated elapsed time on success, + * an '{elapsed_string}' if $point1 is empty + * or an empty string if $point1 is not found. */ public function elapsed_time($point1 = '', $point2 = '', $decimals = 4) { - if ($point1 == '') + if ($point1 === '') { return '{elapsed_time}'; } @@ -93,13 +95,10 @@ class CI_Benchmark { if ( ! isset($this->marker[$point2])) { - $this->marker[$point2] = microtime(); + $this->marker[$point2] = microtime(TRUE); } - list($sm, $ss) = explode(' ', $this->marker[$point1]); - list($em, $es) = explode(' ', $this->marker[$point2]); - - return number_format(($em + $es) - ($sm + $ss), $decimals); + return number_format($this->marker[$point2] - $this->marker[$point1], $decimals); } // -------------------------------------------------------------------- @@ -107,12 +106,13 @@ class CI_Benchmark { /** * Memory Usage * - * This function returns the {memory_usage} pseudo-variable. + * Simply returns the {memory_usage} marker. + * * 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. * - * @return string + * @return string '{memory_usage}' */ public function memory_usage() { @@ -122,4 +122,4 @@ class CI_Benchmark { } /* End of file Benchmark.php */ -/* Location: ./system/core/Benchmark.php */ +/* Location: ./system/core/Benchmark.php */
\ No newline at end of file diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php index 4885f310c..89081b572 100755..100644 --- a/system/core/CodeIgniter.php +++ b/system/core/CodeIgniter.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,8 +24,7 @@ * @since Version 1.0 * @filesource */ - -// ------------------------------------------------------------------------ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * System Initialization File @@ -33,7 +32,7 @@ * Loads the base classes and executes the request. * * @package CodeIgniter - * @subpackage codeigniter + * @subpackage CodeIgniter * @category Front-controller * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/ @@ -42,7 +41,7 @@ /** * CodeIgniter Version * - * @var string + * @var string * */ define('CI_VERSION', '3.0-dev'); @@ -52,7 +51,7 @@ * Load the global functions * ------------------------------------------------------ */ - require(BASEPATH.'core/Common.php'); + require_once(BASEPATH.'core/Common.php'); /* * ------------------------------------------------------ @@ -75,9 +74,9 @@ */ set_error_handler('_exception_handler'); - if ( ! is_php('5.3')) + if ( ! is_php('5.4')) { - @set_magic_quotes_runtime(0); // Kill magic quotes + @ini_set('magic_quotes_runtime', 0); // Kill magic quotes } /* @@ -96,24 +95,13 @@ * Note: Since the config file data is cached it doesn't * hurt to load it here. */ - if (isset($assign_to_config['subclass_prefix']) && $assign_to_config['subclass_prefix'] != '') + if ( ! empty($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') && @ini_get('safe_mode') == 0 - && php_sapi_name() !== 'cli') // Do not override the Time Limit value if running from Command Line - { - @set_time_limit(300); - } - -/* - * ------------------------------------------------------ * Start the timer... tick tock tick tock... * ------------------------------------------------------ */ @@ -143,9 +131,12 @@ $CFG =& load_class('Config', 'core'); // Do we have any manually set config items in the index.php file? - if (isset($assign_to_config)) + if (isset($assign_to_config) && is_array($assign_to_config)) { - $CFG->_assign_to_config($assign_to_config); + foreach ($assign_to_config as $key => $value) + { + $CFG->set_item($key, $value); + } } /* @@ -155,7 +146,7 @@ * * 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 + * properly determine if UTF-8 can be supported until * after the Config class is instantiated. * */ @@ -195,7 +186,7 @@ * ------------------------------------------------------ */ if ($EXT->call_hook('cache_override') === FALSE - && $OUT->_display_cache($CFG, $URI) == TRUE) + && $OUT->_display_cache($CFG, $URI) === TRUE) { exit; } @@ -230,12 +221,18 @@ // Load the base controller class require BASEPATH.'core/Controller.php'; + /** + * Reference to the CI_Controller method. + * + * Returns current CI instance object + * + * @return object + */ 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'; @@ -259,28 +256,27 @@ * Security check * ------------------------------------------------------ * - * None of the functions in the app controller or the + * None of the methods in the app controller or the * loader class can be called via the URI, nor can - * controller functions that begin with an underscore + * controller functions that begin with an underscore. */ $class = $RTR->fetch_class(); $method = $RTR->fetch_method(); - if ( ! class_exists($class) - OR strpos($method, '_') === 0 - OR in_array(strtolower($method), array_map('strtolower', get_class_methods('CI_Controller'))) - ) + if ( ! class_exists($class) OR $method[0] === '_' OR method_exists('CI_Controller', $method)) { if ( ! empty($RTR->routes['404_override'])) { - $x = explode('/', $RTR->routes['404_override'], 2); - $class = $x[0]; - $method = (isset($x[1]) ? $x[1] : 'index'); + if (sscanf($RTR->routes['404_override'], '%[^/]/%s', $class, $method) !== 2) + { + $method = 'index'; + } + if ( ! class_exists($class)) { if ( ! file_exists(APPPATH.'controllers/'.$class.'.php')) { - show_404("{$class}/{$method}"); + show_404($class.'/'.$method); } include_once(APPPATH.'controllers/'.$class.'.php'); @@ -288,10 +284,46 @@ } else { - show_404("{$class}/{$method}"); + show_404($class.'/'.$method); } } + if (method_exists($class, '_remap')) + { + $params = array($method, array_slice($URI->rsegments, 2)); + $method = '_remap'; + } + else + { + // WARNING: It appears that there are issues with is_callable() even in PHP 5.2! + // Furthermore, there are bug reports and feature/change requests related to it + // that make it unreliable to use in this context. Please, DO NOT change this + // work-around until a better alternative is available. + if ( ! in_array(strtolower($method), array_map('strtolower', get_class_methods($class)), TRUE)) + { + if (empty($RTR->routes['404_override'])) + { + show_404($class.'/'.$method); + } + elseif (sscanf($RTR->routes['404_override'], '%[^/]/%s', $class, $method) !== 2) + { + $method = 'index'; + } + + if ( ! class_exists($class)) + { + if ( ! file_exists(APPPATH.'controllers/'.$class.'.php')) + { + show_404($class.'/'.$method); + } + + include_once(APPPATH.'controllers/'.$class.'.php'); + } + } + + $params = array_slice($URI->rsegments, 2); + } + /* * ------------------------------------------------------ * Is there a "pre_controller" hook? @@ -321,45 +353,7 @@ * 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'], 2); - $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)); - } + call_user_func_array(array(&$CI, $method), $params); // Mark a benchmark end point $BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end'); @@ -388,15 +382,5 @@ */ $EXT->call_hook('post_system'); -/* - * ------------------------------------------------------ - * Close the DB connection if one exists - * ------------------------------------------------------ - */ - if (class_exists('CI_DB') && isset($CI->db)) - { - $CI->db->close(); - } - /* End of file CodeIgniter.php */ -/* Location: ./system/core/CodeIgniter.php */ +/* Location: ./system/core/CodeIgniter.php */
\ No newline at end of file diff --git a/system/core/Common.php b/system/core/Common.php index aeb784bbe..7feb16bfd 100644 --- a/system/core/Common.php +++ b/system/core/Common.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Common Functions @@ -31,7 +32,7 @@ * Loads the base classes and executes the request. * * @package CodeIgniter - * @subpackage codeigniter + * @subpackage CodeIgniter * @category Common Functions * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/ @@ -39,25 +40,25 @@ // ------------------------------------------------------------------------ -/** - * 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. - * - * @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') + /** + * 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.3 + * we'll set a static variable. + * + * @param string + * @return bool TRUE if the current version is $version or higher + */ + function is_php($version = '5.3.0') { static $_is_php; $version = (string) $version; if ( ! isset($_is_php[$version])) { - $_is_php[$version] = (version_compare(PHP_VERSION, $version) < 0) ? FALSE : TRUE; + $_is_php[$version] = (version_compare(PHP_VERSION, $version) >= 0); } return $_is_php[$version]; @@ -66,18 +67,18 @@ if ( ! function_exists('is_php')) // ------------------------------------------------------------------------ -/** - * 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. - * - * @param string - * @return void - */ if ( ! function_exists('is_really_writable')) { + /** + * 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. + * + * @param string + * @return void + */ function is_really_writable($file) { // If we're on a Unix server with safe_mode off we call is_writable @@ -114,20 +115,20 @@ if ( ! function_exists('is_really_writable')) // ------------------------------------------------------------------------ -/** - * 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. - * - * @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')) { + /** + * 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. + * + * @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 + */ function &load_class($class, $directory = 'libraries', $prefix = 'CI_') { static $_classes = array(); @@ -150,7 +151,7 @@ if ( ! function_exists('load_class')) if (class_exists($name) === FALSE) { - require($path.$directory.'/'.$class.'.php'); + require_once($path.$directory.'/'.$class.'.php'); } break; @@ -164,7 +165,7 @@ if ( ! function_exists('load_class')) if (class_exists($name) === FALSE) { - require(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php'); + require_once(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php'); } } @@ -172,7 +173,7 @@ if ( ! function_exists('load_class')) if ($name === FALSE) { // Note: We use exit() rather then show_error() in order to avoid a - // self-referencing loop with the Excptions class + // self-referencing loop with the Exceptions class set_status_header(503); exit('Unable to locate the specified class: '.$class.'.php'); } @@ -187,20 +188,20 @@ if ( ! function_exists('load_class')) // -------------------------------------------------------------------- -/** - * Keeps track of which libraries have been loaded. This function is - * called by the load_class() function above - * - * @param string - * @return array - */ if ( ! function_exists('is_loaded')) { + /** + * Keeps track of which libraries have been loaded. This function is + * called by the load_class() function above + * + * @param string + * @return array + */ function &is_loaded($class = '') { static $_is_loaded = array(); - if ($class != '') + if ($class !== '') { $_is_loaded[strtolower($class)] = $class; } @@ -211,17 +212,17 @@ if ( ! function_exists('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 - * - * @param array - * @return array - */ if ( ! function_exists('get_config')) { + /** + * Loads the main config.php file + * + * This function lets us grab the config file even if the Config class + * hasn't been instantiated yet + * + * @param array + * @return array + */ function &get_config($replace = array()) { static $_config; @@ -231,21 +232,25 @@ if ( ! function_exists('get_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'; + $found = FALSE; + if (file_exists($file_path)) { - $file_path = APPPATH.'config/config.php'; + $found = TRUE; + require($file_path); } - // Fetch the config file - if ( ! file_exists($file_path)) + // Is the config file in the environment folder? + if (defined('ENVIRONMENT') && file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php')) + { + require($file_path); + } + elseif ( ! $found) { set_status_header(503); 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)) { @@ -271,14 +276,14 @@ if ( ! function_exists('get_config')) // ------------------------------------------------------------------------ -/** - * Returns the specified config item - * - * @param string - * @return mixed - */ if ( ! function_exists('config_item')) { + /** + * Returns the specified config item + * + * @param string + * @return mixed + */ function config_item($item) { static $_config_item = array(); @@ -300,22 +305,66 @@ if ( ! function_exists('config_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. - * - * @param string - * @param int - * @param string - * @return void - */ +if ( ! function_exists('get_mimes')) +{ + /** + * Returns the MIME types array from config/mimes.php + * + * @return array + */ + function &get_mimes() + { + static $_mimes = array(); + + if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php')) + { + $_mimes = include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'); + } + elseif (is_file(APPPATH.'config/mimes.php')) + { + $_mimes = include(APPPATH.'config/mimes.php'); + } + + return $_mimes; + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('is_https')) +{ + /** + * Is HTTPS? + * + * Determines if the application is accessed via an encrypted + * (HTTPS) connection. + * + * @return bool + */ + function is_https() + { + return ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off'); + } +} + +// ------------------------------------------------------------------------ + if ( ! function_exists('show_error')) { + /** + * 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. + * + * @param string + * @param int + * @param string + * @return void + */ function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered') { $_error =& load_class('Exceptions', 'core'); @@ -326,19 +375,19 @@ if ( ! function_exists('show_error')) // ------------------------------------------------------------------------ -/** - * 404 Page Handler - * - * This function is similar to the show_error() function above - * However, instead of the standard error template it displays - * 404 errors. - * - * @param string - * @param bool - * @return void - */ if ( ! function_exists('show_404')) { + /** + * 404 Page Handler + * + * This function is similar to the show_error() function above + * However, instead of the standard error template it displays + * 404 errors. + * + * @param string + * @param bool + * @return void + */ function show_404($page = '', $log_error = TRUE) { $_error =& load_class('Exceptions', 'core'); @@ -349,102 +398,107 @@ if ( ! function_exists('show_404')) // ------------------------------------------------------------------------ -/** - * Error Logging Interface - * - * We use this as a simple mechanism to access the logging - * class and send messages to be logged. - * - * @param string - * @param string - * @param bool - * @return void - */ if ( ! function_exists('log_message')) { + /** + * Error Logging Interface + * + * We use this as a simple mechanism to access the logging + * class and send messages to be logged. + * + * @param string + * @param string + * @param bool + * @return void + */ function log_message($level = 'error', $message, $php_error = FALSE) { static $_log; - if (config_item('log_threshold') == 0) + if (config_item('log_threshold') === 0) { return; } - $_log =& load_class('Log'); + $_log =& load_class('Log', 'core'); $_log->write_log($level, $message, $php_error); } } // ------------------------------------------------------------------------ -/** - * Set HTTP Status Header - * - * @param int the status code - * @param string - * @return void - */ if ( ! function_exists('set_status_header')) { + /** + * Set HTTP Status Header + * + * @param int the status code + * @param string + * @return void + */ function set_status_header($code = 200, $text = '') { $stati = array( - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - - 400 => 'Bad Request', - 401 => 'Unauthorized', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 422 => 'Unprocessable Entity', - - 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)) + 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', + 303 => 'See Other', + 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', + 422 => 'Unprocessable Entity', + + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported' + ); + + if (empty($code) OR ! is_numeric($code)) { show_error('Status codes must be numeric', 500); } - if (isset($stati[$code]) && $text == '') - { - $text = $stati[$code]; - } + is_int($code) OR $code = (int) $code; - if ($text == '') + if (empty($text)) { - show_error('No status text available. Please check your status code number or supply your own message text.', 500); + if (isset($stati[$code])) + { + $text = $stati[$code]; + } + else + { + 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; @@ -453,63 +507,49 @@ if ( ! function_exists('set_status_header')) { header('Status: '.$code.' '.$text, TRUE); } - elseif ($server_protocol === 'HTTP/1.0') - { - header('HTTP/1.0 '.$code.' '.$text, TRUE, $code); - } else { - header('HTTP/1.1 '.$code.' '.$text, TRUE, $code); + header(($server_protocol ? $server_protocol : '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. - * - * @param int - * @param string - * @param string - * @param int - * @return void - */ if ( ! function_exists('_exception_handler')) { + /** + * 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. + * + * @param int + * @param string + * @param string + * @param int + * @return void + */ 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 + // Should we ignore 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) + if (($severity & error_reporting()) !== $severity) { - $_error->show_php_error($severity, $message, $filepath, $line); + return; } - // Should we log the error? No? We're done... - if (config_item('log_threshold') == 0) + // Should we display the error? + if ((bool) ini_get('display_errors') === TRUE) { - return; + $_error->show_php_error($severity, $message, $filepath, $line); } $_error->log_exception($severity, $message, $filepath, $line); @@ -518,18 +558,18 @@ if ( ! function_exists('_exception_handler')) // -------------------------------------------------------------------- -/** - * Remove Invisible Characters - * - * This prevents sandwiching null characters - * between ascii characters, like Java\0script. - * - * @param string - * @param bool - * @return string - */ if ( ! function_exists('remove_invisible_characters')) { + /** + * Remove Invisible Characters + * + * This prevents sandwiching null characters + * between ascii characters, like Java\0script. + * + * @param string + * @param bool + * @return string + */ function remove_invisible_characters($str, $url_encoded = TRUE) { $non_displayables = array(); @@ -556,14 +596,14 @@ if ( ! function_exists('remove_invisible_characters')) // ------------------------------------------------------------------------ -/** - * Returns HTML escaped variable - * - * @param mixed - * @return mixed - */ if ( ! function_exists('html_escape')) { + /** + * Returns HTML escaped variable + * + * @param mixed + * @return mixed + */ function html_escape($var) { return is_array($var) @@ -572,5 +612,91 @@ if ( ! function_exists('html_escape')) } } +// ------------------------------------------------------------------------ + +if ( ! function_exists('_stringify_attributes')) +{ + /** + * Stringify attributes for use in HTML tags. + * + * Helper function used to convert a string, array, or object + * of attributes to a string. + * + * @param mixed string, array, object + * @param bool + * @return string + */ + function _stringify_attributes($attributes, $js = FALSE) + { + $atts = NULL; + + if (empty($attributes)) + { + return $atts; + } + + if (is_string($attributes)) + { + return ' '.$attributes; + } + + $attributes = (array) $attributes; + + foreach ($attributes as $key => $val) + { + $atts .= ($js) ? $key.'='.$val.',' : ' '.$key.'="'.$val.'"'; + } + + return rtrim($atts, ','); + } +} + +// ------------------------------------------------------------------------ + +if ( ! function_exists('function_usable')) +{ + /** + * Function usable + * + * Executes a function_exists() check, and if the Suhosin PHP + * extension is loaded - checks whether the function that is + * checked might be disabled in there as well. + * + * This is useful as function_exists() will return FALSE for + * functions disabled via the *disable_functions* php.ini + * setting, but not for *suhosin.executor.func.blacklist* and + * *suhosin.executor.disable_eval*. These settings will just + * terminate script execution if a disabled function is executed. + * + * @link http://www.hardened-php.net/suhosin/ + * @param string $function_name Function to check for + * @return bool TRUE if the function exists and is safe to call, + * FALSE otherwise. + */ + function function_usable($function_name) + { + static $_suhosin_func_blacklist; + + if (function_exists($function_name)) + { + if ( ! isset($_suhosin_func_blacklist)) + { + $_suhosin_func_blacklist = extension_loaded('suhosin') + ? array() + : explode(',', trim(@ini_get('suhosin.executor.func.blacklist'))); + + if ( ! in_array('eval', $_suhosin_func_blacklist, TRUE) && @ini_get('suhosin.executor.disable_eval')) + { + $_suhosin_func_blacklist[] = 'eval'; + } + } + + return in_array($function_name, $_suhosin_func_blacklist, TRUE); + } + + return FALSE; + } +} + /* End of file Common.php */ /* Location: ./system/core/Common.php */
\ No newline at end of file diff --git a/system/core/Config.php b/system/core/Config.php index 91826bd41..8250b5b1a 100755..100644 --- a/system/core/Config.php +++ b/system/core/Config.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,11 +24,10 @@ * @since Version 1.0 * @filesource */ - -// ------------------------------------------------------------------------ +defined('BASEPATH') OR exit('No direct script access allowed'); /** - * CodeIgniter Config Class + * Config Class * * This class contains functions that enable config files to be managed * @@ -43,32 +42,31 @@ class CI_Config { /** * List of all loaded config values * - * @var array + * @var array */ public $config = array(); + /** * List of all loaded config files * - * @var array + * @var array */ - public $is_loaded = array(); + public $is_loaded = array(); + /** * List of paths to search when trying to load a config file. - * This must be public as it's used by the Loader class. * - * @var array + * @used-by CI_Loader + * @var array */ - public $_config_paths = array(APPPATH); + public $_config_paths = array(APPPATH); /** - * Constructor + * Class constructor * - * Sets the $config data from the primary config.php file as a class variable + * Sets the $config data from the primary config.php file as a class variable. * - * @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 + * @return void */ public function __construct() { @@ -80,9 +78,9 @@ class CI_Config { { if (isset($_SERVER['HTTP_HOST'])) { - $base_url = ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http'; - $base_url .= '://'. $_SERVER['HTTP_HOST'] - . str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']); + $base_url = is_https() ? 'https' : 'http'; + $base_url .= '://'.$_SERVER['HTTP_HOST'] + .str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']); } else { @@ -98,22 +96,22 @@ class CI_Config { /** * Load Config File * - * @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 + * @param string $file Configuration file name + * @param bool $use_sections Whether configuration values should be loaded into their own section + * @param bool $fail_gracefully Whether to just return FALSE or display an error message + * @return bool TRUE if the file was loaded correctly or FALSE on failure */ public function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) { - $file = ($file == '') ? 'config' : str_replace('.php', '', $file); + $file = ($file === '') ? 'config' : str_replace('.php', '', $file); $found = $loaded = FALSE; + $check_locations = defined('ENVIRONMENT') + ? array(ENVIRONMENT.'/'.$file, $file) + : array($file); + foreach ($this->_config_paths as $path) { - $check_locations = defined('ENVIRONMENT') - ? array(ENVIRONMENT.'/'.$file, $file) - : array($file); - foreach ($check_locations as $location) { $file_path = $path.'config/'.$location.'.php'; @@ -177,7 +175,7 @@ class CI_Config { { return FALSE; } - show_error('The configuration file '.$file.'.php'.' does not exist.'); + show_error('The configuration file '.$file.'.php does not exist.'); } return TRUE; @@ -188,11 +186,9 @@ class CI_Config { /** * Fetch a config file item * - * - * @param string the config item name - * @param string the index name - * @param bool - * @return string + * @param string $item Config item name + * @param string $index Index name + * @return string|bool The configuration item or FALSE on failure */ public function item($item, $index = '') { @@ -207,11 +203,10 @@ class CI_Config { // -------------------------------------------------------------------- /** - * Fetch a config file item - adds slash after item (if item is not empty) + * Fetch a config file item with slash appended (if not empty) * - * @param string the config item name - * @param bool - * @return string + * @param string $item Config item name + * @return string|bool The configuration item or FALSE on failure */ public function slash_item($item) { @@ -219,7 +214,7 @@ class CI_Config { { return FALSE; } - elseif (trim($this->config[$item]) == '') + elseif (trim($this->config[$item]) === '') { return ''; } @@ -231,54 +226,77 @@ class CI_Config { /** * Site URL + * * Returns base_url . index_page [. uri_string] * - * @param string the URI string + * @uses CI_Config::_uri_string() + * + * @param string|string[] $uri URI string or an array of segments * @return string */ public function site_url($uri = '') { - if ($uri == '') + if (empty($uri)) { return $this->slash_item('base_url').$this->item('index_page'); } - if ($this->item('enable_query_strings') == FALSE) + $uri = $this->_uri_string($uri); + + 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; + $suffix = ($this->item('url_suffix') === FALSE) ? '' : $this->item('url_suffix'); + + if ($suffix !== '' && ($offset = strpos($uri, '?')) !== FALSE) + { + $uri = substr($uri, 0, $offset).$suffix.substr($uri, $offset); + } + else + { + $uri .= $suffix; + } + + return $this->slash_item('base_url').$this->slash_item('index_page').$uri; } - else + elseif (strpos($uri, '?') === FALSE) { - return $this->slash_item('base_url').$this->item('index_page').'?'.$this->_uri_string($uri); + $uri = '?'.$uri; } + + return $this->slash_item('base_url').$this->item('index_page').$uri; } // ------------------------------------------------------------- /** * Base URL + * * Returns base_url [. uri_string] * - * @param string $uri - * @return string + * @uses CI_Config::_uri_string() + * + * @param string|string[] $uri URI string or an array of segments + * @return string */ public function base_url($uri = '') { - return $this->slash_item('base_url').ltrim($this->_uri_string($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() + * Build URI string * - * @param mixed $uri - * @return string + * @used-by CI_Config::site_url() + * @used-by CI_Config::base_url() + * + * @param string|string[] $uri URI string or an array of segments + * @return string */ protected function _uri_string($uri) { - if ($this->item('enable_query_strings') == FALSE) + if ($this->item('enable_query_strings') === FALSE) { if (is_array($uri)) { @@ -288,15 +306,7 @@ class CI_Config { } elseif (is_array($uri)) { - $i = 0; - $str = ''; - foreach ($uri as $key => $val) - { - $prefix = ($i === 0) ? '' : '&'; - $str .= $prefix.$key.'='.$val; - $i++; - } - return $str; + return http_build_query($uri); } return $uri; @@ -320,8 +330,8 @@ class CI_Config { /** * Set a config file item * - * @param string the config item key - * @param string the config item value + * @param string $item Config item key + * @param string $value Config item value * @return void */ public function set_item($item, $value) @@ -329,29 +339,7 @@ class CI_Config { $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 - * - * @param array - * @return void - */ - public function _assign_to_config($items = array()) - { - if (is_array($items)) - { - foreach ($items as $key => $val) - { - $this->set_item($key, $val); - } - } - } } /* End of file Config.php */ -/* Location: ./system/core/Config.php */ +/* Location: ./system/core/Config.php */
\ No newline at end of file diff --git a/system/core/Controller.php b/system/core/Controller.php index 05e1bf5bf..ee6fec8d5 100644 --- a/system/core/Controller.php +++ b/system/core/Controller.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,11 +24,10 @@ * @since Version 1.0 * @filesource */ - -// ------------------------------------------------------------------------ +defined('BASEPATH') OR exit('No direct script access allowed'); /** - * CodeIgniter Application Controller Class + * Application Controller Class * * This class object is the super class that every library in * CodeIgniter will be assigned to. @@ -41,8 +40,18 @@ */ class CI_Controller { + /** + * Reference to the CI singleton + * + * @var object + */ private static $instance; + /** + * Class constructor + * + * @return void + */ public function __construct() { self::$instance =& $this; @@ -60,11 +69,20 @@ class CI_Controller { log_message('debug', 'Controller Class Initialized'); } + // -------------------------------------------------------------------- + + /** + * Get the CI singleton + * + * @static + * @return object + */ public static function &get_instance() { return self::$instance; } + } /* End of file Controller.php */ -/* Location: ./system/core/Controller.php */ +/* Location: ./system/core/Controller.php */
\ No newline at end of file diff --git a/system/core/Exceptions.php b/system/core/Exceptions.php index f36b31598..ced65ece4 100755..100644 --- a/system/core/Exceptions.php +++ b/system/core/Exceptions.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Exceptions Class @@ -36,39 +37,38 @@ */ class CI_Exceptions { - public $action; - public $severity; - public $message; - public $filename; - public $line; - /** * Nesting level of the output buffering mechanism * - * @var int + * @var int */ public $ob_level; /** * List if available error levels * - * @var array + * @var array */ public $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' - ); + 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' + ); + /** + * Class constructor + * + * @return void + */ public function __construct() { $this->ob_level = ob_get_level(); @@ -80,28 +80,30 @@ class CI_Exceptions { /** * Exception Logger * - * This function logs PHP generated error messages + * Logs PHP generated error messages * - * @param string the error severity - * @param string the error string - * @param string the error filepath - * @param string the error line number + * @param int $severity Log level + * @param string $message Error message + * @param string $filepath File path + * @param int $line Line number * @return void */ public function log_exception($severity, $message, $filepath, $line) { - $severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity]; + $severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity; log_message('error', 'Severity: '.$severity.' --> '.$message. ' '.$filepath.' '.$line, TRUE); } // -------------------------------------------------------------------- /** - * 404 Page Not Found Handler + * 404 Error Handler + * + * @uses CI_Exceptions::show_error() * - * @param string the page - * @param bool log error yes/no - * @return string + * @param string $page Page URI + * @param bool $log_error Whether to log the error + * @return void */ public function show_404($page = '', $log_error = TRUE) { @@ -123,28 +125,28 @@ class CI_Exceptions { /** * 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. + * Takes an error message as input (either as a string or an array) + * and displays it using the specified template. + * + * @param string $heading Page heading + * @param string|string[] $message Error message + * @param string $template Template name + * @param int $status_code (default: 500) * - * @param string the heading - * @param string the message - * @param string the template name - * @param int the status code - * @return string + * @return string Error page output */ public 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>'; + $message = '<p>'.implode('</p><p>', is_array($message) ? $message : array($message)).'</p>'; if (ob_get_level() > $this->ob_level + 1) { ob_end_flush(); } ob_start(); - include(APPPATH.'errors/'.$template.'.php'); + include(VIEWPATH.'errors/'.$template.'.php'); $buffer = ob_get_contents(); ob_end_clean(); return $buffer; @@ -155,15 +157,15 @@ class CI_Exceptions { /** * Native PHP error handler * - * @param string the error severity - * @param string the error string - * @param string the error filepath - * @param string the error line number - * @return string + * @param int $severity Error level + * @param string $message Error message + * @param string $filepath File path + * @param int $line Line number + * @return string Error page output */ public function show_php_error($severity, $message, $filepath, $line) { - $severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity]; + $severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity; $filepath = str_replace('\\', '/', $filepath); // For safety reasons we do not show the full file path @@ -178,7 +180,7 @@ class CI_Exceptions { ob_end_flush(); } ob_start(); - include(APPPATH.'errors/'.'error_php.php'); + include(VIEWPATH.'errors/error_php.php'); $buffer = ob_get_contents(); ob_end_clean(); echo $buffer; diff --git a/system/core/Hooks.php b/system/core/Hooks.php index 68e30ef0f..3c28ec9ba 100755..100644 --- a/system/core/Hooks.php +++ b/system/core/Hooks.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,9 +24,10 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** - * CodeIgniter Hooks Class + * Hooks Class * * Provides a mechanism to extend the base system without hacking. * @@ -39,26 +40,30 @@ class CI_Hooks { /** - * Determines wether hooks are enabled + * Determines whether hooks are enabled * - * @var bool + * @var bool */ - public $enabled = FALSE; + public $enabled = FALSE; + /** * List of all hooks set in config/hooks.php * - * @var array + * @var array */ - public $hooks = array(); + public $hooks = array(); + /** - * Determines wether hook is in progress, used to prevent infinte loops + * In progress flag + * + * Determines whether hook is in progress, used to prevent infinte loops * - * @var bool + * @var bool */ - public $in_progress = FALSE; + protected $_in_progress = FALSE; /** - * Initialize the Hooks Preferences + * Class constructor * * @return void */ @@ -70,7 +75,7 @@ class CI_Hooks { // If hooks are not enabled in the config file // there is nothing else to do - if ($CFG->item('enable_hooks') == FALSE) + if ($CFG->item('enable_hooks') === FALSE) { return; } @@ -102,8 +107,10 @@ class CI_Hooks { * * Calls a particular hook. Called by CodeIgniter.php. * - * @param string the hook name - * @return mixed + * @uses CI_Hooks::_run_hook() + * + * @param string $which Hook name + * @return bool TRUE on success or FALSE on failure */ public function call_hook($which = '') { @@ -134,8 +141,8 @@ class CI_Hooks { * * Runs a particular hook * - * @param array the hook details - * @return bool + * @param array $data Hook details + * @return bool TRUE on success or FALSE on failure */ protected function _run_hook($data) { @@ -150,7 +157,7 @@ class CI_Hooks { // If the script being called happens to have the same // hook call within it a loop can happen - if ($this->in_progress == TRUE) + if ($this->_in_progress === TRUE) { return; } @@ -171,44 +178,20 @@ class CI_Hooks { return FALSE; } - // ----------------------------------- - // Set class/function name - // ----------------------------------- - - $class = FALSE; - $function = FALSE; - $params = ''; - - if ( ! empty($data['class'])) - { - $class = $data['class']; - } - - if ( ! empty($data['function'])) - { - $function = $data['function']; - } - - if (isset($data['params'])) - { - $params = $data['params']; - } + // Determine and class and/or function names + $class = empty($data['class']) ? FALSE : $data['class']; + $function = empty($data['function']) ? FALSE : $data['function']; + $params = isset($data['params']) ? $data['params'] : ''; if ($class === FALSE && $function === FALSE) { return FALSE; } - // ----------------------------------- - // Set the in_progress flag - // ----------------------------------- - - $this->in_progress = TRUE; + // Set the _in_progress flag + $this->_in_progress = TRUE; - // ----------------------------------- // Call the requested class and/or function - // ----------------------------------- - if ($class !== FALSE) { if ( ! class_exists($class)) @@ -216,7 +199,7 @@ class CI_Hooks { require($filepath); } - $HOOK = new $class; + $HOOK = new $class(); $HOOK->$function($params); } else @@ -229,7 +212,7 @@ class CI_Hooks { $function($params); } - $this->in_progress = FALSE; + $this->_in_progress = FALSE; return TRUE; } diff --git a/system/core/Input.php b/system/core/Input.php index 6e6885992..4d73fa424 100755..100644 --- a/system/core/Input.php +++ b/system/core/Input.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Input Class @@ -41,53 +42,80 @@ class CI_Input { /** * IP address of the current user * - * @var string + * @var string */ - public $ip_address = FALSE; + public $ip_address = FALSE; + /** - * user agent (web browser) being used by the current user + * User agent strin * - * @var string + * @var string */ - public $user_agent = FALSE; + public $user_agent = FALSE; + /** - * If FALSE, then $_GET will be set to an empty array + * Allow GET array flag + * + * If set to FALSE, then $_GET will be set to an empty array. * - * @var bool + * @var bool */ - protected $_allow_get_array = TRUE; + protected $_allow_get_array = TRUE; + /** - * If TRUE, then newlines are standardized + * Standartize new lines flag + * + * If set to TRUE, then newlines are standardized. * - * @var bool + * @var bool */ - protected $_standardize_newlines = TRUE; + protected $_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 + * Enable XSS flag + * + * 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 bool */ - protected $_enable_xss = FALSE; + protected $_enable_xss = FALSE; + /** + * Enable CSRF flag + * * Enables a CSRF cookie token to be set. - * Set automatically based on config setting + * Set automatically based on config setting. * - * @var bool + * @var bool */ - protected $_enable_csrf = FALSE; + protected $_enable_csrf = FALSE; + /** * List of all HTTP request headers * * @var array */ - protected $headers = array(); + protected $headers = array(); /** - * Constructor + * Input stream data * - * Sets whether to globally enable the XSS processing - * and whether to allow the $_GET array + * Parsed from php://input at runtime + * + * @see CI_Input::input_stream() + * @var array + */ + protected $_input_stream = NULL; + + /** + * Class constructor + * + * Determines whether to globally enable the XSS processing + * and whether to allow the $_GET array. + * + * @return void */ public function __construct() { @@ -116,18 +144,18 @@ class CI_Input { /** * Fetch from array * - * This is a helper function to retrieve values from global arrays + * Internal method used to retrieve values from global arrays. * - * @param array - * @param string - * @param bool - * @return string + * @param array &$array $_GET, $_POST, $_COOKIE, $_SERVER, etc. + * @param string $index Index for item to be fetched from $array + * @param bool $xss_clean Whether to apply XSS filtering + * @return mixed */ protected function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE) { if ( ! isset($array[$index])) { - return FALSE; + return NULL; } if ($xss_clean === TRUE) @@ -141,12 +169,12 @@ class CI_Input { // -------------------------------------------------------------------- /** - * Fetch an item from the GET array - * - * @param string - * @param bool - * @return string - */ + * Fetch an item from the GET array + * + * @param string $index Index for item to be fetched from $_GET + * @param bool $xss_clean Whether to apply XSS filtering + * @return mixed + */ public function get($index = NULL, $xss_clean = FALSE) { // Check if a field has been provided @@ -168,12 +196,12 @@ class CI_Input { // -------------------------------------------------------------------- /** - * Fetch an item from the POST array - * - * @param string - * @param bool - * @return string - */ + * Fetch an item from the POST array + * + * @param string $index Index for item to be fetched from $_POST + * @param bool $xss_clean Whether to apply XSS filtering + * @return mixed + */ public function post($index = NULL, $xss_clean = FALSE) { // Check if a field has been provided @@ -192,16 +220,15 @@ class CI_Input { return $this->_fetch_from_array($_POST, $index, $xss_clean); } - // -------------------------------------------------------------------- /** - * Fetch an item from either the GET array or the POST - * - * @param string The index key - * @param bool XSS cleaning - * @return string - */ + * Fetch an item from POST data with fallback to GET + * + * @param string $index Index for item to be fetched from $_POST or $_GET + * @param bool $xss_clean Whether to apply XSS filtering + * @return mixed + */ public function get_post($index = '', $xss_clean = FALSE) { return isset($_POST[$index]) @@ -212,35 +239,80 @@ class CI_Input { // -------------------------------------------------------------------- /** - * Fetch an item from the COOKIE array - * - * @param string - * @param bool - * @return string - */ + * Fetch an item from the COOKIE array + * + * @param string $index Index for item to be fetched from $_COOKIE + * @param bool $xss_clean Whether to apply XSS filtering + * @return mixed + */ public function cookie($index = '', $xss_clean = FALSE) { return $this->_fetch_from_array($_COOKIE, $index, $xss_clean); } + // -------------------------------------------------------------------- + + /** + * Fetch an item from the SERVER array + * + * @param string $index Index for item to be fetched from $_SERVER + * @param bool $xss_clean Whether to apply XSS filtering + * @return mixed + */ + public function server($index = '', $xss_clean = FALSE) + { + return $this->_fetch_from_array($_SERVER, $index, $xss_clean); + } + // ------------------------------------------------------------------------ /** - * Set cookie - * - * Accepts seven parameters, or you can submit an associative - * array in the first parameter containing all the values. - * - * @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 - * @param bool true makes the cookie accessible via http(s) only (no javascript) - * @return void - */ + * Fetch an item from the php://input stream + * + * Useful when you need to access PUT, DELETE or PATCH request data. + * + * @param string $index Index for item to be fetched + * @param bool $xss_clean Whether to apply XSS filtering + * @return mixed + */ + public function input_stream($index = '', $xss_clean = FALSE) + { + // The input stream can only be read once, so we'll need to check + // if we have already done that first. + if (is_array($this->_input_stream)) + { + return $this->_fetch_from_array($this->_input_stream, $index, $xss_clean); + } + + // Parse the input stream in our cache var + parse_str(file_get_contents('php://input'), $this->_input_stream); + if ( ! is_array($this->_input_stream)) + { + $this->_input_stream = array(); + return NULL; + } + + return $this->_fetch_from_array($this->_input_stream, $index, $xss_clean); + } + + // ------------------------------------------------------------------------ + + /** + * Set cookie + * + * Accepts an arbitrary number of parameters (up to 7) or an associative + * array in the first parameter containing all the values. + * + * @param string|mixed[] $name Cookie name or an array containing parameters + * @param string $value Cookie value + * @param int $expire Cookie expiration time in seconds + * @param string $domain Cookie domain (e.g.: '.yourdomain.com') + * @param string $path Cookie path (default: '/') + * @param string $prefix Cookie name prefix + * @param bool $secure Whether to only transfer cookies via SSL + * @param bool $httponly Whether to only makes the cookie accessible via HTTP (no javascript) + * @return void + */ public function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE) { if (is_array($name)) @@ -255,23 +327,27 @@ class CI_Input { } } - if ($prefix == '' && config_item('cookie_prefix') != '') + if ($prefix === '' && config_item('cookie_prefix') !== '') { $prefix = config_item('cookie_prefix'); } + if ($domain == '' && config_item('cookie_domain') != '') { $domain = config_item('cookie_domain'); } - if ($path == '/' && config_item('cookie_path') !== '/') + + if ($path === '/' && config_item('cookie_path') !== '/') { $path = config_item('cookie_path'); } - if ($secure == FALSE && config_item('cookie_secure') != FALSE) + + if ($secure === FALSE && config_item('cookie_secure') !== FALSE) { $secure = config_item('cookie_secure'); } - if ($httponly == FALSE && config_item('cookie_httponly') != FALSE) + + if ($httponly === FALSE && config_item('cookie_httponly') !== FALSE) { $httponly = config_item('cookie_httponly'); } @@ -291,24 +367,12 @@ class CI_Input { // -------------------------------------------------------------------- /** - * Fetch an item from the SERVER array - * - * @param string - * @param bool - * @return string - */ - public function server($index = '', $xss_clean = FALSE) - { - return $this->_fetch_from_array($_SERVER, $index, $xss_clean); - } - - // -------------------------------------------------------------------- - - /** - * Fetch the IP Address - * - * @return string - */ + * Fetch the IP Address + * + * Determines and validates the visitor's IP address. + * + * @return string IP address + */ public function ip_address() { if ($this->ip_address !== FALSE) @@ -316,39 +380,117 @@ class CI_Input { return $this->ip_address; } - if (config_item('proxy_ips') != '' && $this->server('HTTP_X_FORWARDED_FOR') && $this->server('REMOTE_ADDR')) + $proxy_ips = config_item('proxy_ips'); + if ( ! empty($proxy_ips) && ! is_array($proxy_ips)) { - $proxies = preg_split('/[\s,]/', config_item('proxy_ips'), -1, PREG_SPLIT_NO_EMPTY); - $proxies = is_array($proxies) ? $proxies : array($proxies); - - $this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']; - } - elseif ( ! $this->server('HTTP_CLIENT_IP') && $this->server('REMOTE_ADDR')) - { - $this->ip_address = $_SERVER['REMOTE_ADDR']; - } - elseif ($this->server('REMOTE_ADDR') && $this->server('HTTP_CLIENT_IP')) - { - $this->ip_address = $_SERVER['HTTP_CLIENT_IP']; - } - elseif ($this->server('HTTP_CLIENT_IP')) - { - $this->ip_address = $_SERVER['HTTP_CLIENT_IP']; - } - elseif ($this->server('HTTP_X_FORWARDED_FOR')) - { - $this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR']; + $proxy_ips = explode(',', str_replace(' ', '', $proxy_ips)); } - if ($this->ip_address === FALSE) - { - return $this->ip_address = '0.0.0.0'; - } + $this->ip_address = $this->server('REMOTE_ADDR'); - if (strpos($this->ip_address, ',') !== FALSE) + if ($proxy_ips) { - $x = explode(',', $this->ip_address); - $this->ip_address = trim(end($x)); + 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)) !== NULL) + { + // 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. + sscanf($spoof, '%[^,]', $spoof); + + if ( ! $this->valid_ip($spoof)) + { + $spoof = NULL; + } + else + { + break; + } + } + } + + if ($spoof) + { + for ($i = 0, $c = count($proxy_ips); $i < $c; $i++) + { + // Check if we have an IP address or a subnet + if (strpos($proxy_ips[$i], '/') === FALSE) + { + // An IP address (and not a subnet) is specified. + // We can compare right away. + if ($proxy_ips[$i] === $this->ip_address) + { + $this->ip_address = $spoof; + break; + } + + continue; + } + + // We have a subnet ... now the heavy lifting begins + isset($separator) OR $separator = $this->valid_ip($this->ip_address, 'ipv6') ? ':' : '.'; + + // If the proxy entry doesn't match the IP protocol - skip it + if (strpos($proxy_ips[$i], $separator) === FALSE) + { + continue; + } + + // Convert the REMOTE_ADDR IP address to binary, if needed + if ( ! isset($ip, $sprintf)) + { + if ($separator === ':') + { + // Make sure we're have the "full" IPv6 format + $ip = explode(':', + str_replace('::', + str_repeat(':', 9 - substr_count($this->ip_address, ':')), + $this->ip_address + ) + ); + + for ($i = 0; $i < 8; $i++) + { + $ip[$i] = intval($ip[$i], 16); + } + + $sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b'; + } + else + { + $ip = explode('.', $this->ip_address); + $sprintf = '%08b%08b%08b%08b'; + } + + $ip = vsprintf($sprintf, $ip); + } + + // Split the netmask length off the network address + sscanf($proxy_ips[$i], '%[^/]/%d', $netaddr, $masklen); + + // Again, an IPv6 address is most likely in a compressed form + if ($separator === ':') + { + $netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr)); + for ($i = 0; $i < 8; $i++) + { + $netaddr[$i] = intval($netaddr[$i], 16); + } + } + else + { + $netaddr = explode('.', $netaddr); + } + + // Convert to binary and finally compare + if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0) + { + $this->ip_address = $spoof; + break; + } + } + } } if ( ! $this->valid_ip($this->ip_address)) @@ -362,25 +504,37 @@ class CI_Input { // -------------------------------------------------------------------- /** - * Validate IP Address - * - * Updated version suggested by Geert De Deckere - * - * @param string - * @return bool - */ - public function valid_ip($ip) + * Validate IP Address + * + * @param string $ip IP address + * @param string $which IP protocol: 'ipv4' or 'ipv6' + * @return bool + */ + public function valid_ip($ip, $which = '') { - return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); + switch (strtolower($which)) + { + case 'ipv4': + $which = FILTER_FLAG_IPV4; + break; + case 'ipv6': + $which = FILTER_FLAG_IPV6; + break; + default: + $which = NULL; + break; + } + + return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which); } // -------------------------------------------------------------------- /** - * User Agent - * - * @return string - */ + * Fetch User Agent string + * + * @return string|null User Agent string or NULL if it doesn't exist + */ public function user_agent() { if ($this->user_agent !== FALSE) @@ -388,58 +542,75 @@ class CI_Input { return $this->user_agent; } - return $this->user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : FALSE; + return $this->user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : NULL; } // -------------------------------------------------------------------- /** - * 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 - * - * @return void - */ + * Sanitize Globals + * + * Internal method serving for the following purposes: + * + * - Unsets $_GET data (if query strings are not enabled) + * - Unsets all globals if register_globals is enabled + * - Cleans POST, COOKIE and SERVER data + * - Standardizes newline characters to PHP_EOL + * + * @return void + */ protected 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. + $protected = array( + '_SERVER', + '_GET', + '_POST', + '_FILES', + '_REQUEST', + '_SESSION', + '_ENV', + 'GLOBALS', + 'HTTP_RAW_POST_DATA', + 'system_folder', + 'application_folder', + 'BM', + 'EXT', + 'CFG', + 'URI', + 'RTR', + 'OUT', + 'IN' + ); + + // Unset globals for security. // This is effectively the same as register_globals = off - foreach (array($_GET, $_POST, $_COOKIE) as $global) + // PHP 5.4 no longer has the register_globals functionality. + if ( ! is_php('5.4')) { - if ( ! is_array($global)) - { - if ( ! in_array($global, $protected)) - { - global $$global; - $$global = NULL; - } - } - else + foreach (array($_GET, $_POST, $_COOKIE) as $global) { - foreach ($global as $key => $val) + if (is_array($global)) { - if ( ! in_array($key, $protected)) + foreach ($global as $key => $val) { - global $$key; - $$key = NULL; + if ( ! in_array($key, $protected)) + { + global $$key; + $$key = NULL; + } } } + elseif ( ! in_array($global, $protected)) + { + global $$global; + $$global = NULL; + } } } // Is $_GET data allowed? If not we'll set the $_GET to an empty array - if ($this->_allow_get_array == FALSE) + if ($this->_allow_get_array === FALSE) { $_GET = array(); } @@ -482,7 +653,7 @@ class CI_Input { $_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']); // CSRF Protection check - if ($this->_enable_csrf == TRUE) + if ($this->_enable_csrf === TRUE && ! $this->is_cli_request()) { $this->security->csrf_verify(); } @@ -493,22 +664,22 @@ class CI_Input { // -------------------------------------------------------------------- /** - * Clean Input Data - * - * This is a helper function. It escapes data and - * standardizes newline characters to \n - * - * @param string - * @return string - */ + * Clean Input Data + * + * Internal method that aids in escaping data and + * standardizing newline characters to PHP_EOL. + * + * @param string|string[] $str Input string(s) + * @return string + */ protected function _clean_input_data($str) { if (is_array($str)) { $new_array = array(); - foreach ($str as $key => $val) + foreach (array_keys($str) as $key) { - $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val); + $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($str[$key]); } return $new_array; } @@ -539,7 +710,7 @@ class CI_Input { } // Standardize newlines if needed - if ($this->_standardize_newlines == TRUE && strpos($str, "\r") !== FALSE) + if ($this->_standardize_newlines === TRUE && strpos($str, "\r") !== FALSE) { return str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str); } @@ -550,18 +721,18 @@ class CI_Input { // -------------------------------------------------------------------- /** - * 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. - * - * @param string - * @return string - */ + * Clean Keys + * + * Internal method that helps 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. + * + * @param string $str Input string + * @return string + */ protected function _clean_input_keys($str) { - if ( ! preg_match('/^[a-z0-9:_\/-]+$/i', $str)) + if ( ! preg_match('/^[a-z0-9:_\/|-]+$/i', $str)) { set_status_header(503); exit('Disallowed Key Characters.'); @@ -581,15 +752,12 @@ class CI_Input { /** * 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 + * @param bool $xss_clean Whether to apply XSS filtering * @return array */ public function request_headers($xss_clean = FALSE) { - // Look at Apache go! + // In Apache, you can simply call apache_request_headers() if (function_exists('apache_request_headers')) { $headers = apache_request_headers(); @@ -600,9 +768,9 @@ class CI_Input { foreach ($_SERVER as $key => $val) { - if (strpos($key, 'HTTP_') === 0) + if (sscanf($key, 'HTTP_%s', $header) === 1) { - $headers[substr($key, 5)] = $this->_fetch_from_array($_SERVER, $key, $xss_clean); + $headers[$header] = $this->_fetch_from_array($_SERVER, $key, $xss_clean); } } } @@ -626,9 +794,9 @@ class CI_Input { * * Returns the value of a single member of the headers class member * - * @param string array key for $this->headers - * @param bool XSS Clean or not - * @return mixed FALSE on failure, string on success + * @param string $index Header name + * @param bool $xss_clean Whether to apply XSS filtering + * @return string|bool The requested header on success or FALSE on failure */ public function get_request_header($index, $xss_clean = FALSE) { @@ -639,7 +807,7 @@ class CI_Input { if ( ! isset($this->headers[$index])) { - return FALSE; + return NULL; } return ($xss_clean === TRUE) @@ -650,9 +818,9 @@ class CI_Input { // -------------------------------------------------------------------- /** - * Is ajax Request? + * Is AJAX request? * - * Test to see if a request contains the HTTP_X_REQUESTED_WITH header + * Test to see if a request contains the HTTP_X_REQUESTED_WITH header. * * @return bool */ @@ -664,9 +832,9 @@ class CI_Input { // -------------------------------------------------------------------- /** - * Is cli Request? + * Is CLI request? * - * Test to see if a request was made from the command line + * Test to see if a request was made from the command line. * * @return bool */ @@ -680,10 +848,11 @@ class CI_Input { /** * Get Request Method * - * Return the Request Method + * Return the request method * - * @param bool uppercase or lowercase - * @return bool + * @param bool $upper Whether to return in upper or lower case + * (default: FALSE) + * @return string */ public function method($upper = FALSE) { @@ -695,4 +864,4 @@ class CI_Input { } /* End of file Input.php */ -/* Location: ./system/core/Input.php */ +/* Location: ./system/core/Input.php */
\ No newline at end of file diff --git a/system/core/Lang.php b/system/core/Lang.php index 9ef76f4d6..896385134 100755..100644 --- a/system/core/Lang.php +++ b/system/core/Lang.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,8 +24,7 @@ * @since Version 1.0 * @filesource */ - -// ------------------------------------------------------------------------ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Language Class @@ -41,16 +40,22 @@ class CI_Lang { /** * List of translations * - * @var array + * @var array */ - public $language = array(); + public $language = array(); + /** * List of loaded language files * - * @var array + * @var array */ - public $is_loaded = array(); + public $is_loaded = array(); + /** + * Class constructor + * + * @return void + */ public function __construct() { log_message('debug', 'Language Class Initialized'); @@ -61,39 +66,38 @@ class CI_Lang { /** * Load a language file * - * @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 + * @param mixed $langfile Language file name + * @param string $idiom Language name (english, etc.) + * @param bool $return Whether to return the loaded array of translations + * @param bool $add_suffix Whether to add suffix to $langfile + * @param string $alt_path Alternative path to look for the language file + * + * @return void|string[] Array containing translations, if $return is set to TRUE */ - public function load($langfile = '', $idiom = '', $return = FALSE, $add_suffix = TRUE, $alt_path = '') + public function load($langfile, $idiom = '', $return = FALSE, $add_suffix = TRUE, $alt_path = '') { $langfile = str_replace('.php', '', $langfile); - if ($add_suffix == TRUE) + if ($add_suffix === TRUE) { - $langfile = str_replace('_lang.', '', $langfile).'_lang'; + $langfile = str_replace('_lang', '', $langfile).'_lang'; } $langfile .= '.php'; - if (in_array($langfile, $this->is_loaded, TRUE)) + if (empty($idiom) OR ! ctype_alpha($idiom)) { - return; + $config =& get_config(); + $idiom = empty($config['language']) ? 'english' : $config['language']; } - $config =& get_config(); - - if ($idiom == '') + if ($return === FALSE && isset($this->is_loaded[$langfile]) && $this->is_loaded[$langfile] === $idiom) { - $deft_lang = ( ! isset($config['language'])) ? 'english' : $config['language']; - $idiom = ($deft_lang == '') ? 'english' : $deft_lang; + return; } // Determine where the language file is and load it - if ($alt_path != '' && file_exists($alt_path.'language/'.$idiom.'/'.$langfile)) + if ($alt_path !== '' && file_exists($alt_path.'language/'.$idiom.'/'.$langfile)) { include($alt_path.'language/'.$idiom.'/'.$langfile); } @@ -117,21 +121,24 @@ class CI_Lang { } } - if ( ! isset($lang) OR ! is_array($lang)) { log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile); + + if ($return === TRUE) + { + return array(); + } return; } - if ($return == TRUE) + if ($return === TRUE) { return $lang; } - $this->is_loaded[] = $langfile; + $this->is_loaded[$langfile] = $idiom; $this->language = array_merge($this->language, $lang); - unset($lang); log_message('debug', 'Language file loaded: language/'.$idiom.'/'.$langfile); return TRUE; @@ -140,14 +147,16 @@ class CI_Lang { // -------------------------------------------------------------------- /** - * Fetch a single line of text from the language array + * Language line + * + * Fetches a single line of text from the language array * - * @param string $line the language line - * @return string + * @param string $line Language line key + * @return string Translation */ public function line($line = '') { - $value = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line]; + $value = ($line === '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line]; // Because killer robots like unicorns! if ($value === FALSE) @@ -161,4 +170,4 @@ class CI_Lang { } /* End of file Lang.php */ -/* Location: ./system/core/Lang.php */ +/* Location: ./system/core/Lang.php */
\ No newline at end of file diff --git a/system/core/Loader.php b/system/core/Loader.php index 027ed20e5..1e6eafe8a 100644 --- a/system/core/Loader.php +++ b/system/core/Loader.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,16 +24,17 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Loader Class * - * Loads views and files + * Loads framework components. * * @package CodeIgniter * @subpackage Libraries - * @author EllisLab Dev Team * @category Loader + * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/libraries/loader.html */ class CI_Loader { @@ -42,83 +43,96 @@ class CI_Loader { /** * Nesting level of the output buffering mechanism * - * @var int + * @var int */ protected $_ci_ob_level; + /** * List of paths to load views from * - * @var array + * @var array */ - protected $_ci_view_paths = array(); + protected $_ci_view_paths = array(); + /** * List of paths to load libraries from * - * @var array + * @var array */ - protected $_ci_library_paths = array(); + protected $_ci_library_paths = array(); + /** * List of paths to load models from * - * @var array + * @var array */ - protected $_ci_model_paths = array(); + protected $_ci_model_paths = array(); + /** * List of paths to load helpers from * - * @var array + * @var array */ - protected $_ci_helper_paths = array(); + protected $_ci_helper_paths = array(); + /** * List of loaded base classes * - * @var array + * @var array */ - protected $_base_classes = array(); // Set by the controller class + protected $_base_classes = array(); // Set by the controller class + /** * List of cached variables * - * @var array + * @var array */ - protected $_ci_cached_vars = array(); + protected $_ci_cached_vars = array(); + /** * List of loaded classes * - * @var array + * @var array */ - protected $_ci_classes = array(); + protected $_ci_classes = array(); + /** * List of loaded files * - * @var array + * @var array */ - protected $_ci_loaded_files = array(); + protected $_ci_loaded_files = array(); + /** * List of loaded models * - * @var array + * @var array */ - protected $_ci_models = array(); + protected $_ci_models = array(); + /** * List of loaded helpers * - * @var array + * @var array */ - protected $_ci_helpers = array(); + protected $_ci_helpers = array(); + /** * List of class name mappings * - * @var array + * @var array */ - protected $_ci_varmap = array( - 'unit_test' => 'unit', - 'user_agent' => 'agent' - ); + protected $_ci_varmap = array( + 'unit_test' => 'unit', + 'user_agent' => 'agent' + ); /** - * Constructor + * Class constructor + * + * Sets component load paths, gets the initial output buffering level. * - * Sets the path to the view files and gets the initial output buffering level + * @return void */ public function __construct() { @@ -134,22 +148,18 @@ class CI_Loader { // -------------------------------------------------------------------- /** - * Initialize the Loader + * Initializer * - * This method is called once in CI_Controller. - * - * @param array - * @return object + * @todo Figure out a way to move this to the constructor + * without breaking *package_path*() methods. + * @uses CI_Loader::_ci_autoloader() + * @used-by CI_Controller::__construct() + * @return void */ 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; } // -------------------------------------------------------------------- @@ -157,36 +167,29 @@ class CI_Loader { /** * 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. + * A utility method to test if a class is in the self::$_ci_classes array. * - * It is mainly used in the form_helper -> _get_validation_object() + * @used-by Mainly used by Form Helper function _get_validation_object(). * - * @param string class being checked for - * @return mixed class object name on the CI SuperObject or FALSE + * @param string $class Class name to check for + * @return string|bool Class object name if loaded or FALSE */ public function is_loaded($class) { - if (isset($this->_ci_classes[$class])) - { - return $this->_ci_classes[$class]; - } - - return FALSE; + return isset($this->_ci_classes[$class]) ? $this->_ci_classes[$class] : FALSE; } // -------------------------------------------------------------------- /** - * Class Loader + * Library Loader * - * This function lets users load and instantiate classes. - * It is designed to be called from a user's app controllers. + * Loads and instantiates libraries. + * Designed to be called from application controllers. * - * @param string the name of the class - * @param mixed the optional parameters - * @param string an optional object name + * @param string $library Library name + * @param array $params Optional parameters to pass to the library class constructor + * @param string $object_name An optional object name to assign to * @return void */ public function library($library = '', $params = NULL, $object_name = NULL) @@ -201,9 +204,9 @@ class CI_Loader { return; } - if ($library == '' OR isset($this->_base_classes[$library])) + if ($library === '' OR isset($this->_base_classes[$library])) { - return FALSE; + return; } if ( ! is_null($params) && ! is_array($params)) @@ -219,26 +222,25 @@ class CI_Loader { /** * Model Loader * - * This function lets users load and instantiate models. + * Loads and instantiates libraries. * - * @param string the name of the class - * @param string name for the model - * @param bool database connection + * @param string $model Model name + * @param string $name An optional object name to assign to + * @param bool $db_conn An optional database connection configuration to initialize * @return void */ public function model($model, $name = '', $db_conn = FALSE) { - if (is_array($model)) + if (empty($model)) { - foreach ($model as $babe) - { - $this->model($babe); - } return; } - - if ($model == '') + elseif (is_array($model)) { + foreach ($model as $class) + { + $this->model($class); + } return; } @@ -254,7 +256,7 @@ class CI_Loader { $model = substr($model, $last_slash); } - if ($name == '') + if (empty($name)) { $name = $model; } @@ -311,18 +313,21 @@ class CI_Loader { /** * 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 + * @param mixed $params Database configuration options + * @param bool $return Whether to return the database object + * @param bool $query_builder Whether to enable Query Builder + * (overrides the configuration setting) + * + * @return void|object|bool Database object if $return is set to TRUE, + * FALSE on failure, void in any other case */ - public function database($params = '', $return = FALSE, $active_record = NULL) + public function database($params = '', $return = FALSE, $query_builder = NULL) { // Grab the super object $CI =& get_instance(); // Do we even need to load the database class? - if (class_exists('CI_DB') && $return == FALSE && $active_record == NULL && isset($CI->db) && is_object($CI->db)) + if ($return === FALSE && $query_builder === NULL && isset($CI->db) && is_object($CI->db) && ! empty($CI->db->conn_id)) { return FALSE; } @@ -331,7 +336,7 @@ class CI_Loader { if ($return === TRUE) { - return DB($params, $active_record); + return DB($params, $query_builder); } // Initialize the db variable. Needed to prevent @@ -339,34 +344,38 @@ class CI_Loader { $CI->db = ''; // Load the DB class - $CI->db =& DB($params, $active_record); + $CI->db =& DB($params, $query_builder); } // -------------------------------------------------------------------- /** - * Load the Utilities Class + * Load the Database Utilities Class * - * @return string + * @param object $db Database object + * @param bool $return Whether to return the DB Forge class object or not + * @return void|object */ - public function dbutil() + public function dbutil($db = NULL, $return = FALSE) { - 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(); + if ( ! is_object($db) OR ! ($db instanceof CI_DB)) + { + class_exists('CI_DB', FALSE) OR $this->database(); + $db =& $CI->db; + } 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'; + require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_utility.php'); + $class = 'CI_DB_'.$db->dbdriver.'_utility'; + + if ($return === TRUE) + { + return new $class($db); + } - $CI->dbutil = new $class(); + $CI->dbutil = new $class($db); } // -------------------------------------------------------------------- @@ -374,40 +383,56 @@ class CI_Loader { /** * Load the Database Forge Class * - * @return string + * @param object $db Database object + * @param bool $return Whether to return the DB Forge class object or not + * @return void|object */ - public function dbforge() + public function dbforge($db = NULL, $return = FALSE) { - if ( ! class_exists('CI_DB')) + $CI =& get_instance(); + if ( ! is_object($db) OR ! ($db instanceof CI_DB)) { - $this->database(); + class_exists('CI_DB', FALSE) OR $this->database(); + $db =& $CI->db; } - $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'; + require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_forge.php'); - $CI->dbforge = new $class(); + if ( ! empty($db->subdriver)) + { + $driver_path = BASEPATH.'database/drivers/'.$db->dbdriver.'/subdrivers/'.$db->dbdriver.'_'.$db->subdriver.'_forge.php'; + if (file_exists($driver_path)) + { + require_once($driver_path); + $class = 'CI_DB_'.$db->dbdriver.'_'.$db->subdriver.'_forge'; + } + } + else + { + $class = 'CI_DB_'.$db->dbdriver.'_forge'; + } + + if ($return === TRUE) + { + return new $class($db); + } + + $CI->dbforge = new $class($db); } // -------------------------------------------------------------------- /** - * Load View - * - * This function is used to load a "view" file. It has three parameters: + * View Loader * - * 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. + * Loads "view" files. * - * @param string - * @param array - * @param bool + * @param string $view View name + * @param array $vars An associative array of data + * to be extracted for use in the view + * @param bool $return Whether to return the view output + * or leave it to the Output class * @return void */ public function view($view, $vars = array(), $return = FALSE) @@ -418,13 +443,11 @@ class CI_Loader { // -------------------------------------------------------------------- /** - * Load File + * Generic File Loader * - * This is a generic file loader - * - * @param string - * @param bool - * @return string + * @param string $path File path + * @param bool $return Whether to return the file output + * @return void|string */ public function file($path, $return = FALSE) { @@ -439,13 +462,15 @@ class CI_Loader { * Once variables are set they become available within * the controller class and its "view" files. * - * @param array - * @param string + * @param array|object|string $vars + * An associative array or object containing values + * to be set, or a value's name if string + * @param string $val Value to set, only used if $vars is a string * @return void */ public function vars($vars = array(), $val = '') { - if ($val != '' && is_string($vars)) + if ($val !== '' && is_string($vars)) { $vars = array($vars => $val); } @@ -468,8 +493,8 @@ class CI_Loader { * * Check if a variable is set and retrieve it. * - * @param array - * @return void + * @param string $key Variable name + * @return mixed The variable or NULL if not found */ public function get_var($key) { @@ -481,7 +506,7 @@ class CI_Loader { /** * Get Variables * - * Retrieve all loaded variables + * Retrieves all loaded variables. * * @return array */ @@ -493,11 +518,9 @@ class CI_Loader { // -------------------------------------------------------------------- /** - * Load Helper - * - * This function loads the specified helper file. + * Helper Loader * - * @param mixed + * @param string|string[] $helpers Helper name(s) * @return void */ public function helper($helpers = array()) @@ -509,27 +532,34 @@ class CI_Loader { continue; } - $ext_helper = APPPATH.'helpers/'.config_item('subclass_prefix').$helper.'.php'; - // Is this a helper extension request? - if (file_exists($ext_helper)) + $ext_helper = config_item('subclass_prefix').$helper; + $ext_loaded = FALSE; + foreach ($this->_ci_helper_paths as $path) { - $base_helper = BASEPATH.'helpers/'.$helper.'.php'; + if (file_exists($path.'helpers/'.$ext_helper.'.php')) + { + include_once($path.'helpers/'.$ext_helper.'.php'); + $ext_loaded = TRUE; + } + } + // If we have loaded extensions - check if the base one is here + if ($ext_loaded === TRUE) + { + $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 + // No extensions found ... try loading regular helpers and/or overrides foreach ($this->_ci_helper_paths as $path) { if (file_exists($path.'helpers/'.$helper.'.php')) @@ -555,10 +585,11 @@ class CI_Loader { /** * Load Helpers * - * This is simply an alias to the above function in case the - * user has written the plural form of this function. + * An alias for the helper() method in case the developer has + * written the plural form of it. * - * @param array + * @uses CI_Loader::helper() + * @param string|string[] $helpers Helper name(s) * @return void */ public function helpers($helpers = array()) @@ -569,22 +600,21 @@ class CI_Loader { // -------------------------------------------------------------------- /** - * Loads a language file + * Language Loader * - * @param array - * @param string + * Loads language files. + * + * @param string|string[] $files List of language file names to load + * @param string Language name * @return void */ - public function language($file = array(), $lang = '') + public function language($files = array(), $lang = '') { $CI =& get_instance(); - if ( ! is_array($file)) - { - $file = array($file); - } + is_array($files) OR $files = array($files); - foreach ($file as $langfile) + foreach ($files as $langfile) { $CI->lang->load($langfile, $lang); } @@ -593,30 +623,35 @@ class CI_Loader { // -------------------------------------------------------------------- /** - * Loads a config file + * Config Loader * - * @param string - * @param bool - * @param bool - * @return void + * Loads a config file (an alias for CI_Config::load()). + * + * @uses CI_Config::load() + * @param string $file Configuration file name + * @param bool $use_sections Whether configuration values should be loaded into their own section + * @param bool $fail_gracefully Whether to just return FALSE or display an error message + * @return bool TRUE if the file was loaded correctly or FALSE on failure */ public function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) { $CI =& get_instance(); - $CI->config->load($file, $use_sections, $fail_gracefully); + return $CI->config->load($file, $use_sections, $fail_gracefully); } // -------------------------------------------------------------------- /** - * Driver + * Driver Loader * - * Loads a driver library + * Loads a driver library. * - * @param mixed the name of the class or array of classes - * @param mixed the optional parameters - * @param string an optional object name - * @return void + * @param string|string[] $library Driver name(s) + * @param array $params Optional parameters to pass to the driver + * @param string $object_name An optional object name to assign to + * + * @return void|object|bool Object or FALSE on failure if $library is a string + * and $object_name is set. void otherwise. */ public function driver($library = '', $params = NULL, $object_name = NULL) { @@ -626,16 +661,10 @@ class CI_Loader { { $this->driver($driver); } - return FALSE; - } - - 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'; + return; } - if ($library == '') + if ($library === '') { return FALSE; } @@ -655,13 +684,19 @@ class CI_Loader { /** * Add Package Path * - * Prepends a parent path to the library, model, helper, and config path arrays + * Prepends a parent path to the library, model, helper and config + * path arrays. * - * @param string - * @param bool + * @see CI_Loader::$_ci_library_paths + * @see CI_Loader::$_ci_model_paths + * @see CI_Loader::$_ci_helper_paths + * @see CI_Config::$_config_paths + * + * @param string $path Path to add + * @param bool $view_cascade (default: TRUE) * @return void */ - public function add_package_path($path, $view_cascade=TRUE) + public function add_package_path($path, $view_cascade = TRUE) { $path = rtrim($path, '/').'/'; @@ -673,7 +708,7 @@ class CI_Loader { // Add config file path $config =& $this->_ci_get_component('config'); - array_unshift($config->_config_paths, $path); + array_push($config->_config_paths, $path); } // -------------------------------------------------------------------- @@ -681,14 +716,14 @@ class CI_Loader { /** * Get Package Paths * - * Return a list of all package paths, by default it will ignore BASEPATH. + * Return a list of all package paths. * - * @param string - * @return void + * @param bool $include_base Whether to include BASEPATH (default: TRUE) + * @return array */ public function get_package_paths($include_base = FALSE) { - return $include_base === TRUE ? $this->_ci_library_paths : $this->_ci_model_paths; + return ($include_base === TRUE) ? $this->_ci_library_paths : $this->_ci_model_paths; } // -------------------------------------------------------------------- @@ -696,24 +731,24 @@ class CI_Loader { /** * 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. + * Remove a path from the library, model, helper and/or config + * path arrays if it exists. If no path is provided, the most recently + * added path will be removed removed. * - * @param string - * @param bool + * @param string $path Path to remove * @return void */ - public function remove_package_path($path = '', $remove_config_path = TRUE) + public function remove_package_path($path = '') { $config =& $this->_ci_get_component('config'); - if ($path == '') + if ($path === '') { array_shift($this->_ci_library_paths); array_shift($this->_ci_model_paths); array_shift($this->_ci_helper_paths); array_shift($this->_ci_view_paths); - array_shift($config->_config_paths); + array_pop($config->_config_paths); } else { @@ -748,13 +783,16 @@ class CI_Loader { // -------------------------------------------------------------------- /** - * Loader + * Internal CI Data Loader + * + * Used to load views and files. * - * 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 + * variables made available to view files. * - * @param array + * @used-by CI_Loader::view() + * @used-by CI_Loader::file() + * @param array $_ci_data Data to load * @return void */ protected function _ci_load($_ci_data) @@ -768,7 +806,7 @@ class CI_Loader { $file_exists = FALSE; // Set the path to the requested file - if ($_ci_path != '') + if (is_string($_ci_path) && $_ci_path !== '') { $_ci_x = explode('/', $_ci_path); $_ci_file = end($_ci_x); @@ -776,13 +814,13 @@ class CI_Loader { else { $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION); - $_ci_file = ($_ci_ext == '') ? $_ci_view.'.php' : $_ci_view; + $_ci_file = ($_ci_ext === '') ? $_ci_view.'.php' : $_ci_view; - foreach ($this->_ci_view_paths as $view_file => $cascade) + foreach ($this->_ci_view_paths as $_ci_view_file => $cascade) { - if (file_exists($view_file.$_ci_file)) + if (file_exists($_ci_view_file.$_ci_file)) { - $_ci_path = $view_file.$_ci_file; + $_ci_path = $_ci_view_file.$_ci_file; $file_exists = TRUE; break; } @@ -813,7 +851,7 @@ class CI_Loader { /* * Extract and cache variables * - * You can either set variables using the dedicated $this->load_vars() + * 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. @@ -830,17 +868,19 @@ class CI_Loader { * 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. + * 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 ( ! is_php('5.4') && (bool) @ini_get('short_open_tag') === FALSE && config_item('rewrite_short_tags') == TRUE) + if ( ! is_php('5.4') && (bool) @ini_get('short_open_tag') === FALSE + && config_item('rewrite_short_tags') === TRUE && function_usable('eval') + ) { echo eval('?>'.preg_replace('/;*\s*\?>/', '; ?>', str_replace('<?=', '<?php echo ', file_get_contents($_ci_path)))); } @@ -882,13 +922,14 @@ class CI_Loader { // -------------------------------------------------------------------- /** - * Load class + * Internal CI Class Loader * - * This function loads the requested class. + * @used-by CI_Loader::library() + * @uses CI_Loader::_ci_init_class() * - * @param string the item that is being loaded - * @param mixed any additional parameters - * @param string an optional object name + * @param string $class Class name to load + * @param mixed $params Optional parameters to pass to the class constructor + * @param string $object_name Optional object name to assign to * @return void */ protected function _ci_load_class($class, $params = NULL, $object_name = NULL) @@ -908,6 +949,13 @@ class CI_Loader { // Get the filename from the path $class = substr($class, $last_slash); + + // Check for match and driver base class + if (strtolower(trim($subdir, '/')) == strtolower($class) && ! class_exists('CI_Driver_Library')) + { + // We aren't instantiating an object here, just making the base class available + require BASEPATH.'libraries/Driver.php'; + } } // We'll test for both lowercase and capitalized versions of the file name @@ -989,19 +1037,24 @@ class CI_Loader { $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 == '') + if ($subdir === '') { $path = strtolower($class).'/'.$class; - return $this->_ci_load_class($path, $params); + return $this->_ci_load_class($path, $params, $object_name); + } + elseif (ucfirst($subdir) != $subdir) + { + // Lowercase subdir failed - retry capitalized + $path = ucfirst($subdir).$class; + return $this->_ci_load_class($path, $params, $object_name); } // 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) + if ($is_duplicate === FALSE) { log_message('error', 'Unable to load the requested class: '.$class); show_error('Unable to load the requested class: '.$class); @@ -1011,12 +1064,17 @@ class CI_Loader { // -------------------------------------------------------------------- /** - * Instantiates a class + * Internal CI Class Instantiator + * + * @used-by CI_Loader::_ci_load_class() * - * @param string - * @param string - * @param bool - * @param string an optional object name + * @param string $class Class name + * @param string $prefix Class name prefix + * @param array|null|bool $config Optional configuration to pass to the class constructor: + * FALSE to skip; + * NULL to search in config paths; + * array containing configuration data + * @param string $object_name Optional object name to assign to * @return void */ protected function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) @@ -1060,7 +1118,7 @@ class CI_Loader { } } - if ($prefix == '') + if ($prefix === '') { if (class_exists('CI_'.$class)) { @@ -1084,7 +1142,7 @@ class CI_Loader { if ( ! class_exists($name)) { log_message('error', 'Non-existent class: '.$name); - show_error('Non-existent class: '.$class); + show_error('Non-existent class: '.$name); } // Set the variable name we will assign the class to @@ -1118,12 +1176,11 @@ class CI_Loader { // -------------------------------------------------------------------- /** - * Autoloader + * CI Autoloader * - * The config/autoload.php file contains an array that permits sub-systems, - * libraries, and helpers to be loaded automatically. + * Loads component listed in the config/autoload.php file. * - * @param array + * @used-by CI_Loader::initialize() * @return void */ protected function _ci_autoloader() @@ -1187,6 +1244,15 @@ class CI_Loader { } } + // Autoload drivers + if (isset($autoload['drivers'])) + { + foreach ($autoload['drivers'] as $item) + { + $this->driver($item); + } + } + // Autoload models if (isset($autoload['model'])) { @@ -1197,11 +1263,12 @@ class CI_Loader { // -------------------------------------------------------------------- /** - * Object to Array + * CI Object to Array translator * - * Takes an object as input and converts the class variables to array key/vals + * Takes an object as input and converts the class variables to + * an associative array with key/value pairs. * - * @param object + * @param object $object Object data to translate * @return array */ protected function _ci_object_to_array($object) @@ -1212,9 +1279,11 @@ class CI_Loader { // -------------------------------------------------------------------- /** - * Get a reference to a specific library or model + * CI Component getter + * + * Get a reference to a specific library or model. * - * @param string + * @param string $component Component name * @return bool */ protected function &_ci_get_component($component) @@ -1228,10 +1297,11 @@ class CI_Loader { /** * Prep filename * - * This function preps the name of various items to make loading them more reliable. + * This function prepares filenames of various items to + * make their loading more reliable. * - * @param mixed - * @param string + * @param string|string[] $filename Filename(s) + * @param string $extension Filename extension * @return array */ protected function _ci_prep_filename($filename, $extension) diff --git a/system/libraries/Log.php b/system/core/Log.php index 66f9ebff9..e66270840 100644 --- a/system/libraries/Log.php +++ b/system/core/Log.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Logging Class @@ -36,19 +37,65 @@ */ class CI_Log { + /** + * Path to save log files + * + * @var string + */ protected $_log_path; + + /** + * Level of logging + * + * @var int + */ protected $_threshold = 1; + + /** + * Highest level of logging + * + * @var int + */ protected $_threshold_max = 0; + + /** + * Array of threshold levels to log + * + * @var array + */ protected $_threshold_array = array(); + + /** + * Format of timestamp for log files + * + * @var string + */ protected $_date_fmt = 'Y-m-d H:i:s'; + + /** + * Whether or not the logger can write to the log files + * + * @var bool + */ protected $_enabled = TRUE; + + /** + * Predefined logging levels + * + * @var array + */ protected $_levels = array('ERROR' => 1, 'DEBUG' => 2, 'INFO' => 3, 'ALL' => 4); + /** + * Initialize Logging class + * + * @return void + */ public function __construct() { $config =& get_config(); - $this->_log_path = ($config['log_path'] != '') ? $config['log_path'] : APPPATH.'logs/'; + $this->_log_path = ($config['log_path'] !== '') ? $config['log_path'] : APPPATH.'logs/'; if ( ! is_dir($this->_log_path) OR ! is_really_writable($this->_log_path)) { @@ -65,7 +112,7 @@ class CI_Log { $this->_threshold_array = array_flip($config['log_threshold']); } - if ($config['log_date_format'] != '') + if ($config['log_date_format'] !== '') { $this->_date_fmt = $config['log_date_format']; } @@ -105,7 +152,7 @@ class CI_Log { if ( ! file_exists($filepath)) { $newfile = TRUE; - $message .= "<"."?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?".">\n\n"; + $message .= '<'."?php defined('BASEPATH') OR exit('No direct script access allowed'); ?".">\n\n"; } if ( ! $fp = @fopen($filepath, FOPEN_WRITE_CREATE)) @@ -113,7 +160,7 @@ class CI_Log { return FALSE; } - $message .= $level.' '.(($level == 'INFO') ? ' -' : '-').' '.date($this->_date_fmt). ' --> '.$msg."\n"; + $message .= $level.' '.($level === 'INFO' ? ' -' : '-').' '.date($this->_date_fmt).' --> '.$msg."\n"; flock($fp, LOCK_EX); fwrite($fp, $message); diff --git a/system/core/Model.php b/system/core/Model.php index 49b8d34e4..28fdfbb69 100755..100644 --- a/system/core/Model.php +++ b/system/core/Model.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,11 +24,10 @@ * @since Version 1.0 * @filesource */ - -// ------------------------------------------------------------------------ +defined('BASEPATH') OR exit('No direct script access allowed'); /** - * CodeIgniter Model Class + * Model Class * * @package CodeIgniter * @subpackage Libraries @@ -38,25 +37,33 @@ */ class CI_Model { + /** + * Class constructor + * + * @return void + */ public function __construct() { log_message('debug', 'Model Class Initialized'); } + // -------------------------------------------------------------------- + /** - * __get + * __get magic * * Allows models to access CI's loaded classes using the same * syntax as controllers. * - * @param string + * @param string $key */ public function __get($key) { $CI =& get_instance(); return $CI->$key; } + } /* End of file Model.php */ -/* Location: ./system/core/Model.php */ +/* Location: ./system/core/Model.php */
\ No newline at end of file diff --git a/system/core/Output.php b/system/core/Output.php index 3cb40626a..6312ccd86 100755..100644 --- a/system/core/Output.php +++ b/system/core/Output.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,11 +24,12 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Output Class * - * Responsible for sending final output to browser + * Responsible for sending final output to the browser. * * @package CodeIgniter * @subpackage Libraries @@ -39,70 +40,84 @@ class CI_Output { /** - * Current output string + * Final output string * - * @var string + * @var string */ public $final_output; + /** * Cache expiration time * - * @var int + * @var int */ - public $cache_expiration = 0; + public $cache_expiration = 0; + /** * List of server headers * - * @var array + * @var array */ - public $headers = array(); + public $headers = array(); + /** * List of mime types * - * @var array + * @var array */ - public $mime_types = array(); + public $mimes = array(); + /** - * Determines wether profiler is enabled + * Mime-type for the current page * - * @var book + * @var string */ - public $enable_profiler = FALSE; + protected $mime_type = 'text/html'; + /** - * Determines if output compression is enabled + * Enable Profiler flag * - * @var bool + * @var bool */ - protected $_zlib_oc = FALSE; + public $enable_profiler = FALSE; + + /** + * zLib output compression flag + * + * @var bool + */ + protected $_zlib_oc = FALSE; + /** * List of profiler sections * - * @var array + * @var array */ - protected $_profiler_sections = array(); + protected $_profiler_sections = array(); + /** - * Whether or not to parse variables like {elapsed_time} and {memory_usage} + * Parse markers flag + * + * Whether or not to parse variables like {elapsed_time} and {memory_usage}. * - * @var bool + * @var bool */ - public $parse_exec_vars = TRUE; + public $parse_exec_vars = TRUE; + /** + * Class constructor + * + * Determines whether zLib output compression will be used. + * + * @return void + */ public function __construct() { - $this->_zlib_oc = @ini_get('zlib.output_compression'); + $this->_zlib_oc = (bool) @ini_get('zlib.output_compression'); // Get mime types for later - if (defined('ENVIRONMENT') && file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php')) - { - include APPPATH.'config/'.ENVIRONMENT.'/mimes.php'; - } - else - { - include APPPATH.'config/mimes.php'; - } - + $this->mimes =& get_mimes(); - $this->mime_types = $mimes; log_message('debug', 'Output Class Initialized'); } @@ -111,7 +126,7 @@ class CI_Output { /** * Get Output * - * Returns the current output string + * Returns the current output string. * * @return string */ @@ -125,10 +140,10 @@ class CI_Output { /** * Set Output * - * Sets the output string + * Sets the output string. * - * @param string - * @return void + * @param string $output Output data + * @return object $this */ public function set_output($output) { @@ -141,14 +156,14 @@ class CI_Output { /** * Append Output * - * Appends data onto the output string + * Appends data onto the output string. * - * @param string - * @return void + * @param string $output Data to append + * @return object $this */ public function append_output($output) { - if ($this->final_output == '') + if (empty($this->final_output)) { $this->final_output = $output; } @@ -165,14 +180,14 @@ class CI_Output { /** * Set Header * - * Lets you set a server header which will be outputted with the final display. + * Lets you set a server header which will be sent with the final output. * - * 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... + * Note: If a file is cached, headers will not be sent. + * @todo We need to figure out how to permit headers to be cached. * - * @param string - * @param bool - * @return void + * @param string $header Header + * @param bool $replace Whether to replace the old header value, if already set + * @return object $this */ public function set_header($header, $replace = TRUE) { @@ -180,9 +195,9 @@ class CI_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) + if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) === 0) { - return; + return $this; } $this->headers[] = array($header, $replace); @@ -192,21 +207,22 @@ class CI_Output { // -------------------------------------------------------------------- /** - * Set Content Type Header + * Set Content-Type Header * - * @param string extension of the file we're outputting - * @return void + * @param string $mime_type Extension of the file we're outputting + * @param string $charset Character set (default: NULL) + * @return object $this */ - public function set_content_type($mime_type) + public function set_content_type($mime_type, $charset = NULL) { if (strpos($mime_type, '/') === FALSE) { $extension = ltrim($mime_type, '.'); // Is this extension supported? - if (isset($this->mime_types[$extension])) + if (isset($this->mimes[$extension])) { - $mime_type =& $this->mime_types[$extension]; + $mime_type =& $this->mimes[$extension]; if (is_array($mime_type)) { @@ -215,7 +231,15 @@ class CI_Output { } } - $header = 'Content-Type: '.$mime_type; + $this->mime_type = $mime_type; + + if (empty($charset)) + { + $charset = config_item('charset'); + } + + $header = 'Content-Type: '.$mime_type + .(empty($charset) ? NULL : '; charset='.strtolower($charset)); $this->headers[] = array($header, TRUE); return $this; @@ -224,7 +248,7 @@ class CI_Output { // -------------------------------------------------------------------- /** - * Get Current Content Type Header + * Get Current Content-Type Header * * @return string 'text/html', if not already set */ @@ -232,9 +256,9 @@ class CI_Output { { for ($i = 0, $c = count($this->headers); $i < $c; $i++) { - if (preg_match('/^Content-Type:\s(.+)$/', $this->headers[$i][0], $matches)) + if (sscanf($this->headers[$i][0], 'Content-Type: %s', $content_type) === 1) { - return $matches[1]; + return $content_type; } } @@ -245,11 +269,13 @@ class CI_Output { /** * Set HTTP Status Header - * moved to Common procedural functions in 1.7.2 * - * @param int the status code - * @param string - * @return void + * As of version 1.7.2, this is an alias for common function + * set_status_header(). + * + * @param int $code Status code (default: 200) + * @param string $text Optional message + * @return object $this */ public function set_status_header($code = 200, $text = '') { @@ -262,8 +288,8 @@ class CI_Output { /** * Enable/disable Profiler * - * @param bool - * @return void + * @param bool $val TRUE to enable or FALSE to disable + * @return object $this */ public function enable_profiler($val = TRUE) { @@ -276,13 +302,20 @@ class CI_Output { /** * Set Profiler Sections * - * Allows override of default / config settings for Profiler section display + * Allows override of default/config settings for + * Profiler section display. * - * @param array - * @return void + * @param array $sections Profiler sections + * @return object $this */ public function set_profiler_sections($sections) { + if (isset($sections['query_toggle_count'])) + { + $this->_profiler_sections['query_toggle_count'] = (int) $sections['query_toggle_count']; + unset($sections['query_toggle_count']); + } + foreach ($sections as $section => $enable) { $this->_profiler_sections[$section] = ($enable !== FALSE); @@ -296,8 +329,8 @@ class CI_Output { /** * Set Cache * - * @param int - * @return void + * @param int $time Cache expiration time in seconds + * @return object $this */ public function cache($time) { @@ -310,16 +343,16 @@ class CI_Output { /** * Display Output * - * All "view" data is automatically put into this variable by the controller class: + * Processes sends the sends finalized output data to the browser along + * with any server headers and profile data. It also stops benchmark + * timers so the page rendering speed and memory usage can be shown. * - * $this->final_output + * Note: All "view" data is automatically put into $this->final_output + * by controller class. * - * 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. - * - * @param string - * @return mixed + * @uses CI_Output::$final_output + * @param string $output Output data override + * @return void */ public function _display($output = '') { @@ -337,14 +370,22 @@ class CI_Output { // -------------------------------------------------------------------- // Set the output data - if ($output == '') + if ($output === '') { $output =& $this->final_output; } // -------------------------------------------------------------------- - // Do we need to write a cache file? Only if the controller does not have its + // Is minify requested? + if ($CFG->item('minify_output') === TRUE) + { + $output = $this->minify($output, $this->mime_type); + } + + // -------------------------------------------------------------------- + + // 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')) @@ -361,7 +402,7 @@ class CI_Output { if ($this->parse_exec_vars === TRUE) { - $memory = function_exists('memory_get_usage') ? round(memory_get_usage()/1024/1024, 2).'MB' : '0'; + $memory = round(memory_get_usage() / 1024 / 1024, 2).'MB'; $output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output); } @@ -369,7 +410,7 @@ class CI_Output { // -------------------------------------------------------------------- // Is compression requested? - if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc == FALSE + if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc === FALSE && extension_loaded('zlib') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE) { @@ -397,14 +438,14 @@ class CI_Output { echo $output; log_message('debug', 'Final output sent to browser'); log_message('debug', 'Total execution time: '.$elapsed); - return TRUE; + return; } // -------------------------------------------------------------------- // Do we need to generate profile data? // If so, load the Profile class and run it. - if ($this->enable_profiler == TRUE) + if ($this->enable_profiler === TRUE) { $CI->load->library('profiler'); if ( ! empty($this->_profiler_sections)) @@ -439,16 +480,16 @@ class CI_Output { // -------------------------------------------------------------------- /** - * Write a Cache File + * Write Cache * - * @param string + * @param string $output Output data to cache * @return void */ public function _write_cache($output) { $CI =& get_instance(); $path = $CI->config->item('cache_path'); - $cache_path = ($path == '') ? APPPATH.'cache/' : $path; + $cache_path = ($path === '') ? APPPATH.'cache/' : $path; if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path)) { @@ -484,20 +525,26 @@ class CI_Output { @chmod($cache_path, FILE_WRITE_MODE); log_message('debug', 'Cache file written: '.$cache_path); + + // Send HTTP cache-control headers to browser to match file cache settings. + $this->set_cache_header($_SERVER['REQUEST_TIME'], $expire); } // -------------------------------------------------------------------- /** - * Update/serve a cached file + * Update/serve cached output * - * @param object config class - * @param object uri class - * @return void + * @uses CI_Config + * @uses CI_URI + * + * @param object &$CFG CI_Config class instance + * @param object &$URI CI_URI class instance + * @return bool TRUE on success or FALSE on failure */ public function _display_cache(&$CFG, &$URI) { - $cache_path = ($CFG->item('cache_path') == '') ? APPPATH.'cache/' : $CFG->item('cache_path'); + $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; @@ -516,25 +563,172 @@ class CI_Output { fclose($fp); // Strip out the embedded timestamp - if ( ! preg_match('/(\d+TS--->)/', $cache, $match)) + 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])) && is_really_writable($cache_path)) + $last_modified = filemtime($cache_path); + $expire = $match[1]; + + // Has the file expired? + if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path)) { + // If so we'll delete it. @unlink($filepath); log_message('debug', 'Cache file has expired. File deleted.'); return FALSE; } + else + { + // Or else send the HTTP cache control headers. + $this->set_cache_header($last_modified, $expire); + } // Display the cache - $this->_display(str_replace($match[0], '', $cache)); + $this->_display(substr($cache, strlen($match[0]))); log_message('debug', 'Cache file is current. Sending it to browser.'); return TRUE; } + // -------------------------------------------------------------------- + + /** + * Set Cache Header + * + * Set the HTTP headers to match the server-side file cache settings + * in order to reduce bandwidth. + * + * @param int $last_modified Timestamp of when the page was last modified + * @param int $expiration Timestamp of when should the requested page expire from cache + * @return void + */ + public function set_cache_header($last_modified, $expiration) + { + $max_age = $expiration - $_SERVER['REQUEST_TIME']; + + if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $last_modified <= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) + { + $this->set_status_header(304); + exit; + } + else + { + header('Pragma: public'); + header('Cache-Control: max-age=' . $max_age . ', public'); + header('Expires: '.gmdate('D, d M Y H:i:s', $expiration).' GMT'); + header('Last-modified: '.gmdate('D, d M Y H:i:s', $last_modified).' GMT'); + } + } + + // -------------------------------------------------------------------- + + /** + * Minify + * + * Reduce excessive size of HTML/CSS/JavaScript content. + * + * @param string $output Output to minify + * @param string $type Output content MIME type + * @return string Minified output + */ + public function minify($output, $type = 'text/html') + { + switch ($type) + { + case 'text/html': + + $size_before = strlen($output); + + if ($size_before === 0) + { + return ''; + } + + // Find all the <pre>,<code>,<textarea>, and <javascript> tags + // We'll want to return them to this unprocessed state later. + preg_match_all('{<pre.+</pre>}msU', $output, $pres_clean); + preg_match_all('{<code.+</code>}msU', $output, $codes_clean); + preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_clean); + preg_match_all('{<script.+</script>}msU', $output, $javascript_clean); + + // Minify the CSS in all the <style> tags. + preg_match_all('{<style.+</style>}msU', $output, $style_clean); + foreach ($style_clean[0] as $s) + { + $output = str_replace($s, $this->minify($s, 'text/css'), $output); + } + + // Minify the javascript in <script> tags. + foreach ($javascript_clean[0] as $s) + { + $javascript_mini[] = $this->minify($s, 'text/javascript'); + } + + // Replace multiple spaces with a single space. + $output = preg_replace('!\s{2,}!', ' ', $output); + + // Remove comments (non-MSIE conditionals) + $output = preg_replace('{\s*<!--[^\[].*-->\s*}msU', '', $output); + + // Remove spaces around block-level elements. + $output = preg_replace('/\s*(<\/?(html|head|title|meta|script|link|style|body|h[1-6]|div|p|br)[^>]*>)\s*/is', '$1', $output); + + // Replace mangled <pre> etc. tags with unprocessed ones. + + if ( ! empty($pres_clean)) + { + preg_match_all('{<pre.+</pre>}msU', $output, $pres_messed); + $output = str_replace($pres_messed[0], $pres_clean[0], $output); + } + + if ( ! empty($codes_clean)) + { + preg_match_all('{<code.+</code>}msU', $output, $codes_messed); + $output = str_replace($codes_messed[0], $codes_clean[0], $output); + } + + if ( ! empty($codes_clean)) + { + preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_messed); + $output = str_replace($textareas_messed[0], $textareas_clean[0], $output); + } + + if (isset($javascript_mini)) + { + preg_match_all('{<script.+</script>}msU', $output, $javascript_messed); + $output = str_replace($javascript_messed[0], $javascript_mini, $output); + } + + $size_removed = $size_before - strlen($output); + $savings_percent = round(($size_removed / $size_before * 100)); + + log_message('debug', 'Minifier shaved '.($size_removed / 1000).'KB ('.$savings_percent.'%) off final HTML output.'); + + break; + + case 'text/css': + + //Remove CSS comments + $output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $output); + + // Remove spaces around curly brackets, colons, + // semi-colons, parenthesis, commas + $output = preg_replace('!\s*(:|;|,|}|{|\(|\))\s*!', '$1', $output); + + break; + + case 'text/javascript': + + // Currently leaves JavaScript untouched. + break; + + default: break; + } + + return $output; + } + } /* End of file Output.php */ diff --git a/system/core/Router.php b/system/core/Router.php index 5477fed5d..01f44bc83 100755..100644 --- a/system/core/Router.php +++ b/system/core/Router.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Router Class @@ -32,59 +33,60 @@ * * @package CodeIgniter * @subpackage Libraries - * @author EllisLab Dev Team * @category Libraries + * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/general/routing.html */ class CI_Router { /** - * Config class + * CI_Config class object * - * @var object + * @var object */ public $config; + /** * List of routes * - * @var array + * @var array */ - public $routes = array(); - /** - * List of error routes - * - * @var array - */ - public $error_routes = array(); + public $routes = array(); + /** * Current class name * - * @var string + * @var string */ - public $class = ''; + public $class = ''; + /** * Current method name * - * @var string + * @var string */ - public $method = 'index'; + public $method = 'index'; + /** * Sub-directory that contains the requested controller class * - * @var string + * @var string */ - public $directory = ''; + public $directory = ''; + /** * Default controller (and method if specific) * - * @var string + * @var string */ public $default_controller; /** - * Constructor + * Class constructor * * Runs the route mapping function. + * + * @return void */ public function __construct() { @@ -96,9 +98,9 @@ class CI_Router { // -------------------------------------------------------------------- /** - * Set the route mapping + * Set route mapping * - * This function determines what should be served based on the URI request, + * Determines what should be served based on the URI request, * as well as any "routes" that have been set in the routing config file. * * @return void @@ -140,12 +142,12 @@ class CI_Router { include(APPPATH.'config/routes.php'); } - $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route; + $this->routes = (isset($route) && is_array($route)) ? $route : array(); 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 = empty($this->routes['default_controller']) ? FALSE : strtolower($this->routes['default_controller']); + $this->default_controller = empty($this->routes['default_controller']) ? FALSE : $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) @@ -171,31 +173,27 @@ class CI_Router { // -------------------------------------------------------------------- /** - * Set the default controller + * Set default controller * * @return void */ protected function _set_default_controller() { - if ($this->default_controller === FALSE) + if (empty($this->default_controller)) { 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) + if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2) { - $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')); + $method = 'index'; } + $this->set_class($class); + $this->set_method($method); + $this->_set_request(array($class, $method)); + // re-index the routed segments array so it starts with 1 rather than 0 $this->uri->_reindex_segments(); @@ -205,13 +203,12 @@ class CI_Router { // -------------------------------------------------------------------- /** - * Set the Route + * Set request route * - * This function takes an array of URI segments as - * input, and sets the current class/method + * Takes an array of URI segments as input and sets the class/method + * to be called. * - * @param array - * @param bool + * @param array $segments URI segments * @return void */ protected function _set_request($segments = array()) @@ -225,17 +222,8 @@ class CI_Router { $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'; - } + isset($segments[1]) OR $segments[1] = 'index'; + $this->set_method($segments[1]); // Update our "routed" segment array to contain the segments. // Note: If there is no custom routing, this array will be @@ -246,11 +234,12 @@ class CI_Router { // -------------------------------------------------------------------- /** - * Validates the supplied segments. - * Attempts to determine the path to the controller. + * Validate request * - * @param array - * @return array + * Attempts validate the URI request and determine the controller path. + * + * @param array $segments URI segments + * @return array URI segments */ protected function _validate_request($segments) { @@ -259,9 +248,13 @@ class CI_Router { return $segments; } + $temp = str_replace('-', '_', $segments[0]); + // Does the requested controller exist in the root folder? - if (file_exists(APPPATH.'controllers/'.$segments[0].'.php')) + if (file_exists(APPPATH.'controllers/'.$temp.'.php')) { + $segments[0] = $temp; + empty($segments[1]) OR $segments[1] = str_replace('-', '_', $segments[1]); return $segments; } @@ -269,22 +262,19 @@ class CI_Router { 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); - + $this->set_directory(array_shift($segments)); if (count($segments) > 0) { + $segments[0] = str_replace('-', '_', $segments[0]); + empty($segments[1]) OR $segments[1] = str_replace('-', '_', $segments[1]); + // 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; + $this->directory = ''; + return explode('/', $this->routes['404_override'], 2); } else { @@ -295,40 +285,26 @@ class CI_Router { 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')) + $segments = explode('/', $this->default_controller); + if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].'.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'); + if (sscanf($this->routes['404_override'], '%[^/]/%s', $class, $method) !== 2) + { + $method = 'index'; + } - return $x; + return array($class, $method); } // Nothing else to do at this point but show a 404 @@ -340,9 +316,8 @@ class CI_Router { /** * 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. + * 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. * * @return void */ @@ -352,7 +327,7 @@ class CI_Router { $uri = implode('/', $this->uri->segments); // Is there a literal match? If so we're done - if (isset($this->routes[$uri])) + if (isset($this->routes[$uri]) && is_string($this->routes[$uri])) { return $this->_set_request(explode('/', $this->routes[$uri])); } @@ -361,13 +336,51 @@ class CI_Router { foreach ($this->routes as $key => $val) { // Convert wild-cards to RegEx - $key = str_replace(array(':any', ':num'), array('.+', '[0-9]+'), $key); + $key = str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $key); // Does the RegEx match? - if (preg_match('#^'.$key.'$#', $uri)) + if (preg_match('#^'.$key.'$#', $uri, $matches)) { - // Do we have a back-reference? - if (strpos($val, '$') !== FALSE && strpos($key, '(') !== FALSE) + // Are we using callbacks to process back-references? + if ( ! is_string($val) && is_callable($val)) + { + // Remove the original string from the matches array. + array_shift($matches); + + // Get the match count. + $match_count = count($matches); + + // Determine how many parameters the callback has. + $reflection = new ReflectionFunction($val); + $param_count = $reflection->getNumberOfParameters(); + + // Are there more parameters than matches? + if ($param_count > $match_count) + { + // Any params without matches will be set to an empty string. + $matches = array_merge($matches, array_fill($match_count, $param_count - $match_count, '')); + + $match_count = $param_count; + } + + // Get the parameters so we can use their default values. + $params = $reflection->getParameters(); + + for ($m = 0; $m < $match_count; $m++) + { + // Is the match empty and does a default value exist? + if (empty($matches[$m]) && $params[$m]->isDefaultValueAvailable()) + { + // Substitute the empty match for the default value. + $matches[$m] = $params[$m]->getDefaultValue(); + } + } + + // Execute the callback using the values in matches as its parameters. + $val = call_user_func_array($val, $matches); + } + // Are we using the default routing method for back-references? + elseif (strpos($val, '$') !== FALSE && strpos($key, '(') !== FALSE) { $val = preg_replace('#^'.$key.'$#', $val, $uri); } @@ -384,9 +397,9 @@ class CI_Router { // -------------------------------------------------------------------- /** - * Set the class name + * Set class name * - * @param string + * @param string $class Class name * @return void */ public function set_class($class) @@ -409,9 +422,9 @@ class CI_Router { // -------------------------------------------------------------------- /** - * Set the method name + * Set method name * - * @param string + * @param string $method Method name * @return void */ public function set_method($method) @@ -428,20 +441,15 @@ class CI_Router { */ public function fetch_method() { - if ($this->method == $this->fetch_class()) - { - return 'index'; - } - - return $this->method; + return ($this->method === $this->fetch_class()) ? 'index' : $this->method; } // -------------------------------------------------------------------- /** - * Set the directory name + * Set directory name * - * @param string + * @param string $dir Directory name * @return void */ public function set_directory($dir) @@ -452,7 +460,10 @@ class CI_Router { // -------------------------------------------------------------------- /** - * Fetch the sub-directory (if any) that contains the requested controller class + * Fetch directory + * + * Feches the sub-directory (if any) that contains the requested + * controller class. * * @return string */ @@ -464,9 +475,9 @@ class CI_Router { // -------------------------------------------------------------------- /** - * Set the controller overrides + * Set controller overrides * - * @param array + * @param array $routing Route overrides * @return void */ public function _set_overrides($routing) @@ -481,14 +492,14 @@ class CI_Router { $this->set_directory($routing['directory']); } - if (isset($routing['controller']) && $routing['controller'] != '') + if ( ! empty($routing['controller'])) { $this->set_class($routing['controller']); } if (isset($routing['function'])) { - $routing['function'] = ($routing['function'] == '') ? 'index' : $routing['function']; + $routing['function'] = empty($routing['function']) ? 'index' : $routing['function']; $this->set_method($routing['function']); } } diff --git a/system/core/Security.php b/system/core/Security.php index ac39ce97b..b8e66c087 100755..100644 --- a/system/core/Security.php +++ b/system/core/Security.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Security Class @@ -37,71 +38,87 @@ class CI_Security { /** - * Random Hash for protecting URLs + * XSS Hash * - * @var string + * Random Hash for protecting URLs. + * + * @var string */ - protected $_xss_hash = ''; + protected $_xss_hash = ''; /** - * Random Hash for Cross Site Request Forgery Protection Cookie + * CSRF Hash + * + * Random hash for Cross Site Request Forgery protection cookie * - * @var string + * @var string */ - protected $_csrf_hash = ''; + protected $_csrf_hash = ''; /** - * Expiration time for Cross Site Request Forgery Protection Cookie - * Defaults to two hours (in seconds) + * CSRF Expire time + * + * Expiration time for Cross Site Request Forgery protection cookie. + * Defaults to two hours (in seconds). * - * @var int + * @var int */ - protected $_csrf_expire = 7200; + protected $_csrf_expire = 7200; /** - * Token name for Cross Site Request Forgery Protection Cookie + * CSRF Token name * - * @var string + * Token name for Cross Site Request Forgery protection cookie. + * + * @var string */ - protected $_csrf_token_name = 'ci_csrf_token'; + protected $_csrf_token_name = 'ci_csrf_token'; /** - * Cookie name for Cross Site Request Forgery Protection Cookie + * CSRF Cookie name + * + * Cookie name for Cross Site Request Forgery protection cookie. * - * @var string + * @var string */ - protected $_csrf_cookie_name = 'ci_csrf_token'; + protected $_csrf_cookie_name = 'ci_csrf_token'; /** * List of never allowed strings * - * @var array + * @var array */ - protected $_never_allowed_str = array( - 'document.cookie' => '[removed]', - 'document.write' => '[removed]', - '.parentNode' => '[removed]', - '.innerHTML' => '[removed]', - 'window.location' => '[removed]', - '-moz-binding' => '[removed]', - '<!--' => '<!--', - '-->' => '-->', - '<![CDATA[' => '<![CDATA[', - '<comment>' => '<comment>' - ); + protected $_never_allowed_str = array( + 'document.cookie' => '[removed]', + 'document.write' => '[removed]', + '.parentNode' => '[removed]', + '.innerHTML' => '[removed]', + 'window.location' => '[removed]', + '-moz-binding' => '[removed]', + '<!--' => '<!--', + '-->' => '-->', + '<![CDATA[' => '<![CDATA[', + '<comment>' => '<comment>' + ); /** - * List of never allowed regex replacement + * List of never allowed regex replacements * - * @var array + * @var array */ protected $_never_allowed_regex = array( - 'javascript\s*:', - 'expression\s*(\(|&\#40;)', // CSS and IE - 'vbscript\s*:', // IE, surprise! - 'Redirect\s+302' - ); + 'javascript\s*:', + 'expression\s*(\(|&\#40;)', // CSS and IE + 'vbscript\s*:', // IE, surprise! + 'Redirect\s+302', + "([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?" + ); + /** + * Class constructor + * + * @return void + */ public function __construct() { // Is CSRF protection enabled? @@ -132,7 +149,7 @@ class CI_Security { // -------------------------------------------------------------------- /** - * Verify Cross Site Request Forgery Protection + * CSRF Verify * * @return object */ @@ -155,8 +172,8 @@ class CI_Security { } // Do the tokens exist in both the _POST and _COOKIE arrays? - if ( ! isset($_POST[$this->_csrf_token_name]) OR ! isset($_COOKIE[$this->_csrf_cookie_name]) - OR $_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name]) // Do the tokens match? + if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name]) + OR $_POST[$this->_csrf_token_name] !== $_COOKIE[$this->_csrf_cookie_name]) // Do the tokens match? { $this->csrf_show_error(); } @@ -182,8 +199,9 @@ class CI_Security { // -------------------------------------------------------------------- /** - * Set Cross Site Request Forgery Protection Cookie + * CSRF Set Cookie * + * @codeCoverageIgnore * @return object */ public function csrf_set_cookie() @@ -191,17 +209,17 @@ class CI_Security { $expire = time() + $this->_csrf_expire; $secure_cookie = (bool) config_item('cookie_secure'); - if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off')) + if ($secure_cookie && ! is_https()) { return FALSE; } setcookie( - $this->_csrf_cookie_name, - $this->_csrf_hash, - $expire, - config_item('cookie_path'), - config_item('cookie_domain'), + $this->_csrf_cookie_name, + $this->_csrf_hash, + $expire, + config_item('cookie_path'), + config_item('cookie_domain'), $secure_cookie, config_item('cookie_httponly') ); @@ -227,9 +245,8 @@ class CI_Security { /** * Get CSRF Hash * - * Getter Method - * - * @return string self::_csrf_hash + * @see CI_Security::$_csrf_hash + * @return string CSRF hash */ public function get_csrf_hash() { @@ -241,9 +258,8 @@ class CI_Security { /** * Get CSRF Token Name * - * Getter Method - * - * @return string self::_csrf_token_name + * @see CI_Security::$_csrf_token_name + * @return string CSRF token name */ public function get_csrf_token_name() { @@ -256,26 +272,26 @@ class CI_Security { * XSS Clean * * Sanitizes data so that Cross Site Scripting Hacks can be - * prevented. This function does a fair amount of work but + * prevented. This method 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. + * Note: 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 + * @link http://channel.bitflux.ch/wiki/XSS_Prevention + * Based in part on some code and ideas from Bitflux. * - * 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 + * @link http://ha.ckers.org/xss.html + * 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. * - * @param mixed string or array - * @param bool + * @param string|string[] $str Input data + * @param bool $is_image Whether the input is an image * @return string */ public function xss_clean($str, $is_image = FALSE) @@ -362,9 +378,10 @@ class CI_Security { * These words are compacted back to their correct state. */ $words = array( - 'javascript', 'expression', 'vbscript', 'script', - 'applet', 'alert', 'document', 'write', 'cookie', 'window' - ); + 'javascript', 'expression', 'vbscript', 'script', 'base64', + 'applet', 'alert', 'document', 'write', 'cookie', 'window' + ); + foreach ($words as $word) { @@ -387,20 +404,20 @@ class CI_Security { if (preg_match('/<a/i', $str)) { - $str = preg_replace_callback('#<a\s+([^>]*?)(>|$)#si', array($this, '_js_link_removal'), $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); + $str = preg_replace_callback('#<img\s+([^>]*?)(?:\s?/?>|$)#si', array($this, '_js_img_removal'), $str); } - if (preg_match('/(script|xss)/i', $str)) + if (preg_match('/script|xss/i', $str)) { - $str = preg_replace('#<(/*)(script|xss)(.*?)\>#si', '[removed]', $str); + $str = preg_replace('#</*(?:script|xss).*?>#si', '[removed]', $str); } } - while($original != $str); + while ($original !== $str); unset($original); @@ -461,13 +478,16 @@ class CI_Security { // -------------------------------------------------------------------- /** - * Random Hash for protecting URLs + * XSS Hash * - * @return string + * Generates the XSS hash if needed and returns it. + * + * @see CI_Security::$_xss_hash + * @return string XSS hash */ public function xss_hash() { - if ($this->_xss_hash == '') + if ($this->_xss_hash === '') { mt_srand(); $this->_xss_hash = md5(time() + mt_rand(0, 1999999999)); @@ -481,7 +501,7 @@ class CI_Security { /** * HTML Entities Decode * - * This function is a replacement for html_entity_decode() + * 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 @@ -489,8 +509,10 @@ class CI_Security { * 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 + * @link http://php.net/html-entity-decode + * + * @param string $str Input + * @param string $charset Character set * @return string */ public function entity_decode($str, $charset = NULL) @@ -513,32 +535,32 @@ class CI_Security { // -------------------------------------------------------------------- /** - * Filename Security + * Sanitize Filename * - * @param string - * @param bool + * @param string $str Input file name + * @param bool $relative_path Whether to preserve paths * @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' // = - ); + '../', '<!--', '-->', '<', '>', + "'", '"', '&', '$', '#', + '{', '}', '[', ']', '=', + ';', '?', '%20', '%22', + '%3c', // < + '%253c', // < + '%3e', // > + '%0e', // > + '%28', // ( + '%29', // ) + '%2528', // ( + '%26', // & + '%24', // $ + '%3f', // ? + '%3b', // ; + '%3d' // = + ); if ( ! $relative_path) { @@ -553,13 +575,27 @@ class CI_Security { // ---------------------------------------------------------------- /** + * Strip Image Tags + * + * @param string $str + * @return string + */ + public function strip_image_tags($str) + { + return preg_replace(array('#<img\s+.*?src\s*=\s*["\'](.+?)["\'].*?\>#', '#<img\s+.*?src\s*=\s*(.+?).*?\>#'), '\\1', $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 + * Callback method for xss_clean() to remove whitespace from + * things like 'j a v a s c r i p t'. * - * @param type - * @return type + * @used-by CI_Security::xss_clean() + * @param array $matches + * @return string */ protected function _compact_exploded_words($matches) { @@ -568,20 +604,26 @@ class CI_Security { // -------------------------------------------------------------------- - /* - * Remove Evil HTML Attributes (like evenhandlers and style) + /** + * Remove Evil HTML Attributes (like event handlers and style) * * It removes the evil attribute and either: - * - Everything up until a space - * For example, everything between the pipes: + * + * - Everything up until a space. For example, everything between the pipes: + * + * <code> * <a |style=document.write('hello');alert('world');| class=link> - * - Everything inside the quotes - * For example, everything between the pipes: + * </code> + * + * - Everything inside the quotes. For example, everything between the pipes: + * + * <code> * <a |style="document.write('hello'); alert('world');"| class="link"> + * </code> * - * @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 + * @param string $str The string to check + * @param bool $is_image Whether the input is an image + * @return string The string with the evil attributes removed */ protected function _remove_evil_attributes($str, $is_image) { @@ -602,10 +644,11 @@ class CI_Security { $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); + preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*([^\s>]*)/is', $str, $matches, PREG_SET_ORDER); foreach ($matches as $attr) { + $attribs[] = preg_quote($attr[0], '/'); } @@ -620,7 +663,7 @@ class CI_Security { // replace illegal attribute strings that are inside an html tag if (count($attribs) > 0) { - $str = preg_replace('/<(\/?[^><]+?)([^A-Za-z\-])('.implode('|', $attribs).')([\s><])([><]*)/i', '<$1$2$4$5', $str, -1, $count); + $str = preg_replace('/<(\/?[^><]+?)([^A-Za-z<>\-])(.*?)('.implode('|', $attribs).')(.*?)([\s><])([><]*)/i', '<$1 $3$5$6$7', $str, -1, $count); } } while ($count); @@ -633,9 +676,10 @@ class CI_Security { /** * Sanitize Naughty HTML * - * Callback function for xss_clean() to remove naughty HTML elements + * Callback method for xss_clean() to remove naughty HTML elements. * - * @param array + * @used-by CI_Security::xss_clean() + * @param array $matches * @return string */ protected function _sanitize_naughty_html($matches) @@ -650,18 +694,20 @@ class CI_Security { /** * JS Link Removal * - * Callback function for xss_clean() to sanitize links + * Callback method 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 + * PHP 5.2+ on link-heavy strings. * - * @param array + * @used-by CI_Security::xss_clean() + * @param array $match * @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|base64\s*,)#si', + 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])) ), @@ -673,18 +719,20 @@ class CI_Security { /** * JS Image Removal * - * Callback function for xss_clean() to sanitize image tags + * Callback method 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 + * PHP 5.2+ on image tag heavy strings. * - * @param array + * @used-by CI_Security::xss_clean() + * @param array $match * @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', + 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])) ), @@ -696,9 +744,8 @@ class CI_Security { /** * Attribute Conversion * - * Used as a callback for XSS Clean - * - * @param array + * @used-by CI_Security::xss_clean() + * @param array $match * @return string */ protected function _convert_attribute($match) @@ -711,9 +758,11 @@ class CI_Security { /** * Filter Attributes * - * Filters tag attributes for consistency and safety + * Filters tag attributes for consistency and safety. * - * @param string + * @used-by CI_Security::_js_img_removal() + * @used-by CI_Security::_js_link_removal() + * @param string $str * @return string */ protected function _filter_attributes($str) @@ -735,9 +784,8 @@ class CI_Security { /** * HTML Entity Decode Callback * - * Used as a callback for XSS Clean - * - * @param array + * @used-by CI_Security::xss_clean() + * @param array $match * @return string */ protected function _decode_entity($match) @@ -750,9 +798,8 @@ class CI_Security { /** * Validate URL entities * - * Called by xss_clean() - * - * @param string + * @used-by CI_Security::xss_clean() + * @param string $str * @return string */ protected function _validate_entities($str) @@ -790,8 +837,7 @@ class CI_Security { /** * Do Never Allowed * - * A utility function for xss_clean() - * + * @used-by CI_Security::xss_clean() * @param string * @return string */ @@ -801,7 +847,7 @@ class CI_Security { foreach ($this->_never_allowed_regex as $regex) { - $str = preg_replace('#'.$regex.'#i', '[removed]', $str); + $str = preg_replace('#'.$regex.'#is', '[removed]', $str); } return $str; @@ -810,20 +856,20 @@ class CI_Security { // -------------------------------------------------------------------- /** - * Set Cross Site Request Forgery Protection Cookie + * Set CSRF Hash and Cookie * * @return string */ protected function _csrf_set_hash() { - if ($this->_csrf_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]) && - $_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]; } @@ -838,4 +884,4 @@ class CI_Security { } /* End of file Security.php */ -/* Location: ./system/core/Security.php */ +/* Location: ./system/core/Security.php */
\ No newline at end of file diff --git a/system/core/URI.php b/system/core/URI.php index 48bb7ae3c..91740254c 100755..100644 --- a/system/core/URI.php +++ b/system/core/URI.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -22,9 +22,9 @@ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 1.0 + * @filesource */ - -// ------------------------------------------------------------------------ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * URI Class @@ -40,37 +40,43 @@ class CI_URI { /** - * List of cached uri segments + * List of cached URI segments * - * @var array + * @var array */ - public $keyval = array(); + public $keyval = array(); + /** - * Current uri string + * Current URI string * - * @var string + * @var string */ public $uri_string; + /** - * List of uri segments + * List of URI segments * - * @var array + * @var array */ - public $segments = array(); + public $segments = array(); + /** - * Re-indexed list of uri segments - * Starts at 1 instead of 0 + * Re-indexed list of URI segments + * + * Starts at 1 instead of 0. * - * @var array + * @var array */ - public $rsegments = array(); + public $rsegments = array(); /** - * Constructor + * Class constructor * * Simply globalizes the $RTR object. The front * loads the Router class early on so it's not available * normally as other classes are. + * + * @return void */ public function __construct() { @@ -81,10 +87,9 @@ class CI_URI { // -------------------------------------------------------------------- /** - * Get the URI String - * - * Called by CI_Router + * Fetch URI String * + * @used-by CI_Router * @return void */ public function _fetch_uri_string() @@ -94,36 +99,33 @@ class CI_URI { // Is the request coming from the command line? if ($this->_is_cli_request()) { - $this->_set_uri_string($this->_parse_cli_args()); + $this->_set_uri_string($this->_parse_argv()); return; } - // Let's try the REQUEST_URI first, this will work in most situations - if ($uri = $this->_detect_uri()) + // Is there a PATH_INFO variable? This should be the easiest solution. + if (isset($_SERVER['PATH_INFO'])) { - $this->_set_uri_string($uri); + $this->_set_uri_string($_SERVER['PATH_INFO']); 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) + // Let's try REQUEST_URI then, this will work in most situations + if (($uri = $this->_parse_request_uri()) !== '') { - $this->_set_uri_string($path); + $this->_set_uri_string($uri); return; } - // No PATH_INFO?... What about QUERY_STRING? - $path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING'); - if (trim($path, '/') != '') + // No REQUEST_URI either?... What about QUERY_STRING? + if (($uri = $this->_parse_query_string()) !== '') { - $this->_set_uri_string($path); + $this->_set_uri_string($uri); return; } // As a last ditch effort lets try using the $_GET array - if (is_array($_GET) && count($_GET) === 1 && trim(key($_GET), '/') != '') + if (is_array($_GET) && count($_GET) === 1 && trim(key($_GET), '/') !== '') { $this->_set_uri_string(key($_GET)); return; @@ -136,138 +138,166 @@ class CI_URI { $uri = strtoupper($this->config->item('uri_protocol')); - if ($uri === 'REQUEST_URI') + if ($uri === 'CLI') { - $this->_set_uri_string($this->_detect_uri()); + $this->_set_uri_string($this->_parse_argv()); return; } - elseif ($uri === 'CLI') + elseif (method_exists($this, ($method = '_parse_'.strtolower($uri)))) { - $this->_set_uri_string($this->_parse_cli_args()); + $this->_set_uri_string($this->$method()); return; } - $path = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri); - $this->_set_uri_string($path); + $uri = isset($_SERVER[$uri]) ? $_SERVER[$uri] : @getenv($uri); + $this->_set_uri_string($uri); } // -------------------------------------------------------------------- /** - * Set the URI String + * Set URI String * - * @param string + * @param string $str * @return void */ - public function _set_uri_string($str) + protected 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; + // Filter out control characters and trim slashes + $this->uri_string = trim(remove_invisible_characters($str, FALSE), '/'); } // -------------------------------------------------------------------- /** - * Detects the URI + * Parse REQUEST_URI * - * This function will detect the URI automatically and fix the query string - * if necessary. + * Will parse REQUEST_URI and automatically detect the URI from it, + * while fixing the query string if necessary. * + * @used-by CI_URI::_fetch_uri_string() * @return string */ - protected function _detect_uri() + protected function _parse_request_uri() { - if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME'])) + if ( ! isset($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME'])) { return ''; } - $uri = $_SERVER['REQUEST_URI']; + $uri = parse_url($_SERVER['REQUEST_URI']); + $query = isset($uri['query']) ? $uri['query'] : ''; + $uri = isset($uri['path']) ? rawurldecode($uri['path']) : ''; + if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) { - $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME'])); + $uri = (string) substr($uri, strlen($_SERVER['SCRIPT_NAME'])); } elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0) { - $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME']))); + $uri = (string) 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) + if (trim($uri, '/') === '' && strncmp($query, '/', 1) === 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); + $query = explode('?', $query, 2); + $uri = rawurldecode($query[0]); + $_SERVER['QUERY_STRING'] = isset($query[1]) ? $query[1] : ''; } else { - $_SERVER['QUERY_STRING'] = ''; - $_GET = array(); + $_SERVER['QUERY_STRING'] = $query; } - if ($uri == '/' OR empty($uri)) + parse_str($_SERVER['QUERY_STRING'], $_GET); + + if ($uri === '/' OR $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, '/')); } // -------------------------------------------------------------------- - + /** - * Is cli Request? + * Parse QUERY_STRING * - * Duplicate of function from the Input class to test to see if a request was made from the command line + * Will parse QUERY_STRING and automatically detect the URI from it. * - * @return boolean + * @used-by CI_URI::_fetch_uri_string() + * @return string + */ + protected function _parse_query_string() + { + $uri = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING'); + + if (trim($uri, '/') === '') + { + return ''; + } + elseif (strncmp($uri, '/', 1) === 0) + { + $uri = explode('?', $uri, 2); + $_SERVER['QUERY_STRING'] = isset($uri[1]) ? $uri[1] : ''; + $uri = rawurldecode($uri[0]); + } + + parse_str($_SERVER['QUERY_STRING'], $_GET); + + return str_replace(array('//', '../'), '/', trim($uri, '/')); + } + + // -------------------------------------------------------------------- + + /** + * Is CLI Request? + * + * Duplicate of method from the Input class to test to see if + * a request was made from the command line. + * + * @see CI_Input::is_cli_request() + * @used-by CI_URI::_fetch_uri_string() + * @return bool */ protected function _is_cli_request() { - return (php_sapi_name() == 'cli') OR defined('STDIN'); + return (php_sapi_name() === 'cli') OR defined('STDIN'); } - // -------------------------------------------------------------------- /** - * Parse cli arguments + * Parse CLI arguments * * Take each command line argument and assume it is a URI segment. * * @return string */ - protected function _parse_cli_args() + protected function _parse_argv() { $args = array_slice($_SERVER['argv'], 1); - return $args ? '/' . implode('/', $args) : ''; + return $args ? implode('/', $args) : ''; } // -------------------------------------------------------------------- /** - * Filter segments for malicious characters + * Filter URI * - * Called by CI_Router + * Filters segments for malicious characters. * - * @param string + * @used-by CI_Router + * @param string $str * @return string */ public function _filter_uri($str) { - if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE) + 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 @@ -287,28 +317,32 @@ class CI_URI { // -------------------------------------------------------------------- /** - * Remove the suffix from the URL if needed + * Remove URL suffix * - * Called by CI_Router + * Removes the suffix from the URL if needed. * + * @used-by CI_Router * @return void */ public function _remove_url_suffix() { - if ($this->config->item('url_suffix') != '') + $suffix = (string) $this->config->item('url_suffix'); + + if ($suffix !== '' && ($offset = strrpos($this->uri_string, $suffix)) !== FALSE) { - $this->uri_string = preg_replace('|'.preg_quote($this->config->item('url_suffix')).'$|', '', $this->uri_string); + $this->uri_string = substr_replace($this->uri_string, '', $offset, strlen($suffix)); } } // -------------------------------------------------------------------- /** - * Explode the URI Segments. The individual segments will - * be stored in the $this->segments array. + * Explode URI segments * - * Called by CI_Router + * The individual segments will be stored in the $this->segments array. * + * @see CI_URI::$segments + * @used-by CI_Router * @return void */ public function _explode_segments() @@ -318,7 +352,7 @@ class CI_URI { // Filter segments for security $val = trim($this->_filter_uri($val)); - if ($val != '') + if ($val !== '') { $this->segments[] = $val; } @@ -326,16 +360,16 @@ class CI_URI { } // -------------------------------------------------------------------- + /** * 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. - * - * Called by CI_Router + * Re-indexes the CI_URI::$segment array so that it starts at 1 rather + * than 0. Doing so makes it simpler to use methods like + * CI_URI::segment(n) since there is a 1:1 relationship between the + * segment array and the actual segments. * + * @used-by CI_Router * @return void */ public function _reindex_segments() @@ -349,68 +383,76 @@ class CI_URI { // -------------------------------------------------------------------- /** - * Fetch a URI Segment - * - * This function returns the URI segment based on the number provided. + * Fetch URI Segment * - * @param integer - * @param bool - * @return string + * @see CI_URI::$segments + * @param int $n Index + * @param mixed $no_result What to return if the segment index is not found + * @return mixed */ - public function segment($n, $no_result = FALSE) + public function segment($n, $no_result = NULL) { - return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n]; + return isset($this->segments[$n]) ? $this->segments[$n] : $no_result; } // -------------------------------------------------------------------- /** - * Fetch a URI "routed" Segment + * Fetch 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() + * Returns the re-routed URI segment (assuming routing rules are used) + * based on the index provided. If there is no routing, will return + * the same result as CI_URI::segment(). * - * @param integer - * @param bool - * @return string + * @see CI_URI::$rsegments + * @see CI_URI::segment() + * @param int $n Index + * @param mixed $no_result What to return if the segment index is not found + * @return mixed */ - public function rsegment($n, $no_result = FALSE) + public function rsegment($n, $no_result = NULL) { - return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n]; + return isset($this->rsegments[$n]) ? $this->rsegments[$n] : $no_result; } // -------------------------------------------------------------------- /** - * Generate a key value pair from the URI string + * URI to assoc * - * This function generates and associative array of URI data starting - * at the supplied segment. For example, if this is your URI: + * Generates an associative array of URI data starting at the supplied + * segment index. 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: + * You can use this method to generate an array with this prototype: * - * array ( - * name => joe - * location => UK - * gender => male - * ) + * array ( + * name => joe + * location => UK + * gender => male + * ) * - * @param integer the starting segment number - * @param array an array of default values + * @param int $n Index (default: 3) + * @param array $default Default values * @return array */ public 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 + * Routed URI to assoc + * + * Identical to CI_URI::uri_to_assoc(), only it uses the re-routed + * segment array. * - * @param integer the starting segment number - * @param array an array of default values + * @see CI_URI::uri_to_assoc() + * @param int $n Index (default: 3) + * @param array $default Default values * @return array */ public function ruri_to_assoc($n = 3, $default = array()) @@ -421,11 +463,15 @@ class CI_URI { // -------------------------------------------------------------------- /** - * Generate a key value pair from the URI string or Re-routed URI string + * Internal URI-to-assoc * - * @param integer the starting segment number - * @param array an array of default values - * @param string which array we should use + * Generates a key/value pair from the URI string or re-routed URI string. + * + * @used-by CI_URI::uri_to_assoc() + * @used-by CI_URI::ruri_to_assoc() + * @param int $n Index (default: 3) + * @param array $default Default values + * @param string $which Array name ('segment' or 'rsegment') * @return array */ protected function _uri_to_assoc($n = 3, $default = array(), $which = 'segment') @@ -435,9 +481,11 @@ class CI_URI { return $default; } - if (isset($this->keyval[$n])) + in_array($which, array('segment', 'rsegment'), TRUE) OR $which = 'segment'; + + if (isset($this->keyval[$which], $this->keyval[$which][$n])) { - return $this->keyval[$n]; + return $this->keyval[$which][$n]; } if ($which === 'segment') @@ -453,18 +501,15 @@ class CI_URI { if ($this->$total_segments() < $n) { - if (count($default) === 0) - { - return array(); - } - - return array_fill_keys($default, FALSE); + return (count($default) === 0) + ? array() + : array_fill_keys($default, NULL); } $segments = array_slice($this->$segment_array(), ($n - 1)); $i = 0; $lastval = ''; - $retval = array(); + $retval = array(); foreach ($segments as $seg) { if ($i % 2) @@ -473,7 +518,7 @@ class CI_URI { } else { - $retval[$seg] = FALSE; + $retval[$seg] = NULL; $lastval = $seg; } @@ -486,29 +531,31 @@ class CI_URI { { if ( ! array_key_exists($val, $retval)) { - $retval[$val] = FALSE; + $retval[$val] = NULL; } } } // Cache the array for reuse - $this->keyval[$n] = $retval; + isset($this->keyval[$which]) OR $this->keyval[$which] = array(); + $this->keyval[$which][$n] = $retval; return $retval; } // -------------------------------------------------------------------- /** - * Generate a URI string from an associative array + * Assoc to URI * + * Generates a URI string from an associative array. * - * @param array an associative array of key/values - * @return array + * @param array $array Input array of key/value pairs + * @return string URI string */ public function assoc_to_uri($array) { $temp = array(); - foreach ((array)$array as $key => $val) + foreach ((array) $array as $key => $val) { $temp[] = $key; $temp[] = $val; @@ -520,10 +567,12 @@ class CI_URI { // -------------------------------------------------------------------- /** - * Fetch a URI Segment and add a trailing slash + * Slash segment * - * @param integer - * @param string + * Fetches an URI segment with a slash. + * + * @param int $n Index + * @param string $where Where to add the slash ('trailing' or 'leading') * @return string */ public function slash_segment($n, $where = 'trailing') @@ -534,10 +583,12 @@ class CI_URI { // -------------------------------------------------------------------- /** - * Fetch a URI Segment and add a trailing slash + * Slash routed segment + * + * Fetches an URI routed segment with a slash. * - * @param integer - * @param string + * @param int $n Index + * @param string $where Where to add the slash ('trailing' or 'leading') * @return string */ public function slash_rsegment($n, $where = 'trailing') @@ -548,11 +599,16 @@ class CI_URI { // -------------------------------------------------------------------- /** - * Fetch a URI Segment and add a trailing slash - helper function + * Internal Slash segment + * + * Fetches an URI Segment and adds a slash to it. + * + * @used-by CI_URI::slash_segment() + * @used-by CI_URI::slash_rsegment() * - * @param integer - * @param string - * @param string + * @param int $n Index + * @param string $where Where to add the slash ('trailing' or 'leading') + * @param string $which Array name ('segment' or 'rsegment') * @return string */ protected function _slash_segment($n, $where = 'trailing', $which = 'segment') @@ -576,7 +632,7 @@ class CI_URI { /** * Segment Array * - * @return array + * @return array CI_URI::$segments */ public function segment_array() { @@ -588,7 +644,7 @@ class CI_URI { /** * Routed Segment Array * - * @return array + * @return array CI_URI::$rsegments */ public function rsegment_array() { @@ -600,7 +656,7 @@ class CI_URI { /** * Total number of segments * - * @return integer + * @return int */ public function total_segments() { @@ -612,7 +668,7 @@ class CI_URI { /** * Total number of routed segments * - * @return integer + * @return int */ public function total_rsegments() { @@ -622,29 +678,35 @@ class CI_URI { // -------------------------------------------------------------------- /** - * Fetch the entire URI string + * Fetch URI string * - * @return string + * @return string CI_URI::$uri_string */ public function uri_string() { return $this->uri_string; } - // -------------------------------------------------------------------- /** - * Fetch the entire Re-routed URI string + * Fetch Re-routed URI string * * @return string */ public function ruri_string() { - return '/'.implode('/', $this->rsegment_array()); + global $RTR; + + if (($dir = $RTR->fetch_directory()) === '/') + { + $dir = ''; + } + + return $dir.implode('/', $this->rsegment_array()); } } /* End of file URI.php */ -/* Location: ./system/core/URI.php */ +/* Location: ./system/core/URI.php */
\ No newline at end of file diff --git a/system/core/Utf8.php b/system/core/Utf8.php index ba3567453..5bc2dd5c9 100644 --- a/system/core/Utf8.php +++ b/system/core/Utf8.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,8 +24,7 @@ * @since Version 2.0 * @filesource */ - -// ------------------------------------------------------------------------ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Utf8 Class @@ -41,38 +40,40 @@ class CI_Utf8 { /** - * Constructor + * Class constructor + * + * Determines if UTF-8 support is to be enabled. * - * Determines if UTF-8 support is to be enabled + * @return void */ public function __construct() { log_message('debug', 'Utf8 Class Initialized'); - global $CFG; + $charset = strtoupper(config_item('charset')); + + // 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($charset); + } + else + { + define('MB_ENABLED', FALSE); + } if ( - @preg_match('/./u', 'é') === 1 // PCRE must support UTF-8 - && function_exists('iconv') // iconv must be installed - && @ini_get('mbstring.func_overload') != 1 // Multibyte string function overloading cannot be enabled - && $CFG->item('charset') === 'UTF-8' // Application charset must be UTF-8 + @preg_match('/./u', 'é') === 1 // PCRE must support UTF-8 + && function_exists('iconv') // iconv must be installed + && MB_ENABLED === TRUE // mbstring must be enabled + && $charset === 'UTF-8' // Application charset must be UTF-8 ) { define('UTF8_ENABLED', TRUE); log_message('debug', 'UTF-8 Support Enabled'); - - // 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 { @@ -86,9 +87,11 @@ class CI_Utf8 { /** * Clean UTF-8 strings * - * Ensures strings are UTF-8 + * Ensures strings contain only valid UTF-8 characters. * - * @param string + * @uses CI_Utf8::_is_ascii() Decide whether a conversion is needed + * + * @param string $str String to clean * @return string */ public function clean_string($str) @@ -108,9 +111,9 @@ class CI_Utf8 { * * Removes all ASCII control characters except horizontal tabs, * line feeds, and carriage returns, as all others can cause - * problems in XML + * problems in XML. * - * @param string + * @param string $str String to clean * @return string */ public function safe_ascii_for_xml($str) @@ -123,11 +126,11 @@ class CI_Utf8 { /** * Convert to UTF-8 * - * Attempts to convert a string to UTF-8 + * Attempts to convert a string to UTF-8. * - * @param string - * @param string - input encoding - * @return string + * @param string $str Input string + * @param string $encoding Input encoding + * @return string $str encoded in UTF-8 or FALSE on failure */ public function convert_to_utf8($str, $encoding) { @@ -135,7 +138,7 @@ class CI_Utf8 { { return @iconv($encoding, 'UTF-8', $str); } - elseif (function_exists('mb_convert_encoding')) + elseif (MB_ENABLED === TRUE) { return @mb_convert_encoding($str, 'UTF-8', $encoding); } @@ -148,9 +151,9 @@ class CI_Utf8 { /** * Is ASCII? * - * Tests if a string is standard 7-bit ASCII or not + * Tests if a string is standard 7-bit ASCII or not. * - * @param string + * @param string $str String to check * @return bool */ protected function _is_ascii($str) @@ -161,4 +164,4 @@ class CI_Utf8 { } /* End of file Utf8.php */ -/* Location: ./system/core/Utf8.php */ +/* Location: ./system/core/Utf8.php */
\ No newline at end of file diff --git a/system/database/DB.php b/system/database/DB.php index 0d81e40d3..f4062fa73 100755..100644 --- a/system/database/DB.php +++ b/system/database/DB.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,17 +24,20 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Initialize the database * * @category Database - * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/database/ - * @param string - * @param bool Determines if active record should be used or not + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + * + * @param string|string[] $params + * @param bool $query_builder_override + * Determines if query builder should be used or not */ -function &DB($params = '', $active_record_override = NULL) +function &DB($params = '', $query_builder_override = NULL) { // Load the DB config file if a DSN string wasn't passed if (is_string($params) && strpos($params, '://') === FALSE) @@ -47,13 +50,28 @@ function &DB($params = '', $active_record_override = NULL) } include($file_path); + // Make packages contain database config files + foreach (get_instance()->load->get_package_paths() as $path) + { + if ($path !== APPPATH) + { + if (file_exists($file_path = $path.'config/'.ENVIRONMENT.'/database.php')) + { + include($file_path); + } + elseif (file_exists($file_path = $path.'config/database.php')) + { + 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 != '') + if ($params !== '') { $active_group = $params; } @@ -67,12 +85,12 @@ function &DB($params = '', $active_record_override = NULL) } 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'; + /** + * 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 (($dsn = @parse_url($params)) === FALSE) { @@ -88,7 +106,7 @@ function &DB($params = '', $active_record_override = NULL) 'database' => isset($dsn['path']) ? rawurldecode(substr($dsn['path'], 1)) : '' ); - // were additional config items set? + // Were additional config items set? if (isset($dsn['query'])) { parse_str($dsn['query'], $extra); @@ -106,38 +124,59 @@ function &DB($params = '', $active_record_override = NULL) } // No DB specified yet? Beat them senseless... - if ( ! isset($params['dbdriver']) OR $params['dbdriver'] == '') + if (empty($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 + // Load the DB classes. Note: Since the query builder 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. - if ($active_record_override !== NULL) + // based on whether we're using the query builder class or not. + if ($query_builder_override !== NULL) { - $active_record = $active_record_override; + $query_builder = $query_builder_override; + } + // Backwards compatibility work-around for keeping the + // $active_record config variable working. Should be + // removed in v3.1 + elseif ( ! isset($query_builder) && isset($active_record)) + { + $query_builder = $active_record; } require_once(BASEPATH.'database/DB_driver.php'); - if ( ! isset($active_record) OR $active_record == TRUE) + if ( ! isset($query_builder) OR $query_builder === TRUE) { - require_once(BASEPATH.'database/DB_active_rec.php'); + require_once(BASEPATH.'database/DB_query_builder.php'); if ( ! class_exists('CI_DB')) { - class CI_DB extends CI_DB_active_record { } + /** + * CI_DB + * + * Acts as an alias for both CI_DB_driver and CI_DB_query_builder. + * + * @see CI_DB_query_builder + * @see CI_DB_driver + */ + class CI_DB extends CI_DB_query_builder { } } } elseif ( ! class_exists('CI_DB')) { + /** + * @ignore + */ class CI_DB extends CI_DB_driver { } } // Load the DB driver $driver_file = BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php'; - if ( ! file_exists($driver_file)) show_error('Invalid DB driver'); + if ( ! file_exists($driver_file)) + { + show_error('Invalid DB driver'); + } require_once($driver_file); @@ -145,12 +184,25 @@ function &DB($params = '', $active_record_override = NULL) $driver = 'CI_DB_'.$params['dbdriver'].'_driver'; $DB = new $driver($params); - if ($DB->autoinit == TRUE) + // Check for a subdriver + if ( ! empty($DB->subdriver)) + { + $driver_file = BASEPATH.'database/drivers/'.$DB->dbdriver.'/subdrivers/'.$DB->dbdriver.'_'.$DB->subdriver.'_driver.php'; + + if (file_exists($driver_file)) + { + require_once($driver_file); + $driver = 'CI_DB_'.$DB->dbdriver.'_'.$DB->subdriver.'_driver'; + $DB = new $driver($params); + } + } + + if ($DB->autoinit === TRUE) { $DB->initialize(); } - if (isset($params['stricton']) && $params['stricton'] == TRUE) + if ( ! empty($params['stricton'])) { $DB->query('SET SESSION sql_mode="STRICT_ALL_TABLES"'); } diff --git a/system/database/DB_cache.php b/system/database/DB_cache.php index ff942856b..1be80c5c7 100644 --- a/system/database/DB_cache.php +++ b/system/database/DB_cache.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Database Cache Class @@ -34,15 +35,39 @@ */ class CI_DB_Cache { + /** + * CI Singleton + * + * @var object + */ public $CI; - public $db; // allows passing of db object so that multiple database connections and returned db objects can be supported + /** + * Database object + * + * Allows passing of DB object so that multiple database connections + * and returned DB objects can be supported. + * + * @var object + */ + public $db; + + // -------------------------------------------------------------------- + + /** + * Constructor + * + * @param object &$db + * @return void + */ public function __construct(&$db) { // Assign the main CI object to $this->CI and load the file helper since we use it a lot $this->CI =& get_instance(); $this->db =& $db; $this->CI->load->helper('file'); + + $this->check_path(); } // -------------------------------------------------------------------- @@ -50,14 +75,14 @@ class CI_DB_Cache { /** * Set Cache Directory Path * - * @param string the path to the cache directory + * @param string $path Path to the cache directory * @return bool */ public function check_path($path = '') { - if ($path == '') + if ($path === '') { - if ($this->db->cachedir == '') + if ($this->db->cachedir === '') { return $this->db->cache_off(); } @@ -66,7 +91,9 @@ class CI_DB_Cache { } // Add a trailing slash to the path if needed - $path = preg_replace('/(.+?)\/*$/', '\\1/', $path); + $path = realpath($path) + ? rtrim(realpath($path), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR + : rtrim($path, '/').'/'; if ( ! is_dir($path) OR ! is_really_writable($path)) { @@ -84,22 +111,18 @@ class CI_DB_Cache { * 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 + * An MD5 hash of the SQL statement will become the cache file name. * + * @param string $sql * @return string */ public 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))) + if (FALSE === ($cachedata = file_get_contents($filepath))) { return FALSE; } @@ -112,15 +135,12 @@ class CI_DB_Cache { /** * Write a query to a cache file * + * @param string $sql + * @param object $object * @return bool */ public 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.'/'; @@ -150,16 +170,18 @@ class CI_DB_Cache { /** * Delete cache files within a particular directory * - * @return bool + * @param string $segment_one + * @param string $segment_two + * @return void */ public function delete($segment_one = '', $segment_two = '') { - if ($segment_one == '') + if ($segment_one === '') { $segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1); } - if ($segment_two == '') + if ($segment_two === '') { $segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2); } @@ -173,11 +195,11 @@ class CI_DB_Cache { /** * Delete all existing cache files * - * @return bool + * @return void */ public function delete_all() { - delete_files($this->db->cachedir, TRUE, 0, TRUE); + delete_files($this->db->cachedir, TRUE, TRUE); } } diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php index 61b05d52b..4fcb6c63c 100644 --- a/system/database/DB_driver.php +++ b/system/database/DB_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Database Driver Class @@ -40,43 +41,316 @@ */ abstract class CI_DB_driver { + /** + * Data Source Name / Connect string + * + * @var string + */ public $dsn; + + /** + * Username + * + * @var string + */ public $username; + + /** + * Password + * + * @var string + */ public $password; + + /** + * Hostname + * + * @var string + */ public $hostname; + + /** + * Database name + * + * @var string + */ public $database; - public $dbdriver = 'mysql'; + + /** + * Database driver + * + * @var string + */ + public $dbdriver = 'mysqli'; + + /** + * Sub-driver + * + * @used-by CI_DB_pdo_driver + * @var string + */ + public $subdriver; + + /** + * Table prefix + * + * @var string + */ public $dbprefix = ''; + + /** + * Character set + * + * @var string + */ public $char_set = 'utf8'; + + /** + * Collation + * + * @var string + */ public $dbcollat = 'utf8_general_ci'; - public $autoinit = TRUE; // Whether to automatically initialize the DB + + /** + * Auto-init flag + * + * Whether to automatically initialize the DB connection. + * + * @var bool + */ + public $autoinit = TRUE; + + /** + * Encryption flag/data + * + * @var mixed + */ + public $encrypt = FALSE; + + /** + * Swap Prefix + * + * @var string + */ public $swap_pre = ''; + + /** + * Database port + * + * @var int + */ public $port = ''; + + /** + * Persistent connection flag + * + * @var bool + */ public $pconnect = FALSE; + + /** + * Connection ID + * + * @var object|resource + */ public $conn_id = FALSE; + + /** + * Result ID + * + * @var object|resource + */ public $result_id = FALSE; + + /** + * Debug flag + * + * Whether to display error messages. + * + * @var bool + */ public $db_debug = FALSE; + + /** + * Benchmark time + * + * @var int + */ public $benchmark = 0; + + /** + * Executed queries count + * + * @var int + */ public $query_count = 0; + + /** + * Bind marker + * + * Character used to identify values in a prepared statement. + * + * @var string + */ public $bind_marker = '?'; + + /** + * Save queries flag + * + * Whether to keep an in-memory history of queries for debugging purposes. + * + * @var bool + */ public $save_queries = TRUE; + + /** + * Queries list + * + * @see CI_DB_driver::$save_queries + * @var string[] + */ public $queries = array(); + + /** + * Query times + * + * A list of times that queries took to execute. + * + * @var array + */ public $query_times = array(); + + /** + * Data cache + * + * An internal generic value cache. + * + * @var array + */ public $data_cache = array(); + /** + * Transaction enabled flag + * + * @var bool + */ public $trans_enabled = TRUE; + + /** + * Strict transaction mode flag + * + * @var bool + */ public $trans_strict = TRUE; + + /** + * Transaction depth level + * + * @var int + */ protected $_trans_depth = 0; - protected $_trans_status = TRUE; // Used with transactions to determine if a rollback should occur + /** + * Transaction status flag + * + * Used with transactions to determine if a rollback should occur. + * + * @var bool + */ + protected $_trans_status = TRUE; + + /** + * Cache On flag + * + * @var bool + */ public $cache_on = FALSE; + + /** + * Cache directory path + * + * @var bool + */ public $cachedir = ''; + + /** + * Cache auto-delete flag + * + * @var bool + */ public $cache_autodel = FALSE; - public $CACHE; // The cache class object + /** + * DB Cache object + * + * @see CI_DB_cache + * @var object + */ + public $CACHE; + + /** + * Protect identifiers flag + * + * @var bool + */ protected $_protect_identifiers = TRUE; - protected $_reserved_identifiers = array('*'); // Identifiers that should NOT be escaped + /** + * List of reserved identifiers + * + * Identifiers that must NOT be escaped. + * + * @var string[] + */ + protected $_reserved_identifiers = array('*'); + + /** + * Identifier escape character + * + * @var string + */ + protected $_escape_char = '"'; + + /** + * ESCAPE statement string + * + * @var string + */ + protected $_like_escape_str = " ESCAPE '%s' "; + + /** + * ESCAPE character + * + * @var string + */ + protected $_like_escape_chr = '!'; + + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('RAND()', 'RAND(%d)'); + + /** + * COUNT string + * + * @used-by CI_DB_driver::count_all() + * @used-by CI_DB_query_builder::count_all_results() + * + * @var string + */ + protected $_count_string = 'SELECT COUNT(*) AS '; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @param array $params + * @return void + */ public function __construct($params) { if (is_array($params)) @@ -113,7 +387,7 @@ abstract class CI_DB_driver { // ---------------------------------------------------------------- // Connect to the database and set the connection ID - $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect(); + $this->conn_id = ($this->pconnect === FALSE) ? $this->db_connect() : $this->db_pconnect(); // No connection resource? Check if there is a failover else throw an error if ( ! $this->conn_id) @@ -131,7 +405,7 @@ abstract class CI_DB_driver { } // Try to connect - $this->conn_id = ($this->pconnect == FALSE) ? $this->db_connect() : $this->db_pconnect(); + $this->conn_id = ($this->pconnect === FALSE) ? $this->db_connect() : $this->db_pconnect(); // If a connection is made break the foreach loop if ($this->conn_id) @@ -291,21 +565,26 @@ abstract class CI_DB_driver { * FALSE upon failure, and if the $db_debug variable is set to TRUE * will raise an error. * - * @param string An SQL query string - * @param array An array of binding data + * @param string $sql + * @param array $binds = FALSE An array of binding data + * @param bool $return_object = NULL * @return mixed */ - public function query($sql, $binds = FALSE, $return_object = TRUE) + public function query($sql, $binds = FALSE, $return_object = NULL) { - if ($sql == '') + if ($sql === '') { log_message('error', 'Invalid query: '.$sql); return ($this->db_debug) ? $this->display_error('db_invalid_query') : FALSE; } + elseif ( ! is_bool($return_object)) + { + $return_object = ! $this->is_write_type($sql); + } // Verify table prefix and replace if necessary - if ($this->dbprefix != '' && $this->swap_pre != '' && $this->dbprefix != $this->swap_pre) + if ($this->dbprefix !== '' && $this->swap_pre !== '' && $this->dbprefix !== $this->swap_pre) { $sql = preg_replace('/(\W)'.$this->swap_pre.'(\S+?)/', '\\1'.$this->dbprefix.'\\2', $sql); } @@ -319,7 +598,7 @@ abstract class CI_DB_driver { // 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 && stripos($sql, 'SELECT') !== FALSE && $this->_cache_init()) + if ($this->cache_on === TRUE && $return_object === TRUE && $this->_cache_init()) { $this->load_rdriver(); if (FALSE !== ($cache = $this->CACHE->read($sql))) @@ -328,19 +607,19 @@ abstract class CI_DB_driver { } } - // Save the query for debugging - if ($this->save_queries == TRUE) + // Save the query for debugging + if ($this->save_queries === TRUE) { $this->queries[] = $sql; } // Start the Query Timer - $time_start = list($sm, $ss) = explode(' ', microtime()); + $time_start = microtime(TRUE); // Run the Query if (FALSE === ($this->result_id = $this->simple_query($sql))) { - if ($this->save_queries == TRUE) + if ($this->save_queries === TRUE) { $this->query_times[] = 0; } @@ -352,7 +631,7 @@ abstract class CI_DB_driver { $error = $this->error(); // Log errors - log_message('error', 'Query error: '.$error['message']); + log_message('error', 'Query error: '.$error['message'].' - Invalid query: '.$sql); if ($this->db_debug) { @@ -370,24 +649,22 @@ abstract class CI_DB_driver { } // Stop and aggregate the query time results - $time_end = list($em, $es) = explode(' ', microtime()); - $this->benchmark += ($em + $es) - ($sm + $ss); + $time_end = microtime(TRUE); + $this->benchmark += $time_end - $time_start; - if ($this->save_queries == TRUE) + if ($this->save_queries === TRUE) { - $this->query_times[] = ($em + $es) - ($sm + $ss); + $this->query_times[] = $time_end - $time_start; } // 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) + // Will we have a result object instantiated? If not - we'll simply return TRUE + if ($return_object !== TRUE) { - // If caching is enabled we'll auto-cleanup any - // existing files related to this particular URI - if ($this->cache_on == TRUE && $this->cache_autodel == TRUE && $this->_cache_init()) + // If caching is enabled we'll auto-cleanup any existing files related to this particular URI + if ($this->cache_on === TRUE && $this->cache_autodel === TRUE && $this->_cache_init()) { $this->CACHE->delete(); } @@ -396,8 +673,6 @@ abstract class CI_DB_driver { } // 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; @@ -409,7 +684,7 @@ abstract class CI_DB_driver { // Is query caching enabled? If so, we'll serialize the // result object and save it to a cache file. - if ($this->cache_on == TRUE && $this->_cache_init()) + if ($this->cache_on === TRUE && $this->_cache_init()) { // We'll create a new instance of the result object // only without the platform specific driver since @@ -495,6 +770,7 @@ abstract class CI_DB_driver { * If strict mode is disabled, each group is treated autonomously, meaning * a failure of one group will not affect any others * + * @param bool $mode = TRUE * @return void */ public function trans_strict($mode = TRUE) @@ -507,6 +783,7 @@ abstract class CI_DB_driver { /** * Start Transaction * + * @param bool $test_mode = FALSE * @return void */ public function trans_start($test_mode = FALSE) @@ -596,35 +873,53 @@ abstract class CI_DB_driver { */ public function compile_binds($sql, $binds) { - if (strpos($sql, $this->bind_marker) === FALSE) + if (empty($binds) OR empty($this->bind_marker) OR strpos($sql, $this->bind_marker) === FALSE) { return $sql; } - - if ( ! is_array($binds)) + elseif ( ! is_array($binds)) { $binds = array($binds); + $bind_count = 1; + } + else + { + // Make sure we're using numeric keys + $binds = array_values($binds); + $bind_count = count($binds); } - // Get the sql segments around the bind markers - $segments = explode($this->bind_marker, $sql); + // We'll need the marker length later + $ml = strlen($this->bind_marker); - // 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)) + // Make sure not to replace a chunk inside a string that happens to match the bind marker + if ($c = preg_match_all("/'[^']*'/i", $sql, $matches)) { - $binds = array_slice($binds, 0, count($segments)-1); + $c = preg_match_all('/'.preg_quote($this->bind_marker, '/').'/i', + str_replace($matches[0], + str_replace($this->bind_marker, str_repeat(' ', $ml), $matches[0]), + $sql, $c), + $matches, PREG_OFFSET_CAPTURE); + + // Bind values' count must match the count of markers in the query + if ($bind_count !== $c) + { + return $sql; + } + } + elseif (($c = preg_match_all('/'.preg_quote($this->bind_marker, '/').'/i', $sql, $matches, PREG_OFFSET_CAPTURE)) !== $bind_count) + { + return $sql; } - // Construct the binded query - $result = $segments[0]; - $i = 0; - foreach ($binds as $bind) + do { - $result .= $this->escape($bind).$segments[++$i]; + $c--; + $sql = substr_replace($sql, $this->escape($binds[$c]), $matches[0][$c][1], $ml); } + while ($c !== 0); - return $result; + return $sql; } // -------------------------------------------------------------------- @@ -637,7 +932,7 @@ abstract class CI_DB_driver { */ public function is_write_type($sql) { - return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql); + return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX)\s+/i', $sql); } // -------------------------------------------------------------------- @@ -742,8 +1037,38 @@ abstract class CI_DB_driver { // -------------------------------------------------------------------- /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the specified database + * + * @param string + * @return int + */ + public function count_all($table = '') + { + if ($table === '') + { + return 0; + } + + $query = $this->query($this->_count_string.$this->escape_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE)); + if ($query->num_rows() === 0) + { + return 0; + } + + $query = $query->row(); + $this->_reset_select(); + return (int) $query->numrows; + } + + // -------------------------------------------------------------------- + + /** * Returns an array of table names * + * @param string $constrain_by_prefix = FALSE * @return array */ public function list_tables($constrain_by_prefix = FALSE) @@ -798,6 +1123,7 @@ abstract class CI_DB_driver { /** * Determine if a particular table exists * + * @param string $table_name * @return bool */ public function table_exists($table_name) @@ -808,7 +1134,7 @@ abstract class CI_DB_driver { // -------------------------------------------------------------------- /** - * Fetch MySQL Field Names + * Fetch Field Names * * @param string the table name * @return array @@ -821,7 +1147,7 @@ abstract class CI_DB_driver { return $this->data_cache['field_names'][$table]; } - if ($table == '') + if ($table === '') { return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE; } @@ -889,7 +1215,7 @@ abstract class CI_DB_driver { */ public function field_data($table = '') { - if ($table == '') + if ($table === '') { return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE; } @@ -905,34 +1231,57 @@ abstract class CI_DB_driver { * * This function escapes column and table names * - * @param string - * @return string + * @param mixed + * @return mixed */ public function escape_identifiers($item) { - if ($this->_escape_char == '') + if ($this->_escape_char === '' OR empty($item) OR in_array($item, $this->_reserved_identifiers)) { return $item; } - - foreach ($this->_reserved_identifiers as $id) + elseif (is_array($item)) { - if (strpos($item, '.'.$id) !== FALSE) + foreach ($item as $key => $value) { - $item = str_replace('.', $this->_escape_char.'.', $item); + $item[$key] = $this->escape_identifiers($value); + } + + return $item; + } + // Avoid breaking functions and literal values inside queries + elseif (ctype_digit($item) OR $item[0] === "'" OR ($this->_escape_char !== '"' && $item[0] === '"') OR strpos($item, '(') !== FALSE) + { + return $item; + } - // remove duplicates if the user already included the escape - return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item); + static $preg_ec = array(); + + if (empty($preg_ec)) + { + if (is_array($this->_escape_char)) + { + $preg_ec = array( + preg_quote($this->_escape_char[0], '/'), preg_quote($this->_escape_char[1], '/'), + $this->_escape_char[0], $this->_escape_char[1] + ); + } + else + { + $preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char, '/'); + $preg_ec[2] = $preg_ec[3] = $this->_escape_char; } } - if (strpos($item, '.') !== FALSE) + foreach ($this->_reserved_identifiers as $id) { - $item = str_replace('.', $this->_escape_char.'.'.$this->_escape_char, $item); + if (strpos($item, '.'.$id) !== FALSE) + { + return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?\./i', $preg_ec[2].'$1'.$preg_ec[3].'.', $item); + } } - // remove duplicates if the user already included the escape - return preg_replace('/['.$this->_escape_char.']+/', $this->_escape_char, $this->_escape_char.$item.$this->_escape_char); + return preg_replace('/'.$preg_ec[0].'?([^'.$preg_ec[1].'\.]+)'.$preg_ec[1].'?(\.)?/i', $preg_ec[2].'$1'.$preg_ec[3].'$2', $item); } // -------------------------------------------------------------------- @@ -960,6 +1309,23 @@ abstract class CI_DB_driver { // -------------------------------------------------------------------- /** + * Insert statement + * + * Generates a platform-specific insert string from the supplied data + * + * @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).')'; + } + + // -------------------------------------------------------------------- + + /** * Generate an update string * * @param string the table upon which the query will be performed @@ -969,44 +1335,44 @@ abstract class CI_DB_driver { */ public function update_string($table, $data, $where) { - if ($where == '') + if (empty($where)) { return FALSE; } + $this->where($where); + $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 '; - $key = $this->protect_identifiers($key); - - if ($val !== '') - { - if ( ! $this->_has_operator($key)) - { - $key .= ' ='; - } + return $this->_update($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest); + } - $val = ' '.$this->escape($val); - } + // -------------------------------------------------------------------- - $dest[] = $prefix.$key.$val; - } + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @param string the table name + * @param array the update data + * @return string + */ + protected function _update($table, $values) + { + foreach ($values as $key => $val) + { + $valstr[] = $key.' = '.$val; } - return $this->_update($this->protect_identifiers($table, TRUE, NULL, FALSE), $fields, $dest); + return 'UPDATE '.$table.' SET '.implode(', ', $valstr) + .$this->_compile_wh('qb_where') + .$this->_compile_order_by() + .($this->qb_limit ? ' LIMIT '.$this->qb_limit : ''); } // -------------------------------------------------------------------- @@ -1019,7 +1385,43 @@ abstract class CI_DB_driver { */ protected function _has_operator($str) { - return (bool) preg_match('/(\s|<|>|!|=|IS NULL|IS NOT NULL)/i', trim($str)); + return (bool) preg_match('/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i', trim($str)); + } + + // -------------------------------------------------------------------- + + /** + * Returns the SQL string operator + * + * @param string + * @return string + */ + protected function _get_operator($str) + { + static $_operators; + + if (empty($_operators)) + { + $_les = ($this->_like_escape_str !== '') + ? '\s+'.preg_quote(trim(sprintf($this->_like_escape_str, $this->_like_escape_chr)), '/') + : ''; + $_operators = array( + '\s*(?:<|>|!)?=\s*', // =, <=, >=, != + '\s*<>?\s*', // <, <> + '\s*>\s*', // > + '\s+IS NULL', // IS NULL + '\s+IS NOT NULL', // IS NOT NULL + '\s+BETWEEN\s+\S+\s+AND\s+\S+', // BETWEEN value AND value + '\s+IN\s*\([^\)]+\)', // IN(list) + '\s+NOT IN\s*\([^\)]+\)', // NOT IN (list) + '\s+LIKE\s+\S+'.$_les, // LIKE 'expr'[ ESCAPE '%s'] + '\s+NOT LIKE\s+\S+'.$_les // NOT LIKE 'expr'[ ESCAPE '%s'] + ); + + } + + return preg_match('/'.implode('|', $_operators).'/i', $str, $match) + ? $match[0] : FALSE; } // -------------------------------------------------------------------- @@ -1027,13 +1429,12 @@ abstract class CI_DB_driver { /** * Enables a native PHP function to be run, using a platform agnostic wrapper. * - * @param string the function name - * @param mixed any parameters needed by the function + * @param string $function Function name * @return mixed */ public function call_function($function) { - $driver = ($this->dbdriver == 'postgre') ? 'pg_' : $this->dbdriver.'_'; + $driver = ($this->dbdriver === 'postgre') ? 'pg_' : $this->dbdriver.'_'; if (FALSE === strpos($driver, $function)) { @@ -1087,12 +1488,13 @@ abstract class CI_DB_driver { return $this->cache_on = FALSE; } - // -------------------------------------------------------------------- /** * Delete the cache files associated with a particular URI * + * @param string $segment_one = '' + * @param string $segment_two = '' * @return bool */ public function cache_delete($segment_one = '', $segment_two = '') @@ -1152,7 +1554,7 @@ abstract class CI_DB_driver { { if ($this->conn_id) { - $this->_close($this->conn_id); + $this->_close(); $this->conn_id = FALSE; } } @@ -1160,6 +1562,20 @@ abstract class CI_DB_driver { // -------------------------------------------------------------------- /** + * Close DB Connection + * + * This method would be overriden by most of the drivers. + * + * @return void + */ + protected function _close() + { + $this->conn_id = FALSE; + } + + // -------------------------------------------------------------------- + + /** * Display an error message * * @param string the error message @@ -1174,13 +1590,13 @@ abstract class CI_DB_driver { $heading = $LANG->line('db_error_heading'); - if ($native == TRUE) + if ($native === TRUE) { $message = (array) $error; } else { - $message = ( ! is_array($error)) ? array(str_replace('%s', $swap, $LANG->line($error))) : $error; + $message = is_array($error) ? $error : array(str_replace('%s', $swap, $LANG->line($error))); } // Find the most likely culprit of the error by going through @@ -1189,10 +1605,16 @@ abstract class CI_DB_driver { $trace = debug_backtrace(); foreach ($trace as $call) { - if (isset($call['file']) && strpos($call['file'], BASEPATH.'database') === FALSE) + // We'll need this on Windows, as APPPATH and BASEPATH will always use forward slashes + if (DIRECTORY_SEPARATOR !== '/') + { + $call['file'] = str_replace('\\', '/', $call['file']); + } + + if (isset($call['file'], $call['class']) && strpos($call['file'], BASEPATH.'database') === FALSE && strpos($call['class'], 'Loader') !== FALSE) { // Found it - use a relative path for safety - $message[] = 'Filename: '.str_replace(array(BASEPATH, APPPATH), '', $call['file']); + $message[] = 'Filename: '.str_replace(array(APPPATH, BASEPATH), '', $call['file']); $message[] = 'Line Number: '.$call['line']; break; } @@ -1208,7 +1630,7 @@ abstract class CI_DB_driver { /** * Protect Identifiers * - * This function is used extensively by the Active Record class, and by + * This function is used extensively by the Query Builder 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 @@ -1243,34 +1665,43 @@ abstract class CI_DB_driver { $escaped_array = array(); foreach ($item as $k => $v) { - $escaped_array[$this->protect_identifiers($k)] = $this->protect_identifiers($v); + $escaped_array[$this->protect_identifiers($k)] = $this->protect_identifiers($v, $prefix_single, $protect_identifiers, $field_exists); } return $escaped_array; } + // 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; + } + // Convert tabs or multiple spaces into single spaces - $item = preg_replace('/[\t ]+/', ' ', $item); + $item = preg_replace('/\s+/', ' ', $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) + // Note: strripos() is used in order to support spaces in table names + if ($offset = strripos($item, ' AS ')) { - $alias = strstr($item, ' '); - $item = substr($item, 0, - strlen($alias)); + $alias = ($protect_identifiers) + ? substr($item, $offset, 4).$this->escape_identifiers(substr($item, $offset + 4)) + : substr($item, $offset); + $item = substr($item, 0, $offset); } - else + elseif ($offset = strrpos($item, ' ')) { - $alias = ''; + $alias = ($protect_identifiers) + ? ' '.$this->escape_identifiers(substr($item, $offset + 1)) + : substr($item, $offset); + $item = substr($item, 0, $offset); } - - // 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) + else { - return $item.$alias; + $alias = ''; } // Break the string apart if it contains periods, then insert the table prefix @@ -1283,7 +1714,7 @@ abstract class CI_DB_driver { // 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 (in_array($parts[0], $this->qb_aliased_tables)) { if ($protect_identifiers === TRUE) { @@ -1302,7 +1733,7 @@ abstract class CI_DB_driver { } // Is there a table prefix defined in the config file? If not, no need to do anything - if ($this->dbprefix != '') + if ($this->dbprefix !== '') { // We now add the table prefix based on some logic. // Do we have 4 segments (hostname.database.table.column)? @@ -1326,13 +1757,13 @@ abstract class CI_DB_driver { // 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) + if ($field_exists === FALSE) { $i++; } // Verify table prefix and replace if necessary - if ($this->swap_pre != '' && strpos($parts[$i], $this->swap_pre) === 0) + if ($this->swap_pre !== '' && strpos($parts[$i], $this->swap_pre) === 0) { $parts[$i] = preg_replace('/^'.$this->swap_pre.'(\S+?)/', $this->dbprefix.'\\1', $parts[$i]); } @@ -1355,15 +1786,15 @@ abstract class CI_DB_driver { } // Is there a table prefix? If not, no need to insert it - if ($this->dbprefix != '') + if ($this->dbprefix !== '') { // Verify table prefix and replace if necessary - if ($this->swap_pre != '' && strpos($item, $this->swap_pre) === 0) + if ($this->swap_pre !== '' && strpos($item, $this->swap_pre) === 0) { $item = preg_replace('/^'.$this->swap_pre.'(\S+?)/', $this->dbprefix.'\\1', $item); } // Do we prefix an item with no segments? - elseif ($prefix_single == TRUE && strpos($item, $this->dbprefix) !== 0) + elseif ($prefix_single === TRUE && strpos($item, $this->dbprefix) !== 0) { $item = $this->dbprefix.$item; } @@ -1380,9 +1811,8 @@ abstract class CI_DB_driver { // -------------------------------------------------------------------- /** - * Dummy method that allows Active Record class to be disabled - * - * This function is used extensively by every db driver. + * Dummy method that allows Query Builder class to be disabled + * and keep count_all() working. * * @return void */ diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php index a519575f0..21046012a 100644 --- a/system/database/DB_forge.php +++ b/system/database/DB_forge.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Database Forge Class @@ -34,22 +35,127 @@ */ abstract class CI_DB_forge { + /** + * Database object + * + * @var object + */ + protected $db; + + /** + * Fields data + * + * @var array + */ public $fields = array(); + + /** + * Keys data + * + * @var array + */ public $keys = array(); + + /** + * Primary Keys data + * + * @var array + */ public $primary_keys = array(); - public $db_char_set = ''; - // Platform specific SQL strings + /** + * Database character set + * + * @var string + */ + public $db_char_set = ''; + + // -------------------------------------------------------------------- + + /** + * CREATE DATABASE statement + * + * @var string + */ protected $_create_database = 'CREATE DATABASE %s'; + + /** + * DROP DATABASE statement + * + * @var string + */ protected $_drop_database = 'DROP DATABASE %s'; - protected $_drop_table = 'DROP TABLE IF EXISTS %s'; - protected $_rename_table = 'ALTER TABLE %s RENAME TO %s'; - public function __construct() + /** + * CREATE TABLE statement + * + * @var string + */ + protected $_create_table = "%s %s (%s\n)"; + + /** + * CREATE TABLE IF statement + * + * @var string + */ + protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS'; + + /** + * CREATE TABLE keys flag + * + * Whether table keys are created from within the + * CREATE TABLE statement. + * + * @var bool + */ + protected $_create_table_keys = FALSE; + + /** + * DROP TABLE IF EXISTS statement + * + * @var string + */ + protected $_drop_table_if = 'DROP TABLE IF EXISTS'; + + /** + * RENAME TABLE statement + * + * @var string + */ + protected $_rename_table = 'ALTER TABLE %s RENAME TO %s;'; + + /** + * UNSIGNED support + * + * @var bool|array + */ + protected $_unsigned = TRUE; + + /** + * NULL value representatin in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_null = ''; + + /** + * DEFAULT value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_default = ' DEFAULT '; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @param object &$db Database object + * @return void + */ + public function __construct(&$db) { - // Assign the main database object to $this->db - $CI =& get_instance(); - $this->db =& $CI->db; + $this->db =& $db; log_message('debug', 'Database Forge Class Initialized'); } @@ -58,20 +164,25 @@ abstract class CI_DB_forge { /** * Create database * - * @param string the database name + * @param string $db_name * @return bool */ public function create_database($db_name) { if ($this->_create_database === FALSE) { - return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE; + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; } elseif ( ! $this->db->query(sprintf($this->_create_database, $db_name, $this->db->char_set, $this->db->dbcollat))) { return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE; } + if ( ! empty($this->db->data_cache['db_names'])) + { + $this->db->data_cache['db_names'][] = $db_name; + } + return TRUE; } @@ -80,25 +191,34 @@ abstract class CI_DB_forge { /** * Drop database * - * @param string the database name + * @param string $db_name * @return bool */ public function drop_database($db_name) { - if ($db_name == '') + if ($db_name === '') { show_error('A table name is required for that operation.'); return FALSE; } elseif ($this->_drop_database === FALSE) { - return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE; + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; } elseif ( ! $this->db->query(sprintf($this->_drop_database, $db_name))) { return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE; } + if ( ! empty($this->db->data_cache['db_names'])) + { + $key = array_search(strtolower($db_name), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); + if ($key !== FALSE) + { + unset($this->db->data_cache['db_names'][$key]); + } + } + return TRUE; } @@ -107,25 +227,25 @@ abstract class CI_DB_forge { /** * Add Key * - * @param string key - * @param string type + * @param string $key + * @param bool $primary * @return object */ public function add_key($key = '', $primary = FALSE) { - if (is_array($key)) + if (empty($key)) + { + show_error('Key information is required for that operation.'); + } + + if ($primary === TRUE && is_array($key)) { foreach ($key as $one) { $this->add_key($one, $primary); } - return; - } - - if ($key == '') - { - show_error('Key information is required for that operation.'); + return $this; } if ($primary === TRUE) @@ -145,12 +265,12 @@ abstract class CI_DB_forge { /** * Add Field * - * @param string collation + * @param array $field * @return object */ public function add_field($field = '') { - if ($field == '') + if (empty($field)) { show_error('Field information is required.'); } @@ -192,24 +312,107 @@ abstract class CI_DB_forge { /** * Create Table * - * @param string the table name + * @param string $table Table name + * @param bool $if_not_exists Whether to add IF NOT EXISTS condition * @return bool */ public function create_table($table = '', $if_not_exists = FALSE) { - if ($table == '') + if ($table === '') { show_error('A table name is required for that operation.'); } + else + { + $table = $this->db->dbprefix.$table; + } 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); + $sql = $this->_create_table($table, $if_not_exists); + + if (is_bool($sql)) + { + $this->_reset(); + if ($sql === FALSE) + { + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; + } + } + + if (($result = $this->db->query($sql)) !== FALSE) + { + empty($this->db->data_cache['table_names']) OR $this->db->data_cache['table_names'][] = $table; + + // Most databases don't support creating indexes from within the CREATE TABLE statement + if ( ! empty($this->keys)) + { + for ($i = 0, $sqls = $this->_process_indexes($table), $c = count($sqls); $i < $c; $i++) + { + $this->db->query($sqls[$i]); + } + } + } + $this->_reset(); - return is_bool($sql) ? $sql : $this->db->query($sql); + return $result; + } + + // -------------------------------------------------------------------- + + /** + * Create Table + * + * @param string $table Table name + * @param bool $if_not_exists Whether to add 'IF NOT EXISTS' condition + * @return mixed + */ + protected function _create_table($table, $if_not_exists) + { + if ($if_not_exists === TRUE && $this->_create_table_if === FALSE) + { + if ($this->db->table_exists($table)) + { + return TRUE; + } + else + { + $if_not_exists = FALSE; + } + } + + $sql = ($if_not_exists) + ? sprintf($this->_create_table_if, $this->db->escape_identifiers($table)) + : 'CREATE TABLE'; + + $columns = $this->_process_fields(TRUE); + for ($i = 0, $c = count($columns); $i < $c; $i++) + { + $columns[$i] = ($columns[$i]['_literal'] !== FALSE) + ? "\n\t".$columns[$i]['_literal'] + : "\n\t".$this->_process_column($columns[$i]); + } + + $columns = implode(',', $columns) + .$this->_process_primary_keys($table); + + // Are indexes created from within the CREATE TABLE statement? (e.g. in MySQL) + if ($this->_create_table_keys === TRUE) + { + $columns .= $this->_process_indexes(); + } + + // _create_table will usually have the following format: "%s %s (%s\n)" + $sql = sprintf($this->_create_table.';', + $sql, + $this->db->escape_identifiers($table), + $columns + ); + + return $sql; } // -------------------------------------------------------------------- @@ -217,21 +420,73 @@ abstract class CI_DB_forge { /** * Drop Table * - * @param string the table name + * @param string $table_name Table name + * @param bool $if_exists Whether to add an IF EXISTS condition * @return bool */ - public function drop_table($table_name) + public function drop_table($table_name, $if_exists = FALSE) { - if ($table_name == '') + if ($table_name === '') { return ($this->db->db_debug) ? $this->db->display_error('db_table_name_required') : FALSE; } - elseif ($this->_drop_table === FALSE) + + $query = $this->_drop_table($this->db->dbprefix.$table_name, $if_exists); + if ($query === FALSE) + { + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; + } + elseif ($query === TRUE) { - return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE; + return TRUE; } - return $this->db->query(sprintf($this->_drop_table, $this->db->escape_identifiers($this->db->dbprefix.$table_name))); + $query = $this->db->query($query); + + // Update table list cache + if ($query && ! empty($this->db->data_cache['table_names'])) + { + $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE); + if ($key !== FALSE) + { + unset($this->db->data_cache['table_names'][$key]); + } + } + + return $query; + } + + // -------------------------------------------------------------------- + + /** + * Drop Table + * + * Generates a platform-specific DROP TABLE string + * + * @param string $table Table name + * @param bool $if_exists Whether to add an IF EXISTS condition + * @return string + */ + protected function _drop_table($table, $if_exists) + { + $sql = 'DROP TABLE'; + + if ($if_exists) + { + if ($this->_drop_table_if === FALSE) + { + if ( ! $this->db->table_exists($table)) + { + return TRUE; + } + } + else + { + $sql = sprintf($this->_drop_table_if, $this->db->escape_identifiers($table)); + } + } + + return $sql.' '.$this->db->escape_identifiers($table); } // -------------------------------------------------------------------- @@ -239,26 +494,37 @@ abstract class CI_DB_forge { /** * Rename Table * - * @param string the old table name - * @param string the new table name + * @param string $table_name Old table name + * @param string $new_table_name New table name * @return bool */ public function rename_table($table_name, $new_table_name) { - if ($table_name == '' OR $new_table_name == '') + if ($table_name === '' OR $new_table_name === '') { show_error('A table name is required for that operation.'); return FALSE; } elseif ($this->_rename_table === FALSE) { - return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE; + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; } - return $this->db->query(sprintf($this->_rename_table, + $result = $this->db->query(sprintf($this->_rename_table, $this->db->escape_identifiers($this->db->dbprefix.$table_name), $this->db->escape_identifiers($this->db->dbprefix.$new_table_name)) ); + + if ($result && ! empty($this->db->data_cache['table_names'])) + { + $key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE); + if ($key !== FALSE) + { + $this->db->data_cache['table_names'][$key] = $this->db->dbprefix.$new_table_name; + } + } + + return $result; } // -------------------------------------------------------------------- @@ -266,33 +532,46 @@ abstract class CI_DB_forge { /** * Column Add * - * @param string the table name - * @param string the column name - * @param string the column definition + * @todo Remove deprecated $_after option in 3.1+ + * @param string $table Table name + * @param array $field Column definition + * @param string $_after Column for AFTER clause (deprecated) * @return bool */ - public function add_column($table = '', $field = array(), $after_field = '') + public function add_column($table = '', $field = array(), $_after = NULL) { - if ($table == '') + 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 (array_keys($field) as $k) + // Work-around for literal column definitions + if ( ! is_array($field)) { - $this->add_field(array($k => $field[$k])); + $field = array($field); + } - if (count($this->fields) == 0) + foreach (array_keys($field) as $k) + { + // Backwards-compatibility work-around for MySQL/CUBRID AFTER clause (remove in 3.1+) + if ($_after !== NULL && is_array($field[$k]) && ! isset($field[$k]['after'])) { - show_error('Field information is required.'); + $field[$k]['after'] = $_after; } - $sql = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->fields, $after_field); - $this->_reset(); + $this->add_field(array($k => $field[$k])); + } - if ($this->db->query($sql) === FALSE) + $sqls = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->_process_fields()); + $this->_reset(); + if ($sqls === FALSE) + { + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; + } + + for ($i = 0, $c = count($sqls); $i < $c; $i++) + { + if ($this->db->query($sqls[$i]) === FALSE) { return FALSE; } @@ -306,23 +585,29 @@ abstract class CI_DB_forge { /** * Column Drop * - * @param string the table name - * @param string the column name + * @param string $table Table name + * @param string $column_name Column name * @return bool */ public function drop_column($table = '', $column_name = '') { - if ($table == '') + if ($table === '') { show_error('A table name is required for that operation.'); } - if ($column_name == '') + if ($column_name === '') { show_error('A column name is required for that operation.'); } - return $this->db->query($this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name)); + $sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name); + if ($sql === FALSE) + { + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; + } + + return $this->db->query($sql); } // -------------------------------------------------------------------- @@ -330,44 +615,374 @@ abstract class CI_DB_forge { /** * Column Modify * - * @param string the table name - * @param string the column name - * @param string the column definition + * @param string $table Table name + * @param string $field Column definition * @return bool */ public function modify_column($table = '', $field = array()) { - if ($table == '') + 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 + // Work-around for literal column definitions + if ( ! is_array($field)) + { + $field = array($field); + } + foreach (array_keys($field) as $k) { - // If no name provided, use the current name - if ( ! isset($field[$k]['name'])) + $this->add_field(array($k => $field[$k])); + } + + if (count($this->fields) === 0) + { + show_error('Field information is required.'); + } + + $sqls = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->fields); + $this->_reset(); + if ($sqls === FALSE) + { + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; + } + + for ($i = 0, $c = count($sqls); $i < $c; $i++) + { + if ($this->db->query($sqls[$i]) === FALSE) { - $field[$k]['name'] = $k; + return FALSE; } + } - $this->add_field(array($k => $field[$k])); - if (count($this->fields) === 0) + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' '; + + // DROP has everything it needs now. + if ($alter_type === 'DROP') + { + return $sql.'DROP COLUMN '.$this->db->escape_identifiers($field); + } + + $sqls = array(); + for ($i = 0, $c = count($field), $sql .= $alter_type.' COLUMN '; $i < $c; $i++) + { + $sqls[] = $sql + .($field[$i]['_literal'] !== FALSE ? $field[$i]['_literal'] : $this->_process_column($field[$i])); + } + + return $sqls; + } + + // -------------------------------------------------------------------- + + /** + * Process fields + * + * @param bool $create_table + * @return array + */ + protected function _process_fields($create_table = FALSE) + { + $fields = array(); + + foreach ($this->fields as $key => $attributes) + { + if (is_int($key) && ! is_array($attributes)) { - show_error('Field information is required.'); + $fields[] = array('_literal' => $attributes); + continue; } - $sql = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->fields); - $this->_reset(); + $attributes = array_change_key_case($attributes, CASE_UPPER); - if ($this->db->query($sql) === FALSE) + if ($create_table === TRUE && empty($attributes['TYPE'])) { - return FALSE; + continue; + } + + if (isset($attributes['TYPE'])) + { + $this->_attr_type($attributes); + $this->_attr_unsigned($attributes, $field); + } + + $field = array( + 'name' => $key, + 'new_name' => isset($attributes['NAME']) ? $attributes['NAME'] : NULL, + 'type' => isset($attributes['TYPE']) ? $attributes['TYPE'] : NULL, + 'length' => '', + 'unsigned' => '', + 'null' => '', + 'unique' => '', + 'default' => '', + 'auto_increment' => '', + '_literal' => FALSE + ); + + $this->_attr_default($attributes, $field); + + if (isset($attributes['NULL'])) + { + if ($attributes['NULL'] === TRUE) + { + $field['null'] = empty($this->_null) ? '' : ' '.$this->_null; + } + elseif ($create_table === TRUE) + { + $field['null'] = ' NOT NULL'; + } } + + $this->_attr_auto_increment($attributes, $field); + $this->_attr_unique($attributes, $field); + + if (isset($attributes['TYPE']) && ! empty($attributes['CONSTRAINT'])) + { + switch (strtoupper($attributes['TYPE'])) + { + case 'ENUM': + case 'SET': + $attributes['CONSTRAINT'] = $this->db->escape($attributes['CONSTRAINT']); + default: + $field['length'] = is_array($attributes['CONSTRAINT']) + ? '('.implode(',', $attributes['CONSTRAINT']).')' + : '('.$attributes['CONSTRAINT'].')'; + break; + } + } + + $fields[] = $field; } - return TRUE; + return $fields; + } + + // -------------------------------------------------------------------- + + /** + * Process column + * + * @param array $field + * @return string + */ + protected function _process_column($field) + { + return $this->db->escape_identifiers($field['name']) + .' '.$field['type'].$field['length'] + .$field['unsigned'] + .$field['default'] + .$field['null'] + .$field['auto_increment'] + .$field['unique']; + } + + // -------------------------------------------------------------------- + + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + // Usually overriden by drivers + } + + // -------------------------------------------------------------------- + + /** + * Field attribute UNSIGNED + * + * Depending on the _unsigned property value: + * + * - TRUE will always set $field['unsigned'] to 'UNSIGNED' + * - FALSE will always set $field['unsigned'] to '' + * - array(TYPE) will set $field['unsigned'] to 'UNSIGNED', + * if $attributes['TYPE'] is found in the array + * - array(TYPE => UTYPE) will change $field['type'], + * from TYPE to UTYPE in case of a match + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_unsigned(&$attributes, &$field) + { + if (empty($attributes['UNSIGNED']) OR $attributes['UNSIGNED'] !== TRUE) + { + return; + } + + // Reset the attribute in order to avoid issues if we do type conversion + $attributes['UNSIGNED'] = FALSE; + + if (is_array($this->_unsigned)) + { + foreach (array_keys($this->_unsigned) as $key) + { + if (is_int($key) && strcasecmp($attributes['TYPE'], $this->_unsigned[$key]) === 0) + { + $field['unsigned'] = ' UNSIGNED'; + return; + } + elseif (is_string($key) && strcasecmp($attributes['TYPE'], $key) === 0) + { + $field['type'] = $key; + return; + } + } + + return; + } + + $field['unsigned'] = ($this->_unsigned === TRUE) ? ' UNSIGNED' : ''; + } + + // -------------------------------------------------------------------- + + /** + * Field attribute DEFAULT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_default(&$attributes, &$field) + { + if ($this->_default === FALSE) + { + return; + } + + if (array_key_exists('DEFAULT', $attributes)) + { + if ($attributes['DEFAULT'] === NULL) + { + $field['default'] = empty($this->_null) ? '' : $this->_default.$this->_null; + + // Override the NULL attribute if that's our default + $attributes['NULL'] = NULL; + $field['null'] = empty($this->_null) ? '' : ' '.$this->_null; + } + else + { + $field['default'] = $this->_default.$this->db->escape($attributes['DEFAULT']); + } + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute UNIQUE + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_unique(&$attributes, &$field) + { + if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) + { + $field['unique'] = ' UNIQUE'; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) + { + $field['auto_increment'] = ' AUTO_INCREMENT'; + } + } + + // -------------------------------------------------------------------- + + /** + * Process primary keys + * + * @param string $table Table name + * @return string + */ + protected function _process_primary_keys($table) + { + $sql = ''; + + for ($i = 0, $c = count($this->primary_keys); $i < $c; $i++) + { + if ( ! isset($this->fields[$this->primary_keys[$i]])) + { + unset($this->primary_keys[$i]); + } + } + + if (count($this->primary_keys) > 0) + { + $sql .= ",\n\tCONSTRAINT ".$this->db->escape_identifiers('pk_'.$table) + .' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($this->primary_keys)).')'; + } + + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Process indexes + * + * @param string $table + * @return string + */ + protected function _process_indexes($table = NULL) + { + $table = $this->db->escape_identifiers($table); + $sqls = array(); + + for ($i = 0, $c = count($this->keys); $i < $c; $i++) + { + if ( ! isset($this->fields[$this->keys[$i]])) + { + unset($this->keys[$i]); + continue; + } + + is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]); + + $sqls[] = 'CREATE INDEX '.$this->db->escape_identifiers(implode('_', $this->keys[$i])) + .' ON '.$this->db->escape_identifiers($table) + .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).');'; + } + + return $sqls; } // -------------------------------------------------------------------- diff --git a/system/database/DB_active_rec.php b/system/database/DB_query_builder.php index a5df7f31a..543d5ccdd 100644 --- a/system/database/DB_active_rec.php +++ b/system/database/DB_query_builder.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,11 +24,12 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** - * Active Record Class + * Query Builder Class * - * This is the platform-independent base Active Record implementation class. + * This is the platform-independent base Query Builder implementation class. * * @package CodeIgniter * @subpackage Drivers @@ -36,46 +37,215 @@ * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ */ -abstract class CI_DB_active_record extends CI_DB_driver { +abstract class CI_DB_query_builder extends CI_DB_driver { + + /** + * Return DELETE SQL flag + * + * @var bool + */ protected $return_delete_sql = FALSE; + + /** + * Reset DELETE data flag + * + * @var bool + */ protected $reset_delete_data = FALSE; - protected $ar_select = array(); - protected $ar_distinct = FALSE; - protected $ar_from = array(); - protected $ar_join = array(); - protected $ar_where = array(); - protected $ar_like = array(); - protected $ar_groupby = array(); - protected $ar_having = array(); - protected $ar_keys = array(); - protected $ar_limit = FALSE; - protected $ar_offset = FALSE; - protected $ar_order = FALSE; - protected $ar_orderby = array(); - protected $ar_set = array(); - protected $ar_wherein = array(); - protected $ar_aliased_tables = array(); - protected $ar_store_array = array(); - protected $ar_where_group_started = FALSE; - protected $ar_where_group_count = 0; - - // Active Record Caching variables - protected $ar_caching = FALSE; - protected $ar_cache_exists = array(); - protected $ar_cache_select = array(); - protected $ar_cache_from = array(); - protected $ar_cache_join = array(); - protected $ar_cache_where = array(); - protected $ar_cache_like = array(); - protected $ar_cache_groupby = array(); - protected $ar_cache_having = array(); - protected $ar_cache_orderby = array(); - protected $ar_cache_set = array(); - - protected $ar_no_escape = array(); - protected $ar_cache_no_escape = array(); + /** + * QB SELECT data + * + * @var array + */ + protected $qb_select = array(); + + /** + * QB DISTINCT flag + * + * @var bool + */ + protected $qb_distinct = FALSE; + + /** + * QB FROM data + * + * @var array + */ + protected $qb_from = array(); + + /** + * QB JOIN data + * + * @var array + */ + protected $qb_join = array(); + + /** + * QB WHERE data + * + * @var array + */ + protected $qb_where = array(); + + /** + * QB GROUP BY data + * + * @var array + */ + protected $qb_groupby = array(); + + /** + * QB HAVING data + * + * @var array + */ + protected $qb_having = array(); + + /** + * QB keys + * + * @var array + */ + protected $qb_keys = array(); + + /** + * QB LIMIT data + * + * @var int + */ + protected $qb_limit = FALSE; + + /** + * QB OFFSET data + * + * @var int + */ + protected $qb_offset = FALSE; + + /** + * QB ORDER BY data + * + * @var array + */ + protected $qb_orderby = array(); + + /** + * QB data sets + * + * @var array + */ + protected $qb_set = array(); + + /** + * QB aliased tables list + * + * @var array + */ + protected $qb_aliased_tables = array(); + + /** + * QB WHERE group started flag + * + * @var bool + */ + protected $qb_where_group_started = FALSE; + + /** + * QB WHERE group count + * + * @var int + */ + protected $qb_where_group_count = 0; + + // Query Builder Caching variables + + /** + * QB Caching flag + * + * @var bool + */ + protected $qb_caching = FALSE; + + /** + * QB Cache exists list + * + * @var array + */ + protected $qb_cache_exists = array(); + + /** + * QB Cache SELECT data + * + * @var array + */ + protected $qb_cache_select = array(); + + /** + * QB Cache FROM data + * + * @var array + */ + protected $qb_cache_from = array(); + + /** + * QB Cache JOIN data + * + * @var array + */ + protected $qb_cache_join = array(); + + /** + * QB Cache WHERE data + * + * @var array + */ + protected $qb_cache_where = array(); + + /** + * QB Cache GROUP BY data + * + * @var array + */ + protected $qb_cache_groupby = array(); + + /** + * QB Cache HAVING data + * + * @var array + */ + protected $qb_cache_having = array(); + + /** + * QB Cache ORDER BY data + * + * @var array + */ + protected $qb_cache_orderby = array(); + + /** + * QB Cache data sets + * + * @var array + */ + protected $qb_cache_set = array(); + + /** + * QB No Escape data + * + * @var array + */ + protected $qb_no_escape = array(); + + /** + * QB Cache No Escape data + * + * @var array + */ + protected $qb_cache_no_escape = array(); + + // -------------------------------------------------------------------- /** * Select @@ -83,6 +253,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { * Generates the SELECT portion of the query * * @param string + * @param mixed * @return object */ public function select($select = '*', $escape = NULL) @@ -92,20 +263,23 @@ abstract class CI_DB_active_record extends CI_DB_driver { $select = explode(',', $select); } + // If the escape value was not set will will base it on the global setting + is_bool($escape) OR $escape = $this->_protect_identifiers; + foreach ($select as $val) { $val = trim($val); - if ($val != '') + if ($val !== '') { - $this->ar_select[] = $val; - $this->ar_no_escape[] = $escape; + $this->qb_select[] = $val; + $this->qb_no_escape[] = $escape; - if ($this->ar_caching === TRUE) + if ($this->qb_caching === TRUE) { - $this->ar_cache_select[] = $val; - $this->ar_cache_exists[] = 'select'; - $this->ar_cache_no_escape[] = $escape; + $this->qb_cache_select[] = $val; + $this->qb_cache_exists[] = 'select'; + $this->qb_cache_no_escape[] = $escape; } } } @@ -180,20 +354,21 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** - * Processing Function for the four functions above: + * SELECT [MAX|MIN|AVG|SUM]() * - * select_max() - * select_min() - * select_avg() - * select_sum() + * @used-by select_max() + * @used-by select_min() + * @used-by select_avg() + * @used-by select_sum() * - * @param string the field - * @param string an alias + * @param string $select Field name + * @param string $alias + * @param string $type * @return object */ protected function _max_min_avg_sum($select = '', $alias = '', $type = 'MAX') { - if ( ! is_string($select) OR $select == '') + if ( ! is_string($select) OR $select === '') { $this->display_error('db_invalid_query'); } @@ -205,19 +380,20 @@ abstract class CI_DB_active_record extends CI_DB_driver { show_error('Invalid function type: '.$type); } - if ($alias == '') + if ($alias === '') { $alias = $this->_create_alias_from_table(trim($select)); } - $sql = $this->protect_identifiers($type.'('.trim($select).')').' AS '.$this->protect_identifiers(trim($alias)); - $this->ar_select[] = $sql; - $this->ar_no_escape[] = NULL; + $sql = $this->protect_identifiers($type.'('.trim($select).')').' AS '.$this->escape_identifiers(trim($alias)); + + $this->qb_select[] = $sql; + $this->qb_no_escape[] = NULL; - if ($this->ar_caching === TRUE) + if ($this->qb_caching === TRUE) { - $this->ar_cache_select[] = $sql; - $this->ar_cache_exists[] = 'select'; + $this->qb_cache_select[] = $sql; + $this->qb_cache_exists[] = 'select'; } return $this; @@ -228,7 +404,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { /** * Determines the alias name based on the table * - * @param string + * @param string $item * @return string */ protected function _create_alias_from_table($item) @@ -249,12 +425,12 @@ abstract class CI_DB_active_record extends CI_DB_driver { * * Sets a flag which tells the query string compiler to add DISTINCT * - * @param bool + * @param bool $val * @return object */ public function distinct($val = TRUE) { - $this->ar_distinct = (is_bool($val)) ? $val : TRUE; + $this->qb_distinct = is_bool($val) ? $val : TRUE; return $this; } @@ -265,12 +441,12 @@ abstract class CI_DB_active_record extends CI_DB_driver { * * Generates the FROM portion of the query * - * @param mixed can be a string or array + * @param mixed $from can be a string or array * @return object */ public function from($from) { - foreach ((array)$from as $val) + foreach ((array) $from as $val) { if (strpos($val, ',') !== FALSE) { @@ -278,12 +454,13 @@ abstract class CI_DB_active_record extends CI_DB_driver { { $v = trim($v); $this->_track_aliases($v); - $v = $this->ar_from[] = $this->protect_identifiers($v, TRUE, NULL, FALSE); - if ($this->ar_caching === TRUE) + $this->qb_from[] = $v = $this->protect_identifiers($v, TRUE, NULL, FALSE); + + if ($this->qb_caching === TRUE) { - $this->ar_cache_from[] = $v; - $this->ar_cache_exists[] = 'from'; + $this->qb_cache_from[] = $v; + $this->qb_cache_exists[] = 'from'; } } } @@ -292,14 +469,15 @@ abstract class CI_DB_active_record extends CI_DB_driver { $val = trim($val); // Extract any aliases that might exist. We use this information - // in the _protect_identifiers to know whether to add a table prefix + // in the protect_identifiers to know whether to add a table prefix $this->_track_aliases($val); - $this->ar_from[] = $val = $this->protect_identifiers($val, TRUE, NULL, FALSE); - if ($this->ar_caching === TRUE) + $this->qb_from[] = $val = $this->protect_identifiers($val, TRUE, NULL, FALSE); + + if ($this->qb_caching === TRUE) { - $this->ar_cache_from[] = $val; - $this->ar_cache_exists[] = 'from'; + $this->qb_cache_from[] = $val; + $this->qb_cache_exists[] = 'from'; } } } @@ -310,22 +488,23 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** - * Join + * JOIN * * Generates the JOIN portion of the query * * @param string * @param string the join condition * @param string the type of join + * @param string whether not to try to escape identifiers * @return object */ - public function join($table, $cond, $type = '') + public function join($table, $cond, $type = '', $escape = NULL) { - if ($type != '') + if ($type !== '') { $type = strtoupper(trim($type)); - if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'))) + if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'), TRUE)) { $type = ''; } @@ -336,22 +515,59 @@ abstract class CI_DB_active_record extends CI_DB_driver { } // Extract any aliases that might exist. We use this information - // in the _protect_identifiers to know whether to add a table prefix + // in the protect_identifiers to know whether to add a table prefix $this->_track_aliases($table); - // Strip apart the condition and protect the identifiers - if (preg_match('/([\[\w\.]+)([\W\s]+)(.+)/', $cond, $match)) + is_bool($escape) OR $escape = $this->_protect_identifiers; + + // Split multiple conditions + if ($escape === TRUE && preg_match_all('/\sAND\s|\sOR\s/i', $cond, $m, PREG_OFFSET_CAPTURE)) + { + $newcond = ''; + $m[0][] = array('', strlen($cond)); + + for ($i = 0, $c = count($m[0]), $s = 0; + $i < $c; + $s = $m[0][$i][1] + strlen($m[0][$i][0]), $i++) + { + $temp = substr($cond, $s, ($m[0][$i][1] - $s)); + + $newcond .= preg_match("/([\[\]\w\.'-]+)(\s*[^\"\[`'\w]+\s*)(.+)/i", $temp, $match) + ? $this->protect_identifiers($match[1]).$match[2].$this->protect_identifiers($match[3]) + : $temp; + + $newcond .= $m[0][$i][0]; + } + + $cond = ' ON '.$newcond; + } + // Split apart the condition and protect the identifiers + elseif ($escape === TRUE && preg_match("/([\[\]\w\.'-]+)(\s*[^\"\[`'\w]+\s*)(.+)/i", $cond, $match)) + { + $cond = ' ON '.$this->protect_identifiers($match[1]).$match[2].$this->protect_identifiers($match[3]); + } + elseif ( ! $this->_has_operator($cond)) + { + $cond = ' USING ('.($escape ? $this->escape_identifiers($cond) : $cond).')'; + } + else + { + $cond = ' ON '.$cond; + } + + // Do we want to escape the table name? + if ($escape === TRUE) { - $cond = $this->protect_identifiers($match[1]).$match[2].$this->protect_identifiers($match[3]); + $table = $this->protect_identifiers($table, TRUE, NULL, FALSE); } // Assemble the JOIN statement - $this->ar_join[] = $join = $type.'JOIN '.$this->protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond; + $this->qb_join[] = $join = $type.'JOIN '.$table.$cond; - if ($this->ar_caching === TRUE) + if ($this->qb_caching === TRUE) { - $this->ar_cache_join[] = $join; - $this->ar_cache_exists[] = 'join'; + $this->qb_cache_join[] = $join; + $this->qb_cache_exists[] = 'join'; } return $this; @@ -360,52 +576,59 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** - * Where + * WHERE * - * Generates the WHERE portion of the query. Separates - * multiple calls with AND + * Generates the WHERE portion of the query. + * Separates multiple calls with 'AND'. * * @param mixed * @param mixed + * @param bool * @return object */ - public function where($key, $value = NULL, $escape = TRUE) + public function where($key, $value = NULL, $escape = NULL) { - return $this->_where($key, $value, 'AND ', $escape); + return $this->_wh('qb_where', $key, $value, 'AND ', $escape); } // -------------------------------------------------------------------- /** - * OR Where + * OR WHERE * - * Generates the WHERE portion of the query. Separates - * multiple calls with OR + * Generates the WHERE portion of the query. + * Separates multiple calls with 'OR'. * * @param mixed * @param mixed + * @param bool * @return object */ - public function or_where($key, $value = NULL, $escape = TRUE) + public function or_where($key, $value = NULL, $escape = NULL) { - return $this->_where($key, $value, 'OR ', $escape); + return $this->_wh('qb_where', $key, $value, 'OR ', $escape); } // -------------------------------------------------------------------- /** - * Where + * WHERE, HAVING * - * Called by where() or or_where() + * @used-by where() + * @used-by or_where() + * @used-by having() + * @used-by or_having() * - * @param mixed - * @param mixed - * @param string + * @param string $qb_key 'qb_where' or 'qb_having' + * @param mixed $key + * @param mixed $value + * @param string $type + * @param bool $escape * @return object */ - protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL) + protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL) { - $type = $this->_group_get_type($type); + $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where'; if ( ! is_array($key)) { @@ -413,14 +636,13 @@ abstract class CI_DB_active_record extends CI_DB_driver { } // If the escape value was not set will will base it on the global setting - if ( ! is_bool($escape)) - { - $escape = $this->_protect_identifiers; - } + is_bool($escape) OR $escape = $this->_protect_identifiers; foreach ($key as $k => $v) { - $prefix = (count($this->ar_where) === 0 && count($this->ar_cache_where) === 0) ? '' : $type; + $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0) + ? $this->_group_get_type('') + : $this->_group_get_type($type); if (is_null($v) && ! $this->_has_operator($k)) { @@ -432,8 +654,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { { if ($escape === TRUE) { - $k = $this->protect_identifiers($k, FALSE, $escape); - $v = ' '.$this->escape($v); + $v = ' '.(is_int($v) ? $v : $this->escape($v)); } if ( ! $this->_has_operator($k)) @@ -441,16 +662,12 @@ abstract class CI_DB_active_record extends CI_DB_driver { $k .= ' = '; } } - else - { - $k = $this->protect_identifiers($k, FALSE, $escape); - } - $this->ar_where[] = $prefix.$k.$v; - if ($this->ar_caching === TRUE) + $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape); + if ($this->qb_caching === TRUE) { - $this->ar_cache_where[] = $prefix.$k.$v; - $this->ar_cache_exists[] = 'where'; + $this->{$qb_cache_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape); + $this->qb_cache_exists[] = substr($qb_key, 3); } } @@ -461,244 +678,268 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** - * Where_in + * WHERE IN * - * Generates a WHERE field IN ('item', 'item') SQL query joined with - * AND if appropriate + * 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 + * @param string $key The field to search + * @param array $values The values searched on + * @param bool $escape * @return object */ - public function where_in($key = NULL, $values = NULL) + public function where_in($key = NULL, $values = NULL, $escape = NULL) { - return $this->_where_in($key, $values); + return $this->_where_in($key, $values, FALSE, 'AND ', $escape); } // -------------------------------------------------------------------- /** - * Where_in_or + * OR WHERE IN * - * Generates a WHERE field IN ('item', 'item') SQL query joined with - * OR if appropriate + * 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 + * @param string $key The field to search + * @param array $values The values searched on + * @param bool $escape * @return object */ - public function or_where_in($key = NULL, $values = NULL) + public function or_where_in($key = NULL, $values = NULL, $escape = NULL) { - return $this->_where_in($key, $values, FALSE, 'OR '); + return $this->_where_in($key, $values, FALSE, 'OR ', $escape); } // -------------------------------------------------------------------- /** - * Where_not_in + * WHERE NOT IN * - * Generates a WHERE field NOT IN ('item', 'item') SQL query joined - * with AND if appropriate + * 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 + * @param string $key The field to search + * @param array $values The values searched on + * @param bool $escape * @return object */ - public function where_not_in($key = NULL, $values = NULL) + public function where_not_in($key = NULL, $values = NULL, $escape = NULL) { - return $this->_where_in($key, $values, TRUE); + return $this->_where_in($key, $values, TRUE, 'AND ', $escape); } // -------------------------------------------------------------------- /** - * Where_not_in_or + * OR WHERE NOT IN * - * Generates a WHERE field NOT IN ('item', 'item') SQL query joined - * with OR if appropriate + * 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 + * @param string $key The field to search + * @param array $values The values searched on + * @param bool $escape * @return object */ - public function or_where_not_in($key = NULL, $values = NULL) + public function or_where_not_in($key = NULL, $values = NULL, $escape = NULL) { - return $this->_where_in($key, $values, TRUE, 'OR '); + return $this->_where_in($key, $values, TRUE, 'OR ', $escape); } // -------------------------------------------------------------------- /** - * Where_in + * Internal WHERE IN * - * Called by where_in, where_in_or, where_not_in, where_not_in_or + * @used-by where_in() + * @used-by or_where_in() + * @used-by where_not_in() + * @used-by or_where_not_in() * - * @param string The field to search - * @param array The values searched on - * @param bool If the statement would be IN or NOT IN - * @param string + * @param string $key The field to search + * @param array $values The values searched on + * @param bool $not If the statement would be IN or NOT IN + * @param string $type + * @param bool $escape * @return object */ - protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ') + protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ', $escape = NULL) { if ($key === NULL OR $values === NULL) { - return; + return $this; } - $type = $this->_group_get_type($type); - if ( ! is_array($values)) { $values = array($values); } + is_bool($escape) OR $escape = $this->_protect_identifiers; + $not = ($not) ? ' NOT' : ''; + $where_in = array(); foreach ($values as $value) { - $this->ar_wherein[] = $this->escape($value); + $where_in[] = $this->escape($value); } - $prefix = (count($this->ar_where) === 0) ? '' : $type; - $this->ar_where[] = $where_in = $prefix.$this->protect_identifiers($key).$not.' IN ('.implode(', ', $this->ar_wherein).') '; + $prefix = (count($this->qb_where) === 0) ? $this->_group_get_type('') : $this->_group_get_type($type); + $where_in = array( + 'condition' => $prefix.$key.$not.' IN('.implode(', ', $where_in).')', + 'escape' => $escape + ); - if ($this->ar_caching === TRUE) + $this->qb_where[] = $where_in; + if ($this->qb_caching === TRUE) { - $this->ar_cache_where[] = $where_in; - $this->ar_cache_exists[] = 'where'; + $this->qb_cache_where[] = $where_in; + $this->qb_cache_exists[] = 'where'; } - // reset the array for multiple calls - $this->ar_wherein = array(); return $this; } // -------------------------------------------------------------------- /** - * Like + * LIKE * - * Generates a %LIKE% portion of the query. Separates - * multiple calls with AND + * Generates a %LIKE% portion of the query. + * Separates multiple calls with 'AND'. * - * @param mixed - * @param mixed + * @param mixed $field + * @param string $match + * @param string $side + * @param bool $escape * @return object */ - public function like($field, $match = '', $side = 'both') + public function like($field, $match = '', $side = 'both', $escape = NULL) { - return $this->_like($field, $match, 'AND ', $side); + return $this->_like($field, $match, 'AND ', $side, '', $escape); } // -------------------------------------------------------------------- /** - * Not Like + * NOT LIKE * - * Generates a NOT LIKE portion of the query. Separates - * multiple calls with AND + * Generates a NOT LIKE portion of the query. + * Separates multiple calls with 'AND'. * - * @param mixed - * @param mixed + * @param mixed $field + * @param string $match + * @param string $side + * @param bool $escape * @return object */ - public function not_like($field, $match = '', $side = 'both') + public function not_like($field, $match = '', $side = 'both', $escape = NULL) { - return $this->_like($field, $match, 'AND ', $side, 'NOT'); + return $this->_like($field, $match, 'AND ', $side, 'NOT', $escape); } // -------------------------------------------------------------------- /** - * OR Like + * OR LIKE * - * Generates a %LIKE% portion of the query. Separates - * multiple calls with OR + * Generates a %LIKE% portion of the query. + * Separates multiple calls with 'OR'. * - * @param mixed - * @param mixed + * @param mixed $field + * @param string $match + * @param string $side + * @param bool $escape * @return object */ - public function or_like($field, $match = '', $side = 'both') + public function or_like($field, $match = '', $side = 'both', $escape = NULL) { - return $this->_like($field, $match, 'OR ', $side); + return $this->_like($field, $match, 'OR ', $side, '', $escape); } // -------------------------------------------------------------------- /** - * OR Not Like + * OR NOT LIKE * - * Generates a NOT LIKE portion of the query. Separates - * multiple calls with OR + * Generates a NOT LIKE portion of the query. + * Separates multiple calls with 'OR'. * - * @param mixed - * @param mixed + * @param mixed $field + * @param string $match + * @param string $side + * @param bool $escape * @return object */ - public function or_not_like($field, $match = '', $side = 'both') + public function or_not_like($field, $match = '', $side = 'both', $escape = NULL) { - return $this->_like($field, $match, 'OR ', $side, 'NOT'); + return $this->_like($field, $match, 'OR ', $side, 'NOT', $escape); } // -------------------------------------------------------------------- /** - * Like + * Internal LIKE * - * Called by like() or orlike() + * @used-by like() + * @used-by or_like() + * @used-by not_like() + * @used-by or_not_like() * - * @param mixed - * @param mixed - * @param string + * @param mixed $field + * @param string $match + * @param string $type + * @param string $side + * @param string $not + * @param bool $escape * @return object */ - protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '') + protected function _like($field, $match = '', $type = 'AND ', $side = 'both', $not = '', $escape = NULL) { - $type = $this->_group_get_type($type); - if ( ! is_array($field)) { $field = array($field => $match); } + is_bool($escape) OR $escape = $this->_protect_identifiers; + $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) + ? $this->_group_get_type('') : $this->_group_get_type($type); + 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}'"; + $like_statement = "{$prefix} {$k} {$not} LIKE '{$v}'"; } elseif ($side === 'before') { - $like_statement = $prefix." $k $not LIKE '%{$v}'"; + $like_statement = "{$prefix} {$k} {$not} LIKE '%{$v}'"; } elseif ($side === 'after') { - $like_statement = $prefix." $k $not LIKE '{$v}%'"; + $like_statement = "{$prefix} {$k} {$not} LIKE '{$v}%'"; } else { - $like_statement = $prefix." $k $not LIKE '%{$v}%'"; + $like_statement = "{$prefix} {$k} {$not} LIKE '%{$v}%'"; } // some platforms require an escape sequence definition for LIKE wildcards - if ($this->_like_escape_str != '') + if ($this->_like_escape_str !== '') { - $like_statement = $like_statement.sprintf($this->_like_escape_str, $this->_like_escape_chr); + $like_statement .= sprintf($this->_like_escape_str, $this->_like_escape_chr); } - $this->ar_like[] = $like_statement; - if ($this->ar_caching === TRUE) + $this->qb_where[] = array('condition' => $like_statement, 'escape' => $escape); + if ($this->qb_caching === TRUE) { - $this->ar_cache_like[] = $like_statement; - $this->ar_cache_exists[] = 'like'; + $this->qb_cache_where[] = $like_statement; + $this->qb_cache_exists[] = 'where'; } - } return $this; @@ -709,20 +950,25 @@ abstract class CI_DB_active_record extends CI_DB_driver { /** * Starts a query group. * - * @param string (Internal use only) - * @param string (Internal use only) + * @param string $not (Internal use only) + * @param string $type (Internal use only) * @return object */ public function group_start($not = '', $type = 'AND ') { $type = $this->_group_get_type($type); - $this->ar_where_group_started = TRUE; - $prefix = (count($this->ar_where) === 0 && count($this->ar_cache_where) === 0) ? '' : $type; - $this->ar_where[] = $value = $prefix.$not.str_repeat(' ', ++$this->ar_where_group_count).' ('; - if ($this->ar_caching) + $this->qb_where_group_started = TRUE; + $prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type; + $where = array( + 'condition' => $prefix.$not.str_repeat(' ', ++$this->qb_where_group_count).' (', + 'escape' => FALSE + ); + + $this->qb_where[] = $where; + if ($this->qb_caching) { - $this->ar_cache_where[] = $value; + $this->qb_cache_where[] = $where; } return $this; @@ -773,12 +1019,16 @@ abstract class CI_DB_active_record extends CI_DB_driver { */ public function group_end() { - $this->ar_where_group_started = FALSE; - $this->ar_where[] = $value = str_repeat(' ', $this->ar_where_group_count--) . ')'; + $this->qb_where_group_started = FALSE; + $where = array( + 'condition' => str_repeat(' ', $this->qb_where_group_count--).')', + 'escape' => FALSE + ); - if ($this->ar_caching) + $this->qb_where[] = $where; + if ($this->qb_caching) { - $this->ar_cache_where[] = $value; + $this->qb_cache_where[] = $where; } return $this; @@ -789,17 +1039,20 @@ abstract class CI_DB_active_record extends CI_DB_driver { /** * Group_get_type * - * Called by group_start(), _like(), _where() and _where_in() + * @used-by group_start() + * @used-by _like() + * @used-by _wh() + * @used-by _where_in() * - * @param string + * @param string $type * @return string */ protected function _group_get_type($type) { - if ($this->ar_where_group_started) + if ($this->qb_where_group_started) { $type = ''; - $this->ar_where_group_started = FALSE; + $this->qb_where_group_started = FALSE; } return $type; @@ -810,28 +1063,34 @@ abstract class CI_DB_active_record extends CI_DB_driver { /** * GROUP BY * - * @param string + * @param string $by + * @param bool $escape * @return object */ - public function group_by($by) + public function group_by($by, $escape = NULL) { + is_bool($escape) OR $escape = $this->_protect_identifiers; + if (is_string($by)) { - $by = explode(',', $by); + $by = ($escape === TRUE) + ? explode(',', $by) + : array($by); } foreach ($by as $val) { $val = trim($val); - if ($val != '') + if ($val !== '') { - $this->ar_groupby[] = $val = $this->protect_identifiers($val); + $val = array('field' => $val, 'escape' => $escape); - if ($this->ar_caching === TRUE) + $this->qb_groupby[] = $val; + if ($this->qb_caching === TRUE) { - $this->ar_cache_groupby[] = $val; - $this->ar_cache_exists[] = 'groupby'; + $this->qb_cache_groupby[] = $val; + $this->qb_cache_exists[] = 'groupby'; } } } @@ -842,136 +1101,91 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** - * Sets the HAVING value + * HAVING * - * Separates multiple calls with AND + * Separates multiple calls with 'AND'. * - * @param string - * @param string + * @param string $key + * @param string $value + * @param bool $escape * @return object */ - public function having($key, $value = '', $escape = TRUE) + public function having($key, $value = NULL, $escape = NULL) { - return $this->_having($key, $value, 'AND ', $escape); + return $this->_wh('qb_having', $key, $value, 'AND ', $escape); } // -------------------------------------------------------------------- /** - * Sets the OR HAVING value + * OR HAVING * - * Separates multiple calls with OR + * Separates multiple calls with 'OR'. * - * @param string - * @param string + * @param string $key + * @param string $value + * @param bool $escape * @return object */ - public function or_having($key, $value = '', $escape = TRUE) + public function or_having($key, $value = NULL, $escape = NULL) { - return $this->_having($key, $value, 'OR ', $escape); + return $this->_wh('qb_having', $key, $value, 'OR ', $escape); } // -------------------------------------------------------------------- /** - * Sets the HAVING values - * - * Called by having() or or_having() + * ORDER BY * - * @param string - * @param string + * @param string $orderby + * @param string $direction ASC or DESC + * @param bool $escape * @return object */ - protected function _having($key, $value = '', $type = 'AND ', $escape = TRUE) + public function order_by($orderby, $direction = '', $escape = NULL) { - if ( ! is_array($key)) - { - $key = array($key => $value); - } + $direction = strtoupper(trim($direction)); - foreach ($key as $k => $v) + if ($direction === 'RANDOM') { - $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); - } + $direction = ''; - $this->ar_having[] = $prefix.$k.$v; - if ($this->ar_caching === TRUE) - { - $this->ar_cache_having[] = $prefix.$k.$v; - $this->ar_cache_exists[] = 'having'; - } + // Do we have a seed value? + $orderby = ctype_digit((string) $orderby) + ? $orderby = sprintf($this->_random_keyword[1], $orderby) + : $this->_random_keyword[0]; } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Sets the ORDER BY value - * - * @param string - * @param string direction: asc or desc - * @param bool enable field name escaping - * @return object - */ - public function order_by($orderby, $direction = '', $escape = TRUE) - { - if (strtolower($direction) === 'random') + elseif (empty($orderby)) { - $orderby = ''; // Random results want or don't need a field name - $direction = $this->_random_keyword; + return $this; } - elseif (trim($direction) != '') + elseif ($direction !== '') { - $direction = (in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE)) ? ' '.$direction : ' ASC'; + $direction = in_array($direction, array('ASC', 'DESC'), TRUE) ? ' '.$direction : ''; } + is_bool($escape) OR $escape = $this->_protect_identifiers; - if ((strpos($orderby, ',') !== FALSE) && $escape === TRUE) + if ($escape === 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); + $qb_orderby[] = array('field' => $orderby, 'direction' => $direction, 'escape' => FALSE); } - elseif ($direction != $this->_random_keyword) + else { - if ($escape === TRUE) + $qb_orderby = array(); + foreach (explode(',', $orderby) as $field) { - $orderby = $this->protect_identifiers($orderby); + $qb_orderby[] = ($direction === '' && preg_match('/\s+(ASC|DESC)$/i', rtrim($field), $match, PREG_OFFSET_CAPTURE)) + ? array('field' => ltrim(substr($field, 0, $match[0][1])), 'direction' => ' '.$match[1][0], 'escape' => TRUE) + : array('field' => trim($field), 'direction' => $direction, 'escape' => TRUE); } } - $this->ar_orderby[] = $orderby_statement = $orderby.$direction; - - if ($this->ar_caching === TRUE) + $this->qb_orderby = array_merge($this->qb_orderby, $qb_orderby); + if ($this->qb_caching === TRUE) { - $this->ar_cache_orderby[] = $orderby_statement; - $this->ar_cache_exists[] = 'orderby'; + $this->qb_cache_orderby = array_merge($this->qb_cache_orderby, $qb_orderby); + $this->qb_cache_exists[] = 'orderby'; } return $this; @@ -980,20 +1194,16 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** - * Sets the LIMIT value + * LIMIT * - * @param int the limit value - * @param int the offset value + * @param int $value LIMIT value + * @param int $offset OFFSET value * @return object */ - public function limit($value, $offset = NULL) + public function limit($value, $offset = FALSE) { - $this->ar_limit = (int) $value; - - if ( ! is_null($offset)) - { - $this->ar_offset = (int) $offset; - } + is_null($value) OR $this->qb_limit = (int) $value; + empty($offset) OR $this->qb_offset = (int) $offset; return $this; } @@ -1003,26 +1213,43 @@ abstract class CI_DB_active_record extends CI_DB_driver { /** * Sets the OFFSET value * - * @param int the offset value + * @param int $offset OFFSET value * @return object */ public function offset($offset) { - $this->ar_offset = (int) $offset; + empty($offset) OR $this->qb_offset = (int) $offset; return $this; } // -------------------------------------------------------------------- /** - * The "set" function. Allows key/value pairs to be set for inserting or updating + * LIMIT string + * + * Generates a platform-specific LIMIT clause. + * + * @param string $sql SQL Query + * @return string + */ + protected function _limit($sql) + { + return $sql.' LIMIT '.($this->qb_offset ? $this->qb_offset.', ' : '').$this->qb_limit; + } + + // -------------------------------------------------------------------- + + /** + * The "set" function. + * + * Allows key/value pairs to be set for inserting or updating * * @param mixed * @param string * @param bool * @return object */ - public function set($key, $value = '', $escape = TRUE) + public function set($key, $value = '', $escape = NULL) { $key = $this->_object_to_array($key); @@ -1031,16 +1258,12 @@ abstract class CI_DB_active_record extends CI_DB_driver { $key = array($key => $value); } + is_bool($escape) OR $escape = $this->_protect_identifiers; + 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); - } + $this->qb_set[$this->protect_identifiers($k, FALSE, $escape)] = ($escape) + ? $this->escape($v) : $v; } return $this; @@ -1054,18 +1277,18 @@ abstract class CI_DB_active_record extends CI_DB_driver { * Compiles a SELECT query string and returns the sql. * * @param string the table name to select from (optional) - * @param bool TRUE: resets AR values; FALSE: leave AR vaules alone + * @param bool TRUE: resets QB values; FALSE: leave QB vaules alone * @return string */ public function get_compiled_select($table = '', $reset = TRUE) { - if ($table != '') + if ($table !== '') { $this->_track_aliases($table); $this->from($table); } - $select = $this->_compile_select(); + $select = $this->_compile_select(); if ($reset === TRUE) { @@ -1088,15 +1311,15 @@ abstract class CI_DB_active_record extends CI_DB_driver { * @param string the offset clause * @return object */ - public function get($table = '', $limit = null, $offset = null) + public function get($table = '', $limit = NULL, $offset = NULL) { - if ($table != '') + if ($table !== '') { $this->_track_aliases($table); $this->from($table); } - if ( ! is_null($limit)) + if ( ! empty($limit)) { $this->limit($limit, $offset); } @@ -1106,24 +1329,28 @@ abstract class CI_DB_active_record extends CI_DB_driver { return $result; } + // -------------------------------------------------------------------- + /** * "Count All Results" query * * Generates a platform-specific query string that counts all records - * returned by an Active Record query. + * returned by an Query Builder query. * * @param string * @return string */ public function count_all_results($table = '') { - if ($table != '') + if ($table !== '') { $this->_track_aliases($table); $this->from($table); } - $result = $this->query($this->_compile_select($this->_count_string.$this->protect_identifiers('numrows'))); + $result = ($this->qb_distinct === TRUE) + ? $this->query($this->_count_string.$this->protect_identifiers('numrows')."\nFROM (\n".$this->_compile_select()."\n) CI_count_all_results") + : $this->query($this->_compile_select($this->_count_string.$this->protect_identifiers('numrows'))); $this->_reset_select(); if ($result->num_rows() === 0) @@ -1134,6 +1361,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { $row = $result->row(); return (int) $row->numrows; } + // -------------------------------------------------------------------- /** @@ -1141,14 +1369,15 @@ abstract class CI_DB_active_record extends CI_DB_driver { * * 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 + * @param string $table + * @param string $where + * @param int $limit + * @param int $offset * @return object */ - public function get_where($table = '', $where = null, $limit = null, $offset = null) + public function get_where($table = '', $where = NULL, $limit = NULL, $offset = NULL) { - if ($table != '') + if ($table !== '') { $this->from($table); } @@ -1158,7 +1387,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { $this->where($where); } - if ( ! is_null($limit)) + if ( ! empty($limit)) { $this->limit($limit, $offset); } @@ -1175,57 +1404,56 @@ abstract class CI_DB_active_record extends CI_DB_driver { * * 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 + * @param string $table Table to insert into + * @param array $set An associative array of insert values + * @param bool $escape Whether to escape values and identifiers + * @return int Number of rows inserted or FALSE on failure */ - public function insert_batch($table = '', $set = NULL) + public function insert_batch($table = '', $set = NULL, $escape = NULL) { if ( ! is_null($set)) { - $this->set_insert_batch($set); + $this->set_insert_batch($set, '', $escape); } - if (count($this->ar_set) === 0) + if (count($this->qb_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; + // No valid data array. Folds in cases where keys and values did not match up + return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE; } - if ($table == '') + if ($table === '') { - if ( ! isset($this->ar_from[0])) + if ( ! isset($this->qb_from[0])) { return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; } - $table = $this->ar_from[0]; + $table = $this->qb_from[0]; } // Batch this baby - for ($i = 0, $total = count($this->ar_set); $i < $total; $i += 100) + $affected_rows = 0; + for ($i = 0, $total = count($this->qb_set); $i < $total; $i += 100) { - $this->query($this->_insert_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_keys, array_slice($this->ar_set, $i, 100))); + $this->query($this->_insert_batch($this->protect_identifiers($table, TRUE, $escape, FALSE), $this->qb_keys, array_slice($this->qb_set, $i, 100))); + $affected_rows += $this->affected_rows(); } $this->_reset_write(); - return TRUE; + return $affected_rows; } // -------------------------------------------------------------------- /** - * Insert_batch statement + * Insert batch statement * * Generates a platform-specific insert string from the supplied data. * - * @param string the table name - * @param array the insert keys - * @param array the insert values + * @param string $table Table name + * @param array $keys INSERT keys + * @param array $values INSERT values * @return string */ protected function _insert_batch($table, $keys, $values) @@ -1243,7 +1471,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { * @param bool * @return object */ - public function set_insert_batch($key, $value = '', $escape = TRUE) + public function set_insert_batch($key, $value = '', $escape = NULL) { $key = $this->_object_to_array_batch($key); @@ -1252,25 +1480,24 @@ abstract class CI_DB_active_record extends CI_DB_driver { $key = array($key => $value); } - $keys = array_keys(current($key)); + is_bool($escape) OR $escape = $this->_protect_identifiers; + + $keys = array_keys($this->_object_to_array(current($key))); sort($keys); foreach ($key as $row) { + $row = $this->_object_to_array($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(); + $this->qb_set[] = array(); return; } ksort($row); // puts $row in the same order as our keys - if ($escape === FALSE) - { - $this->ar_set[] = '('.implode(',', $row).')'; - } - else + if ($escape !== FALSE) { $clean = array(); foreach ($row as $value) @@ -1278,13 +1505,15 @@ abstract class CI_DB_active_record extends CI_DB_driver { $clean[] = $this->escape($value); } - $this->ar_set[] = '('.implode(',', $clean).')'; + $row = $clean; } + + $this->qb_set[] = '('.implode(',', $row).')'; } foreach ($keys as $k) { - $this->ar_keys[] = $this->protect_identifiers($k); + $this->qb_keys[] = $this->protect_identifiers($k, FALSE, $escape); } return $this; @@ -1298,7 +1527,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { * Compiles an insert query and returns the sql * * @param string the table to insert into - * @param bool TRUE: reset AR values; FALSE: leave AR values alone + * @param bool TRUE: reset QB values; FALSE: leave QB values alone * @return string */ public function get_compiled_insert($table = '', $reset = TRUE) @@ -1309,9 +1538,11 @@ abstract class CI_DB_active_record extends CI_DB_driver { } $sql = $this->_insert( - $this->protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE), - array_keys($this->ar_set), - array_values($this->ar_set) + $this->protect_identifiers( + $this->qb_from[0], TRUE, NULL, FALSE + ), + array_keys($this->qb_set), + array_values($this->qb_set) ); if ($reset === TRUE) @@ -1331,13 +1562,14 @@ abstract class CI_DB_active_record extends CI_DB_driver { * * @param string the table to insert data into * @param array an associative array of insert values + * @param bool $escape Whether to escape values and identifiers * @return object */ - public function insert($table = '', $set = NULL) + public function insert($table = '', $set = NULL, $escape = NULL) { if ( ! is_null($set)) { - $this->set($set); + $this->set($set, '', $escape); } if ($this->_validate_insert($table) === FALSE) @@ -1346,9 +1578,11 @@ abstract class CI_DB_active_record extends CI_DB_driver { } $sql = $this->_insert( - $this->protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE), - array_keys($this->ar_set), - array_values($this->ar_set) + $this->protect_identifiers( + $this->qb_from[0], TRUE, $escape, FALSE + ), + array_keys($this->qb_set), + array_values($this->qb_set) ); $this->_reset_write(); @@ -1358,23 +1592,6 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** - * Insert statement - * - * Generates a platform-specific insert string from the supplied data - * - * @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).')'; - } - - // -------------------------------------------------------------------- - - /** * Validate Insert * * This method is used by both insert() and get_compiled_insert() to @@ -1386,21 +1603,18 @@ abstract class CI_DB_active_record extends CI_DB_driver { */ protected function _validate_insert($table = '') { - if (count($this->ar_set) === 0) + if (count($this->qb_set) === 0) { return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE; } - if ($table == '') + if ($table !== '') { - if ( ! isset($this->ar_from[0])) - { - return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; - } + $this->qb_from[0] = $table; } - else + elseif ( ! isset($this->qb_from[0])) { - $this->ar_from[0] = $table; + return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; } return TRUE; @@ -1424,22 +1638,23 @@ abstract class CI_DB_active_record extends CI_DB_driver { $this->set($set); } - if (count($this->ar_set) === 0) + if (count($this->qb_set) === 0) { return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE; } - if ($table == '') + if ($table === '') { - if ( ! isset($this->ar_from[0])) + if ( ! isset($this->qb_from[0])) { return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; } - $table = $this->ar_from[0]; + $table = $this->qb_from[0]; } - $sql = $this->_replace($this->protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->ar_set), array_values($this->ar_set)); + $sql = $this->_replace($this->protect_identifiers($table, TRUE, NULL, FALSE), array_keys($this->qb_set), array_values($this->qb_set)); + $this->_reset_write(); return $this->query($sql); } @@ -1464,12 +1679,29 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** + * FROM tables + * + * Groups tables in FROM clauses if needed, so there is no confusion + * about operator precedence. + * + * Note: This is only used (and overriden) by MySQL and CUBRID. + * + * @return string + */ + protected function _from_tables() + { + return implode(', ', $this->qb_from); + } + + // -------------------------------------------------------------------- + + /** * Get UPDATE query string * * Compiles an update query and returns the sql * * @param string the table to update - * @param bool TRUE: reset AR values; FALSE: leave AR values alone + * @param bool TRUE: reset QB values; FALSE: leave QB values alone * @return string */ public function get_compiled_update($table = '', $reset = TRUE) @@ -1482,7 +1714,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { return FALSE; } - $sql = $this->_update($this->protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit); + $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set); if ($reset === TRUE) { @@ -1495,13 +1727,14 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** - * Update + * UPDATE * - * Compiles an update string and runs the query + * 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 + * @param string $table + * @param array $set An associative array of update values + * @param mixed $where + * @param int $limit * @return object */ public function update($table = '', $set = NULL, $where = NULL, $limit = NULL) @@ -1519,17 +1752,17 @@ abstract class CI_DB_active_record extends CI_DB_driver { return FALSE; } - if ($where != NULL) + if ($where !== NULL) { $this->where($where); } - if ($limit != NULL) + if ( ! empty($limit)) { $this->limit($limit); } - $sql = $this->_update($this->protect_identifiers($this->ar_from[0], TRUE, NULL, FALSE), $this->ar_set, $this->ar_where, $this->ar_orderby, $this->ar_limit, $this->ar_like); + $sql = $this->_update($this->protect_identifiers($this->qb_from[0], TRUE, NULL, FALSE), $this->qb_set); $this->_reset_write(); return $this->query($sql); } @@ -1537,41 +1770,6 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** - * Update statement - * - * Generates a platform-specific update string from the supplied data - * - * @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 - * @param array the like clause - * @return string - */ - protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array()) - { - foreach ($values as $key => $val) - { - $valstr[] = $key.' = '.$val; - } - - $where = empty($where) ? '' : ' WHERE '.implode(' ', $where); - - if ( ! empty($like)) - { - $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like); - } - - return 'UPDATE '.$table.' SET '.implode(', ', $valstr) - .$where - .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : '') - .($limit ? ' LIMIT '.$limit : ''); - } - - // -------------------------------------------------------------------- - - /** * Validate Update * * This method is used by both update() and get_compiled_update() to @@ -1583,21 +1781,18 @@ abstract class CI_DB_active_record extends CI_DB_driver { */ protected function _validate_update($table = '') { - if (count($this->ar_set) == 0) + if (count($this->qb_set) === 0) { return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE; } - if ($table == '') + if ($table !== '') { - if ( ! isset($this->ar_from[0])) - { - return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; - } + $this->qb_from[0] = $table; } - else + elseif ( ! isset($this->qb_from[0])) { - $this->ar_from[0] = $table; + return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; } return TRUE; @@ -1613,7 +1808,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { * @param string the table to retrieve the results from * @param array an associative array of update values * @param string the where key - * @return bool + * @return int number of rows affected or FALSE on failure */ public function update_batch($table = '', $set = NULL, $index = NULL) { @@ -1630,29 +1825,31 @@ abstract class CI_DB_active_record extends CI_DB_driver { $this->set_update_batch($set, $index); } - if (count($this->ar_set) === 0) + if (count($this->qb_set) === 0) { return ($this->db_debug) ? $this->display_error('db_must_use_set') : FALSE; } - if ($table == '') + if ($table === '') { - if ( ! isset($this->ar_from[0])) + if ( ! isset($this->qb_from[0])) { return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; } - $table = $this->ar_from[0]; + $table = $this->qb_from[0]; } // Batch this baby - for ($i = 0, $total = count($this->ar_set); $i < $total; $i += 100) + $affected_rows = 0; + for ($i = 0, $total = count($this->qb_set); $i < $total; $i += 100) { - $this->query($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($this->_update_batch($this->protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->qb_set, $i, 100), $this->protect_identifiers($index))); + $affected_rows += $this->affected_rows(); } $this->_reset_write(); - return TRUE; + return $affected_rows; } // -------------------------------------------------------------------- @@ -1665,7 +1862,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { * @param bool * @return object */ - public function set_update_batch($key, $index = '', $escape = TRUE) + public function set_update_batch($key, $index = '', $escape = NULL) { $key = $this->_object_to_array_batch($key); @@ -1674,30 +1871,28 @@ abstract class CI_DB_active_record extends CI_DB_driver { // @todo error } + is_bool($escape) OR $escape = $this->_protect_identifiers; + foreach ($key as $k => $v) { $index_set = FALSE; $clean = array(); foreach ($v as $k2 => $v2) { - if ($k2 == $index) + if ($k2 === $index) { $index_set = TRUE; } - else - { - $not[] = $k.'-'.$v; - } - $clean[$this->protect_identifiers($k2)] = ($escape === FALSE) ? $v2 : $this->escape($v2); + $clean[$this->protect_identifiers($k2, FALSE, $escape)] = ($escape === FALSE) ? $v2 : $this->escape($v2); } - if ($index_set == FALSE) + if ($index_set === FALSE) { return $this->display_error('db_batch_missing_index'); } - $this->ar_set[] = $clean; + $this->qb_set[] = $clean; } return $this; @@ -1715,14 +1910,14 @@ abstract class CI_DB_active_record extends CI_DB_driver { */ public function empty_table($table = '') { - if ($table == '') + if ($table === '') { - if ( ! isset($this->ar_from[0])) + if ( ! isset($this->qb_from[0])) { return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; } - $table = $this->ar_from[0]; + $table = $this->qb_from[0]; } else { @@ -1748,14 +1943,14 @@ abstract class CI_DB_active_record extends CI_DB_driver { */ public function truncate($table = '') { - if ($table == '') + if ($table === '') { - if ( ! isset($this->ar_from[0])) + if ( ! isset($this->qb_from[0])) { return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; } - $table = $this->ar_from[0]; + $table = $this->qb_from[0]; } else { @@ -1793,7 +1988,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { * Compiles a delete query string and returns the sql * * @param string the table to delete from - * @param bool TRUE: reset AR values; FALSE: leave AR values alone + * @param bool TRUE: reset QB values; FALSE: leave QB values alone * @return string */ public function get_compiled_delete($table = '', $reset = TRUE) @@ -1815,30 +2010,28 @@ abstract class CI_DB_active_record extends CI_DB_driver { * @param mixed the where clause * @param mixed the limit clause * @param bool - * @return object + * @return mixed */ public function delete($table = '', $where = '', $limit = NULL, $reset_data = TRUE) { // Combine any cached components with the current statements $this->_merge_cache(); - if ($table == '') + if ($table === '') { - if ( ! isset($this->ar_from[0])) + if ( ! isset($this->qb_from[0])) { return ($this->db_debug) ? $this->display_error('db_must_set_table') : FALSE; } - $table = $this->ar_from[0]; + $table = $this->qb_from[0]; } elseif (is_array($table)) { foreach ($table as $single_table) { - $this->delete($single_table, $where, $limit, FALSE); + $this->delete($single_table, $where, $limit, $reset_data); } - - $this->_reset_write(); return; } else @@ -1846,22 +2039,22 @@ abstract class CI_DB_active_record extends CI_DB_driver { $table = $this->protect_identifiers($table, TRUE, NULL, FALSE); } - if ($where != '') + if ($where !== '') { $this->where($where); } - if ($limit != NULL) + if ( ! empty($limit)) { $this->limit($limit); } - if (count($this->ar_where) === 0 && count($this->ar_wherein) === 0 && count($this->ar_like) === 0) + if (count($this->qb_where) === 0) { return ($this->db_debug) ? $this->display_error('db_del_must_use_where') : FALSE; } - $sql = $this->_delete($table, $this->ar_where, $this->ar_like, $this->ar_limit); + $sql = $this->_delete($table); if ($reset_data) { $this->_reset_write(); @@ -1878,21 +2071,12 @@ abstract class CI_DB_active_record extends CI_DB_driver { * Generates a platform-specific delete string from the supplied data * * @param string the table name - * @param array the where clause - * @param array the like clause - * @param string the limit clause * @return string */ - protected function _delete($table, $where = array(), $like = array(), $limit = FALSE) + protected function _delete($table) { - $conditions = array(); - - empty($where) OR $conditions[] = implode(' ', $where); - empty($like) OR $conditions[] = implode(' ', $like); - - return 'DELETE FROM '.$table - .(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : '') - .($limit ? ' LIMIT '.$limit : ''); + return 'DELETE FROM '.$table.$this->_compile_wh('qb_where') + .($this->qb_limit ? ' LIMIT '.$this->qb_limit : ''); } // -------------------------------------------------------------------- @@ -1907,7 +2091,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { */ public function dbprefix($table = '') { - if ($table == '') + if ($table === '') { $this->display_error('db_table_name_required'); } @@ -1962,15 +2146,15 @@ abstract class CI_DB_active_record extends CI_DB_driver { if (strpos($table, ' ') !== FALSE) { // if the alias is written with the AS keyword, remove it - $table = preg_replace('/ AS /i', ' ', $table); + $table = preg_replace('/\s+AS\s+/i', ' ', $table); // Grab the alias $table = trim(strrchr($table, ' ')); // Store the alias, if it doesn't already exist - if ( ! in_array($table, $this->ar_aliased_tables)) + if ( ! in_array($table, $this->qb_aliased_tables)) { - $this->ar_aliased_tables[] = $table; + $this->qb_aliased_tables[] = $table; } } } @@ -1981,8 +2165,9 @@ abstract class CI_DB_active_record extends CI_DB_driver { * Compile the SELECT statement * * Generates a query string based on which functions were used. - * Should not be called directly. The get() function calls it. + * Should not be called directly. * + * @param bool $select_override * @return string */ protected function _compile_select($select_override = FALSE) @@ -1997,9 +2182,9 @@ abstract class CI_DB_active_record extends CI_DB_driver { } else { - $sql = ( ! $this->ar_distinct) ? 'SELECT ' : 'SELECT DISTINCT '; + $sql = ( ! $this->qb_distinct) ? 'SELECT ' : 'SELECT DISTINCT '; - if (count($this->ar_select) === 0) + if (count($this->qb_select) === 0) { $sql .= '*'; } @@ -2008,76 +2193,178 @@ abstract class CI_DB_active_record extends CI_DB_driver { // 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) + foreach ($this->qb_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); + $no_escape = isset($this->qb_no_escape[$key]) ? $this->qb_no_escape[$key] : NULL; + $this->qb_select[$key] = $this->protect_identifiers($val, FALSE, $no_escape); } - $sql .= implode(', ', $this->ar_select); + $sql .= implode(', ', $this->qb_select); } } // Write the "FROM" portion of the query - if (count($this->ar_from) > 0) + if (count($this->qb_from) > 0) { - $sql .= "\nFROM ".$this->_from_tables($this->ar_from); + $sql .= "\nFROM ".$this->_from_tables(); } // Write the "JOIN" portion of the query - if (count($this->ar_join) > 0) + if (count($this->qb_join) > 0) { - $sql .= "\n".implode("\n", $this->ar_join); + $sql .= "\n".implode("\n", $this->qb_join); } - // Write the "WHERE" portion of the query - if (count($this->ar_where) > 0 OR count($this->ar_like) > 0) + $sql .= $this->_compile_wh('qb_where') + .$this->_compile_group_by() + .$this->_compile_wh('qb_having') + .$this->_compile_order_by(); // ORDER BY + + // LIMIT + if ($this->qb_limit) { - $sql .= "\nWHERE "; + return $this->_limit($sql."\n"); } - $sql .= implode("\n", $this->ar_where); + return $sql; + } - // Write the "LIKE" portion of the query - if (count($this->ar_like) > 0) + // -------------------------------------------------------------------- + + /** + * Compile WHERE, HAVING statements + * + * Escapes identifiers in WHERE and HAVING statements at execution time. + * + * Required so that aliases are tracked properly, regardless of wether + * where(), or_where(), having(), or_having are called prior to from(), + * join() and dbprefix is added only if needed. + * + * @param string $qb_key 'qb_where' or 'qb_having' + * @return string SQL statement + */ + protected function _compile_wh($qb_key) + { + if (count($this->$qb_key) > 0) { - if (count($this->ar_where) > 0) + for ($i = 0, $c = count($this->$qb_key); $i < $c; $i++) { - $sql .= "\nAND "; + if ($this->{$qb_key}[$i]['escape'] === FALSE) + { + $this->{$qb_key}[$i] = $this->{$qb_key}[$i]['condition']; + continue; + } + + // Split multiple conditions + $conditions = preg_split( + '/(\s*AND\s+|\s*OR\s+)/i', + $this->{$qb_key}[$i]['condition'], + -1, + PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY + ); + + for ($ci = 0, $cc = count($conditions); $ci < $cc; $ci++) + { + if (($op = $this->_get_operator($conditions[$ci])) === FALSE + OR ! preg_match('/^(\(?)(.*)('.preg_quote($op, '/').')\s*(.*(?<!\)))?(\)?)$/i', $conditions[$ci], $matches)) + { + continue; + } + + // $matches = array( + // 0 => '(test <= foo)', /* the whole thing */ + // 1 => '(', /* optional */ + // 2 => 'test', /* the field name */ + // 3 => ' <= ', /* $op */ + // 4 => 'foo', /* optional, if $op is e.g. 'IS NULL' */ + // 5 => ')' /* optional */ + // ); + + if ( ! empty($matches[4])) + { + $this->_is_literal($matches[4]) OR $matches[4] = $this->protect_identifiers(trim($matches[4])); + $matches[4] = ' '.$matches[4]; + } + + $conditions[$ci] = $matches[1].$this->protect_identifiers(trim($matches[2])) + .' '.trim($matches[3]).$matches[4].$matches[5]; + } + + $this->{$qb_key}[$i] = implode('', $conditions); } - $sql .= implode("\n", $this->ar_like); + return ($qb_key === 'qb_having' ? "\nHAVING " : "\nWHERE ") + .implode("\n", $this->$qb_key); } - // Write the "GROUP BY" portion of the query - if (count($this->ar_groupby) > 0) - { - $sql .= "\nGROUP BY ".implode(', ', $this->ar_groupby); - } + return ''; + } - // Write the "HAVING" portion of the query - if (count($this->ar_having) > 0) + // -------------------------------------------------------------------- + + /** + * Compile GROUP BY + * + * Escapes identifiers in GROUP BY statements at execution time. + * + * Required so that aliases are tracked properly, regardless of wether + * group_by() is called prior to from(), join() and dbprefix is added + * only if needed. + * + * @return string SQL statement + */ + protected function _compile_group_by() + { + if (count($this->qb_groupby) > 0) { - $sql .= "\nHAVING ".implode("\n", $this->ar_having); + for ($i = 0, $c = count($this->qb_groupby); $i < $c; $i++) + { + $this->qb_groupby[$i] = ($this->qb_groupby[$i]['escape'] === FALSE OR $this->_is_literal($this->qb_groupby[$i]['field'])) + ? $this->qb_groupby[$i]['field'] + : $this->protect_identifiers($this->qb_groupby[$i]['field']); + } + + return "\nGROUP BY ".implode(', ', $this->qb_groupby); } - // Write the "ORDER BY" portion of the query - if (count($this->ar_orderby) > 0) + return ''; + } + + // -------------------------------------------------------------------- + + /** + * Compile ORDER BY + * + * Escapes identifiers in ORDER BY statements at execution time. + * + * Required so that aliases are tracked properly, regardless of wether + * order_by() is called prior to from(), join() and dbprefix is added + * only if needed. + * + * @return string SQL statement + */ + protected function _compile_order_by() + { + if (is_array($this->qb_orderby) && count($this->qb_orderby) > 0) { - $sql .= "\nORDER BY ".implode(', ', $this->ar_orderby); - if ($this->ar_order !== FALSE) + for ($i = 0, $c = count($this->qb_orderby); $i < $c; $i++) { - $sql .= ($this->ar_order == 'desc') ? ' DESC' : ' ASC'; + if ($this->qb_orderby[$i]['escape'] !== FALSE && ! $this->_is_literal($this->qb_orderby[$i]['field'])) + { + $this->qb_orderby[$i]['field'] = $this->protect_identifiers($this->qb_orderby[$i]['field']); + } + + $this->qb_orderby[$i] = $this->qb_orderby[$i]['field'].$this->qb_orderby[$i]['direction']; } - } - // Write the "LIMIT" portion of the query - if (is_numeric($this->ar_limit)) + return $this->qb_orderby = "\nORDER BY ".implode(', ', $this->qb_orderby); + } + elseif (is_string($this->qb_orderby)) { - return $this->_limit($sql."\n", $this->ar_limit, $this->ar_offset); + return $this->qb_orderby; } - return $sql; + return ''; } // -------------------------------------------------------------------- @@ -2090,7 +2377,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { * @param object * @return array */ - public function _object_to_array($object) + protected function _object_to_array($object) { if ( ! is_object($object)) { @@ -2101,7 +2388,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { 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') + if ( ! is_object($val) && ! is_array($val) && $key !== '_parent_name') { $array[$key] = $val; } @@ -2120,7 +2407,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { * @param object * @return array */ - public function _object_to_array_batch($object) + protected function _object_to_array_batch($object) { if ( ! is_object($object)) { @@ -2152,13 +2439,13 @@ abstract class CI_DB_active_record extends CI_DB_driver { /** * Start Cache * - * Starts AR caching + * Starts QB caching * * @return void */ public function start_cache() { - $this->ar_caching = TRUE; + $this->qb_caching = TRUE; } // -------------------------------------------------------------------- @@ -2166,13 +2453,13 @@ abstract class CI_DB_active_record extends CI_DB_driver { /** * Stop Cache * - * Stops AR caching + * Stops QB caching * * @return void */ public function stop_cache() { - $this->ar_caching = FALSE; + $this->qb_caching = FALSE; } // -------------------------------------------------------------------- @@ -2180,24 +2467,23 @@ abstract class CI_DB_active_record extends CI_DB_driver { /** * Flush Cache * - * Empties the AR cache + * Empties the QB cache * * @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() + 'qb_cache_select' => array(), + 'qb_cache_from' => array(), + 'qb_cache_join' => array(), + 'qb_cache_where' => array(), + 'qb_cache_groupby' => array(), + 'qb_cache_having' => array(), + 'qb_cache_orderby' => array(), + 'qb_cache_set' => array(), + 'qb_cache_exists' => array(), + 'qb_cache_no_escape' => array() )); } @@ -2206,47 +2492,77 @@ abstract class CI_DB_active_record extends CI_DB_driver { /** * Merge Cache * - * When called, this function merges any cached AR arrays with + * When called, this function merges any cached QB arrays with * locally called ones. * * @return void */ protected function _merge_cache() { - if (count($this->ar_cache_exists) === 0) + if (count($this->qb_cache_exists) === 0) { return; } - foreach ($this->ar_cache_exists as $val) + foreach ($this->qb_cache_exists as $val) { - $ar_variable = 'ar_'.$val; - $ar_cache_var = 'ar_cache_'.$val; + $qb_variable = 'qb_'.$val; + $qb_cache_var = 'qb_cache_'.$val; - if (count($this->$ar_cache_var) === 0) + if (count($this->$qb_cache_var) === 0) { continue; } - $this->$ar_variable = array_unique(array_merge($this->$ar_cache_var, $this->$ar_variable)); + $this->$qb_variable = array_unique(array_merge($this->$qb_cache_var, $this->$qb_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 && count($this->ar_cache_from) > 0) + if ($this->_protect_identifiers === TRUE && count($this->qb_cache_from) > 0) { - $this->_track_aliases($this->ar_from); + $this->_track_aliases($this->qb_from); } - $this->ar_no_escape = $this->ar_cache_no_escape; + $this->qb_no_escape = $this->qb_cache_no_escape; } // -------------------------------------------------------------------- /** - * Reset Active Record values. + * Is literal * - * Publicly-visible method to reset the AR values. + * Determines if a string represents a literal value or a field name + * + * @param string + * @return bool + */ + protected function _is_literal($str) + { + $str = trim($str); + + if (empty($str)) + { + return TRUE; + } + + static $_str; + + if (empty($_str)) + { + $_str = ($this->_escape_char !== '"') + ? array('"', "'") : array("'"); + } + + return (ctype_digit($str) OR in_array($str[0], $_str, TRUE)); + } + + // -------------------------------------------------------------------- + + /** + * Reset Query Builder values. + * + * Publicly-visible method to reset the QB values. * * @return void */ @@ -2259,47 +2575,41 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** - * Resets the active record values. Called by the get() function + * Resets the query builder values. Called by the get() function * * @param array An array of fields to reset * @return void */ - protected function _reset_run($ar_reset_items) + protected function _reset_run($qb_reset_items) { - foreach ($ar_reset_items as $item => $default_value) + foreach ($qb_reset_items as $item => $default_value) { - if ( ! in_array($item, $this->ar_store_array)) - { - $this->$item = $default_value; - } + $this->$item = $default_value; } } // -------------------------------------------------------------------- /** - * Resets the active record values. Called by the get() function + * Resets the query builder values. Called by the get() function * * @return void */ protected function _reset_select() { $this->_reset_run(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 + 'qb_select' => array(), + 'qb_from' => array(), + 'qb_join' => array(), + 'qb_where' => array(), + 'qb_groupby' => array(), + 'qb_having' => array(), + 'qb_orderby' => array(), + 'qb_aliased_tables' => array(), + 'qb_no_escape' => array(), + 'qb_distinct' => FALSE, + 'qb_limit' => FALSE, + 'qb_offset' => FALSE ) ); } @@ -2307,7 +2617,7 @@ abstract class CI_DB_active_record extends CI_DB_driver { // -------------------------------------------------------------------- /** - * Resets the active record "write" values. + * Resets the query builder "write" values. * * Called by the insert() update() insert_batch() update_batch() and delete() functions * @@ -2316,19 +2626,17 @@ abstract class CI_DB_active_record extends CI_DB_driver { protected function _reset_write() { $this->_reset_run(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 + 'qb_set' => array(), + 'qb_from' => array(), + 'qb_where' => array(), + 'qb_orderby' => array(), + 'qb_keys' => array(), + 'qb_limit' => FALSE ) ); } } -/* End of file DB_active_rec.php */ -/* Location: ./system/database/DB_active_rec.php */
\ No newline at end of file +/* End of file DB_query_builder.php */ +/* Location: ./system/database/DB_query_builder.php */
\ No newline at end of file diff --git a/system/database/DB_result.php b/system/database/DB_result.php index 196febe2c..9d19075ba 100644 --- a/system/database/DB_result.php +++ b/system/database/DB_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Database Result Class @@ -38,32 +39,123 @@ */ class CI_DB_result { - public $conn_id = NULL; - public $result_id = NULL; + /** + * Connection ID + * + * @var resource|object + */ + public $conn_id; + + /** + * Result ID + * + * @var resource|object + */ + public $result_id; + + /** + * Result Array + * + * @var array[] + */ public $result_array = array(); + + /** + * Result Object + * + * @var object[] + */ public $result_object = array(); + + /** + * Custom Result Object + * + * @var object[] + */ public $custom_result_object = array(); + + /** + * Current Row index + * + * @var int + */ public $current_row = 0; - public $num_rows = 0; - public $row_data = NULL; + /** + * Number of rows + * + * @var int + */ + public $num_rows; + + /** + * Row data + * + * @var array + */ + public $row_data; + + // -------------------------------------------------------------------- + + /** + * Constructor + * + * @param object $driver_object + * @return void + */ public function __construct(&$driver_object) { $this->conn_id = $driver_object->conn_id; $this->result_id = $driver_object->result_id; } + // -------------------------------------------------------------------- + /** - * Query result. Acts as a wrapper function for the following functions. + * Number of rows in the result set * - * @param string can be "object" or "array" - * @return object + * @return int + */ + public function num_rows() + { + if (is_int($this->num_rows)) + { + return $this->num_rows; + } + elseif (count($this->result_array) > 0) + { + return $this->num_rows = count($this->result_array); + } + elseif (count($this->result_object) > 0) + { + return $this->num_rows = count($this->result_object); + } + + return $this->num_rows = count($this->result_array()); + } + + // -------------------------------------------------------------------- + + /** + * Query result. Acts as a wrapper function for the following functions. + * + * @param string $type 'object', 'array' or a custom class name + * @return array */ public function result($type = 'object') { - if ($type === 'array') return $this->result_array(); - elseif ($type === 'object') return $this->result_object(); - else return $this->custom_result_object($type); + if ($type === 'array') + { + return $this->result_array(); + } + elseif ($type === 'object') + { + return $this->result_object(); + } + else + { + return $this->custom_result_object($type); + } } // -------------------------------------------------------------------- @@ -71,38 +163,55 @@ class CI_DB_result { /** * Custom query result. * - * @param string A string that represents the type of object you want back - * @return array of objects + * @param string $class_name + * @return array */ public function custom_result_object($class_name) { - if (array_key_exists($class_name, $this->custom_result_object)) + if (isset($this->custom_result_object[$class_name])) { return $this->custom_result_object[$class_name]; } - - if ($this->result_id === FALSE OR $this->num_rows() == 0) + elseif ( ! $this->result_id OR $this->num_rows === 0) { return array(); } - // add the data to the object - $this->_data_seek(0); - $result_object = array(); + // Don't fetch the result set again if we already have it + $_data = NULL; + if (($c = count($this->result_array)) > 0) + { + $_data = 'result_array'; + } + elseif (($c = count($this->result_object)) > 0) + { + $_data = 'result_object'; + } - while ($row = $this->_fetch_object()) + if ($_data !== NULL) { - $object = new $class_name(); - foreach ($row as $key => $value) + for ($i = 0; $i < $c; $i++) { - $object->$key = $value; + $this->custom_result_object[$class_name][$i] = new $class_name(); + + foreach ($this->{$_data}[$i] as $key => $value) + { + $this->custom_result_object[$class_name][$i]->$key = $value; + } } - $result_object[] = $object; + return $this->custom_result_object[$class_name]; } - // return the array - return $this->custom_result_object[$class_name] = $result_object; + $this->_data_seek(0); + $this->custom_result_object[$class_name] = array(); + + while ($row = $this->_fetch_object($class_name)) + { + $this->custom_result_object[$class_name][] = $row; + } + + return $this->custom_result_object[$class_name]; } // -------------------------------------------------------------------- @@ -119,14 +228,24 @@ class CI_DB_result { 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) + // In the event that query caching is on, the result_id variable + // will not be a valid resource so we'll simply return an empty + // array. + if ( ! $this->result_id OR $this->num_rows === 0) { return array(); } + if (($c = count($this->result_array)) > 0) + { + for ($i = 0; $i < $c; $i++) + { + $this->result_object[$i] = (object) $this->result_array[$i]; + } + + return $this->result_object; + } + $this->_data_seek(0); while ($row = $this->_fetch_object()) { @@ -139,7 +258,7 @@ class CI_DB_result { // -------------------------------------------------------------------- /** - * Query result. "array" version. + * Query result. "array" version. * * @return array */ @@ -150,14 +269,24 @@ class CI_DB_result { 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) + // In the event that query caching is on, the result_id variable + // will not be a valid resource so we'll simply return an empty + // array. + if ( ! $this->result_id OR $this->num_rows === 0) { return array(); } + if (($c = count($this->result_object)) > 0) + { + for ($i = 0; $i < $c; $i++) + { + $this->result_array[$i] = (array) $this->result_object[$i]; + } + + return $this->result_array; + } + $this->_data_seek(0); while ($row = $this->_fetch_assoc()) { @@ -170,29 +299,28 @@ class CI_DB_result { // -------------------------------------------------------------------- /** - * Query result. Acts as a wrapper function for the following functions. + * Row + * + * A wrapper method. * - * @param string - * @param string can be "object" or "array" - * @return mixed either a result object or array + * @param mixed $n + * @param string $type 'object' or 'array' + * @return mixed */ 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); - } + is_array($this->row_data) OR $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)) + // array_key_exists() instead of isset() to allow for NULL values + if (empty($this->row_data) OR ! array_key_exists($n, $this->row_data)) { - return $this->row_data[$n]; + return NULL; } - // reset the $n variable if the result was not achieved - $n = 0; + + return $this->row_data[$n]; } if ($type === 'object') return $this->row_object($n); @@ -205,6 +333,8 @@ class CI_DB_result { /** * Assigns an item into a particular column slot * + * @param mixed $key + * @param mixed $value * @return void */ public function set_row($key, $value = NULL) @@ -224,7 +354,7 @@ class CI_DB_result { return; } - if ($key != '' && ! is_null($value)) + if ($key !== '' && ! is_null($value)) { $this->row_data[$key] = $value; } @@ -235,27 +365,33 @@ class CI_DB_result { /** * Returns a single result row - custom object version * + * @param int $n + * @param string $type * @return object */ public function custom_row_object($n, $type) { - $result = $this->custom_result_object($type); - if (count($result) === 0) + isset($this->custom_result_object[$type]) OR $this->custom_result_object($type); + + if (count($this->custom_result_object[$type]) === 0) { - return $result; + return NULL; } - if ($n != $this->current_row && isset($result[$n])) + if ($n !== $this->current_row && isset($this->custom_result_object[$type][$n])) { $this->current_row = $n; } - return $result[$this->current_row]; + return $this->custom_result_object[$type][$this->current_row]; } + // -------------------------------------------------------------------- + /** * Returns a single result row - object version * + * @param int $n * @return object */ public function row_object($n = 0) @@ -263,10 +399,10 @@ class CI_DB_result { $result = $this->result_object(); if (count($result) === 0) { - return $result; + return NULL; } - if ($n != $this->current_row && isset($result[$n])) + if ($n !== $this->current_row && isset($result[$n])) { $this->current_row = $n; } @@ -279,6 +415,7 @@ class CI_DB_result { /** * Returns a single result row - array version * + * @param int $n * @return array */ public function row_array($n = 0) @@ -286,10 +423,10 @@ class CI_DB_result { $result = $this->result_array(); if (count($result) === 0) { - return $result; + return NULL; } - if ($n != $this->current_row && isset($result[$n])) + if ($n !== $this->current_row && isset($result[$n])) { $this->current_row = $n; } @@ -302,12 +439,13 @@ class CI_DB_result { /** * Returns the "first" row * - * @return object + * @param string $type + * @return mixed */ public function first_row($type = 'object') { $result = $this->result($type); - return (count($result) === 0) ? $result : $result[0]; + return (count($result) === 0) ? NULL : $result[0]; } // -------------------------------------------------------------------- @@ -315,12 +453,13 @@ class CI_DB_result { /** * Returns the "last" row * - * @return object + * @param string $type + * @return mixed */ public function last_row($type = 'object') { $result = $this->result($type); - return (count($result) === 0) ? $result : $result[count($result) - 1]; + return (count($result) === 0) ? NULL : $result[count($result) - 1]; } // -------------------------------------------------------------------- @@ -328,14 +467,15 @@ class CI_DB_result { /** * Returns the "next" row * - * @return object + * @param string $type + * @return mixed */ public function next_row($type = 'object') { $result = $this->result($type); if (count($result) === 0) { - return $result; + return NULL; } if (isset($result[$this->current_row + 1])) @@ -351,14 +491,15 @@ class CI_DB_result { /** * Returns the "previous" row * - * @return object + * @param string $type + * @return mixed */ public function previous_row($type = 'object') { $result = $this->result($type); if (count($result) === 0) { - return $result; + return NULL; } if (isset($result[$this->current_row - 1])) @@ -371,7 +512,29 @@ class CI_DB_result { // -------------------------------------------------------------------- /** - * The following functions are normally overloaded by the identically named + * Returns an unbuffered row and move pointer to next row + * + * @param string $type 'array', 'object' or a custom class name + * @return mixed + */ + public function unbuffered_row($type = 'object') + { + if ($type === 'array') + { + return $this->_fetch_assoc(); + } + elseif ($type === 'object') + { + return $this->_fetch_object(); + } + + return $this->_fetch_object($type); + } + + // -------------------------------------------------------------------- + + /** + * The following methods 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 @@ -379,14 +542,118 @@ class CI_DB_result { * 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() { $this->result_id = FALSE; } - protected function _data_seek() { return FALSE; } - protected function _fetch_assoc() { return array(); } - protected function _fetch_object() { return array(); } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * Overriden by driver result classes. + * + * @return int + */ + public function num_fields() + { + return 0; + } + + // -------------------------------------------------------------------- + + /** + * Fetch Field Names + * + * Generates an array of column names. + * + * Overriden by driver result classes. + * + * @return array + */ + public function list_fields() + { + return array(); + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data. + * + * Overriden by driver result classes. + * + * @return array + */ + public function field_data() + { + return array(); + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * Overriden by driver result classes. + * + * @return void + */ + public function free_result() + { + $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. + * + * Overriden by driver result classes. + * + * @param int $n + * @return bool + */ + protected function _data_seek($n = 0) + { + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array. + * + * Overriden by driver result classes. + * + * @return array + */ + protected function _fetch_assoc() + { + return array(); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object. + * + * Overriden by driver result classes. + * + * @param string $class_name + * @return object + */ + protected function _fetch_object($class_name = 'stdClass') + { + return array(); + } } diff --git a/system/database/DB_utility.php b/system/database/DB_utility.php index 587dfdc01..a32fd4455 100644 --- a/system/database/DB_utility.php +++ b/system/database/DB_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Database Utility Class @@ -32,21 +33,49 @@ * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ */ -abstract class CI_DB_utility extends CI_DB_forge { +abstract class CI_DB_utility { - public $db; - public $data_cache = array(); + /** + * Database object + * + * @var object + */ + protected $db; + + // -------------------------------------------------------------------- + + /** + * List databases statement + * + * @var string + */ + protected $_list_databases = FALSE; - // Platform specific SQL strings - // Just setting those defaults to FALSE as they are mostly MySQL-specific + /** + * OPTIMIZE TABLE statement + * + * @var string + */ protected $_optimize_table = FALSE; + + /** + * REPAIR TABLE statement + * + * @var string + */ protected $_repair_table = FALSE; - public function __construct() + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @param object &$db Database object + * @return void + */ + public function __construct(&$db) { - // Assign the main database object to $this->db - $CI =& get_instance(); - $this->db =& $CI->db; + $this->db =& $db; log_message('debug', 'Database Utility Class Initialized'); } @@ -60,29 +89,29 @@ abstract class CI_DB_utility extends CI_DB_forge { public function list_databases() { // Is there a cached result? - if (isset($this->data_cache['db_names'])) + if (isset($this->db->data_cache['db_names'])) { - return $this->data_cache['db_names']; + return $this->db->data_cache['db_names']; } elseif ($this->_list_databases === FALSE) { - return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE; + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; } - $this->data_cache['db_names'] = array(); + $this->db->data_cache['db_names'] = array(); $query = $this->db->query($this->_list_databases); if ($query === FALSE) { - return $this->data_cache['db_names']; + return $this->db->data_cache['db_names']; } - for ($i = 0, $c = count($query); $i < $c; $i++) + for ($i = 0, $query = $query->result_array(), $c = count($query); $i < $c; $i++) { - $this->data_cache['db_names'] = current($query[$i]); + $this->db->data_cache['db_names'][] = current($query[$i]); } - return $this->data_cache['db_names']; + return $this->db->data_cache['db_names']; } // -------------------------------------------------------------------- @@ -90,7 +119,7 @@ abstract class CI_DB_utility extends CI_DB_forge { /** * Determine if a particular database exists * - * @param string + * @param string $database_name * @return bool */ public function database_exists($database_name) @@ -103,14 +132,14 @@ abstract class CI_DB_utility extends CI_DB_forge { /** * Optimize Table * - * @param string the table name + * @param string $table_name * @return mixed */ public function optimize_table($table_name) { if ($this->_optimize_table === FALSE) { - return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE; + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; } $query = $this->db->query(sprintf($this->_optimize_table, $this->db->escape_identifiers($table_name))); @@ -134,7 +163,7 @@ abstract class CI_DB_utility extends CI_DB_forge { { if ($this->_optimize_table === FALSE) { - return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE; + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; } $result = array(); @@ -164,14 +193,14 @@ abstract class CI_DB_utility extends CI_DB_forge { /** * Repair Table * - * @param string the table name + * @param string $table_name * @return mixed */ public function repair_table($table_name) { if ($this->_repair_table === FALSE) { - return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE; + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; } $query = $this->db->query(sprintf($this->_repair_table, $this->db->escape_identifiers($table_name))); @@ -189,10 +218,10 @@ abstract class CI_DB_utility extends CI_DB_forge { /** * Generate CSV from a query result object * - * @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 + * @param object $query Query result object + * @param string $delim Delimiter (default: ,) + * @param string $newline Newline character (default: \n) + * @param string $enclosure Enclosure (default: ") * @return string */ public function csv_from_result($query, $delim = ',', $newline = "\n", $enclosure = '"') @@ -212,7 +241,7 @@ abstract class CI_DB_utility extends CI_DB_forge { $out = rtrim($out).$newline; // Next blast through the result array and build out the rows - foreach ($query->result_array() as $row) + while ($row = $query->unbuffered_row('array')) { foreach ($row as $item) { @@ -229,8 +258,8 @@ abstract class CI_DB_utility extends CI_DB_forge { /** * Generate XML data from a query result object * - * @param object The query result object - * @param array Any preferences + * @param object $query Query result object + * @param array $params Any preferences * @return string */ public function xml_from_result($query, $params = array()) @@ -258,7 +287,7 @@ abstract class CI_DB_utility extends CI_DB_forge { // Generate the result $xml = '<'.$root.'>'.$newline; - foreach ($query->result_array() as $row) + while ($row = $query->unbuffered_row()) { $xml .= $tab.'<'.$element.'>'.$newline; foreach ($row as $key => $val) @@ -276,6 +305,7 @@ abstract class CI_DB_utility extends CI_DB_forge { /** * Database Backup * + * @param array $params * @return void */ public function backup($params = array()) @@ -288,8 +318,6 @@ abstract class CI_DB_utility extends CI_DB_forge { $params = array('tables' => $params); } - // ------------------------------------------------------ - // Set up our default preferences $prefs = array( 'tables' => array(), @@ -333,7 +361,7 @@ abstract class CI_DB_utility extends CI_DB_forge { { if ($this->db->db_debug) { - return $this->db->display_error('db_unsuported_compression'); + return $this->db->display_error('db_unsupported_compression'); } $prefs['format'] = 'txt'; @@ -343,7 +371,7 @@ abstract class CI_DB_utility extends CI_DB_forge { if ($prefs['format'] === 'zip') { // Set the filename if not provided (only needed with Zip files) - if ($prefs['filename'] == '') + if ($prefs['filename'] === '') { $prefs['filename'] = (count($prefs['tables']) === 1 ? $prefs['tables'] : $this->db->database) .date('Y-m-d_H-i', time()).'.sql'; @@ -369,7 +397,7 @@ abstract class CI_DB_utility extends CI_DB_forge { $CI->zip->add_data($prefs['filename'], $this->_backup($prefs)); return $CI->zip->get_zip(); } - elseif ($prefs['format'] == 'txt') // Was a text file requested? + elseif ($prefs['format'] === 'txt') // Was a text file requested? { return $this->_backup($prefs); } diff --git a/system/database/drivers/cubrid/cubrid_driver.php b/system/database/drivers/cubrid/cubrid_driver.php index 7a5c048f9..839413951 100644 --- a/system/database/drivers/cubrid/cubrid_driver.php +++ b/system/database/drivers/cubrid/cubrid_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -21,15 +21,16 @@ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com - * @since Version 2.0.2 + * @since Version 2.1 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CUBRID Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -40,26 +41,44 @@ */ class CI_DB_cubrid_driver extends CI_DB { + /** + * Database driver + * + * @var string + */ public $dbdriver = 'cubrid'; - // The character used for escaping - no need in CUBRID - protected $_escape_char = ''; + /** + * Auto-commit flag + * + * @var bool + */ + public $auto_commit = TRUE; - // clause and character used for LIKE escape sequences - not used in CUBRID - protected $_like_escape_str = ''; - protected $_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. + * Identifier escape character + * + * @var string */ - protected $_count_string = 'SELECT COUNT(*) AS '; - protected $_random_keyword = ' RAND()'; // database specific random keyword + protected $_escape_char = '`'; - // CUBRID-specific properties - public $auto_commit = TRUE; + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('RANDOM()', 'RANDOM(%d)'); + + // -------------------------------------------------------------------- + /** + * Class constructor + * + * @param array $params + * @return void + */ public function __construct($params) { parent::__construct($params); @@ -74,10 +93,12 @@ class CI_DB_cubrid_driver extends CI_DB { else { // If no port is defined by the user, use the default value - $this->port == '' OR $this->port = 33000; + empty($this->port) OR $this->port = 33000; } } + // -------------------------------------------------------------------- + /** * Non-persistent database connection * @@ -115,7 +136,7 @@ class CI_DB_cubrid_driver extends CI_DB { * Except for determining if a persistent connection should be used, * the rest of the logic is the same for db_connect() and db_pconnect(). * - * @param bool + * @param bool $persistent * @return resource */ protected function _cubrid_connect($persistent = FALSE) @@ -165,9 +186,18 @@ class CI_DB_cubrid_driver extends CI_DB { */ public function version() { - return isset($this->data_cache['version']) - ? $this->data_cache['version'] - : $this->data_cache['version'] = cubrid_get_server_info($this->conn_id); + if (isset($this->data_cache['version'])) + { + return $this->data_cache['version']; + } + elseif ( ! $this->conn_id) + { + $this->initialize(); + } + + return ( ! $this->conn_id OR ($version = cubrid_get_server_info($this->conn_id)) === FALSE) + ? FALSE + : $this->data_cache['version'] = $version; } // -------------------------------------------------------------------- @@ -175,7 +205,7 @@ class CI_DB_cubrid_driver extends CI_DB { /** * Execute the query * - * @param string an SQL query + * @param string $sql an SQL query * @return resource */ protected function _execute($sql) @@ -188,17 +218,13 @@ class CI_DB_cubrid_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -206,7 +232,7 @@ class CI_DB_cubrid_driver extends CI_DB { // 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->_trans_failure = ($test_mode === TRUE); if (cubrid_get_autocommit($this->conn_id)) { @@ -225,13 +251,8 @@ class CI_DB_cubrid_driver extends CI_DB { */ 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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -255,13 +276,8 @@ class CI_DB_cubrid_driver extends CI_DB { */ 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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -281,8 +297,8 @@ class CI_DB_cubrid_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -297,7 +313,9 @@ class CI_DB_cubrid_driver extends CI_DB { return $str; } - if (function_exists('cubrid_real_escape_string') AND is_resource($this->conn_id)) + if (function_exists('cubrid_real_escape_string') && + (is_resource($this->conn_id) + OR (get_resource_type($this->conn_id) === 'Unknown' && preg_match('/Resource id #/', strval($this->conn_id))))) { $str = cubrid_real_escape_string($str, $this->conn_id); } @@ -309,7 +327,7 @@ class CI_DB_cubrid_driver extends CI_DB { // escape LIKE condition wildcards if ($like === TRUE) { - $str = str_replace(array('%', '_'), array('\\%', '\\_'), $str); + return str_replace(array('%', '_'), array('\\%', '\\_'), $str); } return $str; @@ -342,49 +360,20 @@ class CI_DB_cubrid_driver extends CI_DB { // -------------------------------------------------------------------- /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified table - * - * @param string - * @return int - */ - 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->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 * - * @param bool + * @param bool $prefix_limit * @return string */ protected function _list_tables($prefix_limit = FALSE) { - $sql = "SHOW TABLES"; + $sql = 'SHOW TABLES'; - if ($prefix_limit !== FALSE AND $this->dbprefix != '') + if ($prefix_limit !== FALSE && $this->dbprefix !== '') { - $sql .= " LIKE '".$this->escape_like_str($this->dbprefix)."%'"; + return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'"; } return $sql; @@ -397,7 +386,7 @@ class CI_DB_cubrid_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @param string the table name + * @param string $table * @return string */ protected function _list_columns($table = '') @@ -412,12 +401,12 @@ class CI_DB_cubrid_driver extends CI_DB { * * Generates a platform-specific query so that the column data can be retrieved * - * @param string the table name + * @param string $table * @return string */ protected function _field_data($table) { - return "SELECT * FROM ".$table." LIMIT 1"; + return 'SELECT * FROM '.$table.' LIMIT 1'; } // -------------------------------------------------------------------- @@ -438,99 +427,62 @@ class CI_DB_cubrid_driver extends CI_DB { // -------------------------------------------------------------------- /** - * From Tables - * - * This function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards - * - * @param array - * @return string - */ - protected function _from_tables($tables) - { - if ( ! is_array($tables)) - { - $tables = array($tables); - } - - return '('.implode(', ', $tables).')'; - } - - // -------------------------------------------------------------------- - - /** * Update_Batch statement * * Generates a platform-specific batch update string from the supplied data * - * @param string the table name - * @param array the update data - * @param array the where clause + * @param string $table Table name + * @param array $values Update data + * @param string $index WHERE key * @return string */ - protected function _update_batch($table, $values, $index, $where = NULL) + protected function _update_batch($table, $values, $index) { $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) + 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, '; + $cases .= $k." = CASE \n" + .implode("\n", $v) + .'ELSE '.$k.' END, '; } - $sql .= substr($cases, 0, -2); - - $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; + $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); - return $sql; + return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); } // -------------------------------------------------------------------- /** - * Limit string + * FROM tables * - * Generates a platform-specific LIMIT clause + * Groups tables in FROM clauses if needed, so there is no confusion + * about operator precedence. * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value * @return string */ - protected function _limit($sql, $limit, $offset) + protected function _from_tables() { - if ($offset == 0) - { - $offset = ''; - } - else + if ( ! empty($this->qb_join) && count($this->qb_from) > 1) { - $offset .= ", "; + return '('.implode(', ', $this->qb_from).')'; } - return $sql."LIMIT ".$offset.$limit; + return implode(', ', $this->qb_from); } // -------------------------------------------------------------------- @@ -538,12 +490,11 @@ class CI_DB_cubrid_driver extends CI_DB { /** * Close DB Connection * - * @param resource * @return void */ - protected function _close($conn_id) + protected function _close() { - @cubrid_close($conn_id); + @cubrid_close($this->conn_id); } } diff --git a/system/database/drivers/cubrid/cubrid_forge.php b/system/database/drivers/cubrid/cubrid_forge.php index 16478ee11..05762ba5a 100644 --- a/system/database/drivers/cubrid/cubrid_forge.php +++ b/system/database/drivers/cubrid/cubrid_forge.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -21,9 +21,10 @@ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com - * @since Version 1.0 + * @since Version 2.1 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CUBRID Forge Class @@ -34,195 +35,174 @@ */ class CI_DB_cubrid_forge extends CI_DB_forge { + /** + * CREATE DATABASE statement + * + * @var string + */ protected $_create_database = FALSE; + + /** + * CREATE TABLE keys flag + * + * Whether table keys are created from within the + * CREATE TABLE statement. + * + * @var bool + */ + protected $_create_table_keys = TRUE; + + /** + * DROP DATABASE statement + * + * @var string + */ protected $_drop_database = FALSE; /** - * Process Fields + * CREATE TABLE IF statement * - * @param mixed the fields - * @return string + * @var string + */ + protected $_create_table_if = FALSE; + + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'SHORT' => 'INTEGER', + 'SMALLINT' => 'INTEGER', + 'INT' => 'BIGINT', + 'INTEGER' => 'BIGINT', + 'BIGINT' => 'NUMERIC', + 'FLOAT' => 'DOUBLE', + 'REAL' => 'DOUBLE' + ); + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] */ - protected function _process_fields($fields) + protected function _alter_table($alter_type, $table, $field) { - $current_field_count = 0; - $sql = ''; + if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) + { + return parent::_alter_table($alter_type, $table, $field); + } - foreach ($fields as $field => $attributes) + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); + $sqls = array(); + for ($i = 0, $c = count($field); $i < $c; $i++) { - // 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)) + if ($field[$i]['_literal'] !== FALSE) { - $sql .= "\n\t$attributes"; + $sqls[] = $sql.' CHANGE '.$field[$i]['_literal']; } 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) + $sqls[] = $sql.' CHANGE '.$this->_process_column($field[$i]); + if ( ! empty($field[$i]['new_name'])) { - $sql .= ' NULL'; + $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name']) + .' AS '.$this->db->escape_identifiers($field[$i]['name']); } - 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; + return $sqls; } // -------------------------------------------------------------------- /** - * Create Table + * Process column * - * @param string the table name - * @param mixed the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return bool + * @param array $field + * @return string */ - protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + protected function _process_column($field) { - $sql = 'CREATE TABLE '; + $extra_clause = isset($field['after']) + ? ' AFTER '.$this->db->escape_identifiers($field['after']) : ''; - if ($if_not_exists === TRUE) + if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE) { - //$sql .= 'IF NOT EXISTS '; - // As of version 8.4.0 CUBRID does not support this SQL syntax. + $extra_clause = ' FIRST'; } - $sql .= $this->db->escape_identifiers($table).' ('.$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)); + return $this->db->escape_identifiers($field['name']) + .(empty($field['new_name']) ? '' : $this->db->escape_identifiers($field['new_name'])) + .' '.$field['type'].$field['length'] + .$field['unsigned'] + .$field['null'] + .$field['default'] + .$field['auto_increment'] + .$field['unique'] + .$extra_clause; + } - $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) + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + switch (strtoupper($attributes['TYPE'])) { - 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) . ")"; - } + case 'TINYINT': + $attributes['TYPE'] = 'SMALLINT'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + default: return; } - - $sql .= "\n);"; - - return $sql; } // -------------------------------------------------------------------- /** - * Alter table query + * Process indexes * - * Generates a platform-specific query so that a table can be altered - * Called by add_column(), drop_column(), and column_alter(), - * - * @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 + * @param string $table (ignored) * @return string */ - protected function _alter_table($alter_type, $table, $fields, $after_field = '') + protected function _process_indexes($table = NULL) { - $sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '; + $sql = ''; - // DROP has everything it needs now. - if ($alter_type == 'DROP') + for ($i = 0, $c = count($this->keys); $i < $c; $i++) { - return $sql.$this->db->protect_identifiers($fields); - } + if ( ! isset($this->fields[$this->keys[$i]])) + { + unset($this->keys[$i]); + continue; + } - $sql .= $this->_process_fields($fields); + is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]); - if ($after_field != '') - { - return $sql.' AFTER '.$this->db->protect_identifiers($after_field); + $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i])) + .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')'; } + $this->keys = array(); + return $sql; } diff --git a/system/database/drivers/cubrid/cubrid_result.php b/system/database/drivers/cubrid/cubrid_result.php index 58dcff29a..30aed38d9 100644 --- a/system/database/drivers/cubrid/cubrid_result.php +++ b/system/database/drivers/cubrid/cubrid_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -21,9 +21,10 @@ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com - * @since Version 2.0.2 + * @since Version 2.1 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CUBRID Result Class @@ -33,6 +34,7 @@ * @category Database * @author Esen Sagynov * @link http://codeigniter.com/user_guide/database/ + * @since 2.1 */ class CI_DB_cubrid_result extends CI_DB_result { @@ -43,7 +45,9 @@ class CI_DB_cubrid_result extends CI_DB_result { */ public function num_rows() { - return @cubrid_num_rows($this->result_id); + return is_int($this->num_rows) + ? $this->num_rows + : $this->num_rows = @cubrid_num_rows($this->result_id); } // -------------------------------------------------------------------- @@ -84,53 +88,20 @@ class CI_DB_cubrid_result extends CI_DB_result { public function field_data() { $retval = array(); - - $tablePrimaryKeys = array(); + $i = 0; 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; + $retval[$i] = new stdClass(); + $retval[$i]->name = $field->name; + // CUBRID returns type as e.g. varchar(100), + // so we need to remove all digits and brackets. + $retval[$i]->type = preg_replace('/[\d()]/', '', $field->type); + $retval[$i]->default = $field->def; + // Use CUBRID's native API to obtain column's max_length, + // otherwise $field->max_length has incorrect info + $retval[$i]->max_length = cubrid_field_len($this->result_id, $i); + $retval[$i++]->primary_key = $field->primary_key; } return $retval; @@ -145,9 +116,8 @@ class CI_DB_cubrid_result extends CI_DB_result { */ public function free_result() { - if(is_resource($this->result_id) || - get_resource_type($this->result_id) == "Unknown" && - preg_match('/Resource id #/', strval($this->result_id))) + if (is_resource($this->result_id) OR + (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; @@ -161,8 +131,9 @@ class CI_DB_cubrid_result extends CI_DB_result { * * Moves the internal pointer to the desired offset. We call * this internally before fetching results to make sure the - * result set starts at zero + * result set starts at zero. * + * @param int $n * @return bool */ protected function _data_seek($n = 0) @@ -191,11 +162,12 @@ class CI_DB_cubrid_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @return object */ - protected function _fetch_object() + protected function _fetch_object($class_name = 'stdClass') { - return cubrid_fetch_object($this->result_id); + return cubrid_fetch_object($this->result_id, $class_name); } } diff --git a/system/database/drivers/cubrid/cubrid_utility.php b/system/database/drivers/cubrid/cubrid_utility.php index 274ff6a48..d76eca432 100644 --- a/system/database/drivers/cubrid/cubrid_utility.php +++ b/system/database/drivers/cubrid/cubrid_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -21,9 +21,10 @@ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com - * @since Version 1.0 + * @since Version 2.1 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CUBRID Utility Class @@ -41,12 +42,12 @@ class CI_DB_cubrid_utility extends CI_DB_utility { */ public function list_databases() { - if (isset($this->data_cache['db_names'])) + if (isset($this->db->data_cache['db_names'])) { - return $this->data_cache['db_names']; + return $this->db->data_cache['db_names']; } - return $this->data_cache['db_names'] = cubrid_list_dbs($this->db->conn_id); + return $this->db->data_cache['db_names'] = cubrid_list_dbs($this->db->conn_id); } // -------------------------------------------------------------------- @@ -62,7 +63,7 @@ class CI_DB_cubrid_utility extends CI_DB_utility { // 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'); + return $this->db->display_error('db_unsupported_feature'); } } diff --git a/system/database/drivers/interbase/interbase_driver.php b/system/database/drivers/ibase/ibase_driver.php index 6587d72ff..02ec354e3 100644 --- a/system/database/drivers/interbase/interbase_driver.php +++ b/system/database/drivers/ibase/ibase_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,12 +24,13 @@ * @since Version 3.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Firebird/Interbase Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -38,27 +39,32 @@ * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ */ -class CI_DB_interbase_driver extends CI_DB { +class CI_DB_ibase_driver extends CI_DB { - public $dbdriver = 'interbase'; + /** + * Database driver + * + * @var string + */ + public $dbdriver = 'ibase'; - // The character used to escape with - protected $_escape_char = '"'; + // -------------------------------------------------------------------- - // clause and character used for LIKE escape sequences - protected $_like_escape_str = " ESCAPE '%s' "; - protected $_like_escape_chr = '!'; + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('RAND()', 'RAND()'); /** - * 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. + * IBase Transaction status flag + * + * @var resource */ - protected $_count_string = 'SELECT COUNT(*) AS '; - protected $_random_keyword = ' Random()'; // database specific random keyword + protected $_ibase_trans; - // Keeps track of the resource for the current transaction - protected $trans; + // -------------------------------------------------------------------- /** * Non-persistent database connection @@ -113,7 +119,7 @@ class CI_DB_interbase_driver extends CI_DB { /** * Execute the query * - * @param string an SQL query + * @param string $sql an SQL query * @return resource */ protected function _execute($sql) @@ -126,6 +132,7 @@ class CI_DB_interbase_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @return bool */ public function trans_begin($test_mode = FALSE) @@ -141,7 +148,7 @@ class CI_DB_interbase_driver extends CI_DB { // even if the queries produce a successful result. $this->_trans_failure = ($test_mode === TRUE); - $this->trans = @ibase_trans($this->conn_id); + $this->_ibase_trans = @ibase_trans($this->conn_id); return TRUE; } @@ -161,7 +168,7 @@ class CI_DB_interbase_driver extends CI_DB { return TRUE; } - return @ibase_commit($this->trans); + return @ibase_commit($this->_ibase_trans); } // -------------------------------------------------------------------- @@ -179,7 +186,7 @@ class CI_DB_interbase_driver extends CI_DB { return TRUE; } - return @ibase_rollback($this->trans); + return @ibase_rollback($this->_ibase_trans); } // -------------------------------------------------------------------- @@ -187,8 +194,8 @@ class CI_DB_interbase_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -235,7 +242,7 @@ class CI_DB_interbase_driver extends CI_DB { * @param int $inc_by * @return int */ - public function insert_id($generator_name, $inc_by=0) + public function insert_id($generator_name, $inc_by = 0) { //If a generator hasn't been used before it will return 0 return ibase_gen_id('"'.$generator_name.'"', $inc_by); @@ -244,49 +251,21 @@ class CI_DB_interbase_driver extends CI_DB { // -------------------------------------------------------------------- /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @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->num_rows() == 0) - { - return 0; - } - - $query = $query->row(); - $this->_reset_select(); - return (int) $query->numrows; - } - - // -------------------------------------------------------------------- - - /** * List table query * * Generates a platform-specific query string so that the table names can be fetched * - * @param bool + * @param bool $prefix_limit * @return string */ protected function _list_tables($prefix_limit = FALSE) { $sql = 'SELECT "RDB$RELATION_NAME" FROM "RDB$RELATIONS" WHERE "RDB$RELATION_NAME" NOT LIKE \'RDB$%\' AND "RDB$RELATION_NAME" NOT LIKE \'MON$%\''; - if ($prefix_limit !== FALSE && $this->dbprefix != '') + if ($prefix_limit !== FALSE && $this->dbprefix !== '') { - return $sql.' AND "RDB$RELATION_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); + return $sql.' AND "RDB$RELATION_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' " + .sprintf($this->_like_escape_str, $this->_like_escape_chr); } return $sql; @@ -299,12 +278,12 @@ class CI_DB_interbase_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @param string the table name + * @param string $table * @return string */ protected function _list_columns($table = '') { - return 'SELECT "RDB$FIELD_NAME" FROM "RDB$RELATION_FIELDS" WHERE "RDB$RELATION_NAME" = \''.$this->escape_str($table)."'"; + return 'SELECT "RDB$FIELD_NAME" FROM "RDB$RELATION_FIELDS" WHERE "RDB$RELATION_NAME" = '.$this->escape($table); } // -------------------------------------------------------------------- @@ -314,15 +293,15 @@ class CI_DB_interbase_driver extends CI_DB { * * Generates a platform-specific query so that the column data can be retrieved * - * @param string the table name + * @param string $table * @return string */ protected function _field_data($table) { - // Need to find a more efficient way to do this - // but Interbase/Firebird seems to lack the - // limit clause - return 'SELECT * FROM '.$table; + $this->qb_limit = 1; + $sql = $this->_limit('SELECT * FROM '.$this->protect_identifiers($table)); + $this->qb_limit = 0; + return $sql; } // -------------------------------------------------------------------- @@ -343,60 +322,20 @@ class CI_DB_interbase_driver extends CI_DB { // -------------------------------------------------------------------- /** - * From Tables - * - * This public function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards - * - * @param array - * @return string - */ - protected function _from_tables($tables) - { - if ( ! is_array($tables)) - { - $tables = array($tables); - } - - //Interbase/Firebird doesn't like grouped tables - return implode(', ', $tables); - } - - // -------------------------------------------------------------------- - - /** * Update statement * * Generates a platform-specific update string from the supplied data * - * @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 (ignored) - * @param array the like clause + * @param string $table + * @param array $values * @return string */ - protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array()) + protected function _update($table, $values) { - foreach ($values as $key => $val) - { - $valstr[] = $key.' = '.$val; - } - - $where = empty($where) ? '' : ' WHERE '.implode(' ', $where); - - if ( ! empty($like)) - { - $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like); - } - - return 'UPDATE '.$table.' SET '.implode(', ', $valstr) - .$where - .(count($orderby) > 0 ? ' ORDER BY '.implode(', ', $orderby) : ''); + $this->qb_limit = FALSE; + return parent::_update($table, $values); } - // -------------------------------------------------------------------- /** @@ -404,10 +343,10 @@ class CI_DB_interbase_driver extends CI_DB { * * Generates a platform-specific truncate string from the supplied data * - * If the database does not support the truncate() command, + * If the database does not support the TRUNCATE statement, * then this method maps to 'DELETE FROM table' * - * @param string the table name + * @param string $table * @return string */ protected function _truncate($table) @@ -422,46 +361,37 @@ class CI_DB_interbase_driver extends CI_DB { * * Generates a platform-specific delete string from the supplied data * - * @param string the table name - * @param array the where clause - * @param array the like clause - * @param string the limit clause (ignored) + * @param string $table * @return string */ - protected function _delete($table, $where = array(), $like = array(), $limit = FALSE) + protected function _delete($table) { - $conditions = array(); - - empty($where) OR $conditions[] = implode(' ', $where); - empty($like) OR $conditions[] = implode(' ', $like); - - return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : ''); + $this->qb_limit = FALSE; + return parent::_delete($table); } // -------------------------------------------------------------------- /** - * Limit string + * LIMIT * * Generates a platform-specific LIMIT clause * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value + * @param string $sql SQL Query * @return string */ - protected function _limit($sql, $limit, $offset) + protected function _limit($sql) { // Limit clause depends on if Interbase or Firebird if (stripos($this->version(), 'firebird') !== FALSE) { - $select = 'FIRST '. (int) $limit - .($offset > 0 ? ' SKIP '. (int) $offset : ''); + $select = 'FIRST '.$this->qb_limit + .($this->qb_offset ? ' SKIP '.$this->qb_offset : ''); } else { $select = 'ROWS ' - .($offset > 0 ? (int) $offset.' TO '.($limit + $offset) : (int) $limit); + .($this->qb_offset ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit); } return preg_replace('`SELECT`i', 'SELECT '.$select, $sql); @@ -472,15 +402,14 @@ class CI_DB_interbase_driver extends CI_DB { /** * Close DB Connection * - * @param resource * @return void */ - protected function _close($conn_id) + protected function _close() { - @ibase_close($conn_id); + @ibase_close($this->conn_id); } } -/* End of file interbase_driver.php */ -/* Location: ./system/database/drivers/interbase/interbase_driver.php */
\ No newline at end of file +/* End of file ibase_driver.php */ +/* Location: ./system/database/drivers/ibase/ibase_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/ibase/ibase_forge.php b/system/database/drivers/ibase/ibase_forge.php new file mode 100644 index 000000000..a0c4e6563 --- /dev/null +++ b/system/database/drivers/ibase/ibase_forge.php @@ -0,0 +1,242 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * Interbase/Firebird Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_ibase_forge extends CI_DB_forge { + + /** + * CREATE TABLE IF statement + * + * @var string + */ + protected $_create_table_if = FALSE; + + /** + * RENAME TABLE statement + * + * @var string + */ + protected $_rename_table = FALSE; + + /** + * DROP TABLE IF statement + * + * @var string + */ + protected $_drop_table_if = FALSE; + + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'SMALLINT' => 'INTEGER', + 'INTEGER' => 'INT64', + 'FLOAT' => 'DOUBLE PRECISION' + ); + + /** + * NULL value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_null = 'NULL'; + + // -------------------------------------------------------------------- + + /** + * Create database + * + * @param string $db_name + * @return string + */ + public function create_database($db_name) + { + // Firebird databases are flat files, so a path is required + + // Hostname is needed for remote access + empty($this->db->hostname) OR $db_name = $this->hostname.':'.$db_name; + + return parent::create_database('"'.$db_name.'"'); + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @param string $db_name (ignored) + * @return bool + */ + public function drop_database($db_name = '') + { + if ( ! ibase_drop_db($this->conn_id)) + { + return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE; + } + elseif ( ! empty($this->db->data_cache['db_names'])) + { + $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); + if ($key !== FALSE) + { + unset($this->db->data_cache['db_names'][$key]); + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) + { + return parent::_alter_table($alter_type, $table, $field); + } + + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); + $sqls = array(); + for ($i = 0, $c = count($field), $sql .= $alter_type.' '; $i < $c; $i++) + { + if ($field[$i]['_literal'] !== FALSE) + { + return FALSE; + } + + if (isset($field[$i]['type'])) + { + $sqls[] = $sql.' TYPE '.$field[$i]['type'].$field[$i]['length']; + } + + if ( ! empty($field[$i]['default'])) + { + $sqls[] = $sql.' ALTER '.$this->db->escape_identifiers($field[$i]['name']) + .' SET '.$field[$i]['default']; + } + + if (isset($field[$i]['null'])) + { + $sqls[] = 'UPDATE "RDB$RELATION_FIELDS" SET "RDB$NULL_FLAG" = ' + .($field[$i]['null'] === TRUE ? 'NULL' : '1') + .' WHERE "RDB$FIELD_NAME" = '.$this->db->escape($field[$i]['name']) + .' AND "RDB$RELATION_NAME" = '.$this->db->escape($table); + } + + if ( ! empty($field[$i]['new_name'])) + { + $sqls[] = $sql.' ALTER '.$this->db->escape_identifiers($field[$i]['name']) + .' TO '.$this->db->escape_identifiers($field[$i]['new_name']); + } + } + + return $sqls; + } + + // -------------------------------------------------------------------- + + /** + * Process column + * + * @param array $field + * @return string + */ + protected function _process_column($field) + { + return $this->db->escape_identifiers($field['name']) + .' '.$field['type'].$field['length'] + .$field['null'] + .$field['unique'] + .$field['default']; + } + + // -------------------------------------------------------------------- + + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + switch (strtoupper($attributes['TYPE'])) + { + case 'TINYINT': + $attributes['TYPE'] = 'SMALLINT'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'INT': + $attributes['TYPE'] = 'INTEGER'; + return; + case 'BIGINT': + $attributes['TYPE'] = 'INT64'; + return; + default: return; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + // Not supported + } + +} + +/* End of file ibase_forge.php */ +/* Location: ./system/database/drivers/ibase/ibase_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/interbase/interbase_result.php b/system/database/drivers/ibase/ibase_result.php index 5ddb6fa47..bbad9d895 100644 --- a/system/database/drivers/interbase/interbase_result.php +++ b/system/database/drivers/ibase/ibase_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -21,9 +21,10 @@ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com - * @since Version 3.0 + * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Interbase/Firebird Result Class @@ -33,30 +34,9 @@ * @category Database * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ + * @since 3.0 */ -class CI_DB_interbase_result extends CI_DB_result { - - public $num_rows; - - /** - * Number of rows in the result set - * - * @return int - */ - public function num_rows() - { - if (is_int($this->num_rows)) - { - return $this->num_rows; - } - - // Get the results so that you can get an accurate rowcount - $this->result(); - - return $this->num_rows; - } - - // -------------------------------------------------------------------- +class CI_DB_ibase_result extends CI_DB_result { /** * Number of fields in the result set @@ -139,13 +119,7 @@ class CI_DB_interbase_result extends CI_DB_result { */ protected function _fetch_assoc() { - if (($row = @ibase_fetch_assoc($this->result_id, IBASE_FETCH_BLOBS)) !== FALSE) - { - //Increment row count - $this->num_rows++; - } - - return $row; + return @ibase_fetch_assoc($this->result_id, IBASE_FETCH_BLOBS); } // -------------------------------------------------------------------- @@ -155,106 +129,28 @@ class CI_DB_interbase_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @return object */ - protected function _fetch_object() - { - if (($row = @ibase_fetch_object($this->result_id, IBASE_FETCH_BLOBS)) !== FALSE) - { - //Increment row count - $this->num_rows++; - } - - return $row; - } - - // -------------------------------------------------------------------- - - /** - * Query result. "object" version. - * - * @return object - */ - public function result_object() + protected function _fetch_object($class_name = 'stdClass') { - if (count($this->result_object) === $this->num_rows) - { - return $this->result_object; - } - - // Convert result array to object so that - // We don't have to get the result again - if (($c = count($this->result_array)) > 0) - { - for ($i = 0; $i < $c; $i++) - { - $this->result_object[$i] = (object) $this->result_array[$i]; - } - - 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) - { - return array(); - } - - $this->num_rows = 0; - while ($row = $this->_fetch_object()) - { - $this->result_object[] = $row; - } - - return $this->result_object; - } - - // -------------------------------------------------------------------- - - /** - * Query result. "array" version. - * - * @return array - */ - public function result_array() - { - if (count($this->result_array) === $this->num_rows) - { - return $this->result_array; - } - - // Since the object and array are really similar, just case - // the result object to an array if need be - if (($c = count($this->result_object)) > 0) - { - for ($i = 0; $i < $c; $i++) - { - $this->result_array[$i] = (array) $this->result_object[$i]; - } - - return $this->result_array; - } + $row = @ibase_fetch_object($this->result_id, IBASE_FETCH_BLOBS); - // 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) + if ($class_name === 'stdClass' OR ! $row) { - return array(); + return $row; } - $this->num_rows = 0; - while ($row = $this->_fetch_assoc()) + $class_name = new $class_name(); + foreach ($row as $key => $value) { - $this->result_array[] = $row; + $class_name->$key = $value; } - return $this->result_array; + return $class_name; } } -/* End of file interbase_result.php */ -/* Location: ./system/database/drivers/interbase/interbase_result.php */
\ No newline at end of file +/* End of file ibase_result.php */ +/* Location: ./system/database/drivers/ibase/ibase_result.php */
\ No newline at end of file diff --git a/system/database/drivers/interbase/interbase_utility.php b/system/database/drivers/ibase/ibase_utility.php index 1b92af9b6..5eb209ae1 100644 --- a/system/database/drivers/interbase/interbase_utility.php +++ b/system/database/drivers/ibase/ibase_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 3.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Interbase/Firebird Utility Class @@ -32,17 +33,15 @@ * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ */ -class CI_DB_interbase_utility extends CI_DB_utility { - - protected $_list_databases = FALSE; +class CI_DB_ibase_utility extends CI_DB_utility { /** - * Interbase/Firebird Export + * Export * * @param string $filename * @return mixed */ - protected function backup($filename) + protected function _backup($filename) { if ($service = ibase_service_attach($this->db->hostname, $this->db->username, $this->db->password)) { @@ -58,5 +57,5 @@ class CI_DB_interbase_utility extends CI_DB_utility { } -/* End of file interbase_utility.php */ -/* Location: ./system/database/drivers/interbase/interbase_utility.php */
\ No newline at end of file +/* End of file ibase_utility.php */ +/* Location: ./system/database/drivers/ibase/ibase_utility.php */
\ No newline at end of file diff --git a/system/database/drivers/interbase/index.html b/system/database/drivers/ibase/index.html index c942a79ce..c942a79ce 100644 --- a/system/database/drivers/interbase/index.html +++ b/system/database/drivers/ibase/index.html diff --git a/system/database/drivers/interbase/interbase_forge.php b/system/database/drivers/interbase/interbase_forge.php deleted file mode 100644 index c850656a8..000000000 --- a/system/database/drivers/interbase/interbase_forge.php +++ /dev/null @@ -1,224 +0,0 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); -/** - * CodeIgniter - * - * An open source application development framework for PHP 5.2.4 or newer - * - * NOTICE OF LICENSE - * - * Licensed under the Open Software License version 3.0 - * - * This source file is subject to the Open Software License (OSL 3.0) that is - * bundled with this package in the files license.txt / license.rst. It is - * also available through the world wide web at this URL: - * http://opensource.org/licenses/OSL-3.0 - * If you did not receive a copy of the license and are unable to obtain it - * through the world wide web, please send an email to - * licensing@ellislab.com so we can send you a copy immediately. - * - * @package CodeIgniter - * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) - * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) - * @link http://codeigniter.com - * @since Version 3.0 - * @filesource - */ - -/** - * Interbase/Firebird Forge Class - * - * @category Database - * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/database/ - */ -class CI_DB_interbase_forge extends CI_DB_forge { - - protected $_drop_table = 'DROP TABLE %s'; - - /** - * Create database - * - * @param string the database name - * @return string - */ - public function create_database($db_name) - { - // Firebird databases are flat files, so a path is required - - // Hostname is needed for remote access - empty($this->db->hostname) OR $db_name = $this->hostname.':'.$db_name; - - return parent::create_database('"'.$db_name.'"'); - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @param string the database name - * - not used in this driver, the current db is dropped - * @return bool - */ - public function drop_database($db_name = '') - { - if ( ! ibase_drop_db($this->conn_id)) - { - return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Create Table - * - * @param string the table name - * @param array the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return string - */ - protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) - { - $sql = 'CREATE TABLE '; - - $sql .= $this->db->protect_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 (" . 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(), - * - * @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 bool should 'NOT NULL' be added - * @param string the field after which we should add the new field - * @return string - */ - protected 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); - - $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; - - } - -} - -/* End of file interbase_forge.php */ -/* Location: ./system/database/drivers/interbase/interbase_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/mssql/mssql_driver.php b/system/database/drivers/mssql/mssql_driver.php index 90609a84d..53f2e55ea 100644 --- a/system/database/drivers/mssql/mssql_driver.php +++ b/system/database/drivers/mssql/mssql_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,12 +24,13 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * MS SQL Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -40,36 +41,78 @@ */ class CI_DB_mssql_driver extends CI_DB { + /** + * Database driver + * + * @var string + */ public $dbdriver = 'mssql'; - // The character used for escaping - protected $_escape_char = ''; + // -------------------------------------------------------------------- - // clause and character used for LIKE escape sequences - protected $_like_escape_str = " ESCAPE '%s' "; - protected $_like_escape_chr = '!'; + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('NEWID()', 'RAND(%d)'); /** - * 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() methods. + * Quoted identifier flag + * + * Whether to use SQL-92 standard quoted identifier + * (double quotes) or brackets for identifier escaping. + * + * @var bool */ - protected $_count_string = 'SELECT COUNT(*) AS '; - protected $_random_keyword = ' NEWID()'; + protected $_quoted_identifier = TRUE; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Appends the port number to the hostname, if needed. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if ( ! empty($this->port)) + { + $this->hostname .= (DIRECTORY_SEPARATOR === '\\' ? ',' : ':').$this->port; + } + } + + // -------------------------------------------------------------------- /** * Non-persistent database connection * + * @param bool $persistent * @return resource */ - public function db_connect() + public function db_connect($persistent = FALSE) { - if ($this->port != '') + $this->conn_id = ($persistent) + ? @mssql_pconnect($this->hostname, $this->username, $this->password) + : @mssql_connect($this->hostname, $this->username, $this->password); + + if ( ! $this->conn_id) { - $this->hostname .= ','.$this->port; + return FALSE; } - return @mssql_connect($this->hostname, $this->username, $this->password); + // Determine how identifiers are escaped + $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi'); + $query = $query->row_array(); + $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi']; + $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']'); + + return $this->conn_id; } // -------------------------------------------------------------------- @@ -81,12 +124,7 @@ class CI_DB_mssql_driver extends CI_DB { */ public function db_pconnect() { - if ($this->port != '') - { - $this->hostname .= ','.$this->port; - } - - return @mssql_pconnect($this->hostname, $this->username, $this->password); + return $this->db_connect(TRUE); } // -------------------------------------------------------------------- @@ -94,7 +132,7 @@ class CI_DB_mssql_driver extends CI_DB { /** * Select the database * - * @param string database name + * @param string $database * @return bool */ public function db_select($database = '') @@ -106,7 +144,7 @@ class CI_DB_mssql_driver extends CI_DB { // Note: The brackets are required in the event that the DB name // contains reserved characters - if (@mssql_select_db('['.$database.']', $this->conn_id)) + if (@mssql_select_db($this->escape_identifiers($database), $this->conn_id)) { $this->database = $database; return TRUE; @@ -120,8 +158,8 @@ class CI_DB_mssql_driver extends CI_DB { /** * Execute the query * - * @param string an SQL query - * @return resource + * @param string $sql an SQL query + * @return mixed resource if rows are returned, bool otherwise */ protected function _execute($sql) { @@ -133,17 +171,13 @@ class CI_DB_mssql_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -151,10 +185,9 @@ class CI_DB_mssql_driver extends CI_DB { // 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->_trans_failure = ($test_mode === TRUE); - $this->simple_query('BEGIN TRAN'); - return TRUE; + return $this->simple_query('BEGIN TRAN'); } // -------------------------------------------------------------------- @@ -166,19 +199,13 @@ class CI_DB_mssql_driver extends CI_DB { */ 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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } - $this->simple_query('COMMIT TRAN'); - return TRUE; + return $this->simple_query('COMMIT TRAN'); } // -------------------------------------------------------------------- @@ -190,19 +217,13 @@ class CI_DB_mssql_driver extends CI_DB { */ 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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } - $this->simple_query('ROLLBACK TRAN'); - return TRUE; + return $this->simple_query('ROLLBACK TRAN'); } // -------------------------------------------------------------------- @@ -210,8 +231,8 @@ class CI_DB_mssql_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -232,7 +253,7 @@ class CI_DB_mssql_driver extends CI_DB { // escape LIKE condition wildcards if ($like === TRUE) { - $str = str_replace( + return 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 @@ -265,28 +286,13 @@ class CI_DB_mssql_driver extends CI_DB { */ public 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; - } + $query = version_compare($this->version(), '8', '>=') + ? 'SELECT SCOPE_IDENTITY() AS last_id' + : 'SELECT @@IDENTITY AS last_id'; - // -------------------------------------------------------------------- - - /** - * Parse major version - * - * Grabs the major version number from the - * database server version string passed in. - * - * @param string $version - * @return int major version number - */ - protected 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. + $query = $this->query($query); + $query = $query->row(); + return $query->last_id; } // -------------------------------------------------------------------- @@ -304,54 +310,26 @@ class CI_DB_mssql_driver extends CI_DB { // -------------------------------------------------------------------- /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @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->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 * - * @param bool + * @param bool $prefix_limit * @return string */ protected function _list_tables($prefix_limit = FALSE) { - $sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name"; + $sql = 'SELECT '.$this->escape_identifiers('name') + .' FROM '.$this->escape_identifiers('sysobjects') + .' WHERE '.$this->escape_identifiers('type')." = 'U'"; - // for future compatibility - if ($prefix_limit !== FALSE AND $this->dbprefix != '') + 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 + $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' " + .sprintf($this->_like_escape_str, $this->_like_escape_chr); } - return $sql; + return $sql.' ORDER BY '.$this->escape_identifiers('name'); } // -------------------------------------------------------------------- @@ -361,7 +339,7 @@ class CI_DB_mssql_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @param string the table name + * @param string $table * @return string */ protected function _list_columns($table = '') @@ -376,12 +354,12 @@ class CI_DB_mssql_driver extends CI_DB { * * Generates a platform-specific query so that the column data can be retrieved * - * @param string the table name + * @param string $table * @return string */ protected function _field_data($table) { - return "SELECT TOP 1 * FROM ".$table; + return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table); } // -------------------------------------------------------------------- @@ -404,54 +382,19 @@ class CI_DB_mssql_driver extends CI_DB { // -------------------------------------------------------------------- /** - * From Tables - * - * This function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards - * - * @param array - * @return string - */ - protected function _from_tables($tables) - { - if ( ! is_array($tables)) - { - $tables = array($tables); - } - - return implode(', ', $tables); - } - - // -------------------------------------------------------------------- - - /** * Update statement * * Generates a platform-specific update string from the supplied data * - * @param string the table name - * @param array the update data - * @param array the where clause - * @param array the orderby clause (ignored) - * @param array the limit clause (ignored) - * @param array the like clause + * @param string $table + * @param array $values * @return string */ - protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array()) + protected function _update($table, $values) { - foreach($values as $key => $val) - { - $valstr[] = $key.' = '.$val; - } - - $where = empty($where) ? '' : ' WHERE '.implode(' ', $where); - - if ( ! empty($like)) - { - $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like); - } - - return 'UPDATE '.$table.' SET '.implode(', ', $valstr).' WHERE '.$where; + $this->qb_limit = FALSE; + $this->qb_orderby = array(); + return parent::_update($table, $values); } // -------------------------------------------------------------------- @@ -461,10 +404,10 @@ class CI_DB_mssql_driver extends CI_DB { * * Generates a platform-specific truncate string from the supplied data * - * If the database does not support the truncate() command, + * If the database does not support the TRUNCATE statement, * then this method maps to 'DELETE FROM table' * - * @param string the table name + * @param string $table * @return string */ protected function _truncate($table) @@ -479,43 +422,91 @@ class CI_DB_mssql_driver extends CI_DB { * * Generates a platform-specific delete string from the supplied data * - * @param string the table name - * @param array the where clause - * @param array the like clause - * @param string the limit clause + * @param string $table * @return string */ - protected function _delete($table, $where = array(), $like = array(), $limit = FALSE) + protected function _delete($table) { - $conditions = array(); - - empty($where) OR $conditions[] = implode(' ', $where); - empty($like) OR $conditions[] = implode(' ', $like); - - $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : ''; + if ($this->qb_limit) + { + return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete'; + } - return ($limit) - ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete' - : 'DELETE FROM '.$table.$conditions; + return parent::_delete($table); } // -------------------------------------------------------------------- /** - * Limit string + * LIMIT * * Generates a platform-specific LIMIT clause * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value + * @param string $sql SQL Query * @return string */ - protected function _limit($sql, $limit, $offset) + protected function _limit($sql) + { + $limit = $this->qb_offset + $this->qb_limit; + + // As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported, + // however an ORDER BY clause is required for it to work + if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby)) + { + $orderby = $this->_compile_order_by(); + + // We have to strip the ORDER BY clause + $sql = trim(substr($sql, 0, strrpos($sql, $orderby))); + + // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results + if (count($this->qb_select) === 0) + { + $select = '*'; // Inevitable + } + else + { + // Use only field names and their aliases, everything else is out of our scope. + $select = array(); + $field_regexp = ($this->_quoted_identifier) + ? '("[^\"]+")' : '(\[[^\]]+\])'; + for ($i = 0, $c = count($this->qb_select); $i < $c; $i++) + { + $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m) + ? $m[1] : $this->qb_select[$i]; + } + $select = implode(', ', $select); + } + + return 'SELECT '.$select." FROM (\n\n" + .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql) + ."\n\n) ".$this->escape_identifiers('CI_subquery') + ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit; + } + + return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql); + } + + // -------------------------------------------------------------------- + + /** + * Insert batch statement + * + * Generates a platform-specific insert string from the supplied data. + * + * @param string $table Table name + * @param array $keys INSERT keys + * @param array $values INSERT values + * @return string|bool + */ + protected function _insert_batch($table, $keys, $values) { - $i = $limit + $offset; + // Multiple-value inserts are only supported as of SQL Server 2008 + if (version_compare($this->version(), '10', '>=')) + { + return parent::_insert_batch($table, $keys, $values); + } - return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$i.' ', $sql); + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; } // -------------------------------------------------------------------- @@ -523,12 +514,11 @@ class CI_DB_mssql_driver extends CI_DB { /** * Close DB Connection * - * @param resource * @return void */ - protected function _close($conn_id) + protected function _close() { - @mssql_close($conn_id); + @mssql_close($this->conn_id); } } diff --git a/system/database/drivers/mssql/mssql_forge.php b/system/database/drivers/mssql/mssql_forge.php index 8f8e7c5b9..5eebedbf7 100644 --- a/system/database/drivers/mssql/mssql_forge.php +++ b/system/database/drivers/mssql/mssql_forge.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * MS SQL Forge Class @@ -34,162 +35,99 @@ */ class CI_DB_mssql_forge extends CI_DB_forge { - protected $_drop_table = 'DROP TABLE %s'; - /** - * Create Table + * CREATE TABLE IF statement * - * @param string the table name - * @param array the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return string + * @var string */ - protected 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'].')'; - } + protected $_create_table_if = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nCREATE TABLE"; - 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'; - } + /** + * DROP TABLE IF statement + * + * @var string + */ + protected $_drop_table_if = "IF EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nDROP TABLE"; - if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) - { - $sql .= ' AUTO_INCREMENT'; - } - } + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'TINYINT' => 'SMALLINT', + 'SMALLINT' => 'INT', + 'INT' => 'BIGINT', + 'REAL' => 'FLOAT' + ); - // don't add a comma on the end of the last field - if (++$current_field_count < count($fields)) - { - $sql .= ','; - } - } + // -------------------------------------------------------------------- - if (count($primary_keys) > 0) + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if (in_array($alter_type, array('ADD', 'DROP'), TRUE)) { - $primary_keys = $this->db->protect_identifiers($primary_keys); - $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + return parent::_alter_table($alter_type, $table, $field); } - if (is_array($keys) && count($keys) > 0) + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN '; + $sqls = array(); + for ($i = 0, $c = count($field); $i < $c; $i++) { - 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) . ")"; - } + $sqls[] = $sql.$this->_process_column($field[$i]); } - $sql .= "\n)"; - - return $sql; + return $sqls; } // -------------------------------------------------------------------- /** - * Alter table query + * Field attribute TYPE * - * Generates a platform-specific query so that a table can be altered - * Called by add_column(), drop_column(), and column_alter(), + * Performs a data type mapping between different databases. * - * @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 bool should 'NOT NULL' be added - * @param string the field after which we should add the new field - * @return string + * @param array &$attributes + * @return void */ - protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + protected function _attr_type(&$attributes) { - $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') + switch (strtoupper($attributes['TYPE'])) { - return $sql; - } - - $sql .= " $column_definition"; - - if ($default_value != '') - { - $sql .= " DEFAULT \"$default_value\""; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'INTEGER': + $attributes['TYPE'] = 'INT'; + return; + default: return; } + } - if ($null === NULL) - { - $sql .= ' NULL'; - } - else - { - $sql .= ' NOT NULL'; - } + // -------------------------------------------------------------------- - if ($after_field != '') + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) { - return $sql.' AFTER '.$this->db->protect_identifiers($after_field); + $field['auto_increment'] = ' IDENTITY(1,1)'; } - - return $sql; - } } diff --git a/system/database/drivers/mssql/mssql_result.php b/system/database/drivers/mssql/mssql_result.php index 4cc87f4cf..c74c70abf 100644 --- a/system/database/drivers/mssql/mssql_result.php +++ b/system/database/drivers/mssql/mssql_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,15 +24,17 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** - * MS SQL Result Class + * MSSQL Result Class * * This class extends the parent result class: CI_DB_result * * @category Database * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ + * @since 1.3 */ class CI_DB_mssql_result extends CI_DB_result { @@ -43,7 +45,9 @@ class CI_DB_mssql_result extends CI_DB_result { */ public function num_rows() { - return @mssql_num_rows($this->result_id); + return is_int($this->num_rows) + ? $this->num_rows + : $this->num_rows = @mssql_num_rows($this->result_id); } // -------------------------------------------------------------------- @@ -92,12 +96,12 @@ class CI_DB_mssql_result extends CI_DB_result { $retval = array(); while ($field = mssql_fetch_field($this->result_id)) { - $F = new stdClass(); - $F->name = $field->name; - $F->type = $field->type; + $F = new stdClass(); + $F->name = $field->name; + $F->type = $field->type; $F->max_length = $field->max_length; $F->primary_key = 0; - $F->default = ''; + $F->default = ''; $retval[] = $F; } @@ -128,8 +132,9 @@ class CI_DB_mssql_result extends CI_DB_result { * * Moves the internal pointer to the desired offset. We call * this internally before fetching results to make sure the - * result set starts at zero + * result set starts at zero. * + * @param int $n * @return bool */ protected function _data_seek($n = 0) @@ -158,11 +163,25 @@ class CI_DB_mssql_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @return object */ - protected function _fetch_object() + protected function _fetch_object($class_name = 'stdClass') { - return mssql_fetch_object($this->result_id); + $row = @mssql_fetch_object($this->result_id); + + if ($class_name === 'stdClass' OR ! $row) + { + return $row; + } + + $class_name = new $class_name(); + foreach ($row as $key => $value) + { + $class_name->$key = $value; + } + + return $class_name; } } diff --git a/system/database/drivers/mssql/mssql_utility.php b/system/database/drivers/mssql/mssql_utility.php index 6d47618ce..76c7cb9c2 100644 --- a/system/database/drivers/mssql/mssql_utility.php +++ b/system/database/drivers/mssql/mssql_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * MS SQL Utility Class @@ -34,19 +35,30 @@ */ class CI_DB_mssql_utility extends CI_DB_utility { + /** + * List databases statement + * + * @var string + */ protected $_list_databases = 'EXEC sp_helpdb'; // Can also be: EXEC sp_databases + + /** + * OPTIMIZE TABLE statement + * + * @var string + */ protected $_optimize_table = 'ALTER INDEX all ON %s REORGANIZE'; /** - * MSSQL Export + * Export * - * @param array Preferences - * @return mixed + * @param array $params Preferences + * @return bool */ protected function _backup($params = array()) { // Currently unsupported - return $this->db->display_error('db_unsuported_feature'); + return $this->db->display_error('db_unsupported_feature'); } } diff --git a/system/database/drivers/mysql/mysql_driver.php b/system/database/drivers/mysql/mysql_driver.php index c2fccc1f7..b1edc2925 100644 --- a/system/database/drivers/mysql/mysql_driver.php +++ b/system/database/drivers/mysql/mysql_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,12 +24,13 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * MySQL Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -40,48 +41,78 @@ */ class CI_DB_mysql_driver extends CI_DB { + /** + * Database driver + * + * @var string + */ public $dbdriver = 'mysql'; - // The character used for escaping - protected $_escape_char = '`'; - - // clause and character used for LIKE escape sequences - not used in MySQL - protected $_like_escape_str = ''; - protected $_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. + * Compression flag + * + * @var bool */ - protected $_count_string = 'SELECT COUNT(*) AS '; - protected $_random_keyword = ' RAND()'; // database specific random keyword + public $compress = FALSE; /** + * DELETE hack flag + * * 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 bool */ public $delete_hack = TRUE; + // -------------------------------------------------------------------- + + /** + * Identifier escape character + * + * @var string + */ + protected $_escape_char = '`'; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @param array $params + * @return void + */ public function __construct($params) { parent::__construct($params); - if ($this->port != '') + if ( ! empty($this->port)) { $this->hostname .= ':'.$this->port; } } + // -------------------------------------------------------------------- + /** * Non-persistent database connection * + * @param bool $persistent * @return resource */ - public function db_connect() + public function db_connect($persistent = FALSE) { - return @mysql_connect($this->hostname, $this->username, $this->password, TRUE); + $client_flags = ($this->compress === FALSE) ? 0 : MYSQL_CLIENT_COMPRESS; + + if ($this->encrypt === TRUE) + { + $client_flags = $client_flags | MYSQL_CLIENT_SSL; + } + + return ($persistent === TRUE) + ? @mysql_pconnect($this->hostname, $this->username, $this->password, $client_flags) + : @mysql_connect($this->hostname, $this->username, $this->password, TRUE, $client_flags); } // -------------------------------------------------------------------- @@ -93,7 +124,7 @@ class CI_DB_mysql_driver extends CI_DB { */ public function db_pconnect() { - return @mysql_pconnect($this->hostname, $this->username, $this->password); + return $this->db_connect(TRUE); } // -------------------------------------------------------------------- @@ -119,7 +150,7 @@ class CI_DB_mysql_driver extends CI_DB { /** * Select the database * - * @param string database name + * @param string $database * @return bool */ public function db_select($database = '') @@ -143,7 +174,7 @@ class CI_DB_mysql_driver extends CI_DB { /** * Set client character set * - * @param string + * @param string $charset * @return bool */ protected function _db_set_charset($charset) @@ -160,9 +191,21 @@ class CI_DB_mysql_driver extends CI_DB { */ public function version() { - return isset($this->data_cache['version']) - ? $this->data_cache['version'] - : $this->data_cache['version'] = @mysql_get_server_info($this->conn_id); + if (isset($this->data_cache['version'])) + { + return $this->data_cache['version']; + } + elseif ( ! $this->conn_id) + { + $this->initialize(); + } + + if ( ! $this->conn_id OR ($version = @mysql_get_server_info($this->conn_id)) === FALSE) + { + return FALSE; + } + + return $this->data_cache['version'] = $version; } // -------------------------------------------------------------------- @@ -170,7 +213,7 @@ class CI_DB_mysql_driver extends CI_DB { /** * Execute the query * - * @param string an SQL query + * @param string $sql an SQL query * @return mixed */ protected function _execute($sql) @@ -185,7 +228,7 @@ class CI_DB_mysql_driver extends CI_DB { * * If needed, each database adapter can prep the query string * - * @param string an SQL query + * @param string $sql an SQL query * @return string */ protected function _prep_query($sql) @@ -205,6 +248,7 @@ class CI_DB_mysql_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @return bool */ public function trans_begin($test_mode = FALSE) @@ -270,8 +314,8 @@ class CI_DB_mysql_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -291,7 +335,9 @@ class CI_DB_mysql_driver extends CI_DB { // escape LIKE condition wildcards if ($like === TRUE) { - return str_replace(array('%', '_'), array('\\%', '\\_'), $str); + return 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; @@ -324,47 +370,18 @@ class CI_DB_mysql_driver extends CI_DB { // -------------------------------------------------------------------- /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @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->num_rows() == 0) - { - return 0; - } - - $query = $query->row(); - $this->_reset_select(); - return (int) $query->numrows; - } - - // -------------------------------------------------------------------- - - /** * List table query * * Generates a platform-specific query string so that the table names can be fetched * - * @param bool + * @param bool $prefix_limit * @return string */ protected function _list_tables($prefix_limit = FALSE) { - $sql = 'SHOW TABLES FROM '.$this->_escape_char.$this->database.$this->_escape_char; + $sql = 'SHOW TABLES FROM '.$this->escape_identifiers($this->database); - if ($prefix_limit !== FALSE && $this->dbprefix != '') + if ($prefix_limit !== FALSE && $this->dbprefix !== '') { return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'"; } @@ -379,10 +396,10 @@ class CI_DB_mysql_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @param string the table name + * @param string $table * @return string */ - public function _list_columns($table = '') + protected function _list_columns($table = '') { return 'SHOW COLUMNS FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE); } @@ -392,12 +409,12 @@ class CI_DB_mysql_driver extends CI_DB { /** * Returns an object with field data * - * @param string the table name + * @param string $table * @return object */ public function field_data($table = '') { - if ($table == '') + if ($table === '') { return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE; } @@ -439,37 +456,16 @@ class CI_DB_mysql_driver extends CI_DB { // -------------------------------------------------------------------- /** - * From Tables - * - * This function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards - * - * @param string table name - * @return string - */ - protected function _from_tables($tables) - { - if ( ! is_array($tables)) - { - $tables = array($tables); - } - - return '('.implode(', ', $tables).')'; - } - - // -------------------------------------------------------------------- - - /** * Update_Batch statement * * Generates a platform-specific batch update string from the supplied data * - * @param string the table name - * @param array the update data - * @param array the where clause + * @param string $table Table name + * @param array $values Update data + * @param string $index WHERE key * @return string */ - protected function _update_batch($table, $values, $index, $where = NULL) + protected function _update_batch($table, $values, $index) { $ids = array(); foreach ($values as $key => $val) @@ -478,7 +474,7 @@ class CI_DB_mysql_driver extends CI_DB { foreach (array_keys($val) as $field) { - if ($field != $index) + if ($field !== $index) { $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; } @@ -493,26 +489,29 @@ class CI_DB_mysql_driver extends CI_DB { .'ELSE '.$k.' END, '; } - return 'UPDATE '.$table.' SET '.substr($cases, 0, -2) - .' WHERE '.(($where != '' && count($where) > 0) ? implode(' ', $where).' AND ' : '') - .$index.' IN('.implode(',', $ids).')'; + $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); + + return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); } // -------------------------------------------------------------------- /** - * Limit string + * FROM tables * - * Generates a platform-specific LIMIT clause + * Groups tables in FROM clauses if needed, so there is no confusion + * about operator precedence. * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value * @return string */ - protected function _limit($sql, $limit, $offset) + protected function _from_tables() { - return $sql.' LIMIT '.($offset == 0 ? '' : $offset.', ').$limit; + if ( ! empty($this->qb_join) && count($this->qb_from) > 1) + { + return '('.implode(', ', $this->qb_from).')'; + } + + return implode(', ', $this->qb_from); } // -------------------------------------------------------------------- @@ -520,12 +519,11 @@ class CI_DB_mysql_driver extends CI_DB { /** * Close DB Connection * - * @param resource * @return void */ - protected function _close($conn_id) + protected function _close() { - @mysql_close($conn_id); + @mysql_close($this->conn_id); } } diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php index 0e39affa7..6c5dfc665 100644 --- a/system/database/drivers/mysql/mysql_forge.php +++ b/system/database/drivers/mysql/mysql_forge.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * MySQL Forge Class @@ -34,151 +35,167 @@ */ class CI_DB_mysql_forge extends CI_DB_forge { + /** + * CREATE DATABASE statement + * + * @var string + */ protected $_create_database = 'CREATE DATABASE %s CHARACTER SET %s COLLATE %s'; /** - * Process Fields + * CREATE TABLE keys flag * - * @param mixed the fields - * @return string + * Whether table keys are created from within the + * CREATE TABLE statement. + * + * @var bool */ - protected function _process_fields($fields) - { - $current_field_count = 0; - $sql = ''; + protected $_create_table_keys = TRUE; - 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) - .( ! empty($attributes['NAME']) ? ' '.$this->db->protect_identifiers($attributes['NAME']).' ' : ''); + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'TINYINT', + 'SMALLINT', + 'MEDIUMINT', + 'INT', + 'INTEGER', + 'BIGINT', + 'REAL', + 'DOUBLE', + 'DOUBLE PRECISION', + 'FLOAT', + 'DECIMAL', + 'NUMERIC' + ); - if ( ! empty($attributes['TYPE'])) - { - $sql .= ' '.$attributes['TYPE']; - - if ( ! empty($attributes['CONSTRAINT'])) - { - switch (strtolower($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'].')'; - } - } - } + /** + * NULL value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_null = 'NULL'; - $sql .= (( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '') - .(isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '') - .(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL') - .(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' AUTO_INCREMENT' : ''); - } + // -------------------------------------------------------------------- - // don't add a comma on the end of the last field - if (++$current_field_count < count($fields)) - { - $sql .= ','; - } - } + /** + * Class constructor + * + * @param object &$db Database object + * @return void + */ + public function __construct(&$db) + { + parent::__construct($db); - return $sql; + $this->_create_table .= ' DEFAULT CHARSET '.$this->db->char_set.' COLLATE '.$this->db->dbcollat; } // -------------------------------------------------------------------- /** - * Create Table + * ALTER TABLE * - * @param string the table name - * @param mixed the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return bool + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] */ - protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + protected function _alter_table($alter_type, $table, $field) { - $sql = 'CREATE TABLE '; - - if ($if_not_exists === TRUE) - { - $sql .= 'IF NOT EXISTS '; - } - - $sql .= $this->db->protect_identifiers($table).' ('.$this->_process_fields($fields); - - if (count($primary_keys) > 0) + if ($alter_type === 'DROP') { - $key_name = $this->db->protect_identifiers(implode('_', $primary_keys)); - $sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->protect_identifiers($primary_keys)).')'; + return parent::_alter_table($alter_type, $table, $field); } - if (is_array($keys) && count($keys) > 0) + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); + for ($i = 0, $c = count($field); $i < $c; $i++) { - foreach ($keys as $key) + if ($field[$i]['_literal'] !== FALSE) { - if (is_array($key)) + $field[$i] = ($alter_type === 'ADD') + ? "\n\tADD ".$field[$i]['_literal'] + : "\n\tMODIFY ".$field[$i]['_literal']; + } + else + { + if ($alter_type === 'ADD') { - $key_name = $this->db->protect_identifiers(implode('_', $key)); - $key = $this->db->protect_identifiers($key); + $field[$i]['_literal'] = "\n\tADD "; } else { - $key_name = $this->db->protect_identifiers($key); - $key = array($key_name); + $field[$i]['_literal'] = empty($field[$i]['new_name']) ? "\n\tMODIFY " : "\n\tCHANGE "; } - $sql .= ",\n\tKEY ".$key_name.' ('.implode(', ', $key).')'; + $field[$i] = $field[$i]['_literal'].$this->_process_column($field[$i]); } } - return $sql."\n) DEFAULT CHARACTER SET ".$this->db->char_set.' COLLATE '.$this->db->dbcollat.';'; + return array($sql.implode(',', $field)); } // -------------------------------------------------------------------- /** - * Alter table query + * Process column * - * Generates a platform-specific query so that a table can be altered - * Called by add_column(), drop_column() and column_alter() + * @param array $field + * @return string + */ + protected function _process_column($field) + { + $extra_clause = isset($field['after']) + ? ' AFTER '.$this->db->escape_identifiers($field['after']) : ''; + + if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE) + { + $extra_clause = ' FIRST'; + } + + return $this->db->escape_identifiers($field['name']) + .(empty($field['new_name']) ? '' : $this->db->escape_identifiers($field['new_name'])) + .' '.$field['type'].$field['length'] + .$field['unsigned'] + .$field['null'] + .$field['default'] + .$field['auto_increment'] + .$field['unique'] + .$extra_clause; + } + + // -------------------------------------------------------------------- + + /** + * Process indexes * - * @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 + * @param string $table (ignored) * @return string */ - protected function _alter_table($alter_type, $table, $fields, $after_field = '') + protected function _process_indexes($table = NULL) { - $sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '; + $sql = ''; - // DROP has everything it needs now. - if ($alter_type === 'DROP') + for ($i = 0, $c = count($this->keys); $i < $c; $i++) { - return $sql.$this->db->protect_identifiers($fields); + if ( ! isset($this->fields[$this->keys[$i]])) + { + unset($this->keys[$i]); + continue; + } + + is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]); + + $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i])) + .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')'; } - return $sql.$this->_process_fields($fields) - .($after_field != '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : ''); + $this->keys = array(); + + return $sql; } } diff --git a/system/database/drivers/mysql/mysql_result.php b/system/database/drivers/mysql/mysql_result.php index 14d6d072a..4bfa0ae35 100644 --- a/system/database/drivers/mysql/mysql_result.php +++ b/system/database/drivers/mysql/mysql_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * MySQL Result Class @@ -33,17 +34,35 @@ * @category Database * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ + * @since 1.0 */ class CI_DB_mysql_result extends CI_DB_result { /** + * Class constructor + * + * @param object &$driver_object + * @return void + */ + public function __construct(&$driver_object) + { + parent::__construct($driver_object); + + // Required, due to mysql_data_seek() causing nightmares + // with empty result sets + $this->num_rows = @mysql_num_rows($this->result_id); + } + + // -------------------------------------------------------------------- + + /** * Number of rows in the result set * * @return int */ public function num_rows() { - return @mysql_num_rows($this->result_id); + return $this->num_rows; } // -------------------------------------------------------------------- @@ -126,13 +145,16 @@ class CI_DB_mysql_result extends CI_DB_result { * * Moves the internal pointer to the desired offset. We call * this internally before fetching results to make sure the - * result set starts at zero + * result set starts at zero. * + * @param int $n * @return bool */ protected function _data_seek($n = 0) { - return mysql_data_seek($this->result_id, $n); + return $this->num_rows + ? @mysql_data_seek($this->result_id, $n) + : FALSE; } // -------------------------------------------------------------------- @@ -156,11 +178,12 @@ class CI_DB_mysql_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @return object */ - protected function _fetch_object() + protected function _fetch_object($class_name = 'stdClass') { - return mysql_fetch_object($this->result_id); + return mysql_fetch_object($this->result_id, $class_name); } } diff --git a/system/database/drivers/mysql/mysql_utility.php b/system/database/drivers/mysql/mysql_utility.php index 642323dbd..8aa051755 100644 --- a/system/database/drivers/mysql/mysql_utility.php +++ b/system/database/drivers/mysql/mysql_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * MySQL Utility Class @@ -34,14 +35,33 @@ */ class CI_DB_mysql_utility extends CI_DB_utility { + /** + * List databases statement + * + * @var string + */ protected $_list_databases = 'SHOW DATABASES'; + + /** + * OPTIMIZE TABLE statement + * + * @var string + */ protected $_optimize_table = 'OPTIMIZE TABLE %s'; + + /** + * REPAIR TABLE statement + * + * @var string + */ protected $_repair_table = 'REPAIR TABLE %s'; + // -------------------------------------------------------------------- + /** - * MySQL Export + * Export * - * @param array Preferences + * @param array $params Preferences * @return mixed */ protected function _backup($params = array()) @@ -65,7 +85,7 @@ class CI_DB_mysql_utility extends CI_DB_utility { } // Get the table schema - $query = $this->db->query('SHOW CREATE TABLE '.$this->db->protect_identifiers($this->db->database).'.'.$this->db->protect_identifiers($table)); + $query = $this->db->query('SHOW CREATE TABLE '.$this->db->escape_identifiers($this->db->database.'.'.$table)); // No result means the table name was invalid if ($query === FALSE) @@ -76,7 +96,7 @@ class CI_DB_mysql_utility extends CI_DB_utility { // Write out the table schema $output .= '#'.$newline.'# TABLE STRUCTURE FOR: '.$table.$newline.'#'.$newline.$newline; - if ($add_drop == TRUE) + if ($add_drop === TRUE) { $output .= 'DROP TABLE IF EXISTS '.$this->db->protect_identifiers($table).';'.$newline.$newline; } @@ -92,7 +112,7 @@ class CI_DB_mysql_utility extends CI_DB_utility { } // If inserts are not needed we're done... - if ($add_insert == FALSE) + if ($add_insert === FALSE) { continue; } @@ -100,7 +120,7 @@ class CI_DB_mysql_utility extends CI_DB_utility { // Grab all the data from the current table $query = $this->db->query('SELECT * FROM '.$this->db->protect_identifiers($table)); - if ($query->num_rows() == 0) + if ($query->num_rows() === 0) { continue; } @@ -120,7 +140,7 @@ class CI_DB_mysql_utility extends CI_DB_utility { TRUE); // Create a string of field names - $field_str .= $this->db->protect_identifiers($field->name).', '; + $field_str .= $this->db->escape_identifiers($field->name).', '; $i++; } @@ -143,7 +163,7 @@ class CI_DB_mysql_utility extends CI_DB_utility { else { // Escape the data if it's not an integer - $val_str .= ($is_int[$i] == FALSE) ? $this->db->escape($v) : $v; + $val_str .= ($is_int[$i] === FALSE) ? $this->db->escape($v) : $v; } // Append a comma diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php index a690682be..ae17703ac 100644 --- a/system/database/drivers/mysqli/mysqli_driver.php +++ b/system/database/drivers/mysqli/mysqli_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,12 +24,13 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * MySQLi Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -40,40 +41,60 @@ */ class CI_DB_mysqli_driver extends CI_DB { + /** + * Database driver + * + * @var string + */ public $dbdriver = 'mysqli'; - // The character used for escaping - protected $_escape_char = '`'; - - // clause and character used for LIKE escape sequences - not used in MySQL - protected $_like_escape_str = ''; - protected $_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. + * Compression flag + * + * @var bool */ - protected $_count_string = 'SELECT COUNT(*) AS '; - protected $_random_keyword = ' RAND()'; // database specific random keyword + public $compress = FALSE; /** + * DELETE hack flag + * * 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 bool */ public $delete_hack = TRUE; + // -------------------------------------------------------------------- + + /** + * Identifier escape character + * + * @var string + */ + protected $_escape_char = '`'; + + // -------------------------------------------------------------------- + /** - * Non-persistent database connection + * Database connection * + * @param bool $persistent * @return object + * @todo SSL support */ - public function db_connect() + public function db_connect($persistent = FALSE) { - return ($this->port != '') - ? @new mysqli($this->hostname, $this->username, $this->password, $this->database, $this->port) - : @new mysqli($this->hostname, $this->username, $this->password, $this->database); + // Persistent connection support was added in PHP 5.3.0 + $hostname = ($persistent === TRUE && is_php('5.3')) + ? 'p:'.$this->hostname : $this->hostname; + $port = empty($this->port) ? NULL : $this->port; + $client_flags = ($this->compress === TRUE) ? MYSQLI_CLIENT_COMPRESS : 0; + $mysqli = mysqli_init(); + + return @$mysqli->real_connect($hostname, $this->username, $this->password, $this->database, $port, NULL, $client_flags) + ? $mysqli : FALSE; } // -------------------------------------------------------------------- @@ -85,15 +106,7 @@ class CI_DB_mysqli_driver extends CI_DB { */ public function db_pconnect() { - // Persistent connection support was added in PHP 5.3.0 - if ( ! is_php('5.3')) - { - return $this->db_connect(); - } - - return ($this->port != '') - ? @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database, $this->port) - : @new mysqli('p:'.$this->hostname, $this->username, $this->password, $this->database); + return $this->db_connect(TRUE); } // -------------------------------------------------------------------- @@ -119,7 +132,7 @@ class CI_DB_mysqli_driver extends CI_DB { /** * Select the database * - * @param string database name + * @param string $database * @return bool */ public function db_select($database = '') @@ -143,7 +156,7 @@ class CI_DB_mysqli_driver extends CI_DB { /** * Set client character set * - * @param string + * @param string $charset * @return bool */ protected function _db_set_charset($charset) @@ -160,9 +173,16 @@ class CI_DB_mysqli_driver extends CI_DB { */ public function version() { - return isset($this->data_cache['version']) - ? $this->data_cache['version'] - : $this->data_cache['version'] = $this->conn_id->server_info; + if (isset($this->data_cache['version'])) + { + return $this->data_cache['version']; + } + elseif ( ! $this->conn_id) + { + $this->initialize(); + } + + return $this->data_cache['version'] = $this->conn_id->server_info; } // -------------------------------------------------------------------- @@ -170,7 +190,7 @@ class CI_DB_mysqli_driver extends CI_DB { /** * Execute the query * - * @param string an SQL query + * @param string $sql an SQL query * @return mixed */ protected function _execute($sql) @@ -185,7 +205,7 @@ class CI_DB_mysqli_driver extends CI_DB { * * If needed, each database adapter can prep the query string * - * @param string an SQL query + * @param string $sql an SQL query * @return string */ protected function _prep_query($sql) @@ -205,6 +225,7 @@ class CI_DB_mysqli_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @return bool */ public function trans_begin($test_mode = FALSE) @@ -270,8 +291,8 @@ class CI_DB_mysqli_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -291,7 +312,9 @@ class CI_DB_mysqli_driver extends CI_DB { // escape LIKE condition wildcards if ($like === TRUE) { - return str_replace(array('%', '_'), array('\\%', '\\_'), $str); + return 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; @@ -324,47 +347,18 @@ class CI_DB_mysqli_driver extends CI_DB { // -------------------------------------------------------------------- /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @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->num_rows() == 0) - { - return 0; - } - - $query = $query->row(); - $this->_reset_select(); - return (int) $query->numrows; - } - - // -------------------------------------------------------------------- - - /** * List table query * * Generates a platform-specific query string so that the table names can be fetched * - * @param bool + * @param bool $prefix_limit * @return string */ protected function _list_tables($prefix_limit = FALSE) { - $sql = 'SHOW TABLES FROM '.$this->_escape_char.$this->database.$this->_escape_char; + $sql = 'SHOW TABLES FROM '.$this->escape_identifiers($this->database); - if ($prefix_limit !== FALSE && $this->dbprefix != '') + if ($prefix_limit !== FALSE && $this->dbprefix !== '') { return $sql." LIKE '".$this->escape_like_str($this->dbprefix)."%'"; } @@ -379,7 +373,7 @@ class CI_DB_mysqli_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @param string the table name + * @param string $table * @return string */ protected function _list_columns($table = '') @@ -392,12 +386,12 @@ class CI_DB_mysqli_driver extends CI_DB { /** * Returns an object with field data * - * @param string the table name + * @param string $table * @return object */ public function field_data($table = '') { - if ($table == '') + if ($table === '') { return ($this->db_debug) ? $this->display_error('db_field_param_missing') : FALSE; } @@ -433,28 +427,15 @@ class CI_DB_mysqli_driver extends CI_DB { */ public function error() { - return array('code' => $this->conn_id->errno, 'message' => $this->conn_id->error); - } - - // -------------------------------------------------------------------- - - /** - * From Tables - * - * This function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards - * - * @param string - * @return string - */ - protected function _from_tables($tables) - { - if ( ! is_array($tables)) + if ( ! empty($this->conn_id->connect_errno)) { - $tables = array($tables); + return array( + 'code' => $this->conn_id->connect_errno, + 'message' => is_php('5.2.9') ? $this->conn_id->connect_error : mysqli_connect_error() + ); } - return '('.implode(', ', $tables).')'; + return array('code' => $this->conn_id->errno, 'message' => $this->conn_id->error); } // -------------------------------------------------------------------- @@ -464,12 +445,12 @@ class CI_DB_mysqli_driver extends CI_DB { * * Generates a platform-specific batch update string from the supplied data * - * @param string the table name - * @param array the update data - * @param array the where clause + * @param string $table Table name + * @param array $values Update data + * @param string $index WHERE key * @return string */ - protected function _update_batch($table, $values, $index, $where = NULL) + protected function _update_batch($table, $values, $index) { $ids = array(); foreach ($values as $key => $val) @@ -478,7 +459,7 @@ class CI_DB_mysqli_driver extends CI_DB { foreach (array_keys($val) as $field) { - if ($field != $index) + if ($field !== $index) { $final[$field][] = 'WHEN '.$index.' = '.$val[$index].' THEN '.$val[$field]; } @@ -493,29 +474,29 @@ class CI_DB_mysqli_driver extends CI_DB { .'ELSE '.$k.' END, '; } - $where = ($where != '' && count($where) > 0) ? implode(' ', $where).' AND ' : ''; + $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); - return 'UPDATE '.$table.' SET '.substr($cases, 0, -2) - .' WHERE '.(($where != '' && count($where) > 0) ? implode(' ', $where).' AND ' : '') - .$index.' IN('.implode(',', $ids).')'; + return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); } // -------------------------------------------------------------------- /** - * Limit string + * FROM tables * - * Generates a platform-specific LIMIT clause + * Groups tables in FROM clauses if needed, so there is no confusion + * about operator precedence. * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value * @return string */ - protected function _limit($sql, $limit, $offset) + protected function _from_tables() { - return $sql.' LIMIT '.$limit - .($offset > 0 ? ' OFFSET '.$offset : ''); + if ( ! empty($this->qb_join) && count($this->qb_from) > 1) + { + return '('.implode(', ', $this->qb_from).')'; + } + + return implode(', ', $this->qb_from); } // -------------------------------------------------------------------- @@ -523,13 +504,11 @@ class CI_DB_mysqli_driver extends CI_DB { /** * Close DB Connection * - * @param object * @return void */ - protected function _close($conn_id) + protected function _close() { $this->conn_id->close(); - $this->conn_id = FALSE; } } diff --git a/system/database/drivers/mysqli/mysqli_forge.php b/system/database/drivers/mysqli/mysqli_forge.php index 503574dfc..a70eef88f 100644 --- a/system/database/drivers/mysqli/mysqli_forge.php +++ b/system/database/drivers/mysqli/mysqli_forge.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * MySQLi Forge Class @@ -34,152 +35,167 @@ */ class CI_DB_mysqli_forge extends CI_DB_forge { + /** + * CREATE DATABASE statement + * + * @var string + */ protected $_create_database = 'CREATE DATABASE %s CHARACTER SET %s COLLATE %s'; /** - * Process Fields + * CREATE TABLE keys flag * - * @param mixed the fields - * @return string + * Whether table keys are created from within the + * CREATE TABLE statement. + * + * @var bool */ - protected function _process_fields($fields) - { - $current_field_count = 0; - $sql = ''; + protected $_create_table_keys = TRUE; - 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) - .( ! empty($attributes['NAME']) ? ' '.$this->db->protect_identifiers($attributes['NAME']).' ' : '') - ; + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'TINYINT', + 'SMALLINT', + 'MEDIUMINT', + 'INT', + 'INTEGER', + 'BIGINT', + 'REAL', + 'DOUBLE', + 'DOUBLE PRECISION', + 'FLOAT', + 'DECIMAL', + 'NUMERIC' + ); - if ( ! empty($attributes['TYPE'])) - { - $sql .= ' '.$attributes['TYPE']; - - if ( ! empty($attributes['CONSTRAINT'])) - { - switch (strtolower($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'].')'; - } - } - } + /** + * NULL value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_null = 'NULL'; - $sql .= (( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '') - .(isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '') - .(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL') - .(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' AUTO_INCREMENT' : ''); - } + // -------------------------------------------------------------------- - // don't add a comma on the end of the last field - if (++$current_field_count < count($fields)) - { - $sql .= ','; - } - } + /** + * Class constructor + * + * @param object &$db Database object + * @return void + */ + public function __construct(&$db) + { + parent::__construct($db); - return $sql; + $this->_create_table .= ' DEFAULT CHARSET '.$this->db->char_set.' COLLATE '.$this->db->dbcollat; } // -------------------------------------------------------------------- /** - * Create Table + * ALTER TABLE * - * @param string the table name - * @param mixed the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return bool + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] */ - protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + protected function _alter_table($alter_type, $table, $field) { - $sql = 'CREATE TABLE '; - - if ($if_not_exists === TRUE) - { - $sql .= 'IF NOT EXISTS '; - } - - $sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields); - - if (count($primary_keys) > 0) + if ($alter_type === 'DROP') { - $key_name = $this->db->protect_identifiers(implode('_', $primary_keys)); - $sql .= ",\n\tPRIMARY KEY ".$key_name.' ('.implode(', ', $this->db->protect_identifiers($primary_keys)).')'; + return parent::_alter_table($alter_type, $table, $field); } - if (is_array($keys) && count($keys) > 0) + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); + for ($i = 0, $c = count($field); $i < $c; $i++) { - foreach ($keys as $key) + if ($field[$i]['_literal'] !== FALSE) { - if (is_array($key)) + $field[$i] = ($alter_type === 'ADD') + ? "\n\tADD ".$field[$i]['_literal'] + : "\n\tMODIFY ".$field[$i]['_literal']; + } + else + { + if ($alter_type === 'ADD') { - $key_name = $this->db->protect_identifiers(implode('_', $key)); - $key = $this->db->protect_identifiers($key); + $field[$i]['_literal'] = "\n\tADD "; } else { - $key_name = $this->db->protect_identifiers($key); - $key = array($key_name); + $field[$i]['_literal'] = empty($field[$i]['new_name']) ? "\n\tMODIFY " : "\n\tCHANGE "; } - $sql .= ",\n\tKEY ".$key_name.' ('.implode(', ', $key).')'; + $field[$i] = $field[$i]['_literal'].$this->_process_column($field[$i]); } } - return $sql."\n) DEFAULT CHARACTER SET ".$this->db->char_set.' COLLATE '.$this->db->dbcollat.';'; + return array($sql.implode(',', $field)); } // -------------------------------------------------------------------- /** - * Alter table query + * Process column * - * Generates a platform-specific query so that a table can be altered - * Called by add_column(), drop_column(), and column_alter(), + * @param array $field + * @return string + */ + protected function _process_column($field) + { + $extra_clause = isset($field['after']) + ? ' AFTER '.$this->db->escape_identifiers($field['after']) : ''; + + if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE) + { + $extra_clause = ' FIRST'; + } + + return $this->db->escape_identifiers($field['name']) + .(empty($field['new_name']) ? '' : $this->db->escape_identifiers($field['new_name'])) + .' '.$field['type'].$field['length'] + .$field['unsigned'] + .$field['null'] + .$field['default'] + .$field['auto_increment'] + .$field['unique'] + .$extra_clause; + } + + // -------------------------------------------------------------------- + + /** + * Process indexes * - * @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 + * @param string $table (ignored) * @return string */ - protected function _alter_table($alter_type, $table, $fields, $after_field = '') + protected function _process_indexes($table = NULL) { - $sql = 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '; + $sql = ''; - // DROP has everything it needs now. - if ($alter_type === 'DROP') + for ($i = 0, $c = count($this->keys); $i < $c; $i++) { - return $sql.$this->db->protect_identifiers($fields); + if ( ! isset($this->fields[$this->keys[$i]])) + { + unset($this->keys[$i]); + continue; + } + + is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]); + + $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i])) + .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')'; } - return $sql.$this->_process_fields($fields) - .($after_field != '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : ''); + $this->keys = array(); + + return $sql; } } diff --git a/system/database/drivers/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php index 9b4d494d4..15e15cd5f 100644 --- a/system/database/drivers/mysqli/mysqli_result.php +++ b/system/database/drivers/mysqli/mysqli_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * MySQLi Result Class @@ -33,6 +34,7 @@ * @category Database * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ + * @since 1.3 */ class CI_DB_mysqli_result extends CI_DB_result { @@ -43,7 +45,9 @@ class CI_DB_mysqli_result extends CI_DB_result { */ public function num_rows() { - return $this->result_id->num_rows; + return is_int($this->num_rows) + ? $this->num_rows + : $this->num_rows = $this->result_id->num_rows; } // -------------------------------------------------------------------- @@ -127,8 +131,9 @@ class CI_DB_mysqli_result extends CI_DB_result { * * Moves the internal pointer to the desired offset. We call * this internally before fetching results to make sure the - * result set starts at zero + * result set starts at zero. * + * @param int $n * @return bool */ protected function _data_seek($n = 0) @@ -157,11 +162,12 @@ class CI_DB_mysqli_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @return object */ - protected function _fetch_object() + protected function _fetch_object($class_name = 'stdClass') { - return $this->result_id->fetch_object(); + return $this->result_id->fetch_object($class_name); } } diff --git a/system/database/drivers/mysqli/mysqli_utility.php b/system/database/drivers/mysqli/mysqli_utility.php index 27d4ef817..345691e84 100644 --- a/system/database/drivers/mysqli/mysqli_utility.php +++ b/system/database/drivers/mysqli/mysqli_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * MySQLi Utility Class @@ -34,21 +35,155 @@ */ class CI_DB_mysqli_utility extends CI_DB_utility { + /** + * List databases statement + * + * @var string + */ protected $_list_databases = 'SHOW DATABASES'; + + /** + * OPTIMIZE TABLE statement + * + * @var string + */ protected $_optimize_table = 'OPTIMIZE TABLE %s'; + + /** + * REPAIR TABLE statement + * + * @var string + */ protected $_repair_table = 'REPAIR TABLE %s'; + // -------------------------------------------------------------------- + /** - * MySQLi Export + * Export * - * @param array Preferences + * @param array $params Preferences * @return mixed */ protected function _backup($params = array()) { - // Currently unsupported - return $this->db->display_error('db_unsuported_feature'); + 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->escape_identifiers($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 '.$this->db->protect_identifiers($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 '.$this->db->protect_identifiers($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 = $query->result_id->fetch_field()) + { + // Most versions of MySQL store timestamp as a string + $is_int[$i] = in_array(strtolower($field->type), + array('tinyint', 'smallint', 'mediumint', 'int', 'bigint'), //, 'timestamp'), + TRUE); + + // Create a string of field names + $field_str .= $this->db->escape_identifiers($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 + $val_str .= ($is_int[$i] === FALSE) ? $this->db->escape($v) : $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 '.$this->db->protect_identifiers($table).' ('.$field_str.') VALUES ('.$val_str.');'.$newline; + } + + $output .= $newline.$newline; + } + + return $output; } + } /* End of file mysqli_utility.php */ diff --git a/system/database/drivers/oci8/oci8_driver.php b/system/database/drivers/oci8/oci8_driver.php index 1b66178c6..62f919145 100644 --- a/system/database/drivers/oci8/oci8_driver.php +++ b/system/database/drivers/oci8/oci8_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,12 +24,13 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * oci8 Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -49,34 +50,80 @@ */ class CI_DB_oci8_driver extends CI_DB { + /** + * Database driver + * + * @var string + */ public $dbdriver = 'oci8'; - // The character used for excaping - protected $_escape_char = '"'; - - // clause and character used for LIKE escape sequences - protected $_like_escape_str = " ESCAPE '%s' "; - protected $_like_escape_chr = '!'; + /** + * Statement ID + * + * @var resource + */ + public $stmt_id; /** - * 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. + * Cursor ID + * + * @var resource */ - protected $_count_string = 'SELECT COUNT(1) AS '; - protected $_random_keyword = ' ASC'; // not currently supported + public $curs_id; - // Set "auto commit" by default + /** + * Commit mode flag + * + * @var int + */ public $commit_mode = OCI_COMMIT_ON_SUCCESS; - // need to track statement id and cursor id - public $stmt_id; - public $curs_id; - - // if we use a limit, we will add a field that will - // throw off num_fields later + /** + * Limit used flag + * + * If we use LIMIT, we'll add a field that will + * throw off num_fields later. + * + * @var bool + */ public $limit_used; + // -------------------------------------------------------------------- + + /** + * List of reserved identifiers + * + * Identifiers that must NOT be escaped. + * + * @var string[] + */ + protected $_reserved_identifiers = array('*', 'rownum'); + + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('ASC', 'ASC'); // not currently supported + + /** + * COUNT string + * + * @used-by CI_DB_driver::count_all() + * @used-by CI_DB_query_builder::count_all_results() + * + * @var string + */ + protected $_count_string = 'SELECT COUNT(1) AS '; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @param array $params + * @return void + */ public function __construct($params) { parent::__construct($params); @@ -156,6 +203,8 @@ class CI_DB_oci8_driver extends CI_DB { $this->dsn = ''; } + // -------------------------------------------------------------------- + /** * Non-persistent database connection * @@ -177,9 +226,9 @@ class CI_DB_oci8_driver extends CI_DB { */ public function db_pconnect() { - return ( ! empty($this->char_set)) - ? @oci_pconnect($this->username, $this->password, $this->dsn, $this->char_set) - : @oci_pconnect($this->username, $this->password, $this->dsn); + return empty($this->char_set) + ? @oci_pconnect($this->username, $this->password, $this->dsn) + : @oci_pconnect($this->username, $this->password, $this->dsn, $this->char_set); } // -------------------------------------------------------------------- @@ -191,9 +240,21 @@ class CI_DB_oci8_driver extends CI_DB { */ public function version() { - return isset($this->data_cache['version']) - ? $this->data_cache['version'] - : $this->data_cache['version'] = oci_server_version($this->conn_id); + if (isset($this->data_cache['version'])) + { + return $this->data_cache['version']; + } + elseif ( ! $this->conn_id) + { + $this->initialize(); + } + + if ( ! $this->conn_id OR ($version = oci_server_version($this->conn_id)) === FALSE) + { + return FALSE; + } + + return $this->data_cache['version'] = $version; } // -------------------------------------------------------------------- @@ -201,7 +262,7 @@ class CI_DB_oci8_driver extends CI_DB { /** * Execute the query * - * @param string an SQL query + * @param string $sql an SQL query * @return resource */ protected function _execute($sql) @@ -215,10 +276,12 @@ class CI_DB_oci8_driver extends CI_DB { return @oci_execute($this->stmt_id, $this->commit_mode); } + // -------------------------------------------------------------------- + /** * Generate a statement ID * - * @param string an SQL query + * @param string $sql an SQL query * @return void */ protected function _set_stmt_id($sql) @@ -234,7 +297,7 @@ class CI_DB_oci8_driver extends CI_DB { /** * Get cursor. Returns a cursor from the database * - * @return cursor id + * @return resource */ public function get_cursor() { @@ -262,7 +325,7 @@ class CI_DB_oci8_driver extends CI_DB { */ public function stored_procedure($package, $procedure, $params) { - if ($package == '' OR $procedure == '' OR ! is_array($params)) + if ($package === '' OR $procedure === '' OR ! is_array($params)) { if ($this->db_debug) { @@ -298,6 +361,7 @@ class CI_DB_oci8_driver extends CI_DB { /** * Bind parameters * + * @param array $params * @return void */ protected function _bind_params($params) @@ -326,6 +390,7 @@ class CI_DB_oci8_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @return bool */ public function trans_begin($test_mode = FALSE) @@ -398,8 +463,8 @@ class CI_DB_oci8_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -455,49 +520,21 @@ class CI_DB_oci8_driver extends CI_DB { // -------------------------------------------------------------------- /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @param string - * @return int - */ - 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 * - * @param bool + * @param bool $prefix_limit * @return string */ protected function _list_tables($prefix_limit = FALSE) { - $sql = 'SELECT TABLE_NAME FROM ALL_TABLES'; + $sql = 'SELECT "TABLE_NAME" FROM "ALL_TABLES"'; - if ($prefix_limit !== FALSE && $this->dbprefix != '') + if ($prefix_limit !== FALSE && $this->dbprefix !== '') { - return $sql." WHERE TABLE_NAME LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); + return $sql.' WHERE "TABLE_NAME" LIKE \''.$this->escape_like_str($this->dbprefix)."%' " + .sprintf($this->_like_escape_str, $this->_like_escape_chr); } return $sql; @@ -510,12 +547,12 @@ class CI_DB_oci8_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @param string the table name + * @param string $table * @return string */ protected function _list_columns($table = '') { - return 'SELECT COLUMN_NAME FROM all_tab_columns WHERE table_name = \''.$table.'\''; + return 'SELECT "COLUMN_NAME" FROM "all_tab_columns" WHERE "TABLE_NAME" = '.$this->escape($table); } // -------------------------------------------------------------------- @@ -525,12 +562,12 @@ class CI_DB_oci8_driver extends CI_DB { * * Generates a platform-specific query so that the column data can be retrieved * - * @param string the table name + * @param string $table * @return string */ protected function _field_data($table) { - return 'SELECT * FROM '.$table.' WHERE rownum = 1'; + return 'SELECT * FROM '.$this->protect_identifiers($table).' WHERE rownum = 1'; } // -------------------------------------------------------------------- @@ -567,29 +604,13 @@ class CI_DB_oci8_driver extends CI_DB { // -------------------------------------------------------------------- /** - * From Tables - * - * This function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards - * - * @param array - * @return string - */ - protected function _from_tables($tables) - { - return is_array($tables) ? implode(', ', $tables) : $tables; - } - - // -------------------------------------------------------------------- - - /** - * Insert_batch statement + * Insert batch statement * * Generates a platform-specific insert string from the supplied data * - * @param string the table name - * @param array the insert keys - * @param array the insert values + * @param string $table Table name + * @param array $keys INSERT keys + * @param array $values INSERT values * @return string */ protected function _insert_batch($table, $keys, $values) @@ -612,10 +633,10 @@ class CI_DB_oci8_driver extends CI_DB { * * Generates a platform-specific truncate string from the supplied data * - * If the database does not support the truncate() command, + * If the database does not support the TRUNCATE statement, * then this method maps to 'DELETE FROM table' * - * @param string the table name + * @param string $table * @return string */ protected function _truncate($table) @@ -630,40 +651,35 @@ class CI_DB_oci8_driver extends CI_DB { * * Generates a platform-specific delete string from the supplied data * - * @param string the table name - * @param array the where clause - * @param array the like clause - * @param string the limit clause + * @param string $table * @return string */ - protected function _delete($table, $where = array(), $like = array(), $limit = FALSE) + protected function _delete($table) { - $conditions = array(); - - empty($where) OR $conditions[] = implode(' ', $where); - empty($like) OR $conditions[] = implode(' ', $like); - empty($limit) OR $conditions[] = 'rownum <= '.$limit; + if ($this->qb_limit) + { + $this->where('rownum <= ',$this->qb_limit, FALSE); + $this->qb_limit = FALSE; + } - return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : ''); + return parent::_delete($table); } // -------------------------------------------------------------------- /** - * Limit string + * LIMIT * * Generates a platform-specific LIMIT clause * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value + * @param string $sql SQL Query * @return string */ - protected function _limit($sql, $limit, $offset) + protected function _limit($sql) { $this->limit_used = TRUE; - return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($offset + $limit).')' - .($offset != 0 ? ' WHERE rnum >= '.$offset : ''); + return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($this->qb_offset + $this->qb_limit + 1).')' + .($this->qb_offset ? ' WHERE rnum >= '.($this->qb_offset + 1): ''); } // -------------------------------------------------------------------- @@ -671,12 +687,11 @@ class CI_DB_oci8_driver extends CI_DB { /** * Close DB Connection * - * @param resource * @return void */ - protected function _close($conn_id) + protected function _close() { - @oci_close($conn_id); + @oci_close($this->conn_id); } } diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php index bd265b6e0..bd9d2df3c 100644 --- a/system/database/drivers/oci8/oci8_forge.php +++ b/system/database/drivers/oci8/oci8_forge.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Oracle Forge Class @@ -34,117 +35,96 @@ */ class CI_DB_oci8_forge extends CI_DB_forge { + /** + * CREATE DATABASE statement + * + * @var string + */ protected $_create_database = FALSE; + + /** + * DROP DATABASE statement + * + * @var string + */ protected $_drop_database = FALSE; - protected $_drop_table = 'DROP TABLE %s'; /** - * Create Table + * DROP TABLE IF statement * - * @param string the table name - * @param array the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return string + * @var string */ - protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) - { - $sql = 'CREATE TABLE '; + protected $_drop_table_if = FALSE; - if ($if_not_exists === TRUE) - { - $sql .= 'IF NOT EXISTS '; - } + /** + * UNSIGNED support + * + * @var bool|array + */ + protected $_unsigned = FALSE; - $sql .= $this->db->escape_identifiers($table).' ('; - $current_field_count = 0; + // -------------------------------------------------------------------- - foreach ($fields as $field => $attributes) + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if ($alter_type === 'DROP') { - // 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).' '.$attributes['TYPE'] - .((isset($attributes['UNSINGED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '') - .(isset($attributes['DEFAULT']) ? " DEFAULT '".$attributes['DEFAULT']."'" : '') - .((isset($attributes['NULL']) && $attributes['NULL'] === TRUE) ? '' : ' NOT NULL') - .(isset($attributes['CONSTRAINT']) ? ' CONSTRAINT '.$attributes['CONSTRAINT'] : ''); - } - - // don't add a comma on the end of the last field - if (++$current_field_count < count($fields)) - { - $sql .= ','; - } + return parent::_alter_table($alter_type, $table, $field); } - - if (count($primary_keys) > 0) + elseif ($alter_type === 'CHANGE') { - $primary_keys = $this->db->protect_identifiers($primary_keys); - $sql .= ",\n\tCONSTRAINT ".$table.' PRIMARY KEY ('.implode(', ', $primary_keys).')'; + $alter_type = 'MODIFY'; } - if (is_array($keys) && count($keys) > 0) + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); + $sqls = array(); + for ($i = 0, $c = count($field); $i < $c; $i++) { - foreach ($keys as $key) + if ($field[$i]['_literal'] !== FALSE) { - if (is_array($key)) - { - $key = $this->db->protect_identifiers($key); - } - else + $field[$i] = "\n\t".$field[$i]['_literal']; + } + else + { + $field[$i]['_literal'] = "\n\t".$this->_process_column($field[$i]); + if ($alter_type === 'MODIFY' && ! empty($field[$i]['new_name'])) { - $key = array($this->db->protect_identifiers($key)); + $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name']) + .' '.$this->db->escape_identifiers($field[$i]['new_name']); } - - $sql .= ",\n\tUNIQUE COLUMNS (".implode(', ', $key).')'; } } - return $sql."\n)"; + $sql .= ' '.$alter_type.' '; + $sql .= (count($field) === 1) + ? $fields[0] + : '('.implode(',', $field).')'; + + // RENAME COLUMN must be executed after MODIFY + array_unshift($sqls, $sql); + return $sql; } // -------------------------------------------------------------------- /** - * Alter table query + * Field attribute AUTO_INCREMENT * - * Generates a platform-specific query so that a table can be altered - * Called by add_column(), drop_column(), and column_alter(), - * - * @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 bool should 'NOT NULL' be added - * @param string the field after which we should add the new field - * @return string + * @param array &$attributes + * @param array &$field + * @return void */ - protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + protected function _attr_auto_increment(&$attributes, &$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; - } - - return $sql.' '.$column_definition - .($default_value != '' ? ' DEFAULT "'.$default_value.'"' : '') - .($null === NULL ? ' NULL' : ' NOT NULL') - .($after_field != '' ? ' AFTER '.$this->db->protect_identifiers($after_field) : ''); - + // Not supported - sequences and triggers must be used instead } } diff --git a/system/database/drivers/oci8/oci8_result.php b/system/database/drivers/oci8/oci8_result.php index 7b05e0a43..7d5bf5172 100644 --- a/system/database/drivers/oci8/oci8_result.php +++ b/system/database/drivers/oci8/oci8_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * oci8 Result Class @@ -33,22 +34,50 @@ * @category Database * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ + * @since 1.4.1 */ class CI_DB_oci8_result extends CI_DB_result { + /** + * Statement ID + * + * @var resource + */ public $stmt_id; + + /** + * Cursor ID + * + * @var resource + */ public $curs_id; + + /** + * Limit used flag + * + * @var bool + */ public $limit_used; - public $commit_mode; - /* Overwriting the parent here, so we have a way to know if it's - * already called or not: + /** + * Commit mode flag + * + * @var int */ - public $num_rows; + public $commit_mode; + + // -------------------------------------------------------------------- + /** + * Class constructor + * + * @param object &$driver_object + * @return void + */ public function __construct(&$driver_object) { parent::__construct($driver_object); + $this->stmt_id = $driver_object->stmt_id; $this->curs_id = $driver_object->curs_id; $this->limit_used = $driver_object->limit_used; @@ -56,33 +85,6 @@ class CI_DB_oci8_result extends CI_DB_result { $driver_object->stmt_id = FALSE; } - /** - * Number of rows in the result set. - * - * Oracle doesn't have a graceful way to return the number of rows - * so we have to use what amounts to a hack. - * - * @return int - */ - public function num_rows() - { - if ( ! is_int($this->num_rows)) - { - if (count($this->result_array) > 0) - { - return $this->num_rows = count($this->result_array); - } - elseif (count($this->result_object) > 0) - { - return $this->num_rows = count($this->result_object); - } - - return $this->num_rows = count($this->result_array()); - } - - return $this->num_rows; - } - // -------------------------------------------------------------------- /** @@ -181,7 +183,7 @@ class CI_DB_oci8_result extends CI_DB_result { protected function _fetch_assoc() { $id = ($this->curs_id) ? $this->curs_id : $this->stmt_id; - return oci_fetch_assoc($id); + return @oci_fetch_assoc($id); } // -------------------------------------------------------------------- @@ -191,450 +193,27 @@ class CI_DB_oci8_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @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. - * - * @return array - */ - public function result_array() - { - if (count($this->result_array) > 0) - { - return $this->result_array; - } - elseif (count($this->result_object) > 0) - { - for ($i = 0, $c = count($this->result_object); $i < $c; $i++) - { - $this->result_array[$i] = (array) $this->result_object[$i]; - } - - return $this->result_array; - } - elseif (is_array($this->row_data)) - { - if (count($this->row_data) === 0) - { - return $this->result_array; - } - else - { - $row_index = count($this->row_data); - } - } - else - { - $row_index = 0; - $this->row_data = array(); - } - - $row = NULL; - while ($row = $this->_fetch_assoc()) - { - $this->row_data[$row_index++] = $row; - } - - return $this->result_array = $this->row_data; - } - - // -------------------------------------------------------------------- - - /** - * Query result. "object" version. - * - * @return array - */ - public function result_object() - { - if (count($this->result_object) > 0) - { - return $this->result_object; - } - elseif (count($this->result_array) > 0) - { - for ($i = 0, $c = count($this->result_array); $i < $c; $i++) - { - $this->result_object[] = (object) $this->result_array[$i]; - } - - return $this->result_object; - } - elseif (is_array($this->row_data)) - { - if (count($this->row_data) === 0) - { - return $this->result_object; - } - else - { - $row_index = count($this->row_data); - for ($i = 0; $i < $row_index; $i++) - { - $this->result_object[$i] = (object) $this->row_data[$i]; - } - } - } - else - { - $row_index = 0; - $this->row_data = array(); - } - - $row = NULL; - while ($row = $this->_fetch_object()) - { - $this->row_data[$row_index] = (array) $row; - $this->result_object[$row_index++] = $row; - } - - return $this->result_object; - } - - // -------------------------------------------------------------------- - - /** - * Query result. Custom object version. - * - * @param string class name used to instantiate rows to - * @return array - */ - public function custom_result_object($class_name) - { - if (isset($this->custom_result_object[$class_name])) - { - return $this->custom_result_object[$class_name]; - } - - if ( ! class_exists($class_name) OR $this->result_id === FALSE OR $this->num_rows() === 0) - { - return array(); - } - - /* Even if we didn't have result_array or result_object - * set prior to custom_result_object() being called, - * num_rows() has already done so. - * Pass by reference, as we don't know how - * large it might be and we don't want 1000 row - * sets being copied. - */ - if (count($this->result_array) > 0) - { - $data = &$this->result_array; - } - elseif (count($this->result_object) > 0) - { - $data = &$this->result_object; - } - - $this->custom_result_object[$class_name] = array(); - for ($i = 0, $c = count($data); $i < $c; $i++) - { - $this->custom_result_object[$class_name][$i] = new $class_name(); - foreach ($data[$i] as $key => $value) - { - $this->custom_result_object[$class_name][$i]->$key = $value; - } - } - - return $this->custom_result_object[$class_name]; - } - - // -------------------------------------------------------------------- - - /* Single row result. - * - * Acts as a wrapper for row_object(), row_array() - * and custom_row_object(). Also used by first_row(), next_row() - * and previous_row(). - * - * @param int row index - * @param string ('object', 'array' or a custom class name) - * @return mixed whatever was passed to the second parameter - */ - public function row($n = 0, $type = 'object') - { - if ($type === 'object') - { - return $this->row_object($n); - } - elseif ($type === 'array') - { - return $this->row_array($n); - } - - return $this->custom_row_object($n, $type); - } - - // -------------------------------------------------------------------- - - /* Single row result. Array version. - * - * @param int row index - * @return array - */ - public function row_array($n = 0) - { - // Make sure $n is not a string - if ( ! is_int($n)) - { - $n = (int) $n; - } - - /* If row_data is initialized, it means that we've already tried - * (at least) to fetch some data, so ... check if we already have - * this row. - */ - if (is_array($this->row_data)) - { - /* If we already have row_data[$n] - return it. - * - * If we enter the elseif, there's a number of reasons to - * return an empty array: - * - * - count($this->row_data) === 0 means there are no results - * - num_rows being set, result_array and/or result_object - * having count() > 0 means that we've already fetched all - * data and $n is greater than our highest row index available - * - $n < $this->current_row means that if such row existed, - * we would've already returned it, therefore $n is an - * invalid index - */ - if (isset($this->row_data[$n])) // We already have this row - { - $this->current_row = $n; - return $this->row_data[$n]; - } - elseif (count($this->row_data) === 0 OR is_int($this->num_rows) - OR count($this->result_array) > 0 OR count($this->result_object) > 0 - OR $n < $this->current_row) - { - // No such row exists - return array(); - } - - // Get the next row index that would actually need to be fetched - $current_row = ($this->current_row < count($this->row_data)) ? count($this->row_data) : $this->current_row + 1; - } - else - { - $current_row = $this->current_row = 0; - $this->row_data = array(); - } - - /* Fetch more data, if available - * - * NOTE: Operator precedence is important here, if you change - * 'AND' with '&&' - it WILL BREAK the results, as - * $row will be assigned the scalar value of both - * expressions! - */ - while ($row = $this->_fetch_assoc() AND $current_row <= $n) - { - $this->row_data[$current_row++] = $row; - } - - // This would mean that there's no (more) data to fetch - if ( ! is_array($this->row_data) OR ! isset($this->row_data[$n])) - { - // Cache what we already have - if (is_array($this->row_data)) - { - $this->num_rows = count($this->row_data); - /* Usually, row_data could have less elements than result_array, - * but at this point - they should be exactly the same. - */ - $this->result_array = $this->row_data; - } - else - { - $this->num_rows = 0; - } - - return array(); - } - - $this->current_row = $n; - return $this->row_data[$n]; - } - - // -------------------------------------------------------------------- - - /* Single row result. Object version. - * - * @param int row index - * @return mixed object if row found; empty array if not - */ - public function row_object($n = 0) + protected function _fetch_object($class_name = 'stdClass') { - // Make sure $n is not a string - if ( ! is_int($n)) - { - $n = (int) $n; - } - /* Logic here is exactly the same as in row_array, - * except we have to cast row_data[$n] to an object. - * - * If we already have result_object though - we can - * directly return from it. - */ - if (isset($this->result_object[$n])) - { - $this->current_row = $n; - // Set this, if not already done. - if ( ! is_int($this->num_rows)) - { - $this->num_rows = count($this->result_object); - } - - return $this->result_object[$n]; - } + $row = ($this->curs_id) + ? oci_fetch_object($this->curs_id) + : oci_fetch_object($this->stmt_id); - $row = $this->row_array($n); - // Cast only if the row exists - if (count($row) > 0) - { - $this->current_row = $n; - return (object) $row; - } - - return array(); - } - - // -------------------------------------------------------------------- - - /* Single row result. Custom object version. - * - * @param int row index - * @param string custom class name - * @return mixed custom object if row found; empty array otherwise - */ - public function custom_row_object($n = 0, $class_name) - { - // Make sure $n is not a string - if ( ! is_int($n)) - { - $n = (int) $n; - } - - if (array_key_exists($class_name, $this->custom_result_object)) - { - /* We already have a the whole result set with this class_name, - * return the specified row if it exists, and an empty array if - * it doesn't. - */ - if (isset($this->custom_result_object[$class_name][$n])) - { - $this->current_row = $n; - return $this->custom_result_object[$class_name][$n]; - } - else - { - return array(); - } - } - elseif ( ! class_exists($class_name)) // No such class exists - { - return array(); - } - - $row = $this->row_array($n); - // An array would mean that the row doesn't exist - if (is_array($row)) + if ($class_name === 'stdClass' OR ! $row) { return $row; } - // Convert to the desired class and return - $row_object = new $class_name(); + $class_name = new $class_name(); foreach ($row as $key => $value) { - $row_object->$key = $value; + $class_name->$key = $value; } - $this->current_row = $n; - return $row_object; - } - - // -------------------------------------------------------------------- - - /* First row result. - * - * @param string ('object', 'array' or a custom class name) - * @return mixed whatever was passed to the second parameter - */ - public function first_row($type = 'object') - { - return $this->row(0, $type); - } - - // -------------------------------------------------------------------- - - /* Last row result. - * - * @param string ('object', 'array' or a custom class name) - * @return mixed whatever was passed to the second parameter - */ - public function last_row($type = 'object') - { - $result = &$this->result($type); - if ( ! isset($this->num_rows)) - { - $this->num_rows = count($result); - } - $this->current_row = $this->num_rows - 1; - return $result[$this->current_row]; - } - - // -------------------------------------------------------------------- - - /* Next row result. - * - * @param string ('object', 'array' or a custom class name) - * @return mixed whatever was passed to the second parameter - */ - public function next_row($type = 'object') - { - if (is_array($this->row_data)) - { - $count = count($this->row_data); - if ($this->current_row > $count OR ($this->current_row === 0 && $count === 0)) - { - $n = $count; - } - else - { - $n = $this->current_row + 1; - } - } - else - { - $n = 0; - } - - return $this->row($n, $type); - } - - // -------------------------------------------------------------------- - - /* Previous row result. - * - * @param string ('object', 'array' or a custom class name) - * @return mixed whatever was passed to the second parameter - */ - public function previous_row($type = 'object') - { - $n = ($this->current_row !== 0) ? $this->current_row - 1 : 0; - return $this->row($n, $type); + return $class_name; } // -------------------------------------------------------------------- @@ -658,9 +237,10 @@ class CI_DB_oci8_result extends CI_DB_result { * some point in the future, but it will only work for resetting the * pointer to zero. * + * @param int $n (ignored) * @return bool */ - protected function _data_seek() + protected function _data_seek($n = 0) { /* The PHP manual says that if OCI_NO_AUTO_COMMIT mode * is used, and oci_rollback() and/or oci_commit() are diff --git a/system/database/drivers/oci8/oci8_utility.php b/system/database/drivers/oci8/oci8_utility.php index 0183eda26..d15537fdf 100644 --- a/system/database/drivers/oci8/oci8_utility.php +++ b/system/database/drivers/oci8/oci8_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Oracle Utility Class @@ -34,18 +35,23 @@ */ class CI_DB_oci8_utility extends CI_DB_utility { + /** + * List databases statement + * + * @var string + */ protected $_list_databases = 'SELECT username FROM dba_users'; // Schemas are actual usernames /** - * Oracle Export + * Export * - * @param array Preferences + * @param array $params Preferences * @return mixed */ protected function _backup($params = array()) { // Currently unsupported - return $this->db->display_error('db_unsuported_feature'); + return $this->db->display_error('db_unsupported_feature'); } } diff --git a/system/database/drivers/odbc/odbc_driver.php b/system/database/drivers/odbc/odbc_driver.php index 38416cf90..a01a9d681 100644 --- a/system/database/drivers/odbc/odbc_driver.php +++ b/system/database/drivers/odbc/odbc_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,12 +24,13 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * ODBC Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -40,36 +41,66 @@ */ class CI_DB_odbc_driver extends CI_DB { + /** + * Database driver + * + * @var string + */ public $dbdriver = 'odbc'; - // the character used to excape - not necessary for ODBC + /** + * Database schema + * + * @var string + */ + public $schema = 'public'; + + // -------------------------------------------------------------------- + + /** + * Identifier escape character + * + * Must be empty for ODBC. + * + * @var string + */ protected $_escape_char = ''; - // clause and character used for LIKE escape sequences + /** + * ESCAPE statement string + * + * @var string + */ protected $_like_escape_str = " {escape '%s'} "; - protected $_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. + * ORDER BY random keyword + * + * @var array */ - protected $_count_string = 'SELECT COUNT(*) AS '; - protected $_random_keyword; + protected $_random_keyword = array('RND()', 'RND(%d)'); + + // -------------------------------------------------------------------- + /** + * Class constructor + * + * @param array $params + * @return void + */ public function __construct($params) { parent::__construct($params); - $this->_random_keyword = ' RND('.time().')'; // database specific random keyword - // Legacy support for DSN in the hostname field - if ($this->dsn == '') + if (empty($this->dsn)) { $this->dsn = $this->hostname; } } + // -------------------------------------------------------------------- + /** * Non-persistent database connection * @@ -97,7 +128,7 @@ class CI_DB_odbc_driver extends CI_DB { /** * Execute the query * - * @param string an SQL query + * @param string $sql an SQL query * @return resource */ protected function _execute($sql) @@ -110,17 +141,13 @@ class CI_DB_odbc_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -128,7 +155,7 @@ class CI_DB_odbc_driver extends CI_DB { // 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->_trans_failure = ($test_mode === TRUE); return odbc_autocommit($this->conn_id, FALSE); } @@ -142,13 +169,8 @@ class CI_DB_odbc_driver extends CI_DB { */ 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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -167,13 +189,8 @@ class CI_DB_odbc_driver extends CI_DB { */ 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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -188,8 +205,8 @@ class CI_DB_odbc_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -204,7 +221,6 @@ class CI_DB_odbc_driver extends CI_DB { return $str; } - // ODBC doesn't require escaping $str = remove_invisible_characters($str); // escape LIKE condition wildcards @@ -239,37 +255,7 @@ class CI_DB_odbc_driver extends CI_DB { */ public function insert_id() { - return ($this->db->db_debug) ? $this->db->display_error('db_unsuported_feature') : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @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->num_rows() == 0) - { - return 0; - } - - $row = $query->row(); - $this->_reset_select(); - return (int) $row->numrows; + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; } // -------------------------------------------------------------------- @@ -279,17 +265,17 @@ class CI_DB_odbc_driver extends CI_DB { * * Generates a platform-specific query string so that the table names can be fetched * - * @param bool + * @param bool $prefix_limit * @return string */ protected function _list_tables($prefix_limit = FALSE) { - $sql = "SHOW TABLES FROM `".$this->database."`"; + $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = '".$this->schema."'"; - if ($prefix_limit !== FALSE AND $this->dbprefix != '') + if ($prefix_limit !== FALSE && $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." AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' " + .sprintf($this->_like_escape_str, $this->_like_escape_chr); } return $sql; @@ -302,12 +288,12 @@ class CI_DB_odbc_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @param string the table name + * @param string $table * @return string */ protected function _list_columns($table = '') { - return "SHOW COLUMNS FROM ".$table; + return 'SHOW COLUMNS FROM '.$table; } // -------------------------------------------------------------------- @@ -317,12 +303,12 @@ class CI_DB_odbc_driver extends CI_DB { * * Generates a platform-specific query so that the column data can be retrieved * - * @param string the table name + * @param string $table * @return string */ protected function _field_data($table) { - return "SELECT TOP 1 FROM ".$table; + return 'SELECT TOP 1 FROM '.$table; } // -------------------------------------------------------------------- @@ -343,22 +329,19 @@ class CI_DB_odbc_driver extends CI_DB { // -------------------------------------------------------------------- /** - * From Tables + * Update statement * - * This function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards + * Generates a platform-specific update string from the supplied data * - * @param array + * @param string $table + * @param array $values * @return string - */ - protected function _from_tables($tables) + */ + protected function _update($table, $values) { - if ( ! is_array($tables)) - { - $tables = array($tables); - } - - return '('.implode(', ', $tables).')'; + $this->qb_limit = FALSE; + $this->qb_orderby = array(); + return parent::_update($table, $values); } // -------------------------------------------------------------------- @@ -368,10 +351,10 @@ class CI_DB_odbc_driver extends CI_DB { * * Generates a platform-specific truncate string from the supplied data * - * If the database does not support the truncate() command, + * If the database does not support the TRUNCATE statement, * then this method maps to 'DELETE FROM table' * - * @param string the table name + * @param string $table * @return string */ protected function _truncate($table) @@ -382,19 +365,17 @@ class CI_DB_odbc_driver extends CI_DB { // -------------------------------------------------------------------- /** - * Limit string + * Delete statement * - * Generates a platform-specific LIMIT clause + * Generates a platform-specific delete string from the supplied data * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value + * @param string $table * @return string */ - protected function _limit($sql, $limit, $offset) + protected function _delete($table) { - // Does ODBC doesn't use the LIMIT clause? - return $sql; + $this->qb_limit = FALSE; + return parent::_delete($table); } // -------------------------------------------------------------------- @@ -402,12 +383,11 @@ class CI_DB_odbc_driver extends CI_DB { /** * Close DB Connection * - * @param resource * @return void */ - protected function _close($conn_id) + protected function _close() { - @odbc_close($conn_id); + @odbc_close($this->conn_id); } } diff --git a/system/database/drivers/odbc/odbc_forge.php b/system/database/drivers/odbc/odbc_forge.php index d59b8a911..fb16ca5cf 100644 --- a/system/database/drivers/odbc/odbc_forge.php +++ b/system/database/drivers/odbc/odbc_forge.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * ODBC Forge Class @@ -34,163 +35,39 @@ */ class CI_DB_odbc_forge extends CI_DB_forge { - protected $_drop_database = 'DROP DATABASE %s'; - protected $_drop_table = 'DROP TABLE %s'; - /** - * Create Table + * CREATE TABLE IF statement * - * @param string the table name - * @param array the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return bool + * @var string */ - protected 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) . ")"; - } - } + protected $_create_table_if = FALSE; - $sql .= "\n)"; + /** + * DROP TABLE IF statement + * + * @var string + */ + protected $_drop_table_if = FALSE; - return $sql; - } + /** + * UNSIGNED support + * + * @var bool|array + */ + protected $_unsigned = 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(), + * Field attribute AUTO_INCREMENT * - * @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 bool should 'NOT NULL' be added - * @param string the field after which we should add the new field - * @return string + * @param array &$attributes + * @param array &$field + * @return void */ - protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + protected function _attr_auto_increment(&$attributes, &$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 != '') - { - return $sql.' AFTER '.$this->db->protect_identifiers($after_field); - } - - return $sql; - + // Not supported (in most databases at least) } } diff --git a/system/database/drivers/odbc/odbc_result.php b/system/database/drivers/odbc/odbc_result.php index ecba5977e..2c50c255b 100644 --- a/system/database/drivers/odbc/odbc_result.php +++ b/system/database/drivers/odbc/odbc_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * ODBC Result Class @@ -33,11 +34,10 @@ * @category Database * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ + * @since 1.3 */ class CI_DB_odbc_result extends CI_DB_result { - public $num_rows; - /** * Number of rows in the result set * @@ -49,14 +49,22 @@ class CI_DB_odbc_result extends CI_DB_result { { return $this->num_rows; } + elseif (($this->num_rows = @odbc_num_rows($this->result_id)) !== -1) + { + return $this->num_rows; + } // Work-around for ODBC subdrivers that don't support num_rows() - if (($this->num_rows = @odbc_num_rows($this->result_id)) === -1) + if (count($this->result_array) > 0) { - $this->num_rows = count($this->result_array()); + return $this->num_rows = count($this->result_array); + } + elseif (count($this->result_object) > 0) + { + return $this->num_rows = count($this->result_object); } - return $this->num_rows; + return $this->num_rows = count($this->result_array()); } // -------------------------------------------------------------------- @@ -148,14 +156,7 @@ class CI_DB_odbc_result extends CI_DB_result { */ protected function _fetch_assoc() { - if (function_exists('odbc_fetch_array')) - { - return odbc_fetch_array($this->result_id); - } - else - { - return $this->_odbc_fetch_array($this->result_id); - } + return odbc_fetch_array($this->result_id); } // -------------------------------------------------------------------- @@ -165,141 +166,93 @@ class CI_DB_odbc_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @return object */ - protected function _fetch_object() + protected function _fetch_object($class_name = 'stdClass') { - if (function_exists('odbc_fetch_object')) - { - return odbc_fetch_object($this->result_id); - } - else + $row = odbc_fetch_object($this->result_id); + + if ($class_name === 'stdClass' OR ! $row) { - return $this->_odbc_fetch_object($this->result_id); + return $row; } - } - - // -------------------------------------------------------------------- - /** - * Result - object - * - * subsititutes the odbc_fetch_object function when - * not available (odbc_fetch_object requires unixODBC) - * - * @return object - */ - protected function _odbc_fetch_object(& $odbc_result) - { - $rs = array(); - $rs_obj = FALSE; - if (odbc_fetch_into($odbc_result, $rs)) + $class_name = new $class_name(); + foreach ($row as $key => $value) { - foreach ($rs as $k => $v) - { - $field_name = odbc_field_name($odbc_result, $k+1); - $rs_obj->$field_name = $v; - } + $class_name->$key = $value; } - return $rs_obj; + + return $class_name; } - // -------------------------------------------------------------------- +} + +// -------------------------------------------------------------------- +if ( ! function_exists('odbc_fetch_array')) +{ /** - * Result - array + * ODBC Fetch array * - * subsititutes the odbc_fetch_array function when - * not available (odbc_fetch_array requires unixODBC) + * Emulates the native odbc_fetch_array() function when + * it is not available (odbc_fetch_array() requires unixODBC) * + * @param resource &$result + * @param int $rownumber * @return array */ - protected function _odbc_fetch_array(& $odbc_result) + function odbc_fetch_array(&$result, $rownumber = 1) { $rs = array(); - $rs_assoc = FALSE; - if (odbc_fetch_into($odbc_result, $rs)) + if ( ! odbc_fetch_into($result, $rs, $rownumber)) { - $rs_assoc = array(); - foreach ($rs as $k => $v) - { - $field_name = odbc_field_name($odbc_result, $k+1); - $rs_assoc[$field_name] = $v; - } + return FALSE; } - return $rs_assoc; - } - // -------------------------------------------------------------------- - - /** - * Query result. Array version. - * - * @return array - */ - public function result_array() - { - if (count($this->result_array) > 0) - { - return $this->result_array; - } - elseif (($c = count($this->result_object)) > 0) - { - for ($i = 0; $i < $c; $i++) - { - $this->result_array[$i] = (array) $this->result_object[$i]; - } - } - elseif ($this->result_id === FALSE) + $rs_assoc = array(); + foreach ($rs as $k => $v) { - return array(); - } - else - { - while ($row = $this->_fetch_assoc()) - { - $this->result_array[] = $row; - } + $field_name = odbc_field_name($result, $k+1); + $rs_assoc[$field_name] = $v; } - return $this->result_array; + return $rs_assoc; } +} - // -------------------------------------------------------------------- +// -------------------------------------------------------------------- +if ( ! function_exists('odbc_fetch_object')) +{ /** - * Query result. Object version. + * ODBC Fetch object * - * @return array + * Emulates the native odbc_fetch_object() function when + * it is not available. + * + * @param resource &$result + * @param int $rownumber + * @return object */ - public function result_object() + function odbc_fetch_object(&$result, $rownumber = 1) { - if (count($this->result_object) > 0) - { - return $this->result_object; - } - elseif (($c = count($this->result_array)) > 0) - { - for ($i = 0; $i < $c; $i++) - { - $this->result_object[$i] = (object) $this->result_array[$i]; - } - } - elseif ($this->result_id === FALSE) + $rs = array(); + if ( ! odbc_fetch_into($result, $rs, $rownumber)) { - return array(); + return FALSE; } - else + + $rs_object = new stdClass(); + foreach ($rs as $k => $v) { - while ($row = $this->_fetch_object()) - { - $this->result_object[] = $row; - } + $field_name = odbc_field_name($result, $k+1); + $rs_object->$field_name = $v; } - return $this->result_object; + return $rs_object; } - } /* End of file odbc_result.php */ diff --git a/system/database/drivers/odbc/odbc_utility.php b/system/database/drivers/odbc/odbc_utility.php index 224d48d2b..908674a9d 100644 --- a/system/database/drivers/odbc/odbc_utility.php +++ b/system/database/drivers/odbc/odbc_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * ODBC Utility Class @@ -34,18 +35,16 @@ */ class CI_DB_odbc_utility extends CI_DB_utility { - protected $_list_databases = FALSE; - /** - * ODBC Export + * Export * - * @param array Preferences + * @param array $params Preferences * @return mixed */ protected function _backup($params = array()) { // Currently unsupported - return $this->db->display_error('db_unsuported_feature'); + return $this->db->display_error('db_unsupported_feature'); } } diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php index 60151b900..923f0e125 100644 --- a/system/database/drivers/pdo/pdo_driver.php +++ b/system/database/drivers/pdo/pdo_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,12 +24,13 @@ * @since Version 2.1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * PDO Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -40,159 +41,103 @@ */ class CI_DB_pdo_driver extends CI_DB { + /** + * Database driver + * + * @var string + */ public $dbdriver = 'pdo'; - // the character used to excape - not necessary for PDO - protected $_escape_char = ''; - - // clause and character used for LIKE escape sequences - protected $_like_escape_str = " ESCAPE '%s' "; - protected $_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. + * Transaction enabled flag + * + * @var bool */ - protected $_count_string = 'SELECT COUNT(*) AS '; - protected $_random_keyword; + public $trans_enabled = FALSE; - // need to track the pdo driver and options - public $pdodriver; + /** + * PDO Options + * + * @var array + */ public $options = array(); + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Validates the DSN string and/or detects the subdriver. + * + * @param array $params + * @return void + */ public function __construct($params) { parent::__construct($params); - if (preg_match('/([^;]+):/', $this->dsn, $match) && count($match) == 2) + if (preg_match('/([^;]+):/', $this->dsn, $match) && count($match) === 2) { // If there is a minimum valid dsn string pattern found, we're done // This is for general PDO users, who tend to have a full DSN string. - $this->pdodriver = end($match); + $this->subdriver = $match[1]; + return; } - else + // Legacy support for DSN specified in the hostname field + elseif (preg_match('/([^;]+):/', $this->hostname, $match) && count($match) === 2) { - // Try to build a complete DSN string from params - $this->_connect_string($params); + $this->dsn = $this->hostname; + $this->hostname = NULL; + $this->subdriver = $match[1]; + return; } - - // clause and character used for LIKE escape sequences - // this one depends on the driver being used - if ($this->pdodriver == 'mysql') + elseif (in_array($this->subdriver, array('mssql', 'sybase'), TRUE)) { - $this->_escape_char = '`'; - $this->_like_escape_str = ''; - $this->_like_escape_chr = ''; + $this->subdriver = 'dblib'; } - elseif ($this->pdodriver == 'odbc') + elseif ($this->subdriver === '4D') { - $this->_like_escape_str = " {escape '%s'} "; + $this->subdriver = '4d'; } - elseif ( ! in_array($this->pdodriver, array('sqlsrv', 'mssql', 'dblib', 'sybase'))) + elseif ( ! in_array($this->subdriver, array('4d', 'cubrid', 'dblib', 'firebird', 'ibm', 'informix', 'mysql', 'oci', 'odbc', 'sqlite', 'sqlsrv'), TRUE)) { - $this->_escape_char = '"'; + log_message('error', 'PDO: Invalid or non-existent subdriver'); + + if ($this->db_debug) + { + show_error('Invalid or non-existent PDO subdriver'); + } } - $this->trans_enabled = FALSE; - $this->_random_keyword = ' RND('.time().')'; // database specific random keyword + $this->dsn = NULL; } + // -------------------------------------------------------------------- + /** - * Connection String + * Database connection * - * @param array - * @return void + * @param bool $persistent + * @return object */ - protected function _connect_string($params) + public function db_connect($persistent = FALSE) { - if (strpos($this->hostname, ':')) + $this->options[PDO::ATTR_PERSISTENT] = $persistent; + + // Connecting... + try { - // hostname generally would have this prototype - // $db['hostname'] = 'pdodriver:host(/Server(/DSN))=hostname(/DSN);'; - // We need to get the prefix (pdodriver used by PDO). - $dsnarray = explode(':', $this->hostname); - $this->pdodriver = $dsnarray[0]; - - // End dsn with a semicolon for extra backward compability - // if database property was not empty. - if ( ! empty($this->database)) - { - $this->dsn .= rtrim($this->hostname, ';').';'; - } + return @new PDO($this->dsn, $this->username, $this->password, $this->options); } - else + catch (PDOException $e) { - // Invalid DSN, display an error - if ( ! array_key_exists('pdodriver', $params)) - { - show_error('Invalid DB Connection String for PDO'); - } - - // Assuming that the following DSN string format is used: - // $dsn = 'pdo://username:password@hostname:port/database?pdodriver=pgsql'; - $this->dsn = $this->pdodriver.':'; - - // Add hostname to the DSN for databases that need it - if ( ! empty($this->hostname) - && strpos($this->hostname, ':') === FALSE - && in_array($this->pdodriver, array('informix', 'mysql', 'pgsql', 'sybase', 'mssql', 'dblib', 'cubrid'))) + if ($this->db_debug && empty($this->failover)) { - $this->dsn .= 'host='.$this->hostname.';'; + $this->display_error($e->getMessage(), '', TRUE); } - // Add a port to the DSN for databases that can use it - if ( ! empty($this->port) && in_array($this->pdodriver, array('informix', 'mysql', 'pgsql', 'ibm', 'cubrid'))) - { - $this->dsn .= 'port='.$this->port.';'; - } + return FALSE; } - - // Add the database name to the DSN, if needed - if (stripos($this->dsn, 'dbname') === FALSE - && in_array($this->pdodriver, array('4D', 'pgsql', 'mysql', 'firebird', 'sybase', 'mssql', 'dblib', 'cubrid'))) - { - $this->dsn .= 'dbname='.$this->database.';'; - } - elseif (stripos($this->dsn, 'database') === FALSE && in_array($this->pdodriver, array('ibm', 'sqlsrv'))) - { - if (stripos($this->dsn, 'dsn') === FALSE) - { - $this->dsn .= 'database='.$this->database.';'; - } - } - elseif ($this->pdodriver === 'sqlite' && $this->dsn === 'sqlite:') - { - if ($this->database !== ':memory') - { - if ( ! file_exists($this->database)) - { - show_error('Invalid DB Connection string for PDO SQLite'); - } - - $this->dsn .= (strpos($this->database, DIRECTORY_SEPARATOR) !== 0) ? DIRECTORY_SEPARATOR : ''; - } - - $this->dsn .= $this->database; - } - - // Add charset to the DSN, if needed - if ( ! empty($this->char_set) && in_array($this->pdodriver, array('4D', 'mysql', 'sybase', 'mssql', 'dblib', 'oci'))) - { - $this->dsn .= 'charset='.$this->char_set.';'; - } - } - - // -------------------------------------------------------------------- - - /** - * Non-persistent database connection - * - * @return object - */ - public function db_connect() - { - return $this->_pdo_connect(); } // -------------------------------------------------------------------- @@ -204,69 +149,44 @@ class CI_DB_pdo_driver extends CI_DB { */ public function db_pconnect() { - return $this->_pdo_connect(TRUE); + return $this->db_connect(TRUE); } // -------------------------------------------------------------------- /** - * PDO connection + * Database version number * - * @param bool - * @return object + * @return string */ - protected function _pdo_connect($persistent = FALSE) + public function version() { - $this->options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_SILENT; - $persistent === FALSE OR $this->options[PDO::ATTR_PERSISTENT] = TRUE; - - /* Prior to PHP 5.3.6, even if the charset was supplied in the DSN - * on connect - it was ignored. This is a work-around for the issue. - * - * Reference: http://www.php.net/manual/en/ref.pdo-mysql.connection.php - */ - if ($this->subdriver === 'mysql' && ! is_php('5.3.6') && ! empty($this->char_set)) + if (isset($this->data_cache['version'])) + { + return $this->data_cache['version']; + } + elseif ( ! $this->conn_id) { - $this->options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$this->char_set - .( ! empty($this->db_collat) ? " COLLATE '".$this->dbcollat."'" : ''); + $this->initialize(); } - // Connecting... + // Not all subdrivers support the getAttribute() method try { - return new PDO($this->dsn, $this->username, $this->password, $this->options); + return $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION); } catch (PDOException $e) { - if ($this->db_debug && empty($this->failover)) - { - $this->display_error($e->getMessage(), '', TRUE); - } - - return FALSE; + return parent::version(); } } // -------------------------------------------------------------------- /** - * Database version number - * - * @return string - */ - public function version() - { - return isset($this->data_cache['version']) - ? $this->data_cache['version'] - : $this->data_cache['version'] = $this->conn_id->getAttribute(PDO::ATTR_SERVER_VERSION); - } - - // -------------------------------------------------------------------- - - /** * Execute the query * - * @param string an SQL query + * @param string $sql SQL query * @return mixed */ protected function _execute($sql) @@ -279,6 +199,7 @@ class CI_DB_pdo_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @return bool */ public function trans_begin($test_mode = FALSE) @@ -338,8 +259,8 @@ class CI_DB_pdo_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -358,7 +279,7 @@ class CI_DB_pdo_driver extends CI_DB { $str = $this->conn_id->quote($str); // If there are duplicated quotes, trim them away - if (strpos($str, "'") === 0) + if ($str[0] === "'") { $str = substr($str, 1, -1); } @@ -391,132 +312,27 @@ class CI_DB_pdo_driver extends CI_DB { /** * Insert ID * - * @param string + * @param string $name * @return int */ public function insert_id($name = NULL) { - if ($this->pdodriver === 'pgsql' && $name === NULL && $this->version() >= '8.1') - { - $query = $this->query('SELECT LASTVAL() AS ins_id'); - $query = $query->row(); - return $query->ins_id; - } - return $this->conn_id->lastInsertId($name); } // -------------------------------------------------------------------- /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @param string - * @return string - */ - public function count_all($table = '') - { - if ($table == '') - { - return 0; - } - - $sql = $this->_count_string.$this->protect_identifiers('numrows').' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE); - $query = $this->query($sql); - - 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 - * - * @param bool - * @return string - */ - protected function _list_tables($prefix_limit = FALSE) - { - if ($this->pdodriver == 'pgsql') - { - // Analog function to show all tables in postgre - $sql = "SELECT * FROM information_schema.tables WHERE table_schema = 'public'"; - } - elseif ($this->pdodriver == 'sqlite') - { - // Analog function to show all tables in sqlite - $sql = "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'"; - } - else - { - $sql = 'SHOW TABLES FROM '.$this->escape_identifiers($this->database); - } - - if ($prefix_limit !== FALSE AND $this->dbprefix != '') - { - return FALSE; - } - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Show column query - * - * Generates a platform-specific query string so that the column names can be fetched - * - * @param string the table name - * @return string - */ - protected function _list_columns($table = '') - { - return 'SHOW COLUMNS FROM '.$this->escape_identifiers($table); - } - - // -------------------------------------------------------------------- - - /** * Field data query * * Generates a platform-specific query so that the column data can be retrieved * - * @param string the table name + * @param string $table * @return string */ protected function _field_data($table) { - if ($this->pdodriver == 'mysql' or $this->pdodriver == 'pgsql') - { - // Analog function for mysql and postgre - return 'SELECT * FROM '.$this->escape_identifiers($table).' LIMIT 1'; - } - elseif ($this->pdodriver == 'oci') - { - // Analog function for oci - return 'SELECT * FROM '.$this->escape_identifiers($table).' WHERE ROWNUM <= 1'; - } - elseif ($this->pdodriver == 'sqlite') - { - // Analog function for sqlite - return 'PRAGMA table_info('.$this->escape_identifiers($table).')'; - } - - return 'SELECT TOP 1 FROM '.$this->escape_identifiers($table); + return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table); } // -------------------------------------------------------------------- @@ -551,57 +367,32 @@ class CI_DB_pdo_driver extends CI_DB { // -------------------------------------------------------------------- /** - * From Tables - * - * This function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards - * - * @param array - * @return string - */ - protected function _from_tables($tables) - { - if ( ! is_array($tables)) - { - $tables = array($tables); - } - - return (count($tables) === 1) ? $tables[0] : '('.implode(', ', $tables).')'; - } - - // -------------------------------------------------------------------- - - /** * Update_Batch statement * * Generates a platform-specific batch update string from the supplied data * - * @param string the table name - * @param array the update data - * @param array the where clause + * @param string $table Table name + * @param array $values Update data + * @param string $index WHERE key * @return string */ - protected function _update_batch($table, $values, $index, $where = NULL) + protected function _update_batch($table, $values, $index) { - $ids = array(); - $where = ($where != '' && count($where) >=1) ? implode(" ", $where).' AND ' : ''; - + $ids = array(); foreach ($values as $key => $val) { $ids[] = $val[$index]; foreach (array_keys($val) as $field) { - if ($field != $index) + 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"; @@ -614,10 +405,9 @@ class CI_DB_pdo_driver extends CI_DB { $cases .= 'ELSE '.$k.' END, '; } - $sql .= substr($cases, 0, -2); - $sql .= ' WHERE '.$where.$index.' IN ('.implode(',', $ids).')'; + $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); - return $sql; + return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); } // -------------------------------------------------------------------- @@ -627,57 +417,15 @@ class CI_DB_pdo_driver extends CI_DB { * * Generates a platform-specific truncate string from the supplied data * - * If the database does not support the truncate() command, + * If the database does not support the TRUNCATE statement, * then this method maps to 'DELETE FROM table' * - * @param string the table name + * @param string $table * @return string */ protected function _truncate($table) { - return 'DELETE FROM '.$table; - } - - // -------------------------------------------------------------------- - - /** - * Limit string - * - * Generates a platform-specific LIMIT clause - * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value - * @return string - */ - protected function _limit($sql, $limit, $offset) - { - if ($this->pdodriver == 'cubrid' OR $this->pdodriver == 'sqlite') - { - $offset = ($offset == 0) ? '' : $offset.', '; - - return $sql.'LIMIT '.$offset.$limit; - } - else - { - $sql .= 'LIMIT '.$limit; - $sql .= ($offset > 0) ? ' OFFSET '.$offset : ''; - - return $sql; - } - } - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @param object - * @return void - */ - protected function _close($conn_id) - { - $this->conn_id = NULL; + return 'TRUNCATE TABLE '.$table; } } diff --git a/system/database/drivers/pdo/pdo_forge.php b/system/database/drivers/pdo/pdo_forge.php index ca8657a0f..130d3667e 100644 --- a/system/database/drivers/pdo/pdo_forge.php +++ b/system/database/drivers/pdo/pdo_forge.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 2.1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * PDO Forge Class @@ -34,169 +35,19 @@ */ class CI_DB_pdo_forge extends CI_DB_forge { - protected $_drop_database = 'DROP DATABASE %s'; - protected $_drop_table = 'DROP TABLE %s'; - /** - * Create Table + * CREATE TABLE IF statement * - * @param string the table name - * @param array the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return bool + * @var string */ - protected 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); - $numeric = array('SERIAL', 'INTEGER'); - - $sql .= "\n\t".$this->db->protect_identifiers($field); - - $sql .= ' '.$attributes['TYPE']; - - if (array_key_exists('CONSTRAINT', $attributes)) - { - // Exception for Postgre numeric which not too happy with constraint within those type - if ( ! ($this->db->pdodriver == 'pgsql' && in_array($attributes['TYPE'], $numeric))) - { - $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; - } - - // -------------------------------------------------------------------- + protected $_create_table_if = 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(), + * DROP TABLE IF statement * - * @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 bool should 'NOT NULL' be added - * @param string the field after which we should add the new field - * @return string + * @var string */ - protected 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 != '') - { - return $sql.' AFTER '.$this->db->protect_identifiers($after_field); - } - - return $sql; - - } + protected $_drop_table_if = FALSE; } diff --git a/system/database/drivers/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php index 19aee1dfc..32ab1c280 100644 --- a/system/database/drivers/pdo/pdo_result.php +++ b/system/database/drivers/pdo/pdo_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -21,9 +21,10 @@ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com - * @since Version 2.1.0 + * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * PDO Result Class @@ -33,77 +34,35 @@ * @category Database * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ + * @since 2.1 */ class CI_DB_pdo_result extends CI_DB_result { /** - * @var bool Hold the flag whether a result handler already fetched before - */ - protected $is_fetched = FALSE; - - /** - * @var mixed Hold the fetched assoc array of a result handler - */ - protected $result_assoc; - - /** * Number of rows in the result set * * @return int */ public function num_rows() { - if (empty($this->result_id) OR ! is_object($this->result_id)) + if (is_int($this->num_rows)) { - // invalid result handler - return 0; + return $this->num_rows; } - elseif (($num_rows = $this->result_id->rowCount()) && $num_rows > 0) + elseif (count($this->result_array) > 0) { - // If rowCount return something, we're done. - return $num_rows; + return $this->num_rows = count($this->result_array); } - - // Fetch the result, instead perform another extra query - return ($this->is_fetched && is_array($this->result_assoc)) ? count($this->result_assoc) : count($this->result_assoc()); - } - - /** - * Fetch the result handler - * - * @return mixed - */ - public function result_assoc() - { - // If the result already fetched before, use that one - if (count($this->result_array) > 0 OR $this->is_fetched) + elseif (count($this->result_object) > 0) { - return $this->result_array(); + return $this->num_rows = count($this->result_object); } - - // Define the output - $output = array('assoc', 'object'); - - // Fetch the result - foreach ($output as $type) + elseif (($num_rows = $this->result_id->rowCount()) > 0) { - // Define the method and handler - $res_method = '_fetch_'.$type; - $res_handler = 'result_'.$type; - - $this->$res_handler = array(); - - while ($row = $this->$res_method()) - { - $this->{$res_handler}[] = $row; - } + return $this->num_rows = $num_rows; } - // Save this as buffer and marked the fetch flag - $this->result_array = $this->result_assoc; - $this->is_fetched = TRUE; - - return $this->result_assoc; + return $this->num_rows = count($this->result_array()); } // -------------------------------------------------------------------- @@ -129,12 +88,14 @@ class CI_DB_pdo_result extends CI_DB_result { */ public function list_fields() { - if ($this->db->db_debug) + $field_names = array(); + for ($i = 0, $c = $this->num_fields(); $i < $c; $i++) { - return $this->db->display_error('db_unsuported_feature'); + $field_names[$i] = @$this->result_id->getColumnMeta(); + $field_names[$i] = $field_names[$i]['name']; } - return FALSE; + return $field_names; } // -------------------------------------------------------------------- @@ -202,7 +163,7 @@ class CI_DB_pdo_result extends CI_DB_result { { if ($this->db->db_debug) { - return $this->db->display_error('db_unsuported_feature'); + return $this->db->display_error('db_unsupported_feature'); } return FALSE; @@ -245,11 +206,12 @@ class CI_DB_pdo_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @return object */ - protected function _fetch_object() + protected function _fetch_object($class_name = 'stdClass') { - return $this->result_id->fetchObject(); + return $this->result_id->fetchObject($class_name); } } diff --git a/system/database/drivers/pdo/pdo_utility.php b/system/database/drivers/pdo/pdo_utility.php index 930842118..86f2b120a 100644 --- a/system/database/drivers/pdo/pdo_utility.php +++ b/system/database/drivers/pdo/pdo_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 2.1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * PDO Utility Class @@ -34,18 +35,16 @@ */ class CI_DB_pdo_utility extends CI_DB_utility { - protected $_list_databases = FALSE; - /** - * PDO Export + * Export * - * @param array Preferences + * @param array $params Preferences * @return mixed */ protected function _backup($params = array()) { // Currently unsupported - return $this->db->display_error('db_unsuported_feature'); + return $this->db->display_error('db_unsupported_feature'); } } diff --git a/system/database/drivers/pdo/subdrivers/index.html b/system/database/drivers/pdo/subdrivers/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/index.html @@ -0,0 +1,10 @@ +<html> +<head> + <title>403 Forbidden</title> +</head> +<body> + +<p>Directory access is forbidden.</p> + +</body> +</html>
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php b/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php new file mode 100644 index 000000000..6ebd92a9b --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_4d_driver.php @@ -0,0 +1,192 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO 4D Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_4d_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = '4d'; + + /** + * Identifier escape character + * + * @var string[] + */ + protected $_escape_char = array('[', ']'); + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = '4D:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); + + empty($this->port) OR $this->dsn .= ';port='.$this->port; + empty($this->database) OR $this->dsn .= ';dbname='.$this->database; + empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; + } + elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 3) === FALSE) + { + $this->dsn .= ';charset='.$this->char_set; + } + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + $sql = 'SELECT '.$this->escape_identifiers('TABLE_NAME').' FROM '.$this->escape_identifiers('_USER_TABLES'); + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + $sql .= ' WHERE '.$this->escape_identifiers('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 + * + * @param string $table + * @return string + */ + protected function _list_columns($table = '') + { + return 'SELECT '.$this->escape_identifiers('COLUMN_NAME').' FROM '.$this->escape_identifiers('_USER_COLUMNS') + .' WHERE '.$this->escape_identifiers('TABLE_NAME').' = '.$this->escape($table); + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @param string $table + * @return string + */ + protected function _field_data($table) + { + return 'SELECT * FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE).' LIMIT 1'; + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @param string $table + * @param array $values + * @return string + */ + protected function _update($table, $values) + { + $this->qb_limit = FALSE; + $this->qb_orderby = array(); + return parent::_update($table, $values); + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @param string $table + * @return string + */ + protected function _delete($table) + { + $this->qb_limit = FALSE; + return parent::_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * LIMIT + * + * Generates a platform-specific LIMIT clause + * + * @param string $sql SQL Query + * @return string + */ + protected function _limit($sql) + { + return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : ''); + } + +} + +/* End of file pdo_4d_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_4d_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_4d_forge.php b/system/database/drivers/pdo/subdrivers/pdo_4d_forge.php new file mode 100644 index 000000000..231ad53a4 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_4d_forge.php @@ -0,0 +1,209 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO 4D Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_4d_forge extends CI_DB_4d_forge { + + /** + * CREATE DATABASE statement + * + * @var string + */ + protected $_create_database = 'CREATE SCHEMA %s'; + + /** + * DROP DATABASE statement + * + * @var string + */ + protected $_drop_database = 'DROP SCHEMA %s'; + + /** + * CREATE TABLE IF statement + * + * @var string + */ + protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS'; + + /** + * RENAME TABLE statement + * + * @var string + */ + protected $_rename_table = FALSE; + + /** + * DROP TABLE IF statement + * + * @var string + */ + protected $_drop_table_if = 'DROP TABLE IF EXISTS'; + + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'INT16' => 'INT', + 'SMALLINT' => 'INT', + 'INT' => 'INT64', + 'INT32' => 'INT64' + ); + + /** + * DEFAULT value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_default = FALSE; + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if (in_array($alter_type, array('ADD', 'DROP'), TRUE)) + { + return parent::_alter_table($alter_table, $table, $field); + } + + // No method of modifying columns is supported + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Process column + * + * @param array $field + * @return string + */ + protected function _process_column($field) + { + return $this->db->escape_identifiers($field['name']) + .' '.$field['type'].$field['length'] + .$field['null'] + .$field['unique'] + .$field['auto_increment']; + } + + // -------------------------------------------------------------------- + + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + switch (strtoupper($attributes['TYPE'])) + { + case 'TINYINT': + $attributes['TYPE'] = 'SMALLINT'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'INTEGER': + $attributes['TYPE'] = 'INT'; + return; + case 'BIGINT': + $attribites['TYPE'] = 'INT64'; + return; + default: return; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute UNIQUE + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_unique(&$attributes, &$field) + { + if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) + { + $field['unique'] = ' UNIQUE'; + + // UNIQUE must be used with NOT NULL + $field['null'] = ' NOT NULL'; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) + { + if (stripos($field['type'], 'int') !== FALSE) + { + $field['auto_increment'] = ' AUTO_INCREMENT'; + } + elseif (strcasecmp($field['type'], 'UUID') === 0) + { + $field['auto_increment'] = ' AUTO_GENERATE'; + } + } + } + +} + +/* End of file pdo_4d_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_4d_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php b/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php new file mode 100644 index 000000000..5a87cf0c7 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php @@ -0,0 +1,223 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO CUBRID Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_cubrid_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = 'cubrid'; + + /** + * Identifier escape character + * + * @var string + */ + protected $_escape_char = '`'; + + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('RANDOM()', 'RANDOM(%d)'); + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = 'cubrid:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); + + empty($this->port) OR $this->dsn .= ';port='.$this->port; + empty($this->database) OR $this->dsn .= ';dbname='.$this->database; + empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; + } + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + $sql = 'SHOW TABLES'; + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + return $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 + * + * @param string $table + * @return string + */ + protected 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 + * + * @param string $table + * @return string + */ + protected function _field_data($table) + { + return 'SELECT * FROM '.$this->protect_identifiers($table).' LIMIT 1'; + } + + // -------------------------------------------------------------------- + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @param string $table Table name + * @param array $values Update data + * @param string $index WHERE key + * @return string + */ + protected function _update_batch($table, $values, $index) + { + $ids = array(); + 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]; + } + } + } + + $cases = ''; + foreach ($final as $k => $v) + { + $cases .= $k." = CASE \n" + .implode("\n", $v)."\n" + .'ELSE '.$k.' END), '; + } + + $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); + + return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); + } + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * + * If the database does not support the TRUNCATE statement, + * then this method maps to 'DELETE FROM table' + * + * @param string $table + * @return string + */ + protected function _truncate($table) + { + return 'TRUNCATE '.$table; + } + + // -------------------------------------------------------------------- + + /** + * FROM tables + * + * Groups tables in FROM clauses if needed, so there is no confusion + * about operator precedence. + * + * @return string + */ + protected function _from_tables() + { + if ( ! empty($this->qb_join) && count($this->qb_from) > 1) + { + return '('.implode(', ', $this->qb_from).')'; + } + + return implode(', ', $this->qb_from); + } + +} + +/* End of file pdo_cubrid_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_cubrid_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_cubrid_forge.php b/system/database/drivers/pdo/subdrivers/pdo_cubrid_forge.php new file mode 100644 index 000000000..e8421ec41 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_cubrid_forge.php @@ -0,0 +1,212 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO CUBRID Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_cubrid_forge extends CI_DB_pdo_forge { + + /** + * CREATE DATABASE statement + * + * @var string + */ + protected $_create_database = FALSE; + + /** + * DROP DATABASE statement + * + * @var string + */ + protected $_drop_database = FALSE; + + /** + * CREATE TABLE keys flag + * + * Whether table keys are created from within the + * CREATE TABLE statement. + * + * @var bool + */ + protected $_create_table_keys = TRUE; + + /** + * DROP TABLE IF statement + * + * @var string + */ + protected $_drop_table_if = 'DROP TABLE IF EXISTS'; + + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'SHORT' => 'INTEGER', + 'SMALLINT' => 'INTEGER', + 'INT' => 'BIGINT', + 'INTEGER' => 'BIGINT', + 'BIGINT' => 'NUMERIC', + 'FLOAT' => 'DOUBLE', + 'REAL' => 'DOUBLE' + ); + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) + { + return parent::_alter_table($alter_type, $table, $field); + } + + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); + $sqls = array(); + for ($i = 0, $c = count($field); $i < $c; $i++) + { + if ($field[$i]['_literal'] !== FALSE) + { + $sqls[] = $sql.' CHANGE '.$field[$i]['_literal']; + } + else + { + $sqls[] = $sql.' CHANGE '.$this->_process_column($field[$i]); + if ( ! empty($field[$i]['new_name'])) + { + $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name']) + .' AS '.$this->db->escape_identifiers($field[$i]['name']); + } + } + } + + return $sqls; + } + + // -------------------------------------------------------------------- + + /** + * Process column + * + * @param array $field + * @return string + */ + protected function _process_column($field) + { + $extra_clause = isset($field['after']) + ? ' AFTER '.$this->db->escape_identifiers($field['after']) : ''; + + if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE) + { + $extra_clause = ' FIRST'; + } + + return $this->db->escape_identifiers($field['name']) + .(empty($field['new_name']) ? '' : $this->db->escape_identifiers($field['new_name'])) + .' '.$field['type'].$field['length'] + .$field['unsigned'] + .$field['null'] + .$field['default'] + .$field['auto_increment'] + .$field['unique'] + .$extra_clause; + } + + // -------------------------------------------------------------------- + + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + switch (strtoupper($attributes['TYPE'])) + { + case 'TINYINT': + $attributes['TYPE'] = 'SMALLINT'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + default: return; + } + } + + // -------------------------------------------------------------------- + + /** + * Process indexes + * + * @param string $table (ignored) + * @return string + */ + protected function _process_indexes($table = NULL) + { + $sql = ''; + + for ($i = 0, $c = count($this->keys); $i < $c; $i++) + { + if ( ! isset($this->fields[$this->keys[$i]])) + { + unset($this->keys[$i]); + continue; + } + + is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]); + + $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i])) + .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')'; + } + + $this->keys = array(); + + return $sql; + } + +} + +/* End of file pdo_cubrid_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_cubrid_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php new file mode 100644 index 000000000..a44fd3afc --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php @@ -0,0 +1,291 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO DBLIB Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_dblib_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = 'dblib'; + + // -------------------------------------------------------------------- + + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('NEWID()', 'RAND(%d)'); + + /** + * Quoted identifier flag + * + * Whether to use SQL-92 standard quoted identifier + * (double quotes) or brackets for identifier escaping. + * + * @var bool + */ + protected $_quoted_identifier; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = $params['subdriver'].':host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); + + if ( ! empty($this->port)) + { + $this->dsn .= (DIRECTORY_SEPARATOR === '\\' ? ',' : ':').$this->port; + } + + empty($this->database) OR $this->dsn .= ';dbname='.$this->database; + empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; + empty($this->appname) OR $this->dsn .= ';appname='.$this->appname; + } + else + { + if ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 6) === FALSE) + { + $this->dsn .= ';charset='.$this->char_set; + } + + $this->subdriver = 'dblib'; + } + } + + // -------------------------------------------------------------------- + + /** + * Database connection + * + * @param bool $persistent + * @return object + */ + public function db_connect($persistent = FALSE) + { + $this->conn_id = parent::db_connect($persistent); + + if ( ! is_object($this->conn_id)) + { + return $this->conn_id; + } + + // Determine how identifiers are escaped + $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi'); + $query = $query->row_array(); + $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi']; + $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']'); + + return $this->conn_id; + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + return 'SELECT '.$this->escape_identifiers('name') + .' FROM '.$this->escape_identifiers('sysobjects') + .' WHERE '.$this->escape_identifiers('type')." = 'U'"; + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' " + .sprintf($this->_like_escape_str, $this->_like_escape_chr); + } + + return $sql.' ORDER BY '.$this->escape_identifiers('name'); + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @param string $table + * @return string + */ + protected function _list_columns($table = '') + { + return 'SELECT '.$this->escape_identifiers('column_name') + .' FROM '.$this->escape_identifiers('information_schema.columns') + .' WHERE '.$this->escape_identifiers('table_name').' = '.$this->escape($table); + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @param string $table + * @param array $values + * @return string + */ + protected function _update($table, $values) + { + $this->qb_limit = FALSE; + $this->qb_orderby = array(); + return parent::_update($table, $values); + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @param string $table + * @return string + */ + protected function _delete($table) + { + if ($this->qb_limit) + { + return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete'; + } + + return parent::_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * LIMIT + * + * Generates a platform-specific LIMIT clause + * + * @param string $sql SQL Query + * @return string + */ + protected function _limit($sql) + { + $limit = $this->qb_offset + $this->qb_limit; + + // As of SQL Server 2005 (9.0.*) ROW_NUMBER() is supported, + // however an ORDER BY clause is required for it to work + if (version_compare($this->version(), '9', '>=') && $this->qb_offset && ! empty($this->qb_orderby)) + { + $orderby = $this->_compile_order_by(); + + // We have to strip the ORDER BY clause + $sql = trim(substr($sql, 0, strrpos($sql, $orderby))); + + // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results + if (count($this->qb_select) === 0) + { + $select = '*'; // Inevitable + } + else + { + // Use only field names and their aliases, everything else is out of our scope. + $select = array(); + $field_regexp = ($this->_quoted_identifier) + ? '("[^\"]+")' : '(\[[^\]]+\])'; + for ($i = 0, $c = count($this->qb_select); $i < $c; $i++) + { + $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m) + ? $m[1] : $this->qb_select[$i]; + } + $select = implode(', ', $select); + } + + return 'SELECT '.$select." FROM (\n\n" + .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql) + ."\n\n) ".$this->escape_identifiers('CI_subquery') + ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit; + } + + return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql); + } + + // -------------------------------------------------------------------- + + /** + * Insert batch statement + * + * Generates a platform-specific insert string from the supplied data. + * + * @param string $table Table name + * @param array $keys INSERT keys + * @param array $values INSERT values + * @return string|bool + */ + protected function _insert_batch($table, $keys, $values) + { + // Multiple-value inserts are only supported as of SQL Server 2008 + if (version_compare($this->version(), '10', '>=')) + { + return parent::_insert_batch($table, $keys, $values); + } + + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; + } + +} + +/* End of file pdo_dblib_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_dblib_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_dblib_forge.php b/system/database/drivers/pdo/subdrivers/pdo_dblib_forge.php new file mode 100644 index 000000000..236e1cce2 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_dblib_forge.php @@ -0,0 +1,136 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO DBLIB Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_dblib_forge extends CI_DB_pdo_forge { + + /** + * CREATE TABLE IF statement + * + * @var string + */ + protected $_create_table_if = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nCREATE TABLE"; + + /** + * DROP TABLE IF statement + * + * @var string + */ + protected $_drop_table_if = "IF EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nDROP TABLE"; + + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'TINYINT' => 'SMALLINT', + 'SMALLINT' => 'INT', + 'INT' => 'BIGINT', + 'REAL' => 'FLOAT' + ); + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if (in_array($alter_type, array('ADD', 'DROP'), TRUE)) + { + return parent::_alter_table($alter_type, $table, $field); + } + + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN '; + $sqls = array(); + for ($i = 0, $c = count($field); $i < $c; $i++) + { + $sqls[] = $sql.$this->_process_column($field[$i]); + } + + return $sqls; + } + + // -------------------------------------------------------------------- + + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + switch (strtoupper($attributes['TYPE'])) + { + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'INTEGER': + $attributes['TYPE'] = 'INT'; + return; + default: return; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) + { + $field['auto_increment'] = ' IDENTITY(1,1)'; + } + } + +} + +/* End of file pdo_dblib_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_dblib_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php new file mode 100644 index 000000000..7c3836691 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php @@ -0,0 +1,230 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO Firebird Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_firebird_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = 'firebird'; + + // -------------------------------------------------------------------- + + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('RAND()', 'RAND()'); + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = 'firebird:'; + + if ( ! empty($this->database)) + { + $this->dsn .= 'dbname='.$this->database; + } + elseif ( ! empty($this->hostname)) + { + $this->dsn .= 'dbname='.$this->hostname; + } + + empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; + empty($this->role) OR $this->dsn .= ';role='.$this->role; + } + elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 9) === FALSE) + { + $this->dsn .= ';charset='.$this->char_set; + } + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + $sql = 'SELECT "RDB$RELATION_NAME" FROM "RDB$RELATIONS" WHERE "RDB$RELATION_NAME" NOT LIKE \'RDB$%\' AND "RDB$RELATION_NAME" NOT LIKE \'MON$%\''; + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + return $sql.' AND "RDB$RELATION_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 + * + * @param string $table + * @return string + */ + protected function _list_columns($table = '') + { + return 'SELECT "RDB$FIELD_NAME" FROM "RDB$RELATION_FIELDS" WHERE "RDB$RELATION_NAME" = '.$this->escape($table); + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @param string $table + * @return string + */ + protected function _field_data($table) + { + return 'SELECT FIRST 1 * FROM '.$this->protect_identifiers($table); + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @param string $table + * @param array $values + * @return string + */ + protected function _update($table, $values) + { + $this->qb_limit = FALSE; + return parent::_update($table, $values); + } + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * + * If the database does not support the TRUNCATE statement, + * then this method maps to 'DELETE FROM table' + * + * @param string $table + * @return string + */ + protected function _truncate($table) + { + return 'DELETE FROM '.$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @param string $table + * @return string + */ + protected function _delete($table) + { + $this->qb_limit = FALSE; + return parent::_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * LIMIT + * + * Generates a platform-specific LIMIT clause + * + * @param string $sql SQL Query + * @return string + */ + protected function _limit($sql) + { + // Limit clause depends on if Interbase or Firebird + if (stripos($this->version(), 'firebird') !== FALSE) + { + $select = 'FIRST '.$this->qb_limit + .($this->qb_offset > 0 ? ' SKIP '.$this->qb_offset : ''); + } + else + { + $select = 'ROWS ' + .($this->qb_offset > 0 ? $this->qb_offset.' TO '.($this->qb_limit + $this->qb_offset) : $this->qb_limit); + } + + return preg_replace('`SELECT`i', 'SELECT '.$select, $sql); + } + +} + +/* End of file pdo_firebird_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_firebird_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_firebird_forge.php b/system/database/drivers/pdo/subdrivers/pdo_firebird_forge.php new file mode 100644 index 000000000..474188f4e --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_firebird_forge.php @@ -0,0 +1,228 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO Firebird Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_firebird_forge extends CI_DB_pdo_forge { + + /** + * RENAME TABLE statement + * + * @var string + */ + protected $_rename_table = FALSE; + + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'SMALLINT' => 'INTEGER', + 'INTEGER' => 'INT64', + 'FLOAT' => 'DOUBLE PRECISION' + ); + + /** + * NULL value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_null = 'NULL'; + + // -------------------------------------------------------------------- + + /** + * Create database + * + * @param string $db_name + * @return string + */ + public function create_database($db_name) + { + // Firebird databases are flat files, so a path is required + + // Hostname is needed for remote access + empty($this->db->hostname) OR $db_name = $this->hostname.':'.$db_name; + + return parent::create_database('"'.$db_name.'"'); + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @param string $db_name (ignored) + * @return bool + */ + public function drop_database($db_name = '') + { + if ( ! ibase_drop_db($this->conn_id)) + { + return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE; + } + elseif ( ! empty($this->db->data_cache['db_names'])) + { + $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); + if ($key !== FALSE) + { + unset($this->db->data_cache['db_names'][$key]); + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) + { + return parent::_alter_table($alter_type, $table, $field); + } + + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); + $sqls = array(); + for ($i = 0, $c = count($field), $sql .= $alter_type.' '; $i < $c; $i++) + { + if ($field[$i]['_literal'] !== FALSE) + { + return FALSE; + } + + if (isset($field[$i]['type'])) + { + $sqls[] = $sql.' TYPE '.$field[$i]['type'].$field[$i]['length']; + } + + if ( ! empty($field[$i]['default'])) + { + $sqls[] = $sql.' ALTER '.$this->db->escape_identifiers($field[$i]['name']) + .' SET '.$field[$i]['default']; + } + + if (isset($field[$i]['null'])) + { + $sqls[] = 'UPDATE "RDB$RELATION_FIELDS" SET "RDB$NULL_FLAG" = ' + .($field[$i]['null'] === TRUE ? 'NULL' : '1') + .' WHERE "RDB$FIELD_NAME" = '.$this->db->escape($field[$i]['name']) + .' AND "RDB$RELATION_NAME" = '.$this->db->escape($table); + } + + if ( ! empty($field[$i]['new_name'])) + { + $sqls[] = $sql.' ALTER '.$this->db->escape_identifiers($field[$i]['name']) + .' TO '.$this->db->escape_identifiers($field[$i]['new_name']); + } + } + + return $sqls; + } + + // -------------------------------------------------------------------- + + /** + * Process column + * + * @param array $field + * @return string + */ + protected function _process_column($field) + { + return $this->db->escape_identifiers($field['name']) + .' '.$field['type'].$field['length'] + .$field['null'] + .$field['unique'] + .$field['default']; + } + + // -------------------------------------------------------------------- + + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + switch (strtoupper($attributes['TYPE'])) + { + case 'TINYINT': + $attributes['TYPE'] = 'SMALLINT'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'INT': + $attributes['TYPE'] = 'INTEGER'; + return; + case 'BIGINT': + $attributes['TYPE'] = 'INT64'; + return; + default: return; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + // Not supported + } + +} + +/* End of file pdo_firebird_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_firebird_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php b/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php new file mode 100644 index 000000000..d8dbc50c0 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php @@ -0,0 +1,227 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO IBM DB2 Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_ibm_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = 'ibm'; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = 'ibm:'; + + // Pre-defined DSN + if (empty($this->hostname) && empty($this->HOSTNAME) && empty($this->port) && empty($this->PORT)) + { + if (isset($this->DSN)) + { + $this->dsn .= 'DSN='.$this->DSN; + } + elseif ( ! empty($this->database)) + { + $this->dsn .= 'DSN='.$this->database; + } + + return; + } + + $this->dsn .= 'DRIVER='.(isset($this->DRIVER) ? '{'.$this->DRIVER.'}' : '{IBM DB2 ODBC DRIVER}').';'; + + if (isset($this->DATABASE)) + { + $this->dsn .= 'DATABASE='.$this->DATABASE.';'; + } + elseif ( ! empty($this->database)) + { + $this->dsn .= 'DATABASE='.$this->database.';'; + } + + if (isset($this->HOSTNAME)) + { + $this->dsn .= 'HOSTNAME='.$this->HOSTNAME.';'; + } + else + { + $this->dsn .= 'HOSTNAME='.(empty($this->hostname) ? '127.0.0.1;' : $this->hostname.';'); + } + + if (isset($this->PORT)) + { + $this->dsn .= 'PORT='.$this->port.';'; + } + elseif ( ! empty($this->port)) + { + $this->dsn .= ';PORT='.$this->port.';'; + } + + $this->dsn .= 'PROTOCOL='.(isset($this->PROTOCOL) ? $this->PROTOCOL.';' : 'TCPIP;'); + } + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + $sql = 'SELECT "tabname" FROM "syscat"."tables" WHERE "type" = \'T\''; + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + $sql .= ' AND "tabname" 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 + * + * @param string $table + * @return string + */ + protected function _list_columns($table = '') + { + return 'SELECT "colname" FROM "syscat"."tables" + WHERE "syscat"."tabtype" = \'T\' AND "syscat"."tabname" = '.$this->escape($table); + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @param string $table + * @return string + */ + protected function _field_data($table) + { + return 'SELECT * FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE).' FETCH FIRST 1 ROWS ONLY'; + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @param string $table + * @param array $values + * @return string + */ + protected function _update($table, $values) + { + $this->qb_limit = FALSE; + $this->qb_orderby = array(); + return parent::_update($table, $values); + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @param string $table + * @return string + */ + protected function _delete($table) + { + $this->qb_limit = FALSE; + return parent::_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * LIMIT + * + * Generates a platform-specific LIMIT clause + * + * @param string $sql SQL Query + * @return string + */ + protected function _limit($sql) + { + $sql .= ' FETCH FIRST '.($this->qb_limit + $this->qb_offset).' ROWS ONLY'; + + return ($this->qb_offset) + ? 'SELECT * FROM ('.$sql.') WHERE rownum > '.$this->qb_offset + : $sql; + } + +} + +/* End of file pdo_ibm_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_ibm_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_ibm_forge.php b/system/database/drivers/pdo/subdrivers/pdo_ibm_forge.php new file mode 100644 index 000000000..f095c717a --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_ibm_forge.php @@ -0,0 +1,146 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO IBM DB2 Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_ibm_forge extends CI_DB_pdo_forge { + + /** + * RENAME TABLE IF statement + * + * @var string + */ + protected $_rename_table = 'RENAME TABLE %s TO %s'; + + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'SMALLINT' => 'INTEGER', + 'INT' => 'BIGINT', + 'INTEGER' => 'BIGINT' + ); + + /** + * DEFAULT value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_default = FALSE; + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if ($alter_type === 'CHANGE') + { + $alter_type = 'MODIFY'; + } + + return parent::_alter_table($alter_type, $table, $field); + } + + // -------------------------------------------------------------------- + + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + switch (strtoupper($attributes['TYPE'])) + { + case 'TINYINT': + $attributes['TYPE'] = 'SMALLINT'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + default: return; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute UNIQUE + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_unique(&$attributes, &$field) + { + if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) + { + $field['unique'] = ' UNIQUE'; + + // UNIQUE must be used with NOT NULL + $field['null'] = ' NOT NULL'; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + // Not supported + } + +} + +/* End of file pdo_ibm_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_ibm_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php b/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php new file mode 100644 index 000000000..03886f442 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_informix_driver.php @@ -0,0 +1,245 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO Informix Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_informix_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = 'informix'; + + // -------------------------------------------------------------------- + + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('ASC', 'ASC'); // Currently not supported + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = 'informix:'; + + // Pre-defined DSN + if (empty($this->hostname) && empty($this->host) && empty($this->port) && empty($this->service)) + { + if (isset($this->DSN)) + { + $this->dsn .= 'DSN='.$this->DSN; + } + elseif ( ! empty($this->database)) + { + $this->dsn .= 'DSN='.$this->database; + } + + return; + } + + if (isset($this->host)) + { + $this->dsn .= 'host='.$this->host; + } + else + { + $this->dsn .= 'host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); + } + + if (isset($this->service)) + { + $this->dsn .= '; service='.$this->service; + } + elseif ( ! empty($this->port)) + { + $this->dsn .= '; service='.$this->port; + } + + empty($this->database) OR $this->dsn .= '; database='.$this->database; + empty($this->server) OR $this->dsn .= '; server='.$this->server; + + $this->dsn .= '; protocol='.(isset($this->protocol) ? $this->protocol : 'onsoctcp') + .'; EnableScrollableCursors=1'; + } + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + $sql = 'SELECT "tabname" FROM "systables" WHERE "tabid" > 99 AND "tabtype" = \'T\''; + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + $sql .= ' AND "tabname" 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 + * + * @param string $table + * @return string + */ + protected function _list_columns($table = '') + { + return 'SELECT "colname" FROM "systables", "syscolumns" + WHERE "systables"."tabid" = "syscolumns"."tabid" AND "systables"."tabtype" = \'T\' AND "systables"."tabname" = ' + .$this->escape($table); + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @param string $table + * @return string + */ + protected function _field_data($table) + { + return 'SELECT FIRST 1 * FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE); + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @param string $table + * @param array $values + * @return string + */ + protected function _update($table, $values) + { + $this->qb_limit = FALSE; + $this->qb_orderby = array(); + return parent::_update($table, $values); + } + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * + * If the database does not support the TRUNCATE statement, + * then this method maps to 'DELETE FROM table' + * + * @param string $table + * @return string + */ + protected function _truncate($table) + { + return 'TRUNCATE TABLE ONLY '.$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @param string $table + * @return string + */ + protected function _delete($table) + { + $this->qb_limit = FALSE; + return parent::_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * LIMIT + * + * Generates a platform-specific LIMIT clause + * + * @param string $sql $SQL Query + * @return string + */ + protected function _limit($sql) + { + $select = 'SELECT '.($this->qb_offset ? 'SKIP '.$this->qb_offset : '').'FIRST '.$this->qb_limit.' '; + return preg_replace('/^(SELECT\s)/i', $select, $sql, 1); + } + +} + +/* End of file pdo_informix_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_informix_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_informix_forge.php b/system/database/drivers/pdo/subdrivers/pdo_informix_forge.php new file mode 100644 index 000000000..8722dd200 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_informix_forge.php @@ -0,0 +1,155 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO Informix Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_informix_forge extends CI_DB_pdo_forge { + + /** + * RENAME TABLE statement + * + * @var string + */ + protected $_rename_table = 'RENAME TABLE %s TO %s'; + + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'SMALLINT' => 'INTEGER', + 'INT' => 'BIGINT', + 'INTEGER' => 'BIGINT', + 'REAL' => 'DOUBLE PRECISION', + 'SMALLFLOAT' => 'DOUBLE PRECISION' + ); + + /** + * DEFAULT value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_default = ', '; + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if ($alter_type === 'CHANGE') + { + $alter_type = 'MODIFY'; + } + + return parent::_alter_table($alter_type, $table, $field); + } + + // -------------------------------------------------------------------- + + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + switch (strtoupper($attributes['TYPE'])) + { + case 'TINYINT': + $attributes['TYPE'] = 'SMALLINT'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'BYTE': + case 'TEXT': + case 'BLOB': + case 'CLOB': + $attributes['UNIQUE'] = FALSE; + if (isset($attributes['DEFAULT'])) + { + unset($attributes['DEFAULT']); + } + return; + default: return; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute UNIQUE + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_unique(&$attributes, &$field) + { + if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE) + { + $field['unique'] = ' UNIQUE CONSTRAINT '.$this->db->escape_identifiers($field['name']); + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + // Not supported + } + +} + +/* End of file pdo_informix_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_informix_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php new file mode 100644 index 000000000..2d076f314 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php @@ -0,0 +1,259 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO MySQL Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_mysql_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = 'mysql'; + + /** + * Compression flag + * + * @var bool + */ + public $compress = FALSE; + + // -------------------------------------------------------------------- + + /** + * Identifier escape character + * + * @var string + */ + protected $_escape_char = '`'; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = 'mysql:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); + + empty($this->port) OR $this->dsn .= ';port='.$this->port; + empty($this->database) OR $this->dsn .= ';dbname='.$this->database; + empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; + } + elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 6) === FALSE && is_php('5.3.6')) + { + $this->dsn .= ';charset='.$this->char_set; + } + } + + // -------------------------------------------------------------------- + + /** + * Database connection + * + * @param bool $persistent + * @return object + * @todo SSL support + */ + public function db_connect($persistent = FALSE) + { + /* Prior to PHP 5.3.6, even if the charset was supplied in the DSN + * on connect - it was ignored. This is a work-around for the issue. + * + * Reference: http://www.php.net/manual/en/ref.pdo-mysql.connection.php + */ + if ( ! is_php('5.3.6') && ! empty($this->char_set)) + { + $this->options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$this->char_set + .(empty($this->dbcollat) ? '' : ' COLLATE '.$this->dbcollat); + } + + if ($this->compress === TRUE) + { + $this->options[PDO::MYSQL_ATTR_COMPRESS] = TRUE; + } + + return parent::db_connect($persistent); + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + $sql = 'SHOW TABLES'; + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + return $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 + * + * @param string $table + * @return string + */ + protected 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 + * + * @param string $table + * @return string + */ + protected function _field_data($table) + { + return 'SELECT * FROM '.$this->protect_identifiers($table).' LIMIT 1'; + } + + // -------------------------------------------------------------------- + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @param string $table Table name + * @param array $values Update data + * @param string $index UPDATE key + * @return string + */ + protected function _update_batch($table, $values, $index) + { + $ids = array(); + 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]; + } + } + } + + $cases = ''; + foreach ($final as $k => $v) + { + $cases .= $k." = CASE \n" + .implode("\n", $v)."\n" + .'ELSE '.$k.' END), '; + } + + $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); + + return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); + } + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * + * If the database does not support the TRUNCATE statement, + * then this method maps to 'DELETE FROM table' + * + * @param string $table + * @return string + */ + protected function _truncate($table) + { + return 'TRUNCATE '.$table; + } + + // -------------------------------------------------------------------- + + /** + * FROM tables + * + * Groups tables in FROM clauses if needed, so there is no confusion + * about operator precedence. + * + * @return string + */ + protected function _from_tables() + { + if ( ! empty($this->qb_join) && count($this->qb_from) > 1) + { + return '('.implode(', ', $this->qb_from).')'; + } + + return implode(', ', $this->qb_from); + } + +} + +/* End of file pdo_mysql_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_mysql_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_mysql_forge.php b/system/database/drivers/pdo/subdrivers/pdo_mysql_forge.php new file mode 100644 index 000000000..866b6fb21 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_mysql_forge.php @@ -0,0 +1,218 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO MySQL Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_mysql_forge extends CI_DB_pdo_forge { + + /** + * CREATE DATABASE statement + * + * @var string + */ + protected $_create_database = 'CREATE DATABASE %s CHARACTER SET %s COLLATE %s'; + + /** + * CREATE TABLE IF statement + * + * @var string + */ + protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS'; + + /** + * CREATE TABLE keys flag + * + * Whether table keys are created from within the + * CREATE TABLE statement. + * + * @var bool + */ + protected $_create_table_keys = TRUE; + + /** + * DROP TABLE IF statement + * + * @var string + */ + protected $_drop_table_if = 'DROP TABLE IF EXISTS'; + + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'TINYINT', + 'SMALLINT', + 'MEDIUMINT', + 'INT', + 'INTEGER', + 'BIGINT', + 'REAL', + 'DOUBLE', + 'DOUBLE PRECISION', + 'FLOAT', + 'DECIMAL', + 'NUMERIC' + ); + + /** + * NULL value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_null = 'NULL'; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @param object &$db Database object + * @return void + */ + public function __construct(&$db) + { + parent::__construct($db); + + $this->_create_table .= ' DEFAULT CHARSET '.$this->db->char_set.' COLLATE '.$this->db->dbcollat; + } + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if ($alter_type === 'DROP') + { + return parent::_alter_table($alter_type, $table, $field); + } + + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); + for ($i = 0, $c = count($field); $i < $c; $i++) + { + if ($field[$i]['_literal'] !== FALSE) + { + $field[$i] = ($alter_type === 'ADD') + ? "\n\tADD ".$field[$i]['_literal'] + : "\n\tMODIFY ".$field[$i]['_literal']; + } + else + { + if ($alter_type === 'ADD') + { + $field[$i]['_literal'] = "\n\tADD "; + } + else + { + $field[$i]['_literal'] = empty($field[$i]['new_name']) ? "\n\tMODIFY " : "\n\tCHANGE "; + } + + $field[$i] = $field[$i]['_literal'].$this->_process_column($field[$i]); + } + } + + return array($sql.implode(',', $field)); + } + + // -------------------------------------------------------------------- + + /** + * Process column + * + * @param array $field + * @return string + */ + protected function _process_column($field) + { + $extra_clause = isset($field['after']) + ? ' AFTER '.$this->db->escape_identifiers($field['after']) : ''; + + if (empty($extra_clause) && isset($field['first']) && $field['first'] === TRUE) + { + $extra_clause = ' FIRST'; + } + + return $this->db->escape_identifiers($field['name']) + .(empty($field['new_name']) ? '' : $this->db->escape_identifiers($field['new_name'])) + .' '.$field['type'].$field['length'] + .$field['unsigned'] + .$field['null'] + .$field['default'] + .$field['auto_increment'] + .$field['unique'] + .$extra_clause; + } + + // -------------------------------------------------------------------- + + /** + * Process indexes + * + * @param string $table (ignored) + * @return string + */ + protected function _process_indexes($table = NULL) + { + $sql = ''; + + for ($i = 0, $c = count($this->keys); $i < $c; $i++) + { + if ( ! isset($this->fields[$this->keys[$i]])) + { + unset($this->keys[$i]); + continue; + } + + is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]); + + $sql .= ",\n\tKEY ".$this->db->escape_identifiers(implode('_', $this->keys[$i])) + .' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).')'; + } + + $this->keys = array(); + + return $sql; + } + +} + +/* End of file pdo_mysql_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_mysql_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php b/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php new file mode 100644 index 000000000..051b7dec8 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_oci_driver.php @@ -0,0 +1,235 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO Oracle Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_oci_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = 'oci'; + + // -------------------------------------------------------------------- + + /** + * List of reserved identifiers + * + * Identifiers that must NOT be escaped. + * + * @var string[] + */ + protected $_reserved_identifiers = array('*', 'rownum'); + + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('ASC', 'ASC'); // Currently not supported + + /** + * COUNT string + * + * @used-by CI_DB_driver::count_all() + * @used-by CI_DB_query_builder::count_all_results() + * + * @var string + */ + protected $_count_string = 'SELECT COUNT(1) AS '; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = 'oci:dbname='; + + // Oracle has a slightly different PDO DSN format (Easy Connect), + // which also supports pre-defined DSNs. + if (empty($this->hostname) && empty($this->port)) + { + $this->dsn .= $this->database; + } + else + { + $this->dsn .= '//'.(empty($this->hostname) ? '127.0.0.1' : $this->hostname) + .(empty($this->port) ? '' : ':'.$this->port).'/'; + + empty($this->database) OR $this->dsn .= $this->database; + } + + empty($this->char_set) OR $this->dsn .= ';charset='.$this->char_set; + } + elseif ( ! empty($this->char_set) && strpos($this->dsn, 'charset=', 4) === FALSE) + { + $this->dsn .= ';charset='.$this->char_set; + } + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + $sql = 'SELECT "TABLE_NAME" FROM "ALL_TABLES"'; + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + return $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 + * + * @param string $table + * @return string + */ + protected function _list_columns($table = '') + { + return 'SELECT "COLUMN_NAME" FROM "all_tab_columns" WHERE "TABLE_NAME" = '.$this->escape($table); + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @param string $table + * @return string + */ + protected function _field_data($table) + { + return 'SELECT * FROM '.$this->protect_identifiers($table).' WHERE rownum = 1'; + } + + // -------------------------------------------------------------------- + + /** + * Insert batch statement + * + * @param string $table Table name + * @param array $keys INSERT keys + * @param array $values 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"; + } + + return $sql.'SELECT * FROM dual'; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @param string $table + * @return string + */ + protected function _delete($table) + { + if ($this->qb_limit) + { + $this->where('rownum <= ',$this->qb_limit, FALSE); + $this->qb_limit = FALSE; + } + + return parent::_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * LIMIT + * + * Generates a platform-specific LIMIT clause + * + * @param string $sql SQL Query + * @return string + */ + protected function _limit($sql) + { + return 'SELECT * FROM (SELECT inner_query.*, rownum rnum FROM ('.$sql.') inner_query WHERE rownum < '.($this->qb_offset + $this->qb_limit + 1).')' + .($this->qb_offset ? ' WHERE rnum >= '.($this->qb_offset + 1): ''); + } + +} + +/* End of file pdo_oci_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_oci_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_oci_forge.php b/system/database/drivers/pdo/subdrivers/pdo_oci_forge.php new file mode 100644 index 000000000..8052d218f --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_oci_forge.php @@ -0,0 +1,133 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO Oracle Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_oci_forge extends CI_DB_pdo_forge { + + /** + * CREATE DATABASE statement + * + * @var string + */ + protected $_create_database = FALSE; + + /** + * DROP DATABASE statement + * + * @var string + */ + protected $_drop_database = FALSE; + + /** + * CREATE TABLE IF statement + * + * @var string + */ + protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS'; + + /** + * UNSIGNED support + * + * @var bool|array + */ + protected $_unsigned = FALSE; + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if ($alter_type === 'DROP') + { + return parent::_alter_table($alter_type, $table, $field); + } + elseif ($alter_type === 'CHANGE') + { + $alter_type = 'MODIFY'; + } + + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); + $sqls = array(); + for ($i = 0, $c = count($field); $i < $c; $i++) + { + if ($field[$i]['_literal'] !== FALSE) + { + $field[$i] = "\n\t".$field[$i]['_literal']; + } + else + { + $field[$i]['_literal'] = "\n\t".$this->_process_column($field[$i]); + if ($alter_type === 'MODIFY' && ! empty($field[$i]['new_name'])) + { + $sqls[] = $sql.' RENAME COLUMN '.$this->db->escape_identifiers($field[$i]['name']) + .' '.$this->db->escape_identifiers($field[$i]['new_name']); + } + } + } + + $sql .= ' '.$alter_type.' '; + $sql .= (count($field) === 1) + ? $fields[0] + : '('.implode(',', $field).')'; + + // RENAME COLUMN must be executed after MODIFY + array_unshift($sqls, $sql); + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + // Not supported - sequences and triggers must be used instead + } + +} + +/* End of file pdo_oci_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_oci_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php new file mode 100644 index 000000000..05b34fa89 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php @@ -0,0 +1,258 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO ODBC Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_odbc_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = 'odbc'; + + /** + * Database schema + * + * @var string + */ + public $schema = 'public'; + + // -------------------------------------------------------------------- + + /** + * Identifier escape character + * + * Must be empty for ODBC. + * + * @var string + */ + protected $_escape_char = ''; + + /** + * ESCAPE statement string + * + * @var string + */ + protected $_like_escape_str = " {escape '%s'} "; + + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('RND()', 'RND(%d)'); + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = 'odbc:'; + + // Pre-defined DSN + if (empty($this->hostname) && empty($this->HOSTNAME) && empty($this->port) && empty($this->PORT)) + { + if (isset($this->DSN)) + { + $this->dsn .= 'DSN='.$this->DSN; + } + elseif ( ! empty($this->database)) + { + $this->dsn .= 'DSN='.$this->database; + } + + return; + } + + // If the DSN is not pre-configured - try to build an IBM DB2 connection string + $this->dsn .= 'DRIVER='.(isset($this->DRIVER) ? '{'.$this->DRIVER.'}' : '{IBM DB2 ODBC DRIVER}').';'; + + if (isset($this->DATABASE)) + { + $this->dsn .= 'DATABASE='.$this->DATABASE.';'; + } + elseif ( ! empty($this->database)) + { + $this->dsn .= 'DATABASE='.$this->database.';'; + } + + if (isset($this->HOSTNAME)) + { + $this->dsn .= 'HOSTNAME='.$this->HOSTNAME.';'; + } + else + { + $this->dsn .= 'HOSTNAME='.(empty($this->hostname) ? '127.0.0.1;' : $this->hostname.';'); + } + + if (isset($this->PORT)) + { + $this->dsn .= 'PORT='.$this->port.';'; + } + elseif ( ! empty($this->port)) + { + $this->dsn .= ';PORT='.$this->port.';'; + } + + $this->dsn .= 'PROTOCOL='.(isset($this->PROTOCOL) ? $this->PROTOCOL.';' : 'TCPIP;'); + } + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = '".$this->schema."'"; + + if ($prefix_limit !== FALSE && $this->dbprefix !== '') + { + return $sql." AND 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 + * + * @param string $table + * @return string + */ + protected function _list_columns($table = '') + { + return 'SELECT column_name FROM information_schema.columns WHERE table_name = '.$this->escape($table); + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @param string $table + * @param array $values + * @return string + */ + protected function _update($table, $values) + { + $this->qb_limit = FALSE; + $this->qb_orderby = array(); + return parent::_update($table, $values); + } + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * + * If the database does not support the TRUNCATE statement, + * then this method maps to 'DELETE FROM table' + * + * @param string $table + * @return string + */ + protected function _truncate($table) + { + return 'DELETE FROM '.$table; + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @param string the table name + * @return string + */ + protected function _delete($table) + { + $this->qb_limit = FALSE; + return parent::_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * LIMIT + * + * Generates a platform-specific LIMIT clause + * + * @param string $sql SQL Query + * @return string + */ + protected function _limit($sql) + { + return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$this->qb_limit.' ', $sql); + } + +} + +/* End of file pdo_odbc_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_odbc_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_odbc_forge.php b/system/database/drivers/pdo/subdrivers/pdo_odbc_forge.php new file mode 100644 index 000000000..ab4d2bf84 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_odbc_forge.php @@ -0,0 +1,62 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO ODBC Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/database/ + */ +class CI_DB_pdo_odbc_forge extends CI_DB_pdo_forge { + + /** + * UNSIGNED support + * + * @var bool|array + */ + protected $_unsigned = FALSE; + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + // Not supported (in most databases at least) + } + +} + +/* End of file pdo_odbc_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_odbc_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php new file mode 100644 index 000000000..45165213f --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php @@ -0,0 +1,359 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO PostgreSQL Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_pgsql_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = 'pgsql'; + + /** + * Database schema + * + * @var string + */ + public $schema = 'public'; + + // -------------------------------------------------------------------- + + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('RANDOM()', 'RANDOM()'); + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = 'pgsql:host='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); + + empty($this->port) OR $this->dsn .= ';port='.$this->port; + empty($this->database) OR $this->dsn .= ';dbname='.$this->database; + } + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @param string $name + * @return int + */ + public function insert_id($name = NULL) + { + if ($name === NULL && version_compare($this->version(), '8.1', '>=')) + { + $query = $this->query('SELECT LASTVAL() AS ins_id'); + $query = $query->row(); + return $query->ins_id; + } + + return $this->conn_id->lastInsertId($name); + } + + // -------------------------------------------------------------------- + + /** + * ORDER BY + * + * @param string $orderby + * @param string $direction ASC or DESC + * @param bool $escape + * @return object + */ + public function order_by($orderby, $direction = '', $escape = NULL) + { + $direction = strtoupper(trim($direction)); + if ($direction === 'RANDOM') + { + if ( ! is_float($orderby) && ctype_digit((string) $orderby)) + { + $orderby = ($orderby > 1) + ? (float) '0.'.$orderby + : (float) $orderby; + } + + if (is_float($orderby)) + { + $this->simple_query('SET SEED '.$orderby); + } + + $orderby = $this->_random_keyword[0]; + $direction = ''; + $escape = FALSE; + } + + return parent::order_by($orderby, $direction, $escape); + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + $sql = 'SELECT "table_name" FROM "information_schema"."tables" WHERE "table_schema" = \''.$this->schema."'"; + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + return $sql.' AND "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 + * + * @param string $table + * @return string + */ + protected function _list_columns($table = '') + { + return 'SELECT "column_name" FROM "information_schema"."columns" WHERE "table_name" = '.$this->escape($table); + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @param string $table + * @return string + */ + protected function _field_data($table) + { + return 'SELECT * FROM '.$this->protect_identifiers($table).' LIMIT 1'; + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @param string $table + * @param array $values + * @return string + */ + protected function _update($table, $values) + { + $this->qb_limit = FALSE; + $this->qb_orderby = array(); + return parent::_update($table, $values); + } + + // -------------------------------------------------------------------- + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @param string $table Table name + * @param array $values Update data + * @param string $index WHERE key + * @return string + */ + protected function _update_batch($table, $values, $index) + { + $ids = array(); + foreach ($values as $key => $val) + { + $ids[] = $val[$index]; + + foreach (array_keys($val) as $field) + { + if ($field !== $index) + { + $final[$field][] = 'WHEN '.$val[$index].' THEN '.$val[$field]; + } + } + } + + $cases = ''; + foreach ($final as $k => $v) + { + $cases .= $k.' = (CASE '.$index."\n" + .implode("\n", $v)."\n" + .'ELSE '.$k.' END), '; + } + + $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); + + return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @param string $table + * @return string + */ + protected function _delete($table) + { + $this->qb_limit = FALSE; + return parent::_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * LIMIT + * + * Generates a platform-specific LIMIT clause + * + * @param string $sql SQL Query + * @return string + */ + protected function _limit($sql) + { + return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : ''); + } + + // -------------------------------------------------------------------- + + /** + * WHERE, HAVING + * + * Called by where(), or_where(), having(), or_having() + * + * @param string 'qb_where' or 'qb_having' + * @param mixed + * @param mixed + * @param string + * @param bool + * @return object + */ + protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL) + { + $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where'; + + if ( ! is_array($key)) + { + $key = array($key => $value); + } + + // If the escape value was not set will will base it on the global setting + is_bool($escape) OR $escape = $this->_protect_identifiers; + + foreach ($key as $k => $v) + { + $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0) + ? $this->_group_get_type('') + : $this->_group_get_type($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 (is_bool($v)) + { + $v = ' '.($v ? 'TRUE' : 'FALSE'); + } + elseif ($escape === TRUE) + { + $v = ' '.(is_int($v) ? $v : $this->escape($v)); + } + + if ( ! $this->_has_operator($k)) + { + $k .= ' = '; + } + } + + $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape); + if ($this->qb_caching === TRUE) + { + $this->{$qb_cache_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape); + $this->qb_cache_exists[] = substr($qb_key, 3); + } + + } + + return $this; + } + +} + +/* End of file pdo_pgsql_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_pgsql_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php b/system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php new file mode 100644 index 000000000..484c1603d --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php @@ -0,0 +1,194 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO PostgreSQL Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_pgsql_forge extends CI_DB_pdo_forge { + + /** + * DROP TABLE IF statement + * + * @var string + */ + protected $_drop_table_if = 'DROP TABLE IF EXISTS'; + + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'INT2' => 'INTEGER', + 'SMALLINT' => 'INTEGER', + 'INT' => 'BIGINT', + 'INT4' => 'BIGINT', + 'INTEGER' => 'BIGINT', + 'INT8' => 'NUMERIC', + 'BIGINT' => 'NUMERIC', + 'REAL' => 'DOUBLE PRECISION', + 'FLOAT' => 'DOUBLE PRECISION' + ); + + /** + * NULL value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_null = 'NULL'; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @param object &$db Database object + * @return void + */ + public function __construct(&$db) + { + parent::__construct($db); + + if (version_compare($this->db->version(), '9.0', '>')) + { + $this->create_table_if = 'CREATE TABLE IF NOT EXISTS'; + } + } + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) + { + return parent::_alter_table($alter_type, $table, $field); + } + + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); + $sqls = array(); + for ($i = 0, $c = count($field), $sql .= $alter_type.' '; $i < $c; $i++) + { + if ($field[$i]['_literal'] !== FALSE) + { + return FALSE; + } + + if (version_compare($this->db->version(), '8', '>=') && isset($field[$i]['type'])) + { + $sqls[] = $sql.' TYPE '.$field[$i]['type'].$field[$i]['length']; + } + + if ( ! empty($field[$i]['default'])) + { + $sqls[] = $sql.' ALTER '.$this->db->escape_identifiers($field[$i]['name']) + .' SET '.$field[$i]['default']; + } + + if (isset($field[$i]['null'])) + { + $sqls[] = $sql.' ALTER '.$this->db->escape_identifiers($field[$i]['name']) + .($field[$i]['null'] === TRUE ? ' DROP NOT NULL' : ' SET NOT NULL'); + } + + if ( ! empty($field[$i]['new_name'])) + { + $sqls[] = $sql.' RENAME '.$this->db->escape_identifiers($field[$i]['name']) + .' TO '.$this->db->escape_identifiers($field[$i]['new_name']); + } + } + + return $sqls; + } + + // -------------------------------------------------------------------- + + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + // Reset field lenghts for data types that don't support it + if (isset($attributes['CONSTRAINT']) && stripos($attributes['TYPE'], 'int') !== FALSE) + { + $attributes['CONSTRAINT'] = NULL; + } + + switch (strtoupper($attributes['TYPE'])) + { + case 'TINYINT': + $attributes['TYPE'] = 'SMALLINT'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + default: return; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $field['type'] = ($field['type'] === 'NUMERIC') + ? 'BIGSERIAL' + : 'SERIAL'; + } + } + +} + +/* End of file pdo_pgsql_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_pgsql_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlite_driver.php b/system/database/drivers/pdo/subdrivers/pdo_sqlite_driver.php new file mode 100644 index 000000000..f9d186f6c --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_sqlite_driver.php @@ -0,0 +1,177 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO SQLite Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_sqlite_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = 'sqlite'; + + // -------------------------------------------------------------------- + + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = ' RANDOM()'; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = 'sqlite:'; + + if (empty($this->database) && empty($this->hostname)) + { + $this->database = ':memory:'; + } + + $this->database = empty($this->database) ? $this->hostname : $this->database; + } + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + $sql = 'SELECT "NAME" FROM "SQLITE_MASTER" WHERE "TYPE" = \'table\''; + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + return $sql.' AND "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 + * + * @param string $table + * @return string + */ + protected function _list_columns($table = '') + { + // Not supported + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Field data query + * + * Generates a platform-specific query so that the column data can be retrieved + * + * @param string $table + * @return string + */ + protected function _field_data($table) + { + return 'SELECT * FROM '.$this->protect_identifiers($table).' LIMIT 0,1'; + } + + // -------------------------------------------------------------------- + + /** + * Replace statement + * + * @param string $table Table name + * @param array $keys INSERT keys + * @param array $values INSERT values + * @return string + */ + protected function _replace($table, $keys, $values) + { + return 'INSERT OR '.parent::_replace($table, $keys, $values); + } + + // -------------------------------------------------------------------- + + /** + * Truncate statement + * + * Generates a platform-specific truncate string from the supplied data + * + * If the database does not support the TRUNCATE statement, + * then this method maps to 'DELETE FROM table' + * + * @param string $table + * @return string + */ + protected function _truncate($table) + { + return 'DELETE FROM '.$table; + } + +} + +/* End of file pdo_sqlite_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlite_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlite_forge.php b/system/database/drivers/pdo/subdrivers/pdo_sqlite_forge.php new file mode 100644 index 000000000..da098df31 --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_sqlite_forge.php @@ -0,0 +1,229 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.1.6 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO SQLite Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_sqlite_forge extends CI_DB_pdo_forge { + + /** + * CREATE TABLE IF statement + * + * @var string + */ + protected $_create_table_if = 'CREATE TABLE IF NOT EXISTS'; + + /** + * DROP TABLE IF statement + * + * @var string + */ + protected $_drop_table_if = 'DROP TABLE IF EXISTS'; + + /** + * UNSIGNED support + * + * @var bool|array + */ + protected $_unsigned = FALSE; + + /** + * NULL value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_null = 'NULL'; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @param object &$db Database object + * @return void + */ + public function __construct(&$db) + { + parent::__construct($db); + + if (version_compare($this->db->version(), '3.3', '<')) + { + $this->_create_table_if = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Create database + * + * @param string $db_name (ignored) + * @return bool + */ + public function create_database($db_name = '') + { + // In SQLite, a database is created when you connect to the database. + // We'll return TRUE so that an error isn't generated + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @param string $db_name (ignored) + * @return bool + */ + public function drop_database($db_name = '') + { + // In SQLite, a database is dropped when we delete a file + if (@file_exists($this->db->database)) + { + // We need to close the pseudo-connection first + $this->db->close(); + if ( ! @unlink($this->db->database)) + { + return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE; + } + elseif ( ! empty($this->db->data_cache['db_names'])) + { + $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); + if ($key !== FALSE) + { + unset($this->db->data_cache['db_names'][$key]); + } + } + + return TRUE; + } + + return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE; + } + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if ($alter_type === 'DROP' OR $alter_type === 'CHANGE') + { + // drop_column(): + // BEGIN TRANSACTION; + // CREATE TEMPORARY TABLE t1_backup(a,b); + // INSERT INTO t1_backup SELECT a,b FROM t1; + // DROP TABLE t1; + // CREATE TABLE t1(a,b); + // INSERT INTO t1 SELECT a,b FROM t1_backup; + // DROP TABLE t1_backup; + // COMMIT; + + return FALSE; + } + + return parent::_alter_table($alter_type, $table, $field); + } + + // -------------------------------------------------------------------- + + /** + * Process column + * + * @param array $field + * @return string + */ + protected function _process_column($field) + { + return $this->db->escape_identifiers($field['name']) + .' '.$field['type'] + .$field['auto_increment'] + .$field['null'] + .$field['unique'] + .$field['default']; + } + + // -------------------------------------------------------------------- + + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + switch (strtoupper($attributes['TYPE'])) + { + case 'ENUM': + case 'SET': + $attributes['TYPE'] = 'TEXT'; + return; + default: return; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) + { + $field['type'] = 'INTEGER PRIMARY KEY'; + $field['default'] = ''; + $field['null'] = ''; + $field['unique'] = ''; + $field['auto_increment'] = ' AUTOINCREMENT'; + + $this->primary_keys = array(); + } + } + +} + +/* End of file pdo_sqlite_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlite_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php new file mode 100644 index 000000000..1a630729d --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php @@ -0,0 +1,325 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO SQLSRV Database Adapter Class + * + * Note: _DB is an extender class that the app controller + * creates dynamically based on whether the query builder + * class is being used or not. + * + * @package CodeIgniter + * @subpackage Drivers + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_sqlsrv_driver extends CI_DB_pdo_driver { + + /** + * Sub-driver + * + * @var string + */ + public $subdriver = 'sqlsrv'; + + // -------------------------------------------------------------------- + + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('NEWID()', 'RAND(%d)'); + + /** + * Quoted identifier flag + * + * Whether to use SQL-92 standard quoted identifier + * (double quotes) or brackets for identifier escaping. + * + * @var bool + */ + protected $_quoted_identifier; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Builds the DSN if not already set. + * + * @param array $params + * @return void + */ + public function __construct($params) + { + parent::__construct($params); + + if (empty($this->dsn)) + { + $this->dsn = 'sqlsrv:Server='.(empty($this->hostname) ? '127.0.0.1' : $this->hostname); + + empty($this->port) OR $this->dsn .= ','.$this->port; + empty($this->database) OR $this->dsn .= ';Database='.$this->database; + + // Some custom options + + if (isset($this->QuotedId)) + { + $this->dsn .= ';QuotedId='.$this->QuotedId; + $this->_quoted_identifier = (bool) $this->QuotedId; + } + + if (isset($this->ConnectionPooling)) + { + $this->dsn .= ';ConnectionPooling='.$this->ConnectionPooling; + } + + if ($this->encrypt === TRUE) + { + $this->dsn .= ';Encrypt=1'; + } + + if (isset($this->TraceOn)) + { + $this->dsn .= ';TraceOn='.$this->TraceOn; + } + + if (isset($this->TrustServerCertificate)) + { + $this->dsn .= ';TrustServerCertificate='.$this->TrustServerCertificate; + } + + empty($this->APP) OR $this->dsn .= ';APP='.$this->APP; + empty($this->Failover_Partner) OR $this->dsn .= ';Failover_Partner='.$this->Failover_Partner; + empty($this->LoginTimeout) OR $this->dsn .= ';LoginTimeout='.$this->LoginTimeout; + empty($this->MultipleActiveResultSets) OR $this->dsn .= ';MultipleActiveResultSets='.$this->MultipleActiveResultSets; + empty($this->TraceFile) OR $this->dsn .= ';TraceFile='.$this->TraceFile; + empty($this->WSID) OR $this->dsn .= ';WSID='.$this->WSID; + } + elseif (preg_match('/QuotedId=(0|1)/', $this->dsn, $match)) + { + $this->_quoted_identifier = (bool) $match[1]; + } + } + + // -------------------------------------------------------------------- + + /** + * Database connection + * + * @param bool $persistent + * @return object + */ + public function db_connect($persistent = FALSE) + { + if ( ! empty($this->char_set) && preg_match('/utf[^8]*8/i', $this->char_set)) + { + $this->options[PDO::SQLSRV_ENCODING_UTF8] = 1; + } + + $this->conn_id = parent::db_connect($persistent); + + if ( ! is_object($this->conn_id) OR is_bool($this->_quoted_identifier)) + { + return $this->conn_id; + } + + // Determine how identifiers are escaped + $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi'); + $query = $query->row_array(); + $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi']; + $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']'); + + return $this->conn_id; + } + + // -------------------------------------------------------------------- + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @param bool $prefix_limit + * @return string + */ + protected function _list_tables($prefix_limit = FALSE) + { + return 'SELECT '.$this->escape_identifiers('name') + .' FROM '.$this->escape_identifiers('sysobjects') + .' WHERE '.$this->escape_identifiers('type')." = 'U'"; + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' " + .sprintf($this->_like_escape_str, $this->_like_escape_chr); + } + + return $sql.' ORDER BY '.$this->escape_identifiers('name'); + } + + // -------------------------------------------------------------------- + + /** + * Show column query + * + * Generates a platform-specific query string so that the column names can be fetched + * + * @param string $table + * @return string + */ + protected function _list_columns($table = '') + { + return 'SELECT '.$this->escape_identifiers('column_name') + .' FROM '.$this->escape_identifiers('information_schema.columns') + .' WHERE '.$this->escape_identifiers('table_name').' = '.$this->escape($table); + } + + // -------------------------------------------------------------------- + + /** + * Update statement + * + * Generates a platform-specific update string from the supplied data + * + * @param string $table + * @param array $values + * @return string + */ + protected function _update($table, $values) + { + $this->qb_limit = FALSE; + $this->qb_orderby = array(); + return parent::_update($table, $values); + } + + // -------------------------------------------------------------------- + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @param string $table + * @return string + */ + protected function _delete($table) + { + if ($this->qb_limit) + { + return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete'; + } + + return parent::_delete($table); + } + + // -------------------------------------------------------------------- + + /** + * LIMIT + * + * Generates a platform-specific LIMIT clause + * + * @param string $sql SQL Query + * @return string + */ + protected function _limit($sql) + { + // As of SQL Server 2012 (11.0.*) OFFSET is supported + if (version_compare($this->version(), '11', '>=')) + { + return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY'; + } + + $limit = $this->qb_offset + $this->qb_limit; + + // An ORDER BY clause is required for ROW_NUMBER() to work + if ($this->qb_offset && ! empty($this->qb_orderby)) + { + $orderby = $this->_compile_order_by(); + + // We have to strip the ORDER BY clause + $sql = trim(substr($sql, 0, strrpos($sql, $orderby))); + + // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results + if (count($this->qb_select) === 0) + { + $select = '*'; // Inevitable + } + else + { + // Use only field names and their aliases, everything else is out of our scope. + $select = array(); + $field_regexp = ($this->_quoted_identifier) + ? '("[^\"]+")' : '(\[[^\]]+\])'; + for ($i = 0, $c = count($this->qb_select); $i < $c; $i++) + { + $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m) + ? $m[1] : $this->qb_select[$i]; + } + $select = implode(', ', $select); + } + + return 'SELECT '.$select." FROM (\n\n" + .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql) + ."\n\n) ".$this->escape_identifiers('CI_subquery') + ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit; + } + + return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql); + } + + // -------------------------------------------------------------------- + + /** + * Insert batch statement + * + * Generates a platform-specific insert string from the supplied data. + * + * @param string $table Table name + * @param array $keys INSERT keys + * @param array $values INSERT values + * @return string|bool + */ + protected function _insert_batch($table, $keys, $values) + { + // Multiple-value inserts are only supported as of SQL Server 2008 + if (version_compare($this->version(), '10', '>=')) + { + return parent::_insert_batch($table, $keys, $values); + } + + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; + } + +} + +/* End of file pdo_sqlsrv_driver.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlsrv_driver.php */
\ No newline at end of file diff --git a/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php new file mode 100644 index 000000000..e4b669f6e --- /dev/null +++ b/system/database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php @@ -0,0 +1,136 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * PDO SQLSRV Forge Class + * + * @category Database + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/database/ + */ +class CI_DB_pdo_sqlsrv_forge extends CI_DB_pdo_forge { + + /** + * CREATE TABLE IF statement + * + * @var string + */ + protected $_create_table_if = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nCREATE TABLE"; + + /** + * DROP TABLE IF statement + * + * @var string + */ + protected $_drop_table_if = "IF EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nDROP TABLE"; + + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'TINYINT' => 'SMALLINT', + 'SMALLINT' => 'INT', + 'INT' => 'BIGINT', + 'REAL' => 'FLOAT' + ); + + // -------------------------------------------------------------------- + + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if (in_array($alter_type, array('ADD', 'DROP'), TRUE)) + { + return parent::_alter_table($alter_type, $table, $field); + } + + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN '; + $sqls = array(); + for ($i = 0, $c = count($field); $i < $c; $i++) + { + $sqls[] = $sql.$this->_process_column($field[$i]); + } + + return $sqls; + } + + // -------------------------------------------------------------------- + + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + switch (strtoupper($attributes['TYPE'])) + { + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'INTEGER': + $attributes['TYPE'] = 'INT'; + return; + default: return; + } + } + + // -------------------------------------------------------------------- + + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) + { + $field['auto_increment'] = ' IDENTITY(1,1)'; + } + } + +} + +/* End of file pdo_sqlsrv_forge.php */ +/* Location: ./system/database/drivers/pdo/subdrivers/pdo_sqlsrv_forge.php */
\ No newline at end of file diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php index 14259be52..a52777b1e 100644 --- a/system/database/drivers/postgre/postgre_driver.php +++ b/system/database/drivers/postgre/postgre_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,12 +24,13 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Postgre Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -40,27 +41,37 @@ */ class CI_DB_postgre_driver extends CI_DB { + /** + * Database driver + * + * @var string + */ public $dbdriver = 'postgre'; - protected $_escape_char = '"'; + /** + * Database schema + * + * @var string + */ + public $schema = 'public'; - // clause and character used for LIKE escape sequences - protected $_like_escape_str = " ESCAPE '%s' "; - protected $_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. + * ORDER BY random keyword + * + * @var array */ - protected $_count_string = 'SELECT COUNT(*) AS '; - protected $_random_keyword = ' RANDOM()'; // database specific random keyword + protected $_random_keyword = array('RANDOM()', 'RANDOM()'); + + // -------------------------------------------------------------------- /** - * Constructor + * Class constructor * * Creates a DSN string to be used for db_connect() and db_pconnect() * + * @param array $params * @return void */ public function __construct($params) @@ -138,7 +149,15 @@ class CI_DB_postgre_driver extends CI_DB { */ public function db_pconnect() { - return @pg_pconnect($this->dsn); + $conn = @pg_pconnect($this->dsn); + if ($conn && pg_connection_status($conn) === PGSQL_CONNECTION_BAD) + { + if (pg_ping($conn) === FALSE) + { + return FALSE; + } + } + return $conn; } // -------------------------------------------------------------------- @@ -164,8 +183,8 @@ class CI_DB_postgre_driver extends CI_DB { /** * Set client character set * - * @param string - * @return bool + * @param string $charset + * @return bool */ protected function _db_set_charset($charset) { @@ -185,8 +204,12 @@ class CI_DB_postgre_driver extends CI_DB { { return $this->data_cache['version']; } + elseif ( ! $this->conn_id) + { + $this->initialize(); + } - if (($pg_version = pg_version($this->conn_id)) === FALSE) + if ( ! $this->conn_id OR ($pg_version = pg_version($this->conn_id)) === FALSE) { return FALSE; } @@ -206,7 +229,7 @@ class CI_DB_postgre_driver extends CI_DB { /** * Execute the query * - * @param string an SQL query + * @param string $sql an SQL query * @return resource */ protected function _execute($sql) @@ -219,6 +242,7 @@ class CI_DB_postgre_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @return bool */ public function trans_begin($test_mode = FALSE) @@ -234,7 +258,7 @@ class CI_DB_postgre_driver extends CI_DB { // even if the queries produce a successful result. $this->_trans_failure = ($test_mode === TRUE); - return @pg_query($this->conn_id, 'BEGIN'); + return (bool) @pg_query($this->conn_id, 'BEGIN'); } // -------------------------------------------------------------------- @@ -252,7 +276,7 @@ class CI_DB_postgre_driver extends CI_DB { return TRUE; } - return @pg_query($this->conn_id, 'COMMIT'); + return (bool) @pg_query($this->conn_id, 'COMMIT'); } // -------------------------------------------------------------------- @@ -270,7 +294,7 @@ class CI_DB_postgre_driver extends CI_DB { return TRUE; } - return @pg_query($this->conn_id, 'ROLLBACK'); + return (bool) @pg_query($this->conn_id, 'ROLLBACK'); } // -------------------------------------------------------------------- @@ -278,8 +302,8 @@ class CI_DB_postgre_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -310,6 +334,27 @@ class CI_DB_postgre_driver extends CI_DB { // -------------------------------------------------------------------- /** + * "Smart" Escape String + * + * Escapes data based on type + * Sets boolean and null types + * + * @param string $str + * @return mixed + */ + public function escape($str) + { + if (is_bool($str)) + { + return ($str) ? 'TRUE' : 'FALSE'; + } + + return parent::escape($str); + } + + // -------------------------------------------------------------------- + + /** * Affected Rows * * @return int @@ -328,63 +373,41 @@ class CI_DB_postgre_driver extends CI_DB { */ public function insert_id() { - $v = $this->version(); + $v = pg_version($this->conn_id); + $v = isset($v['server']) ? $v['server'] : 0; // 'server' key is only available since PosgreSQL 7.4 - $table = func_num_args() > 0 ? func_get_arg(0) : NULL; - $column = func_num_args() > 1 ? func_get_arg(1) : NULL; + $table = (func_num_args() > 0) ? func_get_arg(0) : NULL; + $column = (func_num_args() > 1) ? func_get_arg(1) : NULL; - if ($table == NULL && $v >= '8.1') - { - $sql='SELECT LASTVAL() as ins_id'; - } - elseif ($table != NULL && $column != NULL && $v >= '8.0') + if ($table === NULL && $v >= '8.1') { - $sql = sprintf("SELECT pg_get_serial_sequence('%s','%s') as seq", $table, $column); - $query = $this->query($sql); - $row = $query->row(); - $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $row->seq); + $sql = 'SELECT LASTVAL() AS ins_id'; } - elseif ($table != NULL) + elseif ($table !== NULL) { - // seq_name passed in table parameter - $sql = sprintf("SELECT CURRVAL('%s') as ins_id", $table); + if ($column !== NULL && $v >= '8.0') + { + $sql = 'SELECT pg_get_serial_sequence(\''.$table."', '".$column."') AS seq"; + $query = $this->query($sql); + $query = $query->row(); + $seq = $query->seq; + } + else + { + // seq_name passed in table parameter + $seq = $table; + } + + $sql = 'SELECT CURRVAL(\''.$seq."') AS ins_id"; } else { return pg_last_oid($this->result_id); } - $query = $this->query($sql); - $row = $query->row(); - return $row->ins_id; - } - - // -------------------------------------------------------------------- - - /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @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->num_rows() == 0) - { - return 0; - } - - $row = $query->row(); - $this->_reset_select(); - return (int) $row->numrows; + $query = $this->query($sql); + $query = $query->row(); + return (int) $query->ins_id; } // -------------------------------------------------------------------- @@ -394,16 +417,18 @@ class CI_DB_postgre_driver extends CI_DB { * * Generates a platform-specific query string so that the table names can be fetched * - * @param bool + * @param bool $prefix_limit * @return string */ protected function _list_tables($prefix_limit = FALSE) { - $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'"; + $sql = 'SELECT "table_name" FROM "information_schema"."tables" WHERE "table_schema" = \''.$this->schema."'"; - if ($prefix_limit !== FALSE AND $this->dbprefix != '') + if ($prefix_limit !== FALSE && $this->dbprefix !== '') { - $sql .= " AND table_name LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); + return $sql.' AND "table_name" LIKE \'' + .$this->escape_like_str($this->dbprefix)."%' " + .sprintf($this->_like_escape_str, $this->_like_escape_chr); } return $sql; @@ -416,12 +441,12 @@ class CI_DB_postgre_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @param string the table name + * @param string $table * @return string */ protected function _list_columns($table = '') { - return "SELECT column_name FROM information_schema.columns WHERE table_name ='".$table."'"; + return 'SELECT "column_name" FROM "information_schema"."columns" WHERE "table_name" = '.$this->escape($table); } // -------------------------------------------------------------------- @@ -431,12 +456,12 @@ class CI_DB_postgre_driver extends CI_DB { * * Generates a platform-specific query so that the column data can be retrieved * - * @param string the table name - * @return object + * @param string $table + * @return string */ protected function _field_data($table) { - return "SELECT * FROM ".$table." LIMIT 1"; + return 'SELECT * FROM '.$table.' LIMIT 1'; } // -------------------------------------------------------------------- @@ -457,22 +482,36 @@ class CI_DB_postgre_driver extends CI_DB { // -------------------------------------------------------------------- /** - * From Tables + * ORDER BY * - * This function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards - * - * @param array - * @return string + * @param string $orderby + * @param string $direction ASC or DESC + * @param bool $escape + * @return object */ - protected function _from_tables($tables) + public function order_by($orderby, $direction = '', $escape = NULL) { - if ( ! is_array($tables)) + $direction = strtoupper(trim($direction)); + if ($direction === 'RANDOM') { - $tables = array($tables); + if ( ! is_float($orderby) && ctype_digit((string) $orderby)) + { + $orderby = ($orderby > 1) + ? (float) '0.'.$orderby + : (float) $orderby; + } + + if (is_float($orderby)) + { + $this->simple_query('SET SEED '.$orderby); + } + + $orderby = $this->_random_keyword[0]; + $direction = ''; + $escape = FALSE; } - return implode(', ', $tables); + return parent::order_by($orderby, $direction, $escape); } // -------------------------------------------------------------------- @@ -482,29 +521,56 @@ class CI_DB_postgre_driver extends CI_DB { * * Generates a platform-specific update string from the supplied data * - * @param string the table name - * @param array the update data - * @param array the where clause - * @param array the orderby clause (ignored) - * @param array the limit clause (ignored) - * @param array the like clause + * @param string $table + * @param array $values + * @return string + */ + protected function _update($table, $values) + { + $this->qb_limit = FALSE; + $this->qb_orderby = array(); + return parent::_update($table, $values); + } + + // -------------------------------------------------------------------- + + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + * + * @param string $table Table name + * @param array $values Update data + * @param string $index WHERE key * @return string */ - protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array()) + protected function _update_batch($table, $values, $index) { + $ids = array(); foreach ($values as $key => $val) { - $valstr[] = $key.' = '.$val; - } + $ids[] = $val[$index]; - $where = empty($where) ? '' : ' WHERE '.implode(' ', $where); + foreach (array_keys($val) as $field) + { + if ($field !== $index) + { + $final[$field][] = 'WHEN '.$val[$index].' THEN '.$val[$field]; + } + } + } - if ( ! empty($like)) + $cases = ''; + foreach ($final as $k => $v) { - $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like); + $cases .= $k.' = (CASE '.$index."\n" + .implode("\n", $v)."\n" + .'ELSE '.$k.' END), '; } - return 'UPDATE '.$table.' SET '.implode(', ', $valstr).$where; + $this->where($index.' IN('.implode(',', $ids).')', NULL, FALSE); + + return 'UPDATE '.$table.' SET '.substr($cases, 0, -2).$this->_compile_wh('qb_where'); } // -------------------------------------------------------------------- @@ -514,43 +580,95 @@ class CI_DB_postgre_driver extends CI_DB { * * Generates a platform-specific delete string from the supplied data * - * @param string the table name - * @param array the where clause - * @param array the like clause - * @param string the limit clause (ignored) + * @param string $table * @return string */ - protected function _delete($table, $where = array(), $like = array(), $limit = FALSE) + protected function _delete($table) { - $conditions = array(); - - empty($where) OR $conditions[] = implode(' ', $where); - empty($like) OR $conditions[] = implode(' ', $like); - - return 'DELETE FROM '.$table.(count($conditions) > 0 ? ' WHERE '.implode(' AND ', $conditions) : ''); + $this->qb_limit = FALSE; + return parent::_delete($table); } // -------------------------------------------------------------------- + /** - * Limit string + * LIMIT * * Generates a platform-specific LIMIT clause * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value + * @param string $sql SQL Query * @return string */ - protected function _limit($sql, $limit, $offset) + protected function _limit($sql) + { + return $sql.' LIMIT '.$this->qb_limit.($this->qb_offset ? ' OFFSET '.$this->qb_offset : ''); + } + + // -------------------------------------------------------------------- + + /** + * WHERE, HAVING + * + * Called by where(), or_where(), having(), or_having() + * + * @param string 'qb_where' or 'qb_having' + * @param mixed + * @param mixed + * @param string + * @param bool + * @return object + */ + protected function _wh($qb_key, $key, $value = NULL, $type = 'AND ', $escape = NULL) { - $sql .= "LIMIT ".$limit; + $qb_cache_key = ($qb_key === 'qb_having') ? 'qb_cache_having' : 'qb_cache_where'; - if ($offset > 0) + if ( ! is_array($key)) { - $sql .= " OFFSET ".$offset; + $key = array($key => $value); } - return $sql; + // If the escape value was not set will will base it on the global setting + is_bool($escape) OR $escape = $this->_protect_identifiers; + + foreach ($key as $k => $v) + { + $prefix = (count($this->$qb_key) === 0 && count($this->$qb_cache_key) === 0) + ? $this->_group_get_type('') + : $this->_group_get_type($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 (is_bool($v)) + { + $v = ' '.($v ? 'TRUE' : 'FALSE'); + } + elseif ($escape === TRUE) + { + $v = ' '.(is_int($v) ? $v : $this->escape($v)); + } + + if ( ! $this->_has_operator($k)) + { + $k .= ' = '; + } + } + + $this->{$qb_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape); + if ($this->qb_caching === TRUE) + { + $this->{$qb_cache_key}[] = array('condition' => $prefix.$k.$v, 'escape' => $escape); + $this->qb_cache_exists[] = substr($qb_key, 3); + } + + } + + return $this; } // -------------------------------------------------------------------- @@ -558,12 +676,11 @@ class CI_DB_postgre_driver extends CI_DB { /** * Close DB Connection * - * @param resource * @return void */ - protected function _close($conn_id) + protected function _close() { - @pg_close($conn_id); + @pg_close($this->conn_id); } } diff --git a/system/database/drivers/postgre/postgre_forge.php b/system/database/drivers/postgre/postgre_forge.php index 8b214ebe6..425622fac 100644 --- a/system/database/drivers/postgre/postgre_forge.php +++ b/system/database/drivers/postgre/postgre_forge.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Postgre Forge Class @@ -34,215 +35,151 @@ */ class CI_DB_postgre_forge extends CI_DB_forge { - protected $_drop_table = 'DROP TABLE IF EXISTS %s CASCADE'; + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'INT2' => 'INTEGER', + 'SMALLINT' => 'INTEGER', + 'INT' => 'BIGINT', + 'INT4' => 'BIGINT', + 'INTEGER' => 'BIGINT', + 'INT8' => 'NUMERIC', + 'BIGINT' => 'NUMERIC', + 'REAL' => 'DOUBLE PRECISION', + 'FLOAT' => 'DOUBLE PRECISION' + ); /** - * Process Fields + * NULL value representation in CREATE/ALTER TABLE statements * - * @param mixed the fields - * @return string + * @var string */ - protected function _process_fields($fields, $primary_keys=array()) + protected $_null = 'NULL'; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @param object &$db Database object + * @return void + */ + public function __construct(&$db) { - $sql = ''; - $current_field_count = 0; + parent::__construct($db); - foreach ($fields as $field => $attributes) + if (version_compare($this->db->version(), '9.0', '>')) { - // 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); - - $is_unsigned = (array_key_exists('UNSIGNED', $attributes) && $attributes['UNSIGNED'] === TRUE); - - // Convert datatypes to be PostgreSQL-compatible - switch (strtoupper($attributes['TYPE'])) - { - case 'TINYINT': - $attributes['TYPE'] = 'SMALLINT'; - break; - case 'SMALLINT': - $attributes['TYPE'] = ($is_unsigned) ? 'INTEGER' : 'SMALLINT'; - break; - case 'MEDIUMINT': - $attributes['TYPE'] = 'INTEGER'; - break; - case 'INT': - $attributes['TYPE'] = ($is_unsigned) ? 'BIGINT' : 'INTEGER'; - break; - case 'BIGINT': - $attributes['TYPE'] = ($is_unsigned) ? 'NUMERIC' : 'BIGINT'; - break; - case 'DOUBLE': - $attributes['TYPE'] = 'DOUBLE PRECISION'; - break; - case 'DATETIME': - $attributes['TYPE'] = 'TIMESTAMP'; - break; - case 'LONGTEXT': - $attributes['TYPE'] = 'TEXT'; - break; - case 'BLOB': - $attributes['TYPE'] = 'BYTEA'; - break; - } - - // If this is an auto-incrementing primary key, use the serial data type instead - if (in_array($field, $primary_keys) && array_key_exists('AUTO_INCREMENT', $attributes) - && $attributes['AUTO_INCREMENT'] === TRUE) - { - $sql .= ' SERIAL'; - } - else - { - $sql .= ' '.$attributes['TYPE']; - } - - // Modified to prevent constraints with integer data types - if (array_key_exists('CONSTRAINT', $attributes) && strpos($attributes['TYPE'], 'INT') === false) - { - $sql .= '('.$attributes['CONSTRAINT'].')'; - } - - if (array_key_exists('DEFAULT', $attributes)) - { - $sql .= ' DEFAULT \''.$attributes['DEFAULT'].'\''; - } - - if (array_key_exists('NULL', $attributes) && $attributes['NULL'] === TRUE) - { - $sql .= ' NULL'; - } - else - { - $sql .= ' NOT NULL'; - } - - // Added new attribute to create unqite fields. Also works with MySQL - 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 .= ','; - } + $this->create_table_if = 'CREATE TABLE IF NOT EXISTS'; } - - return $sql; } // -------------------------------------------------------------------- /** - * Create Table + * ALTER TABLE * - * @param string the table name - * @param array the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return bool + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] */ - protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) - { - $sql = 'CREATE TABLE '; + protected function _alter_table($alter_type, $table, $field) + { + if (in_array($alter_type, array('DROP', 'ADD'), TRUE)) + { + return parent::_alter_table($alter_type, $table, $field); + } - if ($if_not_exists === TRUE) + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table); + $sqls = array(); + for ($i = 0, $c = count($field), $sql .= $alter_type.' '; $i < $c; $i++) { - // PostgreSQL doesn't support IF NOT EXISTS syntax so we check if table exists manually - if ($this->db->table_exists($table)) + if ($field[$i]['_literal'] !== FALSE) { - return TRUE; + return FALSE; } - } - $sql .= $this->db->escape_identifiers($table).' ('.$this->_process_fields($fields, $primary_keys); - - if (count($primary_keys) > 0) - { - // Something seems to break when passing an array to protect_identifiers() - foreach ($primary_keys as $index => $key) + if (version_compare($this->db->version(), '8', '>=') && isset($field[$i]['type'])) { - $primary_keys[$index] = $this->db->protect_identifiers($key); + $sqls[] = $sql.' TYPE '.$field[$i]['type'].$field[$i]['length']; } - $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; - } + if ( ! empty($field[$i]['default'])) + { + $sqls[] = $sql.' ALTER '.$this->db->escape_identifiers($field[$i]['name']) + .' SET '.$field[$i]['default']; + } - $sql .= "\n);"; + if (isset($field[$i]['null'])) + { + $sqls[] = $sql.' ALTER '.$this->db->escape_identifiers($field[$i]['name']) + .($field[$i]['null'] === TRUE ? ' DROP NOT NULL' : ' SET NOT NULL'); + } - if (is_array($keys) && count($keys) > 0) - { - foreach ($keys as $key) + if ( ! empty($field[$i]['new_name'])) { - if (is_array($key)) - { - $key = $this->db->protect_identifiers($key); - } - else - { - $key = array($this->db->protect_identifiers($key)); - } - - foreach ($key as $field) - { - $sql .= "CREATE INDEX " . $table . "_" . str_replace(array('"', "'"), '', $field) . "_index ON $table ($field); "; - } + $sqls[] = $sql.' RENAME '.$this->db->escape_identifiers($field[$i]['name']) + .' TO '.$this->db->escape_identifiers($field[$i]['new_name']); } } - return $sql; - } + return $sqls; + } // -------------------------------------------------------------------- /** - * Alter table query + * Field attribute TYPE * - * Generates a platform-specific query so that a table can be altered - * Called by add_column(), drop_column(), and column_alter(), + * Performs a data type mapping between different databases. * - * @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 string + * @param array &$attributes + * @return void */ - protected 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); - } + protected function _attr_type(&$attributes) + { + // Reset field lenghts for data types that don't support it + if (isset($attributes['CONSTRAINT']) && stripos($attributes['TYPE'], 'int') !== FALSE) + { + $attributes['CONSTRAINT'] = NULL; + } - $sql .= $this->_process_fields($fields); + switch (strtoupper($attributes['TYPE'])) + { + case 'TINYINT': + $attributes['TYPE'] = 'SMALLINT'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + default: return; + } + } - if ($after_field != '') - { - return $sql.' AFTER '.$this->db->protect_identifiers($after_field); - } + // -------------------------------------------------------------------- - return $sql; - } + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) + { + $field['type'] = ($field['type'] === 'NUMERIC') + ? 'BIGSERIAL' + : 'SERIAL'; + } + } } diff --git a/system/database/drivers/postgre/postgre_result.php b/system/database/drivers/postgre/postgre_result.php index f913bc9eb..3f73f84c7 100644 --- a/system/database/drivers/postgre/postgre_result.php +++ b/system/database/drivers/postgre/postgre_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Postgres Result Class @@ -33,6 +34,7 @@ * @category Database * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ + * @since 1.3 */ class CI_DB_postgre_result extends CI_DB_result { @@ -43,7 +45,9 @@ class CI_DB_postgre_result extends CI_DB_result { */ public function num_rows() { - return @pg_num_rows($this->result_id); + return is_int($this->num_rows) + ? $this->num_rows + : $this->num_rows = @pg_num_rows($this->result_id); } // -------------------------------------------------------------------- @@ -126,8 +130,9 @@ class CI_DB_postgre_result extends CI_DB_result { * * Moves the internal pointer to the desired offset. We call * this internally before fetching results to make sure the - * result set starts at zero + * result set starts at zero. * + * @param int $n * @return bool */ protected function _data_seek($n = 0) @@ -156,11 +161,12 @@ class CI_DB_postgre_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @return object */ - protected function _fetch_object() + protected function _fetch_object($class_name = 'stdClass') { - return pg_fetch_object($this->result_id); + return pg_fetch_object($this->result_id, NULL, $class_name); } } diff --git a/system/database/drivers/postgre/postgre_utility.php b/system/database/drivers/postgre/postgre_utility.php index c95e6df0c..d3b2b9cdc 100644 --- a/system/database/drivers/postgre/postgre_utility.php +++ b/system/database/drivers/postgre/postgre_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Postgre Utility Class @@ -34,19 +35,32 @@ */ class CI_DB_postgre_utility extends CI_DB_utility { + /** + * List databases statement + * + * @var string + */ protected $_list_databases = 'SELECT datname FROM pg_database'; + + /** + * OPTIMIZE TABLE statement + * + * @var string + */ protected $_optimize_table = 'REINDEX TABLE %s'; + // -------------------------------------------------------------------- + /** - * Postgre Export + * Export * - * @param array Preferences + * @param array $params Preferences * @return mixed */ protected function _backup($params = array()) { // Currently unsupported - return $this->db->display_error('db_unsuported_feature'); + return $this->db->display_error('db_unsupported_feature'); } } diff --git a/system/database/drivers/sqlite/sqlite_driver.php b/system/database/drivers/sqlite/sqlite_driver.php index 5021deb63..23f287b7e 100644 --- a/system/database/drivers/sqlite/sqlite_driver.php +++ b/system/database/drivers/sqlite/sqlite_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,12 +24,13 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * SQLite Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -40,22 +41,23 @@ */ class CI_DB_sqlite_driver extends CI_DB { + /** + * Database driver + * + * @var string + */ public $dbdriver = 'sqlite'; - // The character used to escape with - not needed for SQLite - protected $_escape_char = ''; - - // clause and character used for LIKE escape sequences - protected $_like_escape_str = " ESCAPE '%s' "; - protected $_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. + * ORDER BY random keyword + * + * @var array */ - protected $_count_string = 'SELECT COUNT(*) AS '; - protected $_random_keyword = ' Random()'; // database specific random keyword + protected $_random_keyword = array('RANDOM()', 'RANDOM()'); + + // -------------------------------------------------------------------- /** * Non-persistent database connection @@ -122,12 +124,14 @@ class CI_DB_sqlite_driver extends CI_DB { /** * Execute the query * - * @param string an SQL query + * @param string $sql an SQL query * @return resource */ protected function _execute($sql) { - return @sqlite_query($this->conn_id, $sql); + return $this->is_write_type($sql) + ? @sqlite_exec($this->conn_id, $sql) + : @sqlite_query($this->conn_id, $sql); } // -------------------------------------------------------------------- @@ -135,17 +139,13 @@ class CI_DB_sqlite_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -153,7 +153,7 @@ class CI_DB_sqlite_driver extends CI_DB { // 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->_trans_failure = ($test_mode === TRUE); $this->simple_query('BEGIN TRANSACTION'); return TRUE; @@ -168,13 +168,8 @@ class CI_DB_sqlite_driver extends CI_DB { */ 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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -192,13 +187,8 @@ class CI_DB_sqlite_driver extends CI_DB { */ 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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -212,8 +202,8 @@ class CI_DB_sqlite_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -268,50 +258,22 @@ class CI_DB_sqlite_driver extends CI_DB { // -------------------------------------------------------------------- /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @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->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 * - * @param bool + * @param bool $prefix_limit * @return string */ protected function _list_tables($prefix_limit = FALSE) { - $sql = "SELECT name from sqlite_master WHERE type='table'"; + $sql = "SELECT name FROM sqlite_master WHERE type='table'"; - if ($prefix_limit !== FALSE AND $this->dbprefix != '') + if ($prefix_limit !== FALSE && $this->dbprefix != '') { - $sql .= " AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); + return $sql." AND 'name' LIKE '".$this->escape_like_str($this->dbprefix)."%' ".sprintf($this->_like_escape_str, $this->_like_escape_chr); } + return $sql; } @@ -322,7 +284,7 @@ class CI_DB_sqlite_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @param string the table name + * @param string $table * @return bool */ protected function _list_columns($table = '') @@ -338,12 +300,12 @@ class CI_DB_sqlite_driver extends CI_DB { * * Generates a platform-specific query so that the column data can be retrieved * - * @param string the table name + * @param string $table * @return string */ protected function _field_data($table) { - return "SELECT * FROM ".$table." LIMIT 1"; + return 'SELECT * FROM '.$this->escape_identifiers($table).' LIMIT 1'; } // -------------------------------------------------------------------- @@ -366,34 +328,13 @@ class CI_DB_sqlite_driver extends CI_DB { // -------------------------------------------------------------------- /** - * From Tables - * - * This function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards - * - * @param array - * @return string - */ - protected function _from_tables($tables) - { - if ( ! is_array($tables)) - { - $tables = array($tables); - } - - return '('.implode(', ', $tables).')'; - } - - // -------------------------------------------------------------------- - - /** * Replace statement * * Generates a platform-specific replace string from the supplied data * - * @param string the table name - * @param array the insert keys - * @param array the insert values + * @param string $table Table name + * @param array $keys INSERT keys + * @param array $values INSERT values * @return string */ protected function _replace($table, $keys, $values) @@ -408,10 +349,10 @@ class CI_DB_sqlite_driver extends CI_DB { * * Generates a platform-specific truncate string from the supplied data * - * If the database does not support the truncate() command, + * If the database does not support the TRUNCATE statement, * then this function maps to 'DELETE FROM table' * - * @param string the table name + * @param string $table * @return string */ protected function _truncate($table) @@ -422,40 +363,13 @@ class CI_DB_sqlite_driver extends CI_DB { // -------------------------------------------------------------------- /** - * Limit string - * - * Generates a platform-specific LIMIT clause - * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value - * @return string - */ - protected function _limit($sql, $limit, $offset) - { - if ($offset == 0) - { - $offset = ''; - } - else - { - $offset .= ", "; - } - - return $sql."LIMIT ".$offset.$limit; - } - - // -------------------------------------------------------------------- - - /** * Close DB Connection * - * @param resource * @return void */ - protected function _close($conn_id) + protected function _close() { - @sqlite_close($conn_id); + @sqlite_close($this->conn_id); } } diff --git a/system/database/drivers/sqlite/sqlite_forge.php b/system/database/drivers/sqlite/sqlite_forge.php index dd6f0f78d..6ad583560 100644 --- a/system/database/drivers/sqlite/sqlite_forge.php +++ b/system/database/drivers/sqlite/sqlite_forge.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * SQLite Forge Class @@ -35,9 +36,32 @@ class CI_DB_sqlite_forge extends CI_DB_forge { /** + * CREATE TABLE IF statement + * + * @var string + */ + protected $_create_table_if = FALSE; + + /** + * UNSIGNED support + * + * @var bool|array + */ + protected $_unsigned = FALSE; + + /** + * NULL value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_null = 'NULL'; + + // -------------------------------------------------------------------- + + /** * Create database * - * @param string the database name + * @param string $db_name (ignored) * @return bool */ public function create_database($db_name = '') @@ -52,7 +76,7 @@ class CI_DB_sqlite_forge extends CI_DB_forge { /** * Drop database * - * @param string the database name (ignored) + * @param string $db_name (ignored) * @return bool */ public function drop_database($db_name = '') @@ -61,6 +85,14 @@ class CI_DB_sqlite_forge extends CI_DB_forge { { return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE; } + elseif ( ! empty($this->db->data_cache['db_names'])) + { + $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); + if ($key !== FALSE) + { + unset($this->db->data_cache['db_names'][$key]); + } + } return TRUE; } @@ -68,163 +100,95 @@ class CI_DB_sqlite_forge extends CI_DB_forge { // -------------------------------------------------------------------- /** - * Create Table + * ALTER TABLE * - * @param string the table name - * @param array the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return bool + * @todo implement drop_column(), modify_column() + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] */ - protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + protected function _alter_table($alter_type, $table, $field) { - $sql = 'CREATE TABLE '; - - // IF NOT EXISTS added to SQLite in 3.3.0 - if ($if_not_exists === TRUE && version_compare($this->db->version(), '3.3.0', '>=') === TRUE) - { - $sql .= 'IF NOT EXISTS '; - } - - $sql .= $this->db->escape_identifiers($table).' ('; - $current_field_count = 0; - - foreach ($fields as $field => $attributes) + if ($alter_type === 'DROP' OR $alter_type === 'CHANGE') { - // 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 .= ','; - } - } + // drop_column(): + // BEGIN TRANSACTION; + // CREATE TEMPORARY TABLE t1_backup(a,b); + // INSERT INTO t1_backup SELECT a,b FROM t1; + // DROP TABLE t1; + // CREATE TABLE t1(a,b); + // INSERT INTO t1 SELECT a,b FROM t1_backup; + // DROP TABLE t1_backup; + // COMMIT; - if (count($primary_keys) > 0) - { - $primary_keys = $this->db->protect_identifiers($primary_keys); - $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + return FALSE; } - 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 (" . implode(', ', $key) . ")"; - } - } + return parent::_alter_table($alter_type, $table, $field); + } - $sql .= "\n)"; + // -------------------------------------------------------------------- - return $sql; + /** + * Process column + * + * @param array $field + * @return string + */ + protected function _process_column($field) + { + return $this->db->escape_identifiers($field['name']) + .' '.$field['type'] + .$field['auto_increment'] + .$field['null'] + .$field['unique'] + .$field['default']; } // -------------------------------------------------------------------- /** - * Alter table query + * Field attribute TYPE * - * Generates a platform-specific query so that a table can be altered - * Called by add_column(), drop_column(), and column_alter(), + * Performs a data type mapping between different databases. * - * @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 bool should 'NOT NULL' be added - * @param string the field after which we should add the new field - * @return string + * @param array &$attributes + * @return void */ - protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + protected function _attr_type(&$attributes) { - $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') + switch (strtoupper($attributes['TYPE'])) { - // SQLite does not support dropping columns - // http://www.sqlite.org/omitted.html - // http://www.sqlite.org/faq.html#q11 - return FALSE; + case 'ENUM': + case 'SET': + $attributes['TYPE'] = 'TEXT'; + return; + default: return; } + } - $sql .= " $column_definition"; - - if ($default_value != '') - { - $sql .= " DEFAULT \"$default_value\""; - } + // -------------------------------------------------------------------- - if ($null === NULL) - { - $sql .= ' NULL'; - } - else + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) { - $sql .= ' NOT NULL'; - } + $field['type'] = 'INTEGER PRIMARY KEY'; + $field['default'] = ''; + $field['null'] = ''; + $field['unique'] = ''; + $field['auto_increment'] = ' AUTOINCREMENT'; - if ($after_field != '') - { - return $sql.' AFTER '.$this->db->protect_identifiers($after_field); + $this->primary_keys = array(); } - - return $sql; - } } diff --git a/system/database/drivers/sqlite/sqlite_result.php b/system/database/drivers/sqlite/sqlite_result.php index 741dc9d8d..0e6335f73 100644 --- a/system/database/drivers/sqlite/sqlite_result.php +++ b/system/database/drivers/sqlite/sqlite_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * SQLite Result Class @@ -33,6 +34,7 @@ * @category Database * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ + * @since 1.3 */ class CI_DB_sqlite_result extends CI_DB_result { @@ -43,7 +45,9 @@ class CI_DB_sqlite_result extends CI_DB_result { */ public function num_rows() { - return @sqlite_num_rows($this->result_id); + return is_int($this->num_rows) + ? $this->num_rows + : $this->num_rows = @sqlite_num_rows($this->result_id); } // -------------------------------------------------------------------- @@ -110,8 +114,9 @@ class CI_DB_sqlite_result extends CI_DB_result { * * Moves the internal pointer to the desired offset. We call * this internally before fetching results to make sure the - * result set starts at zero + * result set starts at zero. * + * @param int $n * @return bool */ protected function _data_seek($n = 0) @@ -140,17 +145,12 @@ class CI_DB_sqlite_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @return object */ - protected function _fetch_object() + protected function _fetch_object($class_name = 'stdClass') { - if (function_exists('sqlite_fetch_object')) - { - return sqlite_fetch_object($this->result_id); - } - - $arr = sqlite_fetch_array($this->result_id, SQLITE_ASSOC); - return is_array($arr) ? (object) $arr : FALSE; + return sqlite_fetch_object($this->result_id, $class_name); } } diff --git a/system/database/drivers/sqlite/sqlite_utility.php b/system/database/drivers/sqlite/sqlite_utility.php index 1bcb42d9f..222d02712 100644 --- a/system/database/drivers/sqlite/sqlite_utility.php +++ b/system/database/drivers/sqlite/sqlite_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * SQLite Utility Class @@ -34,18 +35,16 @@ */ class CI_DB_sqlite_utility extends CI_DB_utility { - protected $_list_databases = FALSE; - /** - * SQLite Export + * Export * - * @param array Preferences + * @param array $params Preferences * @return mixed */ protected function _backup($params = array()) { // Currently unsupported - return $this->db->display_error('db_unsuported_feature'); + return $this->db->display_error('db_unsupported_feature'); } } diff --git a/system/database/drivers/sqlite3/sqlite3_driver.php b/system/database/drivers/sqlite3/sqlite3_driver.php index fb45bee9c..f0818aea1 100644 --- a/system/database/drivers/sqlite3/sqlite3_driver.php +++ b/system/database/drivers/sqlite3/sqlite3_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,12 +24,13 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * SQLite3 Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -41,22 +42,23 @@ */ class CI_DB_sqlite3_driver extends CI_DB { + /** + * Database driver + * + * @var string + */ public $dbdriver = 'sqlite3'; - // The character used for escaping - protected $_escape_char = '"'; - - // clause and character used for LIKE escape sequences - protected $_like_escape_str = ' ESCAPE \'%s\' '; - protected $_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. + * ORDER BY random keyword + * + * @var array */ - protected $_count_string = 'SELECT COUNT(*) AS '; - protected $_random_keyword = ' RANDOM()'; + protected $_random_keyword = array('RANDOM()', 'RANDOM()'); + + // -------------------------------------------------------------------- /** * Non-persistent database connection @@ -87,7 +89,7 @@ class CI_DB_sqlite3_driver extends CI_DB { public function db_pconnect() { log_message('debug', 'SQLite3 doesn\'t support persistent connections'); - return $this->db_pconnect(); + return $this->db_connect(); } // -------------------------------------------------------------------- @@ -104,7 +106,7 @@ class CI_DB_sqlite3_driver extends CI_DB { return $this->data_cache['version']; } - $version = $this->conn_id->version(); + $version = SQLite3::version(); return $this->data_cache['version'] = $version['versionString']; } @@ -113,13 +115,12 @@ class CI_DB_sqlite3_driver extends CI_DB { /** * Execute the query * - * @param string an SQL query + * @todo Implement use of SQLite3::querySingle(), if needed + * @param string $sql * @return mixed SQLite3Result object or bool */ protected function _execute($sql) { - // TODO: Implement use of SQLite3::querySingle(), if needed - return $this->is_write_type($sql) ? $this->conn_id->exec($sql) : $this->conn_id->query($sql); @@ -130,6 +131,7 @@ class CI_DB_sqlite3_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @return bool */ public function trans_begin($test_mode = FALSE) @@ -189,8 +191,8 @@ class CI_DB_sqlite3_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -245,35 +247,11 @@ class CI_DB_sqlite3_driver extends CI_DB { // -------------------------------------------------------------------- /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @param string - * @return int - */ - public function count_all($table = '') - { - if ($table == '') - { - return 0; - } - - $result = $this->conn_id->querySingle($this->_count_string.$this->protect_identifiers('numrows') - .' FROM '.$this->protect_identifiers($table, TRUE, NULL, FALSE)); - - return empty($result) ? 0 : (int) $result; - } - - // -------------------------------------------------------------------- - - /** * Show table query * * Generates a platform-specific query string so that the table names can be fetched * - * @param bool + * @param bool $prefix_limit * @return string */ protected function _list_tables($prefix_limit = FALSE) @@ -291,7 +269,7 @@ class CI_DB_sqlite3_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @param string the table name + * @param string $table * @return string */ protected function _list_columns($table = '') @@ -307,7 +285,7 @@ class CI_DB_sqlite3_driver extends CI_DB { * * Generates a platform-specific query so that the column data can be retrieved * - * @param string the table name + * @param string $table * @return string */ protected function _field_data($table) @@ -318,46 +296,16 @@ class CI_DB_sqlite3_driver extends CI_DB { // -------------------------------------------------------------------- /** - * The error message string + * Error * - * @return string - */ - protected function _error_message() - { - return $this->conn_id->lastErrorMsg(); - } - - // -------------------------------------------------------------------- - - /** - * The error message number + * Returns an array containing code and message of the last + * database error that has occured. * - * @return int + * @return array */ - protected function _error_number() + public function error() { - return $this->conn_id->lastErrorCode(); - } - - // -------------------------------------------------------------------- - - /** - * From Tables - * - * This function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards - * - * @param string - * @return string - */ - protected function _from_tables($tables) - { - if ( ! is_array($tables)) - { - $tables = array($tables); - } - - return '('.implode(', ', $tables).')'; + return array('code' => $this->conn_id->lastErrorCode(), 'message' => $this->conn_id->lastErrorMsg()); } // -------------------------------------------------------------------- @@ -367,9 +315,9 @@ class CI_DB_sqlite3_driver extends CI_DB { * * Generates a platform-specific replace string from the supplied data * - * @param string the table name - * @param array the insert keys - * @param array the insert values + * @param string $table Table name + * @param array $keys INSERT keys + * @param array $values INSERT values * @return string */ protected function _replace($table, $keys, $values) @@ -384,10 +332,10 @@ class CI_DB_sqlite3_driver extends CI_DB { * * Generates a platform-specific truncate string from the supplied data * - * If the database does not support the truncate() command, then, + * If the database does not support the TRUNCATE statement, * then this method maps to 'DELETE FROM table' * - * @param string the table name + * @param string $table * @return string */ protected function _truncate($table) @@ -398,29 +346,11 @@ class CI_DB_sqlite3_driver extends CI_DB { // -------------------------------------------------------------------- /** - * Limit string - * - * Generates a platform-specific LIMIT clause - * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value - * @return string - */ - protected function _limit($sql, $limit, $offset) - { - return $sql.' LIMIT '.($offset ? $offset.',' : '').$limit; - } - - // -------------------------------------------------------------------- - - /** * Close DB Connection * - * @param object (ignored) * @return void */ - protected function _close($conn_id) + protected function _close() { $this->conn_id->close(); } diff --git a/system/database/drivers/sqlite3/sqlite3_forge.php b/system/database/drivers/sqlite3/sqlite3_forge.php index 20f1e6f63..e9b91e972 100644 --- a/system/database/drivers/sqlite3/sqlite3_forge.php +++ b/system/database/drivers/sqlite3/sqlite3_forge.php @@ -1,8 +1,8 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * - * An open source application development framework for PHP 5.1.6 or newer + * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * SQLite3 Forge Class @@ -35,9 +36,43 @@ class CI_DB_sqlite3_forge extends CI_DB_forge { /** + * UNSIGNED support + * + * @var bool|array + */ + protected $_unsigned = FALSE; + + /** + * NULL value representation in CREATE/ALTER TABLE statements + * + * @var string + */ + protected $_null = 'NULL'; + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @param object &$db Database object + * @return void + */ + public function __construct(&$db) + { + parent::__construct($db); + + if (version_compare($this->db->version(), '3.3', '<')) + { + $this->create_table_if = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** * Create database * - * @param string the database name + * @param string $db_name * @return bool */ public function create_database($db_name = '') @@ -52,7 +87,7 @@ class CI_DB_sqlite3_forge extends CI_DB_forge { /** * Drop database * - * @param string the database name (ignored) + * @param string $db_name (ignored) * @return bool */ public function drop_database($db_name = '') @@ -66,6 +101,14 @@ class CI_DB_sqlite3_forge extends CI_DB_forge { { return $this->db->db_debug ? $this->db->display_error('db_unable_to_drop') : FALSE; } + elseif ( ! empty($this->db->data_cache['db_names'])) + { + $key = array_search(strtolower($this->db->database), array_map('strtolower', $this->db->data_cache['db_names']), TRUE); + if ($key !== FALSE) + { + unset($this->db->data_cache['db_names'][$key]); + } + } return TRUE; } @@ -76,117 +119,95 @@ class CI_DB_sqlite3_forge extends CI_DB_forge { // -------------------------------------------------------------------- /** - * Create Table + * ALTER TABLE * - * @param string the table name - * @param array the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return bool + * @todo implement drop_column(), modify_column() + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] */ - protected function _create_table($table, $fields, $primary_keys, $keys, $if_not_exists) + protected function _alter_table($alter_type, $table, $field) { - $sql = 'CREATE TABLE '; - - // IF NOT EXISTS added to SQLite in 3.3.0 - if ($if_not_exists === TRUE && version_compare($this->db->version(), '3.3.0', '>=') === TRUE) + if ($alter_type === 'DROP' OR $alter_type === 'CHANGE') { - $sql .= 'IF NOT EXISTS '; + // drop_column(): + // BEGIN TRANSACTION; + // CREATE TEMPORARY TABLE t1_backup(a,b); + // INSERT INTO t1_backup SELECT a,b FROM t1; + // DROP TABLE t1; + // CREATE TABLE t1(a,b); + // INSERT INTO t1 SELECT a,b FROM t1_backup; + // DROP TABLE t1_backup; + // COMMIT; + + return FALSE; } - $sql .= $this->db->escape_identifiers($table).' ('; - $current_field_count = 0; + return parent::_alter_table($alter_type, $table, $field); + } - 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) - .' '.$attributes['TYPE'] - .( ! empty($attributes['CONSTRAINT']) ? '('.$attributes['CONSTRAINT'].')' : '') - .(( ! empty($attributes['UNSIGNED']) && $attributes['UNSIGNED'] === TRUE) ? ' UNSIGNED' : '') - .(isset($attributes['DEFAULT']) ? ' DEFAULT \''.$attributes['DEFAULT'].'\'' : '') - .(( ! empty($attributes['NULL']) && $attributes['NULL'] === TRUE) ? ' NULL' : ' NOT NULL') - .(( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE) ? ' AUTO_INCREMENT' : ''); - } + // -------------------------------------------------------------------- - // don't add a comma on the end of the last field - if (++$current_field_count < count($fields)) - { - $sql .= ','; - } - } + /** + * Process column + * + * @param array $field + * @return string + */ + protected function _process_column($field) + { + return $this->db->escape_identifiers($field['name']) + .' '.$field['type'] + .$field['auto_increment'] + .$field['null'] + .$field['unique'] + .$field['default']; + } - 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) + /** + * Field attribute TYPE + * + * Performs a data type mapping between different databases. + * + * @param array &$attributes + * @return void + */ + protected function _attr_type(&$attributes) + { + switch (strtoupper($attributes['TYPE'])) { - 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 (".implode(', ', $key).')'; - } + case 'ENUM': + case 'SET': + $attributes['TYPE'] = 'TEXT'; + return; + default: return; } - - return $sql."\n)"; } // -------------------------------------------------------------------- /** - * Alter table query - * - * Generates a platform-specific query so that a table can be altered - * Called by add_column(), drop_column(), and column_alter(), + * Field attribute AUTO_INCREMENT * - * @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 bool should 'NOT NULL' be added - * @param string the field after which we should add the new field - * @return string + * @param array &$attributes + * @param array &$field + * @return void */ - protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + protected function _attr_auto_increment(&$attributes, &$field) { - /* SQLite only supports adding new columns and it does - * NOT support the AFTER statement. Each new column will - * be added as the last one in the table. - */ - if ($alter_type !== 'ADD COLUMN') + if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) { - // Not supported - return FALSE; - } + $field['type'] = 'INTEGER PRIMARY KEY'; + $field['default'] = ''; + $field['null'] = ''; + $field['unique'] = ''; + $field['auto_increment'] = ' AUTOINCREMENT'; - return 'ALTER TABLE '.$this->db->protect_identifiers($table).' '.$alter_type.' '.$this->db->protect_identifiers($column_name) - .' '.$column_definition - .($default_value != '' ? ' DEFAULT '.$default_value : '') - // If NOT NULL is specified, the field must have a DEFAULT value other than NULL - .(($null !== NULL && $default_value !== 'NULL') ? ' NOT NULL' : ' NULL'); + $this->primary_keys = array(); + } } } diff --git a/system/database/drivers/sqlite3/sqlite3_result.php b/system/database/drivers/sqlite3/sqlite3_result.php index d83d6b2cd..153e3480a 100644 --- a/system/database/drivers/sqlite3/sqlite3_result.php +++ b/system/database/drivers/sqlite3/sqlite3_result.php @@ -1,8 +1,8 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * - * An open source application development framework for PHP 5.1.6 or newer + * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE * @@ -24,41 +24,20 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** - * SQLite Result Class + * SQLite3 Result Class * * This class extends the parent result class: CI_DB_result * * @category Database - * @author Andrey Andreev - * @link http://codeigniter.com/user_guide/database/ + * @author Andrey Andreev + * @link http://codeigniter.com/user_guide/database/ + * @since 3.0 */ class CI_DB_sqlite3_result extends CI_DB_result { - // Overwriting the parent here, so we have a way to know if it's already set - public $num_rows; - - // num_fields() might be called multiple times, so we'll use this one to cache it's result - protected $_num_fields; - - /** - * Number of rows in the result set - * - * @return int - */ - public function num_rows() - { - /* The SQLite3 driver doesn't have a graceful way to do this, - * so we'll have to do it on our own. - */ - return is_int($this->num_rows) - ? $this->num_rows - : $this->num_rows = count($this->result_array()); - } - - // -------------------------------------------------------------------- - /** * Number of fields in the result set * @@ -66,9 +45,7 @@ class CI_DB_sqlite3_result extends CI_DB_result { */ public function num_fields() { - return ( ! is_int($this->_num_fields)) - ? $this->_num_fields = $this->result_id->numColumns() - : $this->_num_fields; + return $this->result_id->numColumns(); } // -------------------------------------------------------------------- @@ -153,443 +130,28 @@ class CI_DB_sqlite3_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @return object */ - protected function _fetch_object() + protected function _fetch_object($class_name = 'stdClass') { - // No native support for fetching as an object - $row = $this->_fetch_assoc(); - return ($row !== FALSE) ? (object) $row : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Query result. "array" version. - * - * return array - */ - public function result_array() - { - if (count($this->result_array) > 0) - { - return $this->result_array; - } - elseif (is_array($this->row_data)) + // No native support for fetching rows as objects + if (($row = $this->result_id->fetchArray(SQLITE3_ASSOC)) === FALSE) { - if (count($this->row_data) === 0) - { - return $this->result_array; - } - else - { - $row_index = count($this->row_data); - } + return FALSE; } - else + elseif ($class_name === 'stdClass') { - $row_index = 0; - $this->row_data = array(); - } - - $row = NULL; - while ($row = $this->_fetch_assoc()) - { - $this->row_data[$row_index++] = $row; - } - - return $this->result_array = $this->row_data; - } - - // -------------------------------------------------------------------- - - /** - * Query result. "object" version. - * - * @return array - */ - public function result_object() - { - if (count($this->result_object) > 0) - { - return $this->result_object; - } - elseif (count($this->result_array) > 0) - { - for ($i = 0, $c = count($this->result_array); $i < $c; $i++) - { - $this->result_object[] = (object) $this->result_array[$i]; - } - - return $this->result_object; - } - elseif (is_array($this->row_data)) - { - if (count($this->row_data) === 0) - { - return $this->result_object; - } - else - { - $row_index = count($this->row_data); - for ($i = 0; $i < $row_index; $i++) - { - $this->result_object[$i] = (object) $this->row_data[$i]; - } - } - } - else - { - $row_index = 0; - $this->row_data = array(); - } - - $row = NULL; - while ($row = $this->_fetch_assoc()) - { - $this->row_data[$row_index] = $row; - $this->result_object[$row_index++] = (object) $row; - } - - $this->result_array = $this->row_data; - - /* As described for the num_rows() method - there's no easy - * way to get the number of rows selected. Our work-around - * solution (as in here as well) first checks if result_array - * exists and returns its count. It doesn't however check for - * custom_object_result, so - do it here. - */ - if ( ! is_int($this->num_rows)) - { - $this->num_rows = count($this->result_object); - } - - return $this->result_object; - } - - // -------------------------------------------------------------------- - - /** - * Query result. Custom object version. - * - * @param string class name used to instantiate rows to - * @return array - */ - 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 ( ! class_exists($class_name) OR ! is_object($this->result_id) OR $this->num_rows() === 0) - { - return array(); - } - - /* Even if result_array hasn't been set prior to custom_result_object being called, - * num_rows() has done it. - */ - $data = &$this->result_array; - - $result_object = array(); - for ($i = 0, $c = count($data); $i < $c; $i++) - { - $result_object[$i] = new $class_name(); - foreach ($data[$i] as $key => $value) - { - $result_object[$i]->$key = $value; - } - } - - /* As described for the num_rows() method - there's no easy - * way to get the number of rows selected. Our work-around - * solution (as in here as well) first checks if result_array - * exists and returns its count. It doesn't however check for - * custom_object_result, so - do it here. - */ - if ( ! is_int($this->num_rows)) - { - $this->num_rows = count($result_object); - } - - // Cache and return the array - return $this->custom_result_object[$class_name] = $result_object; - } - - // -------------------------------------------------------------------- - - /* Single row result. - * - * Acts as a wrapper for row_object(), row_array() - * and custom_row_object(). Also used by first_row(), next_row() - * and previous_row(). - * - * @param int row index - * @param string ('object', 'array' or a custom class name) - * @return mixed whatever was passed to the second parameter - */ - public function row($n = 0, $type = 'object') - { - if ($type === 'object') - { - return $this->row_object($n); - } - elseif ($type === 'array') - { - return $this->row_array($n); - } - - return $this->custom_row_object($n, $type); - } - - // -------------------------------------------------------------------- - - /* Single row result. Array version. - * - * @param int row index - * @return array - */ - public function row_array($n = 0) - { - // Make sure $n is not a string - if ( ! is_int($n)) - { - $n = (int) $n; - } - - /* If row_data is initialized, it means that we've already tried - * (at least) to fetch some data, so ... check if we already have - * this row. - */ - if (is_array($this->row_data)) - { - /* If we already have row_data[$n] - return it. - * - * If we enter the elseif, there's a number of reasons to - * return an empty array: - * - * - count($this->row_data) === 0 means there are no results - * - num_rows being set or result_array having count() > 0 means - * that we've already fetched all data and $n is greater than - * our highest row index available - * - $n < $this->current_row means that if such row existed, - * we would've already returned it, therefore $n is an - * invalid index - */ - if (isset($this->row_data[$n])) // We already have this row - { - $this->current_row = $n; - return $this->row_data[$n]; - } - elseif (count($this->row_data) === 0 OR is_int($this->num_rows) - OR count($this->result_array) > 0 OR $n < $this->current_row) - { - // No such row exists - return array(); - } - - // Get the next row index that would actually need to be fetched - $current_row = ($this->current_row < count($this->row_data)) ? count($this->row_data) : $this->current_row + 1; - } - else - { - $current_row = $this->current_row = 0; - $this->row_data = array(); - } - - /* Fetch more data, if available - * - * NOTE: Operator precedence is important here, if you change - * 'AND' with '&&' - it WILL BREAK the results, as - * $row will be assigned the scalar value of both - * expressions! - */ - while ($row = $this->_fetch_assoc() AND $current_row <= $n) - { - $this->row_data[$current_row++] = $row; - } - - // This would mean that there's no (more) data to fetch - if ( ! is_array($this->row_data) OR ! isset($this->row_data[$n])) - { - // Cache what we already have - if (is_array($this->row_data)) - { - $this->num_rows = count($this->row_data); - /* Usually, row_data could have less elements than result_array, - * but at this point - they should be exactly the same. - */ - $this->result_array = $this->row_data; - } - else - { - $this->num_rows = 0; - } - - return array(); - } - - $this->current_row = $n; - return $this->row_data[$n]; - } - - // -------------------------------------------------------------------- - - /* Single row result. Object version. - * - * @param int row index - * @return mixed object if row found; empty array if not - */ - public function row_object($n = 0) - { - // Make sure $n is not a string - if ( ! is_int($n)) - { - $n = (int) $n; - } - - /* Logic here is exactly the same as in row_array, - * except we have to cast row_data[$n] to an object. - * - * If we already have result_object though - we can - * directly return from it. - */ - if (isset($this->result_object[$n])) - { - $this->current_row = $n; - return $this->result_object[$n]; - } - - $row = $this->row_array($n); - // Cast only if the row exists - if (count($row) > 0) - { - $this->current_row = $n; return (object) $row; } - return array(); - } - - // -------------------------------------------------------------------- - - /* Single row result. Custom object version. - * - * @param int row index - * @param string custom class name - * @return mixed custom object if row found; empty array otherwise - */ - public function custom_row_object($n = 0, $class_name) - { - // Make sure $n is not a string - if ( ! is_int($n)) - { - $n = (int) $n; - } - - if (array_key_exists($class_name, $this->custom_result_object)) - { - /* We already have a the whole result set with this class_name, - * return the specified row if it exists, and an empty array if - * it doesn't. - */ - if (isset($this->custom_result_object[$class_name][$n])) - { - $this->current_row = $n; - return $this->custom_result_object[$class_name][$n]; - } - else - { - return array(); - } - } - elseif ( ! class_exists($class_name)) // No such class exists - { - return array(); - } - - $row = $this->row_array($n); - // An array would mean that the row doesn't exist - if (is_array($row)) - { - return $row; - } - - // Convert to the desired class and return - $row_object = new $class_name(); - foreach ($row as $key => $value) - { - $row_object->$key = $value; - } - - $this->current_row = $n; - return $row_object; - } - - // -------------------------------------------------------------------- - - /* First row result. - * - * @param string ('object', 'array' or a custom class name) - * @return mixed whatever was passed to the second parameter - */ - public function first_row($type = 'object') - { - return $this->row(0, $type); - } - - // -------------------------------------------------------------------- - - /* Last row result. - * - * @param string ('object', 'array' or a custom class name) - * @return mixed whatever was passed to the second parameter - */ - public function last_row($type = 'object') - { - $result = &$this->result($type); - if ( ! isset($this->num_rows)) - { - $this->num_rows = count($result); - } - $this->current_row = $this->num_rows - 1; - return $result[$this->current_row]; - } - - // -------------------------------------------------------------------- - - /* Next row result. - * - * @param string ('object', 'array' or a custom class name) - * @return mixed whatever was passed to the second parameter - */ - public function next_row($type = 'object') - { - if (is_array($this->row_data)) - { - $count = count($this->row_data); - $n = ($this->current_row > $count OR ($this->current_row === 0 && $count === 0)) ? $count : $this->current_row + 1; - } - else + $class_name = new $class_name(); + foreach (array_keys($row) as $key) { - $n = 0; + $class_name->$key = $row[$key]; } - return $this->row($n, $type); - } - - // -------------------------------------------------------------------- - - /* Previous row result. - * - * @param string ('object', 'array' or a custom class name) - * @return mixed whatever was passed to the second parameter - */ - public function previous_row($type = 'object') - { - $n = ($this->current_row !== 0) ? $this->current_row - 1 : 0; - return $this->row($n, $type); + return $class_name; } // -------------------------------------------------------------------- @@ -599,8 +161,9 @@ class CI_DB_sqlite3_result extends CI_DB_result { * * Moves the internal pointer to the desired offset. We call * this internally before fetching results to make sure the - * result set starts at zero + * result set starts at zero. * + * @param int $n (ignored) * @return array */ protected function _data_seek($n = 0) diff --git a/system/database/drivers/sqlite3/sqlite3_utility.php b/system/database/drivers/sqlite3/sqlite3_utility.php index 965c838e5..c7736cc6d 100644 --- a/system/database/drivers/sqlite3/sqlite3_utility.php +++ b/system/database/drivers/sqlite3/sqlite3_utility.php @@ -1,8 +1,8 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * - * An open source application development framework for PHP 5.1.6 or newer + * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * SQLite3 Utility Class @@ -34,18 +35,16 @@ */ class CI_DB_sqlite3_utility extends CI_DB_utility { - protected $_list_databases = FALSE; - /** - * SQLite Export + * Export * - * @param array Preferences + * @param array $params Preferences * @return mixed */ protected function _backup($params = array()) { // Not supported - return $this->db->display_error('db_unsuported_feature'); + return $this->db->display_error('db_unsupported_feature'); } } diff --git a/system/database/drivers/sqlsrv/sqlsrv_driver.php b/system/database/drivers/sqlsrv/sqlsrv_driver.php index 951567033..a3d3177f7 100644 --- a/system/database/drivers/sqlsrv/sqlsrv_driver.php +++ b/system/database/drivers/sqlsrv/sqlsrv_driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -21,15 +21,16 @@ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com - * @since Version 1.0 + * @since Version 2.0.3 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * SQLSRV Database Adapter Class * * Note: _DB is an extender class that the app controller - * creates dynamically based on whether the active record + * creates dynamically based on whether the query builder * class is being used or not. * * @package CodeIgniter @@ -40,39 +41,52 @@ */ class CI_DB_sqlsrv_driver extends CI_DB { + /** + * Database driver + * + * @var string + */ public $dbdriver = 'sqlsrv'; - // The character used for escaping - protected $_escape_char = ''; + // -------------------------------------------------------------------- - // clause and character used for LIKE escape sequences - protected $_like_escape_str = " ESCAPE '%s' "; - protected $_like_escape_chr = '!'; + /** + * ORDER BY random keyword + * + * @var array + */ + protected $_random_keyword = array('NEWID()', 'RAND(%d)'); /** - * 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. + * Quoted identifier flag + * + * Whether to use SQL-92 standard quoted identifier + * (double quotes) or brackets for identifier escaping. + * + * @var bool */ - protected $_count_string = 'SELECT COUNT(*) AS '; - protected $_random_keyword = ' NEWID()'; // not currently supported + protected $_quoted_identifier = TRUE; + + // -------------------------------------------------------------------- /** - * Non-persistent database connection + * Database connection * + * @param bool $pooling * @return resource */ public function db_connect($pooling = FALSE) { - // Check for a UTF-8 charset being passed as CI's default 'utf8'. - $character_set = (0 === strcasecmp('utf8', $this->char_set)) ? 'UTF-8' : $this->char_set; + $charset = in_array(strtolower($this->char_set), array('utf-8', 'utf8'), TRUE) + ? 'UTF-8' : SQLSRV_ENC_CHAR; $connection = array( 'UID' => empty($this->username) ? '' : $this->username, 'PWD' => empty($this->password) ? '' : $this->password, 'Database' => $this->database, - 'ConnectionPooling' => $pooling ? 1 : 0, - 'CharacterSet' => $character_set, + 'ConnectionPooling' => ($pooling === TRUE) ? 1 : 0, + 'CharacterSet' => $charset, + 'Encrypt' => ($this->encrypt === TRUE) ? 1 : 0, 'ReturnDatesAsStrings' => 1 ); @@ -83,7 +97,15 @@ class CI_DB_sqlsrv_driver extends CI_DB { unset($connection['UID'], $connection['PWD']); } - return sqlsrv_connect($this->hostname, $connection); + $this->conn_id = sqlsrv_connect($this->hostname, $connection); + + // Determine how identifiers are escaped + $query = $this->query('SELECT CASE WHEN (@@OPTIONS | 256) = @@OPTIONS THEN 1 ELSE 0 END AS qi'); + $query = $query->row_array(); + $this->_quoted_identifier = empty($query) ? FALSE : (bool) $query['qi']; + $this->_escape_char = ($this->_quoted_identifier) ? '"' : array('[', ']'); + + return $this->conn_id; } // -------------------------------------------------------------------- @@ -103,7 +125,7 @@ class CI_DB_sqlsrv_driver extends CI_DB { /** * Select the database * - * @param string database name + * @param string $database * @return bool */ public function db_select($database = '') @@ -127,16 +149,14 @@ class CI_DB_sqlsrv_driver extends CI_DB { /** * Execute the query * - * @param string an SQL query + * @param string $sql an SQL query * @return resource */ protected function _execute($sql) { - return sqlsrv_query($this->conn_id, - $sql, - NULL, - array('Scrollable'=> SQLSRV_CURSOR_STATIC, 'SendStreamParamsAtExec' => TRUE) - ); + return ($this->is_write_type($sql) && stripos($sql, 'INSERT') === FALSE) + ? sqlsrv_query($this->conn_id, $sql) + : sqlsrv_query($this->conn_id, $sql, NULL, array('Scrollable' => SQLSRV_CURSOR_STATIC)); } // -------------------------------------------------------------------- @@ -144,17 +164,13 @@ class CI_DB_sqlsrv_driver extends CI_DB { /** * Begin Transaction * + * @param bool $test_mode * @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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -162,7 +178,7 @@ class CI_DB_sqlsrv_driver extends CI_DB { // 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->_trans_failure = ($test_mode === TRUE); return sqlsrv_begin_transaction($this->conn_id); } @@ -176,13 +192,8 @@ class CI_DB_sqlsrv_driver extends CI_DB { */ 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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -199,13 +210,8 @@ class CI_DB_sqlsrv_driver extends CI_DB { */ 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) + if ( ! $this->trans_enabled OR $this->_trans_depth > 0) { return TRUE; } @@ -218,8 +224,8 @@ class CI_DB_sqlsrv_driver extends CI_DB { /** * Escape String * - * @param string - * @param bool whether or not the string will be used in a LIKE condition + * @param string $str + * @param bool $like Whether or not the string will be used in a LIKE condition * @return string */ public function escape_str($str, $like = FALSE) @@ -237,7 +243,7 @@ class CI_DB_sqlsrv_driver extends CI_DB { */ public function affected_rows() { - return @sqlrv_rows_affected($this->conn_id); + return sqlsrv_rows_affected($this->result_id); } // -------------------------------------------------------------------- @@ -269,42 +275,17 @@ class CI_DB_sqlsrv_driver extends CI_DB { { return $this->data_cache['version']; } - - if (($info = sqlsrv_server_info($this->conn_id)) === FALSE) + elseif ( ! $this->conn_id) { - return FALSE; + $this->initialize(); } - return $this->data_cache['version'] = $info['SQLServerVersion']; - } - - // -------------------------------------------------------------------- - - /** - * "Count All" query - * - * Generates a platform-specific query string that counts all records in - * the specified database - * - * @param string - * @return int - */ - public function count_all($table = '') - { - if ($table == '') - { - return 0; - } - - $query = $this->query("SELECT COUNT(*) AS numrows FROM " . $this->dbprefix . $table); - if ($query->num_rows() == 0) + if ( ! $this->conn_id OR ($info = sqlsrv_server_info($this->conn_id)) === FALSE) { - return 0; + return FALSE; } - $row = $query->row(); - $this->_reset_select(); - return (int) $row->numrows; + return $this->data_cache['version'] = $info['SQLServerVersion']; } // -------------------------------------------------------------------- @@ -315,11 +296,21 @@ class CI_DB_sqlsrv_driver extends CI_DB { * Generates a platform-specific query string so that the table names can be fetched * * @param bool - * @return string + * @return string $prefix_limit */ protected function _list_tables($prefix_limit = FALSE) { - return "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name"; + $sql = 'SELECT '.$this->escape_identifiers('name') + .' FROM '.$this->escape_identifiers('sysobjects') + .' WHERE '.$this->escape_identifiers('type')." = 'U'"; + + if ($prefix_limit === TRUE && $this->dbprefix !== '') + { + $sql .= ' AND '.$this->escape_identifiers('name')." LIKE '".$this->escape_like_str($this->dbprefix)."%' " + .sprintf($this->_escape_like_str, $this->_escape_like_chr); + } + + return $sql.' ORDER BY '.$this->escape_identifiers('name'); } // -------------------------------------------------------------------- @@ -329,7 +320,7 @@ class CI_DB_sqlsrv_driver extends CI_DB { * * Generates a platform-specific query string so that the column names can be fetched * - * @param string the table name + * @param string $table * @return string */ protected function _list_columns($table = '') @@ -344,12 +335,12 @@ class CI_DB_sqlsrv_driver extends CI_DB { * * Generates a platform-specific query so that the column data can be retrieved * - * @param string the table name + * @param string $table * @return string */ protected function _field_data($table) { - return 'SELECT TOP 1 * FROM '.$table; + return 'SELECT TOP 1 * FROM '.$this->protect_identifiers($table); } // -------------------------------------------------------------------- @@ -393,54 +384,19 @@ class CI_DB_sqlsrv_driver extends CI_DB { // -------------------------------------------------------------------- /** - * From Tables - * - * This function implicitly groups FROM tables so there is no confusion - * about operator precedence in harmony with SQL standards - * - * @param array - * @return string - */ - protected function _from_tables($tables) - { - if ( ! is_array($tables)) - { - $tables = array($tables); - } - - return implode(', ', $tables); - } - - // -------------------------------------------------------------------- - - /** * Update statement * * Generates a platform-specific update string from the supplied data * - * @param string the table name - * @param array the update data - * @param array the where clause - * @param array the orderby clause (ignored) - * @param array the limit clause (ignored) - * @param array the like clause + * @param string $table + * @param array $values * @return string */ - protected function _update($table, $values, $where, $orderby = array(), $limit = FALSE, $like = array()) + protected function _update($table, $values) { - foreach($values as $key => $val) - { - $valstr[] = $key.' = '.$val; - } - - $where = empty($where) ? '' : ' WHERE '.implode(' ', $where); - - if ( ! empty($like)) - { - $where .= ($where === '' ? ' WHERE ' : ' AND ').implode(' ', $like); - } - - return 'UPDATE '.$table.' SET '.implode(', ', $valstr).' WHERE '.$where; + $this->qb_limit = FALSE; + $this->qb_orderby = array(); + return parent::_update($table, $values); } // -------------------------------------------------------------------- @@ -450,10 +406,10 @@ class CI_DB_sqlsrv_driver extends CI_DB { * * Generates a platform-specific truncate string from the supplied data * - * If the database does not support the truncate() command, + * If the database does not support the TRUNCATE statement, * then this method maps to 'DELETE FROM table' * - * @param string the table name + * @param string $table * @return string */ protected function _truncate($table) @@ -468,41 +424,96 @@ class CI_DB_sqlsrv_driver extends CI_DB { * * Generates a platform-specific delete string from the supplied data * - * @param string the table name - * @param array the where clause - * @param array the like clause - * @param string the limit clause + * @param string $table * @return string */ - protected function _delete($table, $where = array(), $like = array(), $limit = FALSE) + protected function _delete($table) { - $conditions = array(); - - empty($where) OR $conditions[] = implode(' ', $where); - empty($like) OR $conditions[] = implode(' ', $like); - - $conditions = (count($conditions) > 0) ? ' WHERE '.implode(' AND ', $conditions) : ''; + if ($this->qb_limit) + { + return 'WITH ci_delete AS (SELECT TOP '.$this->qb_limit.' * FROM '.$table.$this->_compile_wh('qb_where').') DELETE FROM ci_delete'; + } - return ($limit) - ? 'WITH ci_delete AS (SELECT TOP '.$limit.' * FROM '.$table.$conditions.') DELETE FROM ci_delete' - : 'DELETE FROM '.$table.$conditions; + return parent::_delete($table); } // -------------------------------------------------------------------- /** - * Limit string + * LIMIT * * Generates a platform-specific LIMIT clause * - * @param string the sql query string - * @param int the number of rows to limit the query to - * @param int the offset value + * @param string $sql SQL Query * @return string */ - protected function _limit($sql, $limit, $offset) + protected function _limit($sql) + { + // As of SQL Server 2012 (11.0.*) OFFSET is supported + if (version_compare($this->version(), '11', '>=')) + { + return $sql.' OFFSET '.(int) $this->qb_offset.' ROWS FETCH NEXT '.$this->qb_limit.' ROWS ONLY'; + } + + $limit = $this->qb_offset + $this->qb_limit; + + // An ORDER BY clause is required for ROW_NUMBER() to work + if ($this->qb_offset && ! empty($this->qb_orderby)) + { + $orderby = $this->_compile_order_by(); + + // We have to strip the ORDER BY clause + $sql = trim(substr($sql, 0, strrpos($sql, $orderby))); + + // Get the fields to select from our subquery, so that we can avoid CI_rownum appearing in the actual results + if (count($this->qb_select) === 0) + { + $select = '*'; // Inevitable + } + else + { + // Use only field names and their aliases, everything else is out of our scope. + $select = array(); + $field_regexp = ($this->_quoted_identifier) + ? '("[^\"]+")' : '(\[[^\]]+\])'; + for ($i = 0, $c = count($this->qb_select); $i < $c; $i++) + { + $select[] = preg_match('/(?:\s|\.)'.$field_regexp.'$/i', $this->qb_select[$i], $m) + ? $m[1] : $this->qb_select[$i]; + } + $select = implode(', ', $select); + } + + return 'SELECT '.$select." FROM (\n\n" + .preg_replace('/^(SELECT( DISTINCT)?)/i', '\\1 ROW_NUMBER() OVER('.trim($orderby).') AS '.$this->escape_identifiers('CI_rownum').', ', $sql) + ."\n\n) ".$this->escape_identifiers('CI_subquery') + ."\nWHERE ".$this->escape_identifiers('CI_rownum').' BETWEEN '.($this->qb_offset + 1).' AND '.$limit; + } + + return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.$limit.' ', $sql); + } + + // -------------------------------------------------------------------- + + /** + * Insert batch statement + * + * Generates a platform-specific insert string from the supplied data. + * + * @param string $table Table name + * @param array $keys INSERT keys + * @param array $values INSERT values + * @return string|bool + */ + protected function _insert_batch($table, $keys, $values) { - return preg_replace('/(^\SELECT (DISTINCT)?)/i','\\1 TOP '.($limit + $offset).' ', $sql); + // Multiple-value inserts are only supported as of SQL Server 2008 + if (version_compare($this->version(), '10', '>=')) + { + return parent::_insert_batch($table, $keys, $values); + } + + return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE; } // -------------------------------------------------------------------- @@ -510,12 +521,11 @@ class CI_DB_sqlsrv_driver extends CI_DB { /** * Close DB Connection * - * @param resource * @return void */ - protected function _close($conn_id) + protected function _close() { - @sqlsrv_close($conn_id); + @sqlsrv_close($this->conn_id); } } diff --git a/system/database/drivers/sqlsrv/sqlsrv_forge.php b/system/database/drivers/sqlsrv/sqlsrv_forge.php index e9143b269..da8f68c56 100644 --- a/system/database/drivers/sqlsrv/sqlsrv_forge.php +++ b/system/database/drivers/sqlsrv/sqlsrv_forge.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -21,9 +21,10 @@ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com - * @since Version 1.0 + * @since Version 2.0.3 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * SQLSRV Forge Class @@ -34,162 +35,99 @@ */ class CI_DB_sqlsrv_forge extends CI_DB_forge { - protected $_drop_table = 'DROP TABLE %s'; - /** - * Create Table + * CREATE TABLE IF statement * - * @param string the table name - * @param array the fields - * @param mixed primary key(s) - * @param mixed key(s) - * @param bool should 'IF NOT EXISTS' be added to the SQL - * @return bool + * @var string */ - protected 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'].')'; - } + protected $_create_table_if = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nCREATE TABLE"; - 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'; - } + /** + * DROP TABLE IF statement + * + * @var string + */ + protected $_drop_table_if = "IF EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nDROP TABLE"; - if (array_key_exists('AUTO_INCREMENT', $attributes) && $attributes['AUTO_INCREMENT'] === TRUE) - { - $sql .= ' AUTO_INCREMENT'; - } - } + /** + * UNSIGNED support + * + * @var array + */ + protected $_unsigned = array( + 'TINYINT' => 'SMALLINT', + 'SMALLINT' => 'INT', + 'INT' => 'BIGINT', + 'REAL' => 'FLOAT' + ); - // don't add a comma on the end of the last field - if (++$current_field_count < count($fields)) - { - $sql .= ','; - } - } + // -------------------------------------------------------------------- - if (count($primary_keys) > 0) + /** + * ALTER TABLE + * + * @param string $alter_type ALTER type + * @param string $table Table name + * @param mixed $field Column definition + * @return string|string[] + */ + protected function _alter_table($alter_type, $table, $field) + { + if (in_array($alter_type, array('ADD', 'DROP'), TRUE)) { - $primary_keys = $this->db->protect_identifiers($primary_keys); - $sql .= ",\n\tPRIMARY KEY (" . implode(', ', $primary_keys) . ")"; + return parent::_alter_table($alter_type, $table, $field); } - if (is_array($keys) && count($keys) > 0) + $sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ALTER COLUMN '; + $sqls = array(); + for ($i = 0, $c = count($field); $i < $c; $i++) { - 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) . ")"; - } + $sqls[] = $sql.$this->_process_column($field[$i]); } - $sql .= "\n)"; - - return $sql; + return $sqls; } // -------------------------------------------------------------------- /** - * Alter table query + * Field attribute TYPE * - * Generates a platform-specific query so that a table can be altered - * Called by add_column(), drop_column(), and column_alter(), + * Performs a data type mapping between different databases. * - * @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 bool should 'NOT NULL' be added - * @param string the field after which we should add the new field - * @return string + * @param array &$attributes + * @return void */ - protected function _alter_table($alter_type, $table, $column_name, $column_definition = '', $default_value = '', $null = '', $after_field = '') + protected function _attr_type(&$attributes) { - $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') + switch (strtoupper($attributes['TYPE'])) { - return $sql; - } - - $sql .= " $column_definition"; - - if ($default_value != '') - { - $sql .= " DEFAULT \"$default_value\""; + case 'MEDIUMINT': + $attributes['TYPE'] = 'INTEGER'; + $attributes['UNSIGNED'] = FALSE; + return; + case 'INTEGER': + $attributes['TYPE'] = 'INT'; + return; + default: return; } + } - if ($null === NULL) - { - $sql .= ' NULL'; - } - else - { - $sql .= ' NOT NULL'; - } + // -------------------------------------------------------------------- - if ($after_field != '') + /** + * Field attribute AUTO_INCREMENT + * + * @param array &$attributes + * @param array &$field + * @return void + */ + protected function _attr_auto_increment(&$attributes, &$field) + { + if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE) { - return $sql.' AFTER '.$this->db->protect_identifiers($after_field); + $field['auto_increment'] = ' IDENTITY(1,1)'; } - - return $sql; - } } diff --git a/system/database/drivers/sqlsrv/sqlsrv_result.php b/system/database/drivers/sqlsrv/sqlsrv_result.php index 0802677fc..6d24cc995 100644 --- a/system/database/drivers/sqlsrv/sqlsrv_result.php +++ b/system/database/drivers/sqlsrv/sqlsrv_result.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * SQLSRV Result Class @@ -33,6 +34,7 @@ * @category Database * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/database/ + * @since 2.0.3 */ class CI_DB_sqlsrv_result extends CI_DB_result { @@ -43,7 +45,9 @@ class CI_DB_sqlsrv_result extends CI_DB_result { */ public function num_rows() { - return @sqlsrv_num_rows($this->result_id); + return is_int($this->num_rows) + ? $this->num_rows + : $this->num_rows = @sqlsrv_num_rows($this->result_id); } // -------------------------------------------------------------------- @@ -92,12 +96,12 @@ class CI_DB_sqlsrv_result extends CI_DB_result { $retval = array(); foreach (sqlsrv_field_metadata($this->result_id) as $offset => $field) { - $F = new stdClass(); - $F->name = $field['Name']; - $F->type = $field['Type']; + $F = new stdClass(); + $F->name = $field['Name']; + $F->type = $field['Type']; $F->max_length = $field['Size']; $F->primary_key = 0; - $F->default = ''; + $F->default = ''; $retval[] = $F; } @@ -142,11 +146,12 @@ class CI_DB_sqlsrv_result extends CI_DB_result { * * Returns the result set as an object * + * @param string $class_name * @return object */ - protected function _fetch_object() + protected function _fetch_object($class_name = 'stdClass') { - return sqlsrv_fetch_object($this->result_id); + return sqlsrv_fetch_object($this->result_id, $class_name); } } diff --git a/system/database/drivers/sqlsrv/sqlsrv_utility.php b/system/database/drivers/sqlsrv/sqlsrv_utility.php index 394964b6a..2bc7f9e03 100644 --- a/system/database/drivers/sqlsrv/sqlsrv_utility.php +++ b/system/database/drivers/sqlsrv/sqlsrv_utility.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -21,9 +21,10 @@ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com - * @since Version 1.0 + * @since Version 2.0.3 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * SQLSRV Utility Class @@ -34,19 +35,32 @@ */ class CI_DB_sqlsrv_utility extends CI_DB_utility { + /** + * List databases statement + * + * @var string + */ protected $_list_databases = 'EXEC sp_helpdb'; // Can also be: EXEC sp_databases + + /** + * OPTIMIZE TABLE statement + * + * @var string + */ protected $_optimize_table = 'ALTER INDEX all ON %s REORGANIZE'; + // -------------------------------------------------------------------- + /** - * SQLSRV Export + * Export * - * @param array Preferences - * @return mixed + * @param array $params Preferences + * @return bool */ protected function _backup($params = array()) { // Currently unsupported - return $this->db->display_error('db_unsuported_feature'); + return $this->db->display_error('db_unsupported_feature'); } } diff --git a/system/helpers/array_helper.php b/system/helpers/array_helper.php index 6f56d9db9..0e66e4b77 100644 --- a/system/helpers/array_helper.php +++ b/system/helpers/array_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Array Helpers @@ -37,35 +38,35 @@ // ------------------------------------------------------------------------ -/** - * Element - * - * Lets you determine whether an array index is set and whether it has a value. - * If the element is empty it returns FALSE (or whatever you specify as the default value.) - * - * @param string - * @param array - * @param mixed - * @return mixed depends on what the array contains - */ if ( ! function_exists('element')) { - function element($item, $array, $default = FALSE) + /** + * Element + * + * Lets you determine whether an array index is set and whether it has a value. + * If the element is empty it returns NULL (or whatever you specify as the default value.) + * + * @param string + * @param array + * @param mixed + * @return mixed depends on what the array contains + */ + function element($item, $array, $default = NULL) { - return empty($array[$item]) ? $default : $array[$item]; + return array_key_exists($item, $array) ? $array[$item] : $default; } } // ------------------------------------------------------------------------ -/** - * Random Element - Takes an array as input and returns a random element - * - * @param array - * @return mixed depends on what the array contains - */ if ( ! function_exists('random_element')) { + /** + * Random Element - Takes an array as input and returns a random element + * + * @param array + * @return mixed depends on what the array contains + */ function random_element($array) { return is_array($array) ? $array[array_rand($array)] : $array; @@ -74,20 +75,20 @@ if ( ! function_exists('random_element')) // -------------------------------------------------------------------- -/** - * Elements - * - * Returns only the array items specified. Will return a default value if - * it is not set. - * - * @param array - * @param array - * @param mixed - * @return mixed depends on what the array contains - */ if ( ! function_exists('elements')) { - function elements($items, $array, $default = FALSE) + /** + * Elements + * + * Returns only the array items specified. Will return a default value if + * it is not set. + * + * @param array + * @param array + * @param mixed + * @return mixed depends on what the array contains + */ + function elements($items, $array, $default = NULL) { $return = array(); @@ -95,7 +96,7 @@ if ( ! function_exists('elements')) foreach ($items as $item) { - $return[$item] = isset($array[$item]) ? $array[$item] : $default; + $return[$item] = array_key_exists($item, $array) ? $array[$item] : $default; } return $return; diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php index bdbc62097..e9b167fa9 100644 --- a/system/helpers/captcha_helper.php +++ b/system/helpers/captcha_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter CAPTCHA Helper @@ -32,22 +33,22 @@ * @subpackage Helpers * @category Helpers * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/helpers/xml_helper.html + * @link http://codeigniter.com/user_guide/helpers/captcha_helper.html */ // ------------------------------------------------------------------------ -/** - * Create CAPTCHA - * - * @param array array of data for the CAPTCHA - * @param string path to create the image in - * @param string URL to the CAPTCHA image folder - * @param string server path to font - * @return string - */ if ( ! function_exists('create_captcha')) { + /** + * Create CAPTCHA + * + * @param array array of data for the CAPTCHA + * @param string path to create the image in + * @param string URL to the CAPTCHA image folder + * @param string server path to font + * @return string + */ function create_captcha($data = '', $img_path = '', $img_url = '', $font_path = '') { $defaults = array('word' => '', 'img_path' => '', 'img_url' => '', 'img_width' => '150', 'img_height' => '30', 'font_path' => '', 'expiration' => 7200); @@ -64,7 +65,7 @@ if ( ! function_exists('create_captcha')) } } - if ($img_path == '' OR $img_url == '' + if ($img_path === '' OR $img_url === '' OR ! @is_dir($img_path) OR ! is_writeable($img_path) OR ! extension_loaded('gd')) { @@ -80,8 +81,7 @@ if ( ! function_exists('create_captcha')) $current_dir = @opendir($img_path); while ($filename = @readdir($current_dir)) { - if ($filename !== '.' && $filename !== '..' && $filename !== 'index.html' - && (str_replace('.jpg', '', $filename) + $expiration) < $now) + if (substr($filename, -4) === '.jpg' && (str_replace('.jpg', '', $filename) + $expiration) < $now) { @unlink($img_path.$filename); } @@ -93,7 +93,7 @@ if ( ! function_exists('create_captcha')) // Do we have a "word" yet? // ----------------------------------- - if ($word == '') + if ($word === '') { $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $word = ''; @@ -156,7 +156,7 @@ if ( ! function_exists('create_captcha')) // Write the text // ----------------------------------- - $use_font = ($font_path != '' && file_exists($font_path) && function_exists('imagettftext')); + $use_font = ($font_path !== '' && file_exists($font_path) && function_exists('imagettftext')); if ($use_font === FALSE) { $font_size = 5; @@ -186,7 +186,6 @@ if ( ! function_exists('create_captcha')) } } - // Create the border imagerectangle($im, 0, 0, $img_width - 1, $img_height - 1, $border_color); diff --git a/system/helpers/cookie_helper.php b/system/helpers/cookie_helper.php index 06560e723..02841409d 100644 --- a/system/helpers/cookie_helper.php +++ b/system/helpers/cookie_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Cookie Helpers @@ -37,24 +38,24 @@ // ------------------------------------------------------------------------ -/** - * Set cookie - * - * Accepts seven parameters, or you can submit an associative - * array in the first parameter containing all the values. - * - * @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 - * @param bool true makes the cookie accessible via http(s) only (no javascript) - * @return void - */ if ( ! function_exists('set_cookie')) { + /** + * Set cookie + * + * Accepts seven parameters, or you can submit an associative + * array in the first parameter containing all the values. + * + * @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 + * @param bool true makes the cookie accessible via http(s) only (no javascript) + * @return void + */ function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE) { // Set the config file options @@ -65,15 +66,15 @@ if ( ! function_exists('set_cookie')) // -------------------------------------------------------------------- -/** - * Fetch an item from the COOKIE array - * - * @param string - * @param bool - * @return mixed - */ if ( ! function_exists('get_cookie')) { + /** + * Fetch an item from the COOKIE array + * + * @param string + * @param bool + * @return mixed + */ function get_cookie($index = '', $xss_clean = FALSE) { $CI =& get_instance(); @@ -84,17 +85,17 @@ if ( ! function_exists('get_cookie')) // -------------------------------------------------------------------- -/** - * Delete a COOKIE - * - * @param mixed - * @param string the cookie domain. Usually: .yourdomain.com - * @param string the cookie path - * @param string the cookie prefix - * @return void - */ if ( ! function_exists('delete_cookie')) { + /** + * Delete a COOKIE + * + * @param mixed + * @param string the cookie domain. Usually: .yourdomain.com + * @param string the cookie path + * @param string the cookie prefix + * @return void + */ function delete_cookie($name = '', $domain = '', $path = '/', $prefix = '') { set_cookie($name, '', '', $domain, $path, $prefix); diff --git a/system/helpers/date_helper.php b/system/helpers/date_helper.php index f1ba364f5..7a0552b0b 100644 --- a/system/helpers/date_helper.php +++ b/system/helpers/date_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Date Helpers @@ -37,70 +38,71 @@ // ------------------------------------------------------------------------ -/** - * Get "now" time - * - * Returns time() or its GMT equivalent based on the config file preference - * - * @return int - */ if ( ! function_exists('now')) { - function now() + /** + * Get "now" time + * + * Returns time() based on the timezone parameter or on the + * "time_reference" setting + * + * @param string + * @return int + */ + function now($timezone = NULL) { - $CI =& get_instance(); - - if (strtolower($CI->config->item('time_reference')) == 'gmt') + if (empty($timezone)) { - $now = time(); - $system_time = mktime(gmdate("H", $now), gmdate("i", $now), gmdate("s", $now), gmdate("m", $now), gmdate("d", $now), gmdate("Y", $now)); - - if (strlen($system_time) < 10) - { - $system_time = time(); - log_message('error', 'The Date class could not set a proper GMT timestamp so the local time() value was used.'); - } + $timezone = config_item('time_reference'); + } - return $system_time; + if ($timezone === 'local' OR $timezone === date_default_timezone_get()) + { + return time(); } - return time(); + $datetime = new DateTime('now', new DateTimeZone($timezone)); + sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second); + + return mktime($hour, $minute, $second, $month, $day, $year); } } // ------------------------------------------------------------------------ -/** - * Convert MySQL Style Datecodes - * - * This function is identical to PHPs date() function, - * except that it allows date codes to be formatted using - * the MySQL style, where each code letter is preceded - * with a percent sign: %Y %m %d etc... - * - * The benefit of doing dates this way is that you don't - * have to worry about escaping your text letters that - * match the date codes. - * - * @param string - * @param int - * @return int - */ if ( ! function_exists('mdate')) { + /** + * Convert MySQL Style Datecodes + * + * This function is identical to PHPs date() function, + * except that it allows date codes to be formatted using + * the MySQL style, where each code letter is preceded + * with a percent sign: %Y %m %d etc... + * + * The benefit of doing dates this way is that you don't + * have to worry about escaping your text letters that + * match the date codes. + * + * @param string + * @param int + * @return int + */ function mdate($datestr = '', $time = '') { - if ($datestr == '') + if ($datestr === '') { return ''; } - - $time = ($time == '') ? now() : $time; + elseif (empty($time)) + { + $time = now(); + } $datestr = str_replace( '%\\', '', - preg_replace("/([a-z]+?){1}/i", "\\\\\\1", $datestr) + preg_replace('/([a-z]+?){1}/i', '\\\\\\1', $datestr) ); return date($datestr, $time); @@ -109,75 +111,67 @@ if ( ! function_exists('mdate')) // ------------------------------------------------------------------------ -/** - * Standard Date - * - * Returns a date formatted according to the submitted standard. - * - * @param string the chosen format - * @param int Unix timestamp - * @return string - */ if ( ! function_exists('standard_date')) { - function standard_date($fmt = 'DATE_RFC822', $time = '') + /** + * Standard Date + * + * Returns a date formatted according to the submitted standard. + * + * As of PHP 5.2, the DateTime extension provides constants that + * serve for the exact same purpose and are used with date(). + * + * @todo Remove in version 3.1+. + * @deprecated 3.0.0 Use PHP's native date() instead. + * @link http://www.php.net/manual/en/class.datetime.php#datetime.constants.types + * + * @example date(DATE_RFC822, now()); // default + * @example date(DATE_W3C, $time); // a different format and time + * + * @param string $fmt = 'DATE_RFC822' the chosen format + * @param int $time = NULL Unix timestamp + * @return string + */ + function standard_date($fmt = 'DATE_RFC822', $time = NULL) { - $formats = array( - 'DATE_ATOM' => '%Y-%m-%dT%H:%i:%s%O', - 'DATE_COOKIE' => '%l, %d-%M-%y %H:%i:%s UTC', - 'DATE_ISO8601' => '%Y-%m-%dT%H:%i:%s%O', - 'DATE_RFC822' => '%D, %d %M %y %H:%i:%s %O', - 'DATE_RFC850' => '%l, %d-%M-%y %H:%i:%s UTC', - 'DATE_RFC1036' => '%D, %d %M %y %H:%i:%s %O', - 'DATE_RFC1123' => '%D, %d %M %Y %H:%i:%s %O', - 'DATE_RFC2822' => '%D, %d %M %Y %H:%i:%s %O', - 'DATE_RSS' => '%D, %d %M %Y %H:%i:%s %O', - 'DATE_W3C' => '%Y-%m-%dT%H:%i:%s%O' - ); - - if ( ! isset($formats[$fmt])) + if (empty($time)) + { + $time = now(); + } + + // Procedural style pre-defined constants from the DateTime extension + if (strpos($fmt, 'DATE_') !== 0 OR defined($fmt) === FALSE) { return FALSE; } - return mdate($formats[$fmt], $time); + return date(constant($fmt), $time); } } // ------------------------------------------------------------------------ -/** - * Timespan - * - * Returns a span of seconds in this format: - * 10 days 14 hours 36 minutes 47 seconds - * - * @param int a number of seconds - * @param int Unix timestamp - * @param int a number of display units - * @return string - */ if ( ! function_exists('timespan')) { + /** + * Timespan + * + * Returns a span of seconds in this format: + * 10 days 14 hours 36 minutes 47 seconds + * + * @param int a number of seconds + * @param int Unix timestamp + * @param int a number of display units + * @return string + */ function timespan($seconds = 1, $time = '', $units = 7) { $CI =& get_instance(); $CI->lang->load('date'); - if ( ! is_numeric($seconds)) - { - $seconds = 1; - } - - if ( ! is_numeric($time)) - { - $time = time(); - } - - if ( ! is_numeric($units)) - { - $units = 7; - } + is_numeric($seconds) OR $seconds = 1; + is_numeric($time) OR $time = time(); + is_numeric($units) OR $units = 7; $seconds = ($time <= $seconds) ? 1 : $time - $seconds; @@ -186,7 +180,7 @@ if ( ! function_exists('timespan')) if ($years > 0) { - $str[] = $years.' '.$CI->lang->line((($years > 1) ? 'date_years' : 'date_year')); + $str[] = $years.' '.$CI->lang->line($years > 1 ? 'date_years' : 'date_year'); } $seconds -= $years * 31557600; @@ -196,7 +190,7 @@ if ( ! function_exists('timespan')) { if ($months > 0) { - $str[] = $months.' '.$CI->lang->line((($months > 1) ? 'date_months' : 'date_month')); + $str[] = $months.' '.$CI->lang->line($months > 1 ? 'date_months' : 'date_month'); } $seconds -= $months * 2629743; @@ -208,7 +202,7 @@ if ( ! function_exists('timespan')) { if ($weeks > 0) { - $str[] = $weeks.' '.$CI->lang->line((($weeks > 1) ? 'date_weeks' : 'date_week')); + $str[] = $weeks.' '.$CI->lang->line($weeks > 1 ? 'date_weeks' : 'date_week'); } $seconds -= $weeks * 604800; @@ -220,7 +214,7 @@ if ( ! function_exists('timespan')) { if ($days > 0) { - $str[] = $days.' '.$CI->lang->line((($days > 1) ? 'date_days' : 'date_day')); + $str[] = $days.' '.$CI->lang->line($days > 1 ? 'date_days' : 'date_day'); } $seconds -= $days * 86400; @@ -232,7 +226,7 @@ if ( ! function_exists('timespan')) { if ($hours > 0) { - $str[] = $hours.' '.$CI->lang->line((($hours > 1) ? 'date_hours' : 'date_hour')); + $str[] = $hours.' '.$CI->lang->line($hours > 1 ? 'date_hours' : 'date_hour'); } $seconds -= $hours * 3600; @@ -244,7 +238,7 @@ if ( ! function_exists('timespan')) { if ($minutes > 0) { - $str[] = $minutes.' '.$CI->lang->line((($minutes > 1) ? 'date_minutes' : 'date_minute')); + $str[] = $minutes.' '.$CI->lang->line($minutes > 1 ? 'date_minutes' : 'date_minute'); } $seconds -= $minutes * 60; @@ -252,7 +246,7 @@ if ( ! function_exists('timespan')) if (count($str) === 0) { - $str[] = $seconds.' '.$CI->lang->line((($seconds > 1) ? 'date_seconds' : 'date_second')); + $str[] = $seconds.' '.$CI->lang->line($seconds > 1 ? 'date_seconds' : 'date_second'); } return implode(', ', $str); @@ -261,33 +255,37 @@ if ( ! function_exists('timespan')) // ------------------------------------------------------------------------ -/** - * Number of days in a month - * - * Takes a month/year as input and returns the number of days - * for the given month/year. Takes leap years into consideration. - * - * @param int a numeric month - * @param int a numeric year - * @return int - */ if ( ! function_exists('days_in_month')) { + /** + * Number of days in a month + * + * Takes a month/year as input and returns the number of days + * for the given month/year. Takes leap years into consideration. + * + * @param int a numeric month + * @param int a numeric year + * @return int + */ function days_in_month($month = 0, $year = '') { if ($month < 1 OR $month > 12) { return 0; } - - if ( ! is_numeric($year) OR strlen($year) != 4) + elseif ( ! is_numeric($year) OR strlen($year) !== 4) { $year = date('Y'); } + if ($year >= 1970) + { + return (int) date('t', mktime(12, 0, 0, $month, 1, $year)); + } + if ($month == 2) { - if ($year % 400 == 0 OR ($year % 4 == 0 && $year % 100 != 0)) + if ($year % 400 === 0 OR ($year % 4 === 0 && $year % 100 !== 0)) { return 29; } @@ -300,85 +298,78 @@ if ( ! function_exists('days_in_month')) // ------------------------------------------------------------------------ -/** - * Converts a local Unix timestamp to GMT - * - * @param int Unix timestamp - * @return int - */ if ( ! function_exists('local_to_gmt')) { + /** + * Converts a local Unix timestamp to GMT + * + * @param int Unix timestamp + * @return int + */ function local_to_gmt($time = '') { - if ($time == '') + if ($time === '') { $time = time(); } return mktime( - gmdate("H", $time), - gmdate("i", $time), - gmdate("s", $time), - gmdate("m", $time), - gmdate("d", $time), - gmdate("Y", $time) + gmdate('G', $time), + gmdate('i', $time), + gmdate('s', $time), + gmdate('n', $time), + gmdate('j', $time), + gmdate('Y', $time) ); } } // ------------------------------------------------------------------------ -/** - * Converts GMT time to a localized value - * - * Takes a Unix timestamp (in GMT) as input, and returns - * at the local value based on the timezone and DST setting - * submitted - * - * @param int Unix timestamp - * @param string timezone - * @param bool whether DST is active - * @return int - */ if ( ! function_exists('gmt_to_local')) { + /** + * Converts GMT time to a localized value + * + * Takes a Unix timestamp (in GMT) as input, and returns + * at the local value based on the timezone and DST setting + * submitted + * + * @param int Unix timestamp + * @param string timezone + * @param bool whether DST is active + * @return int + */ function gmt_to_local($time = '', $timezone = 'UTC', $dst = FALSE) { - if ($time == '') + if ($time === '') { return now(); } $time += timezones($timezone) * 3600; - if ($dst == TRUE) - { - $time += 3600; - } - - return $time; + return ($dst === TRUE) ? $time + 3600 : $time; } } // ------------------------------------------------------------------------ -/** - * Converts a MySQL Timestamp to Unix - * - * @param int Unix timestamp - * @return int - */ if ( ! function_exists('mysql_to_unix')) { + /** + * Converts a MySQL Timestamp to Unix + * + * @param int Unix timestamp + * @return int + */ function mysql_to_unix($time = '') { // We'll remove certain characters for backward compatibility // since the formatting changed with MySQL 4.1 // YYYY-MM-DD HH:MM:SS - $time = str_replace('-', '', $time); - $time = str_replace(':', '', $time); - $time = str_replace(' ', '', $time); + $time = str_replace(array('-', ':', ' '), '', $time); // YYYYMMDDHHMMSS return mktime( @@ -394,23 +385,23 @@ if ( ! function_exists('mysql_to_unix')) // ------------------------------------------------------------------------ -/** - * Unix to "Human" - * - * Formats Unix timestamp to the following prototype: 2006-08-21 11:35 PM - * - * @param int Unix timestamp - * @param bool whether to show seconds - * @param string format: us or euro - * @return string - */ if ( ! function_exists('unix_to_human')) { + /** + * Unix to "Human" + * + * Formats Unix timestamp to the following prototype: 2006-08-21 11:35 PM + * + * @param int Unix timestamp + * @param bool whether to show seconds + * @param string format: us or euro + * @return string + */ function unix_to_human($time = '', $seconds = FALSE, $fmt = 'us') { - $r = date('Y', $time).'-'.date('m', $time).'-'.date('d', $time).' '; + $r = date('Y', $time).'-'.date('m', $time).'-'.date('d', $time).' '; - if ($fmt == 'us') + if ($fmt === 'us') { $r .= date('h', $time).':'.date('i', $time); } @@ -424,9 +415,9 @@ if ( ! function_exists('unix_to_human')) $r .= ':'.date('s', $time); } - if ($fmt == 'us') + if ($fmt === 'us') { - $r .= ' '.date('A', $time); + return $r.' '.date('A', $time); } return $r; @@ -435,71 +426,45 @@ if ( ! function_exists('unix_to_human')) // ------------------------------------------------------------------------ -/** - * Convert "human" date to GMT - * - * Reverses the above process - * - * @param string format: us or euro - * @return int - */ if ( ! function_exists('human_to_unix')) { + /** + * Convert "human" date to GMT + * + * Reverses the above process + * + * @param string format: us or euro + * @return int + */ function human_to_unix($datestr = '') { - if ($datestr == '') + if ($datestr === '') { return FALSE; } - $datestr = trim($datestr); - $datestr = preg_replace("/\040+/", ' ', $datestr); + $datestr = preg_replace('/\040+/', ' ', trim($datestr)); - if ( ! preg_match('/^[0-9]{2,4}\-[0-9]{1,2}\-[0-9]{1,2}\s[0-9]{1,2}:[0-9]{1,2}(?::[0-9]{1,2})?(?:\s[AP]M)?$/i', $datestr)) + if ( ! preg_match('/^(\d{2}|\d{4})\-[0-9]{1,2}\-[0-9]{1,2}\s[0-9]{1,2}:[0-9]{1,2}(?::[0-9]{1,2})?(?:\s[AP]M)?$/i', $datestr)) { return FALSE; } - $split = explode(' ', $datestr); - - $ex = explode("-", $split['0']); - - $year = (strlen($ex['0']) == 2) ? '20'.$ex['0'] : $ex['0']; - $month = (strlen($ex['1']) == 1) ? '0'.$ex['1'] : $ex['1']; - $day = (strlen($ex['2']) == 1) ? '0'.$ex['2'] : $ex['2']; - - $ex = explode(":", $split['1']); + sscanf($datestr, '%d-%d-%d %s %s', $year, $month, $day, $time, $ampm); + sscanf($time, '%d:%d:%d', $hour, $min, $sec); + isset($sec) OR $sec = 0; - $hour = (strlen($ex['0']) == 1) ? '0'.$ex['0'] : $ex['0']; - $min = (strlen($ex['1']) == 1) ? '0'.$ex['1'] : $ex['1']; - - if (isset($ex['2']) && preg_match('/[0-9]{1,2}/', $ex['2'])) - { - $sec = (strlen($ex['2']) == 1) ? '0'.$ex['2'] : $ex['2']; - } - else + if (isset($ampm)) { - // Unless specified, seconds get set to zero. - $sec = '00'; - } - - if (isset($split['2'])) - { - $ampm = strtolower($split['2']); - - if (substr($ampm, 0, 1) === 'p' && $hour < 12) - { - $hour = $hour + 12; - } + $ampm = strtolower($ampm); - if (substr($ampm, 0, 1) === 'a' && $hour == 12) + if ($ampm[0] === 'p' && $hour < 12) { - $hour = '00'; + $hour += 12; } - - if (strlen($hour) == 1) + elseif ($ampm[0] === 'a' && $hour === 12) { - $hour = '0'.$hour; + $hour = 0; } } @@ -509,27 +474,31 @@ if ( ! function_exists('human_to_unix')) // ------------------------------------------------------------------------ -/** - * Turns many "reasonably-date-like" strings into something - * that is actually useful. This only works for dates after unix epoch. - * - * @param string The terribly formatted date-like string - * @param string Date format to return (same as php date function) - * @return string - */ if ( ! function_exists('nice_date')) { + /** + * Turns many "reasonably-date-like" strings into something + * that is actually useful. This only works for dates after unix epoch. + * + * @param string The terribly formatted date-like string + * @param string Date format to return (same as php date function) + * @return string + */ function nice_date($bad_date = '', $format = FALSE) { if (empty($bad_date)) { return 'Unknown'; } + elseif (empty($format)) + { + $format = 'U'; + } // Date like: YYYYMM - if (preg_match('/^\d{6}$/', $bad_date)) + if (preg_match('/^\d{6}$/i', $bad_date)) { - if (in_array(substr($bad_date, 0, 2),array('19', '20'))) + if (in_array(substr($bad_date, 0, 2), array('19', '20'))) { $year = substr($bad_date, 0, 4); $month = substr($bad_date, 4, 2); @@ -540,32 +509,27 @@ if ( ! function_exists('nice_date')) $year = substr($bad_date, 2, 4); } - return date($format, strtotime($year . '-' . $month . '-01')); + return date($format, strtotime($year.'-'.$month.'-01')); } // Date Like: YYYYMMDD - if (preg_match('/^\d{8}$/',$bad_date)) + if (preg_match('/^(\d{2})\d{2}(\d{4})$/i', $bad_date, $matches)) { - $month = substr($bad_date, 0, 2); - $day = substr($bad_date, 2, 2); - $year = substr($bad_date, 4, 4); - - return date($format, strtotime($month . '/01/' . $year)); + return date($format, strtotime($matches[1].'/01/'.$matches[2])); } // Date Like: MM-DD-YYYY __or__ M-D-YYYY (or anything in between) - if (preg_match('/^\d{1,2}-\d{1,2}-\d{4}$/',$bad_date)) + if (preg_match('/^(\d{1,2})-(\d{1,2})-(\d{4})$/i', $bad_date, $matches)) { - list($m, $d, $y) = explode('-', $bad_date); - return date($format, strtotime("{$y}-{$m}-{$d}")); + return date($format, strtotime($matches[3].'-'.$matches[1].'-'.$matches[2])); } // Any other kind of string, when converted into UNIX time, // produces "0 seconds after epoc..." is probably bad... // return "Invalid Date". - if (date('U', strtotime($bad_date)) == '0') + if (date('U', strtotime($bad_date)) === '0') { - return "Invalid Date"; + return 'Invalid Date'; } // It's probably a valid-ish date format already @@ -575,59 +539,58 @@ if ( ! function_exists('nice_date')) // ------------------------------------------------------------------------ -/** - * Timezone Menu - * - * Generates a drop-down menu of timezones. - * - * @param string timezone - * @param string classname - * @param string menu name - * @return string - */ if ( ! function_exists('timezone_menu')) { - function timezone_menu($default = 'UTC', $class = "", $name = 'timezones') + /** + * Timezone Menu + * + * Generates a drop-down menu of timezones. + * + * @param string timezone + * @param string classname + * @param string menu name + * @param mixed attributes + * @return string + */ + function timezone_menu($default = 'UTC', $class = '', $name = 'timezones', $attributes = '') { $CI =& get_instance(); $CI->lang->load('date'); - $default = ($default == 'GMT') ? 'UTC' : $default; + $default = ($default === 'GMT') ? 'UTC' : $default; $menu = '<select name="'.$name.'"'; - if ($class != '') + if ($class !== '') { $menu .= ' class="'.$class.'"'; } - $menu .= ">\n"; + $menu .= _stringify_attributes($attributes).">\n"; foreach (timezones() as $key => $val) { - $selected = ($default == $key) ? " selected='selected'" : ''; - $menu .= "<option value='{$key}'{$selected}>".$CI->lang->line($key)."</option>\n"; + $selected = ($default === $key) ? ' selected="selected"' : ''; + $menu .= '<option value="'.$key.'"'.$selected.'>'.$CI->lang->line($key)."</option>\n"; } - $menu .= "</select>"; - - return $menu; + return $menu.'</select>'; } } // ------------------------------------------------------------------------ -/** - * Timezones - * - * Returns an array of timezones. This is a helper function - * for various other ones in this library - * - * @param string timezone - * @return string - */ if ( ! function_exists('timezones')) { + /** + * Timezones + * + * Returns an array of timezones. This is a helper function + * for various other ones in this library + * + * @param string timezone + * @return string + */ function timezones($tz = '') { // Note: Don't change the order of these even though @@ -676,16 +639,145 @@ if ( ! function_exists('timezones')) 'UP14' => +14 ); - if ($tz == '') + if ($tz === '') { return $zones; } - $tz = ($tz == 'GMT') ? 'UTC' : $tz; - return isset($zones[$tz]) ? $zones[$tz] : 0; } } +// ------------------------------------------------------------------------ + +if ( ! function_exists('date_range')) +{ + /** + * Date range + * + * Returns a list of dates within a specified period. + * + * @param int unix_start UNIX timestamp of period start date + * @param int unix_end|days UNIX timestamp of period end date + * or interval in days. + * @param mixed is_unix Specifies whether the second parameter + * is a UNIX timestamp or a day interval + * - TRUE or 'unix' for a timestamp + * - FALSE or 'days' for an interval + * @param string date_format Output date format, same as in date() + * @return array + */ + function date_range($unix_start = '', $mixed = '', $is_unix = TRUE, $format = 'Y-m-d') + { + if ($unix_start == '' OR $mixed == '' OR $format == '') + { + return FALSE; + } + + $is_unix = ! ( ! $is_unix OR $is_unix === 'days'); + + // Validate input and try strtotime() on invalid timestamps/intervals, just in case + if ( ( ! ctype_digit((string) $unix_start) && ($unix_start = @strtotime($unix_time)) === FALSE) + OR ( ! ctype_digit((string) $mixed) && ($is_unix === FALSE OR ($mixed = @strtotime($mixed)) === FALSE)) + OR ($is_unix === TRUE && $mixed < $unix_start)) + { + return FALSE; + } + + if ($is_unix && ($unix_start == $mixed OR date($format, $unix_start) === date($format, $mixed))) + { + return array($start_date); + } + + $range = array(); + + /* NOTE: Even though the DateTime object has many useful features, it appears that + * it doesn't always handle properly timezones, when timestamps are passed + * directly to its constructor. Neither of the following gave proper results: + * + * new DateTime('<timestamp>') + * new DateTime('<timestamp>', '<timezone>') + * + * --- available in PHP 5.3: + * + * DateTime::createFromFormat('<format>', '<timestamp>') + * DateTime::createFromFormat('<format>', '<timestamp>', '<timezone') + * + * ... so we'll have to set the timestamp after the object is instantiated. + * Furthermore, in PHP 5.3 we can use DateTime::setTimestamp() to do that and + * given that we have UNIX timestamps - we should use it. + */ + $from = new DateTime(); + + if (is_php('5.3')) + { + $from->setTimestamp($unix_start); + if ($is_unix) + { + $arg = new DateTime(); + $arg->setTimestamp($mixed); + } + else + { + $arg = (int) $mixed; + } + + $period = new DatePeriod($from, new DateInterval('P1D'), $arg); + foreach ($period as $date) + { + $range[] = $date->format($format); + } + + /* If a period end date was passed to the DatePeriod constructor, it might not + * be in our results. Not sure if this is a bug or it's just possible because + * the end date might actually be less than 24 hours away from the previously + * generated DateTime object, but either way - we have to append it manually. + */ + if ( ! is_int($arg) && $range[count($range) - 1] !== $arg->format($format)) + { + $range[] = $arg->format($format); + } + + return $range; + } + + $from->setDate(date('Y', $unix_start), date('n', $unix_start), date('j', $unix_start)); + $from->setTime(date('G', $unix_start), date('i', $unix_start), date('s', $unix_start)); + if ($is_unix) + { + $arg = new DateTime(); + $arg->setDate(date('Y', $mixed), date('n', $mixed), date('j', $mixed)); + $arg->setTime(date('G', $mixed), date('i', $mixed), date('s', $mixed)); + } + else + { + $arg = (int) $mixed; + } + $range[] = $from->format($format); + + if (is_int($arg)) // Day intervals + { + do + { + $from->modify('+1 day'); + $range[] = $from->format($format); + } + while (--$arg > 0); + } + else // end date UNIX timestamp + { + for ($from->modify('+1 day'), $end_check = $arg->format('Ymd'); $from->format('Ymd') < $end_check; $from->modify('+1 day')) + { + $range[] = $from->format($format); + } + + // Our loop only appended dates prior to our end date + $range[] = $arg->format($format); + } + + return $range; + } +} + /* End of file date_helper.php */ /* Location: ./system/helpers/date_helper.php */
\ No newline at end of file diff --git a/system/helpers/directory_helper.php b/system/helpers/directory_helper.php index 4044ace11..49dcfc8a9 100644 --- a/system/helpers/directory_helper.php +++ b/system/helpers/directory_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Directory Helpers @@ -37,19 +38,21 @@ // ------------------------------------------------------------------------ -/** - * Create a Directory Map - * - * Reads the specified directory and builds an array - * representation of it. Sub-folders contained with the - * directory will be mapped as well. - * - * @param string path to source - * @param int depth of directories to traverse (0 = fully recursive, 1 = current dir, etc) - * @return array - */ if ( ! function_exists('directory_map')) { + /** + * Create a Directory Map + * + * Reads the specified directory and builds an array + * representation of it. Sub-folders contained with the + * directory will be mapped as well. + * + * @param string $source_dir Path to source + * @param int $directory_depth Depth of directories to traverse + * (0 = fully recursive, 1 = current dir, etc) + * @param bool $hidden Whether to show hidden files + * @return array + */ function directory_map($source_dir, $directory_depth = 0, $hidden = FALSE) { if ($fp = @opendir($source_dir)) @@ -61,14 +64,16 @@ if ( ! function_exists('directory_map')) while (FALSE !== ($file = readdir($fp))) { // Remove '.', '..', and hidden files [optional] - if ( ! trim($file, '.') OR ($hidden == FALSE && $file[0] === '.')) + if ($file === '.' OR $file === '..' OR ($hidden === FALSE && $file[0] === '.')) { continue; } + @is_dir($source_dir.$file) AND $file .= DIRECTORY_SEPARATOR; + if (($directory_depth < 1 OR $new_depth > 0) && @is_dir($source_dir.$file)) { - $filedata[$file] = directory_map($source_dir.$file.DIRECTORY_SEPARATOR, $new_depth, $hidden); + $filedata[$file] = directory_map($source_dir.$file, $new_depth, $hidden); } else { diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php index 19192a147..8fe66e222 100644 --- a/system/helpers/download_helper.php +++ b/system/helpers/download_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Download Helpers @@ -37,21 +38,21 @@ // ------------------------------------------------------------------------ -/** - * Force Download - * - * Generates headers that force a download to happen - * - * @param string filename - * @param mixed the data to be downloaded - * @param bool wether to try and send the actual file MIME type - * @return void - */ if ( ! function_exists('force_download')) { + /** + * Force Download + * + * Generates headers that force a download to happen + * + * @param string filename + * @param mixed the data to be downloaded + * @param bool whether to try and send the actual file MIME type + * @return void + */ function force_download($filename = '', $data = '', $set_mime = FALSE) { - if ($filename == '' OR $data == '') + if ($filename === '' OR $data === '') { return FALSE; } @@ -73,14 +74,7 @@ if ( ! function_exists('force_download')) } // Load the mime types - if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php')) - { - include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'); - } - elseif (is_file(APPPATH.'config/mimes.php')) - { - include(APPPATH.'config/mimes.php'); - } + $mimes =& get_mimes(); // Only change the default MIME if we can find one if (isset($mimes[$extension])) @@ -101,6 +95,12 @@ if ( ! function_exists('force_download')) $filename = implode('.', $x); } + // Clean output buffer + if (ob_get_level() !== 0) + { + ob_clean(); + } + // Generate the server headers header('Content-Type: '.$mime); header('Content-Disposition: attachment; filename="'.$filename.'"'); @@ -111,14 +111,11 @@ if ( ! function_exists('force_download')) // Internet Explorer-specific headers if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) { - header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); - header('Pragma: public'); - } - else - { - header('Pragma: no-cache'); + header('Cache-Control: no-cache, no-store, must-revalidate'); } + header('Pragma: no-cache'); + exit($data); } } diff --git a/system/helpers/email_helper.php b/system/helpers/email_helper.php index 497625c10..dfb166a5a 100644 --- a/system/helpers/email_helper.php +++ b/system/helpers/email_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Email Helpers @@ -37,33 +38,35 @@ // ------------------------------------------------------------------------ -/** - * Validate email address - * - * @param string - * @return bool - */ if ( ! function_exists('valid_email')) { - function valid_email($address) + /** + * Validate email address + * + * @deprecated 3.0.0 Use PHP's filter_var() instead + * @param string $email + * @return bool + */ + function valid_email($email) { - return (bool) preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix', $address); + return (bool) filter_var($email, FILTER_VALIDATE_EMAIL); } } // ------------------------------------------------------------------------ -/** - * Send an email - * - * @param string - * @param string - * @param string - * @return bool - */ if ( ! function_exists('send_email')) { - function send_email($recipient, $subject = 'Test email', $message = 'Hello World') + /** + * Send an email + * + * @deprecated 3.0.0 Use PHP's mail() instead + * @param string $recipient + * @param string $subject + * @param string $message + * @return bool + */ + function send_email($recipient, $subject, $message) { return mail($recipient, $subject, $message); } diff --git a/system/helpers/file_helper.php b/system/helpers/file_helper.php index 3a373efd3..aebb6e47a 100644 --- a/system/helpers/file_helper.php +++ b/system/helpers/file_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter File Helpers @@ -32,68 +33,45 @@ * @subpackage Helpers * @category Helpers * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/helpers/file_helpers.html + * @link http://codeigniter.com/user_guide/helpers/file_helper.html */ // ------------------------------------------------------------------------ -/** - * Read File - * - * Opens the file specfied in the path and returns it as a string. - * - * @param string path to file - * @return string - */ if ( ! function_exists('read_file')) { + /** + * Read File + * + * Opens the file specfied in the path and returns it as a string. + * + * @todo Remove in version 3.1+. + * @deprecated 3.0.0 It is now just an alias for PHP's native file_get_contents(). + * @param string $file Path to file + * @return string File contents + */ function read_file($file) { - if ( ! file_exists($file)) - { - return FALSE; - } - - if (function_exists('file_get_contents')) - { - return file_get_contents($file); - } - - if ( ! $fp = @fopen($file, FOPEN_READ)) - { - return FALSE; - } - - flock($fp, LOCK_SH); - - $data = ''; - if (filesize($file) > 0) - { - $data =& fread($fp, filesize($file)); - } - - flock($fp, LOCK_UN); - fclose($fp); - - return $data; + return @file_get_contents($file); } } // ------------------------------------------------------------------------ -/** - * Write File - * - * Writes data to the file specified in the path. - * Creates a new file if non-existent. - * - * @param string path to file - * @param string file data - * @return bool - */ if ( ! function_exists('write_file')) { - function write_file($path, $data, $mode = FOPEN_WRITE_CREATE_DESTRUCTIVE) + /** + * Write File + * + * Writes data to the file specified in the path. + * Creates a new file if non-existent. + * + * @param string $path File path + * @param string $data Data to write + * @param string $mode fopen() mode (default: 'wb') + * @return bool + */ + function write_file($path, $data, $mode = 'wb') { if ( ! $fp = @fopen($path, $mode)) { @@ -111,26 +89,26 @@ if ( ! function_exists('write_file')) // ------------------------------------------------------------------------ -/** - * Delete Files - * - * Deletes all files contained in the supplied directory path. - * Files must be writable or owned by the system in order to be deleted. - * If the second parameter is set to TRUE, any directories contained - * within the supplied base directory will be nuked as well. - * - * @param string path to file - * @param bool whether to delete any directories found in the path - * @param int - * @param bool whether to skip deleting .htaccess and index page files - * @return bool - */ if ( ! function_exists('delete_files')) { - function delete_files($path, $del_dir = FALSE, $level = 0, $htdocs = FALSE) + /** + * Delete Files + * + * Deletes all files contained in the supplied directory path. + * Files must be writable or owned by the system in order to be deleted. + * If the second parameter is set to TRUE, any directories contained + * within the supplied base directory will be nuked as well. + * + * @param string $path File path + * @param bool $del_dir Whether to delete any directories found in the path + * @param bool $htdocs Whether to skip deleting .htaccess and index page files + * @param int $_level Current directory depth level (default: 0; internal use only) + * @return bool + */ + function delete_files($path, $del_dir = FALSE, $htdocs = FALSE, $_level = 0) { // Trim the trailing slash - $path = rtrim($path, DIRECTORY_SEPARATOR); + $path = rtrim($path, '/\\'); if ( ! $current_dir = @opendir($path)) { @@ -143,9 +121,9 @@ if ( ! function_exists('delete_files')) { if (is_dir($path.DIRECTORY_SEPARATOR.$filename) && $filename[0] !== '.') { - delete_files($path.DIRECTORY_SEPARATOR.$filename, $del_dir, $level + 1, $htdocs); + delete_files($path.DIRECTORY_SEPARATOR.$filename, $del_dir, $htdocs, $_level + 1); } - elseif ($htdocs === TRUE && ! preg_match('/^(\.htaccess|index\.(html|htm|php))$/', $filename)) + elseif ($htdocs !== TRUE OR ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename)) { @unlink($path.DIRECTORY_SEPARATOR.$filename); } @@ -153,7 +131,7 @@ if ( ! function_exists('delete_files')) } @closedir($current_dir); - if ($del_dir == TRUE && $level > 0) + if ($del_dir === TRUE && $_level > 0) { return @rmdir($path); } @@ -164,19 +142,19 @@ if ( ! function_exists('delete_files')) // ------------------------------------------------------------------------ -/** - * Get Filenames - * - * Reads the specified directory and builds an array containing the filenames. - * Any sub-folders contained within the specified path are read as well. - * - * @param string path to source - * @param bool whether to include the path as part of the filename - * @param bool internal variable to determine recursion status - do not use in calls - * @return array - */ if ( ! function_exists('get_filenames')) { + /** + * Get Filenames + * + * Reads the specified directory and builds an array containing the filenames. + * Any sub-folders contained within the specified path are read as well. + * + * @param string path to source + * @param bool whether to include the path as part of the filename + * @param bool internal variable to determine recursion status - do not use in calls + * @return array + */ function get_filenames($source_dir, $include_path = FALSE, $_recursion = FALSE) { static $_filedata = array(); @@ -198,7 +176,7 @@ if ( ! function_exists('get_filenames')) } elseif ($file[0] !== '.') { - $_filedata[] = ($include_path == TRUE) ? $source_dir.$file : $file; + $_filedata[] = ($include_path === TRUE) ? $source_dir.$file : $file; } } closedir($fp); @@ -212,21 +190,21 @@ if ( ! function_exists('get_filenames')) // -------------------------------------------------------------------- -/** - * Get Directory File Information - * - * Reads the specified directory and builds an array containing the filenames, - * filesize, dates, and permissions - * - * Any sub-folders contained within the specified path are read as well. - * - * @param string path to source - * @param bool Look only at the top level directory specified? - * @param bool internal variable to determine recursion status - do not use in calls - * @return array - */ if ( ! function_exists('get_dir_file_info')) { + /** + * Get Directory File Information + * + * Reads the specified directory and builds an array containing the filenames, + * filesize, dates, and permissions + * + * Any sub-folders contained within the specified path are read as well. + * + * @param string path to source + * @param bool Look only at the top level directory specified? + * @param bool internal variable to determine recursion status - do not use in calls + * @return array + */ function get_dir_file_info($source_dir, $top_level_only = TRUE, $_recursion = FALSE) { static $_filedata = array(); @@ -265,20 +243,20 @@ if ( ! function_exists('get_dir_file_info')) // -------------------------------------------------------------------- -/** -* Get File Info -* -* Given a file and path, returns the name, path, size, date modified -* Second parameter allows you to explicitly declare what information you want returned -* Options are: name, server_path, size, date, readable, writable, executable, fileperms -* Returns FALSE if the file cannot be found. -* -* @param string path to file -* @param mixed array or comma separated string of information returned -* @return array -*/ if ( ! function_exists('get_file_info')) { + /** + * Get File Info + * + * Given a file and path, returns the name, path, size, date modified + * Second parameter allows you to explicitly declare what information you want returned + * Options are: name, server_path, size, date, readable, writable, executable, fileperms + * Returns FALSE if the file cannot be found. + * + * @param string path to file + * @param mixed array or comma separated string of information returned + * @return array + */ function get_file_info($file, $returned_values = array('name', 'server_path', 'size', 'date')) { @@ -330,54 +308,41 @@ if ( ! function_exists('get_file_info')) // -------------------------------------------------------------------- -/** - * Get Mime by Extension - * - * Translates a file extension into a mime type based on config/mimes.php. - * Returns FALSE if it can't determine the type, or open the mime config file - * - * Note: this is NOT an accurate way of determining file mime types, and is here strictly as a convenience - * It should NOT be trusted, and should certainly NOT be used for security - * - * @param string path to file - * @return mixed - */ if ( ! function_exists('get_mime_by_extension')) { - function get_mime_by_extension($file) + /** + * Get Mime by Extension + * + * Translates a file extension into a mime type based on config/mimes.php. + * Returns FALSE if it can't determine the type, or open the mime config file + * + * Note: this is NOT an accurate way of determining file mime types, and is here strictly as a convenience + * It should NOT be trusted, and should certainly NOT be used for security + * + * @param string $filename File name + * @return string + */ + function get_mime_by_extension($filename) { - $extension = strtolower(substr(strrchr($file, '.'), 1)); + $extension = strtolower(substr(strrchr($filename, '.'), 1)); - global $mimes; + static $mimes; if ( ! is_array($mimes)) { - if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php')) - { - include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'); - } - elseif (is_file(APPPATH.'config/mimes.php')) - { - include(APPPATH.'config/mimes.php'); - } + $mimes =& get_mimes(); - if ( ! is_array($mimes)) + if (empty($mimes)) { return FALSE; } } - if (array_key_exists($extension, $mimes)) + if (isset($mimes[$extension])) { - if (is_array($mimes[$extension])) - { - // Multiple mime types, just give the first one - return current($mimes[$extension]); - } - else - { - return $mimes[$extension]; - } + return is_array($mimes[$extension]) + ? current($mimes[$extension]) // Multiple mime types, just give the first one + : $mimes[$extension]; } return FALSE; @@ -386,17 +351,17 @@ if ( ! function_exists('get_mime_by_extension')) // -------------------------------------------------------------------- -/** - * Symbolic Permissions - * - * Takes a numeric value representing a file's permissions and returns - * standard symbolic notation representing that value - * - * @param int - * @return string - */ if ( ! function_exists('symbolic_permissions')) { + /** + * Symbolic Permissions + * + * Takes a numeric value representing a file's permissions and returns + * standard symbolic notation representing that value + * + * @param int $perms Permissions + * @return string + */ function symbolic_permissions($perms) { if (($perms & 0xC000) === 0xC000) @@ -453,17 +418,17 @@ if ( ! function_exists('symbolic_permissions')) // -------------------------------------------------------------------- -/** - * Octal Permissions - * - * Takes a numeric value representing a file's permissions and returns - * a three character string representing the file's octal permissions - * - * @param int - * @return string - */ if ( ! function_exists('octal_permissions')) { + /** + * Octal Permissions + * + * Takes a numeric value representing a file's permissions and returns + * a three character string representing the file's octal permissions + * + * @param int $perms Permissions + * @return string + */ function octal_permissions($perms) { return substr(sprintf('%o', $perms), -3); diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php index e5b487608..e7bea92cc 100644 --- a/system/helpers/form_helper.php +++ b/system/helpers/form_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -22,7 +22,9 @@ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 1.0 + * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Form Helpers @@ -36,23 +38,23 @@ // ------------------------------------------------------------------------ -/** - * Form Declaration - * - * Creates the opening portion of the form. - * - * @param string the URI segments of the form destination - * @param array a key/value pair of attributes - * @param array a key/value pair hidden data - * @return string - */ if ( ! function_exists('form_open')) { + /** + * Form Declaration + * + * Creates the opening portion of the form. + * + * @param string the URI segments of the form destination + * @param array a key/value pair of attributes + * @param array a key/value pair hidden data + * @return string + */ function form_open($action = '', $attributes = '', $hidden = array()) { $CI =& get_instance(); - if ($attributes == '') + if ($attributes === '') { $attributes = 'method="post"'; } @@ -62,9 +64,11 @@ if ( ! function_exists('form_open')) { $action = $CI->config->site_url($action); } - - // If no action is provided then set to the current url - $action OR $action = $CI->config->site_url($CI->uri->uri_string()); + elseif ( ! $action) + { + // If no action is provided then set to the current url + $action = $CI->config->site_url($CI->uri->uri_string()); + } $form = '<form action="'.$action.'"'._attributes_to_string($attributes, TRUE).">\n"; @@ -76,7 +80,7 @@ if ( ! function_exists('form_open')) if (is_array($hidden) && count($hidden) > 0) { - $form .= sprintf('<div style="display:none;">%s</div>', form_hidden($hidden)); + $form .= '<div style="display:none;">'.form_hidden($hidden).'</div>'; } return $form; @@ -85,18 +89,18 @@ if ( ! function_exists('form_open')) // ------------------------------------------------------------------------ -/** - * Form Declaration - Multipart type - * - * Creates the opening portion of the form, but with "multipart/form-data". - * - * @param string the URI segments of the form destination - * @param array a key/value pair of attributes - * @param array a key/value pair hidden data - * @return string - */ if ( ! function_exists('form_open_multipart')) { + /** + * Form Declaration - Multipart type + * + * Creates the opening portion of the form, but with "multipart/form-data". + * + * @param string the URI segments of the form destination + * @param array a key/value pair of attributes + * @param array a key/value pair hidden data + * @return string + */ function form_open_multipart($action = '', $attributes = array(), $hidden = array()) { if (is_string($attributes)) @@ -114,18 +118,19 @@ if ( ! function_exists('form_open_multipart')) // ------------------------------------------------------------------------ -/** - * Hidden Input Field - * - * Generates hidden fields. You can pass a simple key/value string or - * an associative array with multiple values. - * - * @param mixed - * @param string - * @return string - */ if ( ! function_exists('form_hidden')) { + /** + * Hidden Input Field + * + * Generates hidden fields. You can pass a simple key/value string or + * an associative array with multiple values. + * + * @param mixed $name Field name + * @param string $value Field value + * @param bool $recursing + * @return string + */ function form_hidden($name, $value = '', $recursing = FALSE) { static $form; @@ -146,7 +151,7 @@ if ( ! function_exists('form_hidden')) if ( ! is_array($value)) { - $form .= '<input type="hidden" name="'.$name.'" value="'.form_prep($value, $name)."\" />\n"; + $form .= '<input type="hidden" name="'.$name.'" value="'.form_prep($value)."\" />\n"; } else { @@ -163,16 +168,16 @@ if ( ! function_exists('form_hidden')) // ------------------------------------------------------------------------ -/** - * Text Input Field - * - * @param mixed - * @param string - * @param string - * @return string - */ if ( ! function_exists('form_input')) { + /** + * Text Input Field + * + * @param mixed + * @param string + * @param string + * @return string + */ function form_input($data = '', $value = '', $extra = '') { $defaults = array('type' => 'text', 'name' => ( ! is_array($data) ? $data : ''), 'value' => $value); @@ -183,18 +188,18 @@ if ( ! function_exists('form_input')) // ------------------------------------------------------------------------ -/** - * Password Field - * - * Identical to the input function but adds the "password" type - * - * @param mixed - * @param string - * @param string - * @return string - */ if ( ! function_exists('form_password')) { + /** + * Password Field + * + * Identical to the input function but adds the "password" type + * + * @param mixed + * @param string + * @param string + * @return string + */ function form_password($data = '', $value = '', $extra = '') { if ( ! is_array($data)) @@ -209,18 +214,18 @@ if ( ! function_exists('form_password')) // ------------------------------------------------------------------------ -/** - * Upload Field - * - * Identical to the input function but adds the "file" type - * - * @param mixed - * @param string - * @param string - * @return string - */ if ( ! function_exists('form_upload')) { + /** + * Upload Field + * + * Identical to the input function but adds the "file" type + * + * @param mixed + * @param string + * @param string + * @return string + */ function form_upload($data = '', $value = '', $extra = '') { if ( ! is_array($data)) @@ -235,16 +240,16 @@ if ( ! function_exists('form_upload')) // ------------------------------------------------------------------------ -/** - * Textarea field - * - * @param mixed - * @param string - * @param string - * @return string - */ if ( ! function_exists('form_textarea')) { + /** + * Textarea field + * + * @param mixed $data + * @param string $value + * @param string $extra + * @return string + */ function form_textarea($data = '', $value = '', $extra = '') { $defaults = array('name' => ( ! is_array($data) ? $data : ''), 'cols' => '40', 'rows' => '10'); @@ -260,23 +265,23 @@ if ( ! function_exists('form_textarea')) } $name = is_array($data) ? $data['name'] : $data; - return '<textarea '._parse_form_attributes($data, $defaults).$extra.'>'.form_prep($val, $name)."</textarea>\n"; + return '<textarea '._parse_form_attributes($data, $defaults).$extra.'>'.form_prep($val, TRUE)."</textarea>\n"; } } // ------------------------------------------------------------------------ -/** - * Multi-select menu - * - * @param string - * @param array - * @param mixed - * @param string - * @return string - */ if ( ! function_exists('form_multiselect')) { + /** + * Multi-select menu + * + * @param string + * @param array + * @param mixed + * @param string + * @return string + */ function form_multiselect($name = '', $options = array(), $selected = array(), $extra = '') { if ( ! strpos($extra, 'multiple')) @@ -290,17 +295,17 @@ if ( ! function_exists('form_multiselect')) // -------------------------------------------------------------------- -/** - * Drop-down Menu - * - * @param string - * @param array - * @param string - * @param string - * @return string - */ if ( ! function_exists('form_dropdown')) { + /** + * Drop-down Menu + * + * @param mixed $name + * @param mixed $options + * @param mixed $selected + * @param mixed $extra + * @return string + */ function form_dropdown($name = '', $options = array(), $selected = array(), $extra = '') { // If name is really an array then we'll call the function again using the array @@ -313,10 +318,7 @@ if ( ! function_exists('form_dropdown')) return form_dropdown($name['name'], $name['options'], $name['selected'], $name['extra']); } - if ( ! is_array($selected)) - { - $selected = array($selected); - } + is_array($selected) OR $selected = array($selected); // If no selected state was submitted we will attempt to set it automatically if (count($selected) === 0 && isset($_POST[$name])) @@ -324,7 +326,10 @@ if ( ! function_exists('form_dropdown')) $selected = array($_POST[$name]); } - if ($extra != '') $extra = ' '.$extra; + if ($extra != '') + { + $extra = ' '.$extra; + } $multiple = (count($selected) > 1 && strpos($extra, 'multiple') === FALSE) ? ' multiple="multiple"' : ''; @@ -334,21 +339,29 @@ if ( ! function_exists('form_dropdown')) { $key = (string) $key; - if (is_array($val) && ! empty($val)) + if (is_array($val)) { + if (empty($val)) + { + continue; + } + $form .= '<optgroup label="'.$key."\">\n"; foreach ($val as $optgroup_key => $optgroup_val) { $sel = in_array($optgroup_key, $selected) ? ' selected="selected"' : ''; - $form .= '<option value="'.$optgroup_key.'"'.$sel.'>'.(string) $optgroup_val."</option>\n"; + $form .= '<option value="'.form_prep($optgroup_key).'"'.$sel.'>' + .(string) $optgroup_val."</option>\n"; } $form .= "</optgroup>\n"; } else { - $form .= '<option value="'.$key.'"'.(in_array($key, $selected) ? ' selected="selected"' : '').'>'.(string) $val."</option>\n"; + $form .= '<option value="'.form_prep($key).'"' + .(in_array($key, $selected) ? ' selected="selected"' : '').'>' + .(string) $val."</option>\n"; } } @@ -358,17 +371,17 @@ if ( ! function_exists('form_dropdown')) // ------------------------------------------------------------------------ -/** - * Checkbox Field - * - * @param mixed - * @param string - * @param bool - * @param string - * @return string - */ if ( ! function_exists('form_checkbox')) { + /** + * Checkbox Field + * + * @param mixed + * @param string + * @param bool + * @param string + * @return string + */ function form_checkbox($data = '', $value = '', $checked = FALSE, $extra = '') { $defaults = array('type' => 'checkbox', 'name' => ( ! is_array($data) ? $data : ''), 'value' => $value); @@ -402,17 +415,17 @@ if ( ! function_exists('form_checkbox')) // ------------------------------------------------------------------------ -/** - * Radio Button - * - * @param mixed - * @param string - * @param bool - * @param string - * @return string - */ if ( ! function_exists('form_radio')) { + /** + * Radio Button + * + * @param mixed + * @param string + * @param bool + * @param string + * @return string + */ function form_radio($data = '', $value = '', $checked = FALSE, $extra = '') { if ( ! is_array($data)) @@ -427,16 +440,16 @@ if ( ! function_exists('form_radio')) // ------------------------------------------------------------------------ -/** - * Submit Button - * - * @param mixed - * @param string - * @param string - * @return string - */ if ( ! function_exists('form_submit')) { + /** + * Submit Button + * + * @param mixed + * @param string + * @param string + * @return string + */ function form_submit($data = '', $value = '', $extra = '') { $defaults = array('type' => 'submit', 'name' => ( ! is_array($data) ? $data : ''), 'value' => $value); @@ -446,16 +459,16 @@ if ( ! function_exists('form_submit')) // ------------------------------------------------------------------------ -/** - * Reset Button - * - * @param mixed - * @param string - * @param string - * @return string - */ if ( ! function_exists('form_reset')) { + /** + * Reset Button + * + * @param mixed + * @param string + * @param string + * @return string + */ function form_reset($data = '', $value = '', $extra = '') { $defaults = array('type' => 'reset', 'name' => ( ! is_array($data) ? $data : ''), 'value' => $value); @@ -465,16 +478,16 @@ if ( ! function_exists('form_reset')) // ------------------------------------------------------------------------ -/** - * Form Button - * - * @param mixed - * @param string - * @param string - * @return string - */ if ( ! function_exists('form_button')) { + /** + * Form Button + * + * @param mixed + * @param string + * @param string + * @return string + */ function form_button($data = '', $content = '', $extra = '') { $defaults = array('name' => ( ! is_array($data) ? $data : ''), 'type' => 'button'); @@ -490,22 +503,22 @@ if ( ! function_exists('form_button')) // ------------------------------------------------------------------------ -/** - * Form Label Tag - * - * @param string The text to appear onscreen - * @param string The id the label applies to - * @param string Additional attributes - * @return string - */ if ( ! function_exists('form_label')) { + /** + * Form Label Tag + * + * @param string The text to appear onscreen + * @param string The id the label applies to + * @param string Additional attributes + * @return string + */ function form_label($label_text = '', $id = '', $attributes = array()) { $label = '<label'; - if ($id != '') + if ($id !== '') { $label .= ' for="'.$id.'"'; } @@ -523,22 +536,23 @@ if ( ! function_exists('form_label')) } // ------------------------------------------------------------------------ -/** - * Fieldset Tag - * - * Used to produce <fieldset><legend>text</legend>. To close fieldset - * use form_fieldset_close() - * - * @param string The legend text - * @param string Additional attributes - * @return string - */ + if ( ! function_exists('form_fieldset')) { + /** + * Fieldset Tag + * + * Used to produce <fieldset><legend>text</legend>. To close fieldset + * use form_fieldset_close() + * + * @param string The legend text + * @param string Additional attributes + * @return string + */ function form_fieldset($legend_text = '', $attributes = array()) { $fieldset = '<fieldset'._attributes_to_string($attributes, FALSE).">\n"; - if ($legend_text != '') + if ($legend_text !== '') { return $fieldset.'<legend>'.$legend_text."</legend>\n"; } @@ -549,14 +563,14 @@ if ( ! function_exists('form_fieldset')) // ------------------------------------------------------------------------ -/** - * Fieldset Close Tag - * - * @param string - * @return string - */ if ( ! function_exists('form_fieldset_close')) { + /** + * Fieldset Close Tag + * + * @param string + * @return string + */ function form_fieldset_close($extra = '') { return '</fieldset>'.$extra; @@ -565,14 +579,14 @@ if ( ! function_exists('form_fieldset_close')) // ------------------------------------------------------------------------ -/** - * Form Close Tag - * - * @param string - * @return string - */ if ( ! function_exists('form_close')) { + /** + * Form Close Tag + * + * @param string + * @return string + */ function form_close($extra = '') { return '</form>'.$extra; @@ -581,99 +595,82 @@ if ( ! function_exists('form_close')) // ------------------------------------------------------------------------ -/** - * Form Prep - * - * Formats text so that it can be safely placed in a form field in the event it has HTML tags. - * - * @param string - * @return string - */ if ( ! function_exists('form_prep')) { - function form_prep($str = '', $field_name = '') + /** + * Form Prep + * + * Formats text so that it can be safely placed in a form field in the event it has HTML tags. + * + * @param string|string[] $str Value to escape + * @param bool $is_textarea Whether we're escaping for a textarea element + * @return string|string[] Escaped values + */ + function form_prep($str = '', $is_textarea = FALSE) { - static $prepped_fields = array(); - - // if the field name is an array we do this recursively if (is_array($str)) { - foreach ($str as $key => $val) + foreach (array_keys($str) as $key) { - $str[$key] = form_prep($val); + $str[$key] = form_prep($str[$key], $is_textarea); } return $str; } - if ($str === '') - { - return ''; - } - - // we've already prepped a field with this name - // @todo need to figure out a way to namespace this so - // that we know the *exact* field and not just one with - // the same name - if (isset($prepped_fields[$field_name])) - { - return $str; - } - - if ($field_name != '') + if ($is_textarea === TRUE) { - $prepped_fields[$field_name] = $field_name; + return str_replace(array('<', '>'), array('<', '>'), stripslashes($str)); } - return html_escape($str); + return str_replace(array("'", '"'), array(''', '"'), stripslashes($str)); } } // ------------------------------------------------------------------------ -/** - * Form Value - * - * Grabs a value from the POST array for the specified field so you can - * re-populate an input field or textarea. If Form Validation - * is active it retrieves the info from the validation class - * - * @param string - * @return mixed - */ if ( ! function_exists('set_value')) { - function set_value($field = '', $default = '') + /** + * Form Value + * + * Grabs a value from the POST array for the specified field so you can + * re-populate an input field or textarea. If Form Validation + * is active it retrieves the info from the validation class + * + * @param string $field Field name + * @param string $default Default value + * @param bool $is_textarea Whether the field is a textarea element + * @return string + */ + function set_value($field = '', $default = '', $is_textarea = FALSE) { if (FALSE === ($OBJ =& _get_validation_object())) { - if ( ! isset($_POST[$field])) - { - return $default; - } - - return form_prep($_POST[$field], $field); + return isset($_POST[$field]) + ? form_prep($_POST[$field], $is_textarea) + : form_prep($default, $is_textarea); } - return form_prep($OBJ->set_value($field, $default), $field); + return form_prep($OBJ->set_value($field, $default), $is_textarea); } } // ------------------------------------------------------------------------ -/** - * Set Select - * - * Let's you set the selected value of a <select> menu via data in the POST array. - * If Form Validation is active it retrieves the info from the validation class - * - * @param string - * @param string - * @param bool - * @return string - */ if ( ! function_exists('set_select')) { + /** + * Set Select + * + * Let's you set the selected value of a <select> menu via data in the POST array. + * If Form Validation is active it retrieves the info from the validation class + * + * @param string + * @param string + * @param bool + * @return string + */ function set_select($field = '', $value = '', $default = FALSE) { $OBJ =& _get_validation_object(); @@ -682,7 +679,7 @@ if ( ! function_exists('set_select')) { if ( ! isset($_POST[$field])) { - if (count($_POST) === 0 && $default == TRUE) + if (count($_POST) === 0 && $default === TRUE) { return ' selected="selected"'; } @@ -698,7 +695,7 @@ if ( ! function_exists('set_select')) return ''; } } - elseif (($field == '' OR $value == '') OR ($field != $value)) + elseif (($field == '' OR $value == '') OR $field !== $value) { return ''; } @@ -712,19 +709,19 @@ if ( ! function_exists('set_select')) // ------------------------------------------------------------------------ -/** - * Set Checkbox - * - * Let's you set the selected value of a checkbox via the value in the POST array. - * If Form Validation is active it retrieves the info from the validation class - * - * @param string - * @param string - * @param bool - * @return string - */ if ( ! function_exists('set_checkbox')) { + /** + * Set Checkbox + * + * Let's you set the selected value of a checkbox via the value in the POST array. + * If Form Validation is active it retrieves the info from the validation class + * + * @param string + * @param string + * @param bool + * @return string + */ function set_checkbox($field = '', $value = '', $default = FALSE) { $OBJ =& _get_validation_object(); @@ -733,7 +730,7 @@ if ( ! function_exists('set_checkbox')) { if ( ! isset($_POST[$field])) { - if (count($_POST) === 0 && $default == TRUE) + if (count($_POST) === 0 && $default === TRUE) { return ' checked="checked"'; } @@ -749,7 +746,7 @@ if ( ! function_exists('set_checkbox')) return ''; } } - elseif (($field == '' OR $value == '') OR ($field != $value)) + elseif (($field == '' OR $value == '') OR $field !== $value) { return ''; } @@ -763,19 +760,19 @@ if ( ! function_exists('set_checkbox')) // ------------------------------------------------------------------------ -/** - * Set Radio - * - * Let's you set the selected value of a radio field via info in the POST array. - * If Form Validation is active it retrieves the info from the validation class - * - * @param string - * @param string - * @param bool - * @return string - */ if ( ! function_exists('set_radio')) { + /** + * Set Radio + * + * Let's you set the selected value of a radio field via info in the POST array. + * If Form Validation is active it retrieves the info from the validation class + * + * @param string + * @param string + * @param bool + * @return string + */ function set_radio($field = '', $value = '', $default = FALSE) { $OBJ =& _get_validation_object(); @@ -784,7 +781,7 @@ if ( ! function_exists('set_radio')) { if ( ! isset($_POST[$field])) { - if (count($_POST) === 0 && $default == TRUE) + if (count($_POST) === 0 && $default === TRUE) { return ' checked="checked"'; } @@ -802,7 +799,7 @@ if ( ! function_exists('set_radio')) } else { - if (($field == '' OR $value == '') OR ($field != $value)) + if (($field == '' OR $value == '') OR $field !== $value) { return ''; } @@ -817,19 +814,20 @@ if ( ! function_exists('set_radio')) // ------------------------------------------------------------------------ -/** - * Form Error - * - * Returns the error for a specific form field. This is a helper for the - * form validation class. - * - * @param string - * @param string - * @param string - * @return string - */ + if ( ! function_exists('form_error')) { + /** + * Form Error + * + * Returns the error for a specific form field. This is a helper for the + * form validation class. + * + * @param string + * @param string + * @param string + * @return string + */ function form_error($field = '', $prefix = '', $suffix = '') { if (FALSE === ($OBJ =& _get_validation_object())) @@ -843,18 +841,18 @@ if ( ! function_exists('form_error')) // ------------------------------------------------------------------------ -/** - * Validation Error String - * - * Returns all the errors associated with a form submission. This is a helper - * function for the form validation class. - * - * @param string - * @param string - * @return string - */ if ( ! function_exists('validation_errors')) { + /** + * Validation Error String + * + * Returns all the errors associated with a form submission. This is a helper + * function for the form validation class. + * + * @param string + * @param string + * @return string + */ function validation_errors($prefix = '', $suffix = '') { if (FALSE === ($OBJ =& _get_validation_object())) @@ -868,17 +866,17 @@ if ( ! function_exists('validation_errors')) // ------------------------------------------------------------------------ -/** - * Parse the form attributes - * - * Helper function used by some of the form helpers - * - * @param array - * @param array - * @return string - */ if ( ! function_exists('_parse_form_attributes')) { + /** + * Parse the form attributes + * + * Helper function used by some of the form helpers + * + * @param array $attributes List of attributes + * @param array $default Default values + * @return string + */ function _parse_form_attributes($attributes, $default) { if (is_array($attributes)) @@ -902,9 +900,13 @@ if ( ! function_exists('_parse_form_attributes')) foreach ($default as $key => $val) { - if ($key == 'value') + if ($key === 'value') + { + $val = form_prep($val); + } + elseif ($key === 'name' && ! strlen($default['name'])) { - $val = form_prep($val, $default['name']); + continue; } $att .= $key.'="'.$val.'" '; @@ -916,27 +918,27 @@ if ( ! function_exists('_parse_form_attributes')) // ------------------------------------------------------------------------ -/** - * Attributes To String - * - * Helper function used by some of the form helpers - * - * @param mixed - * @param bool - * @return string - */ if ( ! function_exists('_attributes_to_string')) { + /** + * Attributes To String + * + * Helper function used by some of the form helpers + * + * @param mixed + * @param bool + * @return string + */ function _attributes_to_string($attributes, $formtag = FALSE) { if (is_string($attributes) && strlen($attributes) > 0) { - if ($formtag == TRUE && strpos($attributes, 'method=') === FALSE) + if ($formtag === TRUE && strpos($attributes, 'method=') === FALSE) { $attributes .= ' method="post"'; } - if ($formtag == TRUE && strpos($attributes, 'accept-charset=') === FALSE) + if ($formtag === TRUE && strpos($attributes, 'accept-charset=') === FALSE) { $attributes .= ' accept-charset="'.strtolower(config_item('charset')).'"'; } @@ -975,16 +977,16 @@ if ( ! function_exists('_attributes_to_string')) // ------------------------------------------------------------------------ -/** - * Validation Object - * - * Determines what the form validation class was instantiated as, fetches - * the object and returns it. - * - * @return mixed - */ if ( ! function_exists('_get_validation_object')) { + /** + * Validation Object + * + * Determines what the form validation class was instantiated as, fetches + * the object and returns it. + * + * @return mixed + */ function &_get_validation_object() { $CI =& get_instance(); diff --git a/system/helpers/html_helper.php b/system/helpers/html_helper.php index 0417bd253..fa49f7d75 100644 --- a/system/helpers/html_helper.php +++ b/system/helpers/html_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter HTML Helpers @@ -37,36 +38,37 @@ // ------------------------------------------------------------------------ -/** - * Heading - * - * Generates an HTML heading tag. - * - * @param string content - * @param int heading level - * @return string - */ if ( ! function_exists('heading')) { + /** + * Heading + * + * Generates an HTML heading tag. + * + * @param string content + * @param int heading level + * @param string + * @return string + */ function heading($data = '', $h = '1', $attributes = '') { - return '<h'.$h.($attributes != '' ? ' ' : '').$attributes.'>'.$data.'</h'.$h.'>'; + return '<h'.$h._stringify_attributes($attributes).'>'.$data.'</h'.$h.'>'; } } // ------------------------------------------------------------------------ -/** - * Unordered List - * - * Generates an HTML unordered list from an single or multi-dimensional array. - * - * @param array - * @param mixed - * @return string - */ if ( ! function_exists('ul')) { + /** + * Unordered List + * + * Generates an HTML unordered list from an single or multi-dimensional array. + * + * @param array + * @param mixed + * @return string + */ function ul($list, $attributes = '') { return _list('ul', $list, $attributes); @@ -75,17 +77,17 @@ if ( ! function_exists('ul')) // ------------------------------------------------------------------------ -/** - * Ordered List - * - * Generates an HTML ordered list from an single or multi-dimensional array. - * - * @param array - * @param mixed - * @return string - */ if ( ! function_exists('ol')) { + /** + * Ordered List + * + * Generates an HTML ordered list from an single or multi-dimensional array. + * + * @param array + * @param mixed + * @return string + */ function ol($list, $attributes = '') { return _list('ol', $list, $attributes); @@ -94,19 +96,19 @@ if ( ! function_exists('ol')) // ------------------------------------------------------------------------ -/** - * Generates the list - * - * Generates an HTML ordered list from an single or multi-dimensional array. - * - * @param string - * @param mixed - * @param mixed - * @param int - * @return string - */ if ( ! function_exists('_list')) { + /** + * Generates the list + * + * Generates an HTML ordered list from an single or multi-dimensional array. + * + * @param string + * @param mixed + * @param mixed + * @param int + * @return string + */ function _list($type = 'ul', $list, $attributes = '', $depth = 0) { // If an array wasn't submitted there's nothing to do... @@ -118,23 +120,8 @@ if ( ! function_exists('_list')) // Set the indentation based on the depth $out = str_repeat(' ', $depth); - // Were any attributes submitted? If so generate a string - if (is_array($attributes)) - { - $atts = ''; - foreach ($attributes as $key => $val) - { - $atts .= ' '.$key.'="'.$val.'"'; - } - $attributes = $atts; - } - elseif (is_string($attributes) && strlen($attributes) > 0) - { - $attributes = ' '.$attributes; - } - // Write the opening list tag - $out .= '<'.$type.$attributes.">\n"; + $out .= '<'.$type._stringify_attributes($attributes).">\n"; // Cycle through the list elements. If an array is // encountered we will recursively call _list() @@ -165,34 +152,35 @@ if ( ! function_exists('_list')) // ------------------------------------------------------------------------ -/** - * Generates HTML BR tags based on number supplied - * - * @param int - * @return string - */ if ( ! function_exists('br')) { - function br($num = 1) + /** + * Generates HTML BR tags based on number supplied + * + * @param int $count Number of times to repeat the tag + * @return string + */ + function br($count = 1) { - return str_repeat('<br />', $num); + return str_repeat('<br />', $count); } } // ------------------------------------------------------------------------ -/** - * Image - * - * Generates an <img /> element - * - * @param mixed - * @param bool - * @return string - */ if ( ! function_exists('img')) { - function img($src = '', $index_page = FALSE) + /** + * Image + * + * Generates an <img /> element + * + * @param mixed + * @param bool + * @param mixed + * @return string + */ + function img($src = '', $index_page = FALSE, $attributes = '') { if ( ! is_array($src) ) { @@ -228,26 +216,26 @@ if ( ! function_exists('img')) } } - return $img.'/>'; + return $img._stringify_attributes($attributes).' />'; } } // ------------------------------------------------------------------------ -/** - * Doctype - * - * Generates a page document type declaration - * - * Valid options are xhtml-11, xhtml-strict, xhtml-trans, xhtml-frame, - * html4-strict, html4-trans, and html4-frame. Values are saved in the - * doctypes config file. - * - * @param string type The doctype to be generated - * @return string - */ if ( ! function_exists('doctype')) { + /** + * Doctype + * + * Generates a page document type declaration + * + * Examples of valid options: html5, xhtml-11, xhtml-strict, xhtml-trans, + * xhtml-frame, html4-strict, html4-trans, and html4-frame. + * All values are saved in the doctypes config file. + * + * @param string type The doctype to be generated + * @return string + */ function doctype($type = 'xhtml1-strict') { global $_doctypes; @@ -275,21 +263,21 @@ if ( ! function_exists('doctype')) // ------------------------------------------------------------------------ -/** - * Link - * - * Generates link to a CSS file - * - * @param mixed stylesheet hrefs or an array - * @param string rel - * @param string type - * @param string title - * @param string media - * @param bool should index_page be added to the css path - * @return string - */ if ( ! function_exists('link_tag')) { + /** + * Link + * + * Generates link to a CSS file + * + * @param mixed stylesheet hrefs or an array + * @param string rel + * @param string type + * @param string title + * @param string media + * @param bool should index_page be added to the css path + * @return string + */ function link_tag($href = '', $rel = 'stylesheet', $type = 'text/css', $title = '', $media = '', $index_page = FALSE) { $CI =& get_instance(); @@ -333,12 +321,12 @@ if ( ! function_exists('link_tag')) $link .= 'rel="'.$rel.'" type="'.$type.'" '; - if ($media != '') + if ($media !== '') { $link .= 'media="'.$media.'" '; } - if ($title != '') + if ($title !== '') { $link .= 'title="'.$title.'" '; } @@ -350,17 +338,17 @@ if ( ! function_exists('link_tag')) // ------------------------------------------------------------------------ -/** - * Generates meta tags from an array of key/values - * - * @param array - * @param string - * @param string - * @param string - * @return string - */ if ( ! function_exists('meta')) { + /** + * Generates meta tags from an array of key/values + * + * @param array + * @param string + * @param string + * @param string + * @return string + */ function meta($name = '', $content = '', $type = 'name', $newline = "\n") { // Since we allow the data to be passes as a string, a simple array @@ -378,10 +366,10 @@ if ( ! function_exists('meta')) $str = ''; foreach ($name as $meta) { - $type = ( ! isset($meta['type']) OR $meta['type'] == 'name') ? 'name' : 'http-equiv'; - $name = ( ! isset($meta['name'])) ? '' : $meta['name']; - $content = ( ! isset($meta['content'])) ? '' : $meta['content']; - $newline = ( ! isset($meta['newline'])) ? "\n" : $meta['newline']; + $type = ( ! isset($meta['type']) OR $meta['type'] === 'name') ? 'name' : 'http-equiv'; + $name = isset($meta['name']) ? $meta['name'] : ''; + $content = isset($meta['content']) ? $meta['content'] : ''; + $newline = isset($meta['newline']) ? $meta['newline'] : "\n"; $str .= '<meta '.$type.'="'.$name.'" content="'.$content.'" />'.$newline; } @@ -392,14 +380,14 @@ if ( ! function_exists('meta')) // ------------------------------------------------------------------------ -/** - * Generates non-breaking space entities based on number supplied - * - * @param int - * @return string - */ if ( ! function_exists('nbs')) { + /** + * Generates non-breaking space entities based on number supplied + * + * @param int + * @return string + */ function nbs($num = 1) { return str_repeat(' ', $num); diff --git a/system/helpers/inflector_helper.php b/system/helpers/inflector_helper.php index feeaf57d7..59cb296b2 100644 --- a/system/helpers/inflector_helper.php +++ b/system/helpers/inflector_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Inflector Helpers @@ -37,16 +38,16 @@ // -------------------------------------------------------------------- -/** - * Singular - * - * Takes a plural word and makes it singular - * - * @param string - * @return str - */ if ( ! function_exists('singular')) { + /** + * Singular + * + * Takes a plural word and makes it singular + * + * @param string $str Input string + * @return string + */ function singular($str) { $result = strval($str); @@ -101,18 +102,17 @@ if ( ! function_exists('singular')) // -------------------------------------------------------------------- -/** - * Plural - * - * Takes a singular word and makes it plural - * - * @param string - * @param bool - * @return str - */ if ( ! function_exists('plural')) { - function plural($str, $force = FALSE) + /** + * Plural + * + * Takes a singular word and makes it plural + * + * @param string $str Input string + * @return string + */ + function plural($str) { $result = strval($str); @@ -158,16 +158,16 @@ if ( ! function_exists('plural')) // -------------------------------------------------------------------- -/** - * Camelize - * - * Takes multiple words separated by spaces or underscores and camelizes them - * - * @param string - * @return str - */ if ( ! function_exists('camelize')) { + /** + * Camelize + * + * Takes multiple words separated by spaces or underscores and camelizes them + * + * @param string $str Input string + * @return string + */ function camelize($str) { return strtolower($str[0]).substr(str_replace(' ', '', ucwords(preg_replace('/[\s_]+/', ' ', $str))), 1); @@ -176,16 +176,16 @@ if ( ! function_exists('camelize')) // -------------------------------------------------------------------- -/** - * Underscore - * - * Takes multiple words separated by spaces and underscores them - * - * @param string - * @return str - */ if ( ! function_exists('underscore')) { + /** + * Underscore + * + * Takes multiple words separated by spaces and underscores them + * + * @param string $str Input string + * @return string + */ function underscore($str) { return preg_replace('/[\s]+/', '_', strtolower(trim($str))); @@ -194,34 +194,36 @@ if ( ! function_exists('underscore')) // -------------------------------------------------------------------- -/** - * Humanize - * - * Takes multiple words separated by the separator and changes them to spaces - * - * @param string $str - * @param string $separator - * @return str - */ if ( ! function_exists('humanize')) { + /** + * Humanize + * + * Takes multiple words separated by the separator and changes them to spaces + * + * @param string $str Input string + * @param string $separator Input separator + * @return string + */ function humanize($str, $separator = '_') { return ucwords(preg_replace('/['.$separator.']+/', ' ', strtolower(trim($str)))); } } -/** - * Checks if the given word has a plural version. - * - * @param string the word to check - * @return bool if the word is countable - */ +// -------------------------------------------------------------------- + if ( ! function_exists('is_countable')) { + /** + * Checks if the given word has a plural version. + * + * @param string $word Word to check + * @return bool + */ function is_countable($word) { - return ! in_array(strtolower(strval($word)), + return ! in_array(strtolower($word), array( 'equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'meta' diff --git a/system/helpers/language_helper.php b/system/helpers/language_helper.php index b31c97107..658be6de7 100644 --- a/system/helpers/language_helper.php +++ b/system/helpers/language_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Language Helpers @@ -37,23 +38,23 @@ // ------------------------------------------------------------------------ -/** - * Lang - * - * Fetches a language variable and optionally outputs a form label - * - * @param string the language line - * @param string the id of the form element - * @return string - */ if ( ! function_exists('lang')) { + /** + * Lang + * + * Fetches a language variable and optionally outputs a form label + * + * @param string the language line + * @param string the id of the form element + * @return string + */ function lang($line, $id = '') { $CI =& get_instance(); $line = $CI->lang->line($line); - if ($id != '') + if ($id !== '') { $line = '<label for="'.$id.'">'.$line.'</label>'; } diff --git a/system/helpers/number_helper.php b/system/helpers/number_helper.php index 40da6e7bf..b93096543 100644 --- a/system/helpers/number_helper.php +++ b/system/helpers/number_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Number Helpers @@ -37,14 +38,15 @@ // ------------------------------------------------------------------------ -/** - * Formats a numbers as bytes, based on size, and adds the appropriate suffix - * - * @param mixed // will be cast as int - * @return string - */ if ( ! function_exists('byte_format')) { + /** + * Formats a numbers as bytes, based on size, and adds the appropriate suffix + * + * @param mixed will be cast as int + * @param int + * @return string + */ function byte_format($num, $precision = 1) { $CI =& get_instance(); diff --git a/system/helpers/path_helper.php b/system/helpers/path_helper.php index 6ee99072c..5a798b118 100644 --- a/system/helpers/path_helper.php +++ b/system/helpers/path_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Path Helpers @@ -32,20 +33,20 @@ * @subpackage Helpers * @category Helpers * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/helpers/xml_helper.html + * @link http://codeigniter.com/user_guide/helpers/path_helper.html */ // ------------------------------------------------------------------------ -/** - * Set Realpath - * - * @param string - * @param bool checks to see if the path exists - * @return string - */ if ( ! function_exists('set_realpath')) { + /** + * Set Realpath + * + * @param string + * @param bool checks to see if the path exists + * @return string + */ function set_realpath($path, $check_existance = FALSE) { // Security check to make sure the path is NOT a URL. No remote file inclusion! @@ -55,7 +56,7 @@ if ( ! function_exists('set_realpath')) } // Resolve the path - if (function_exists('realpath') && @realpath($path) !== FALSE) + if (@realpath($path) !== FALSE) { $path = realpath($path); } diff --git a/system/helpers/security_helper.php b/system/helpers/security_helper.php index d6f134c9f..898a49c80 100644 --- a/system/helpers/security_helper.php +++ b/system/helpers/security_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Security Helpers @@ -37,15 +38,15 @@ // ------------------------------------------------------------------------ -/** - * XSS Filtering - * - * @param string - * @param bool whether or not the content is an image file - * @return string - */ if ( ! function_exists('xss_clean')) { + /** + * XSS Filtering + * + * @param string + * @param bool whether or not the content is an image file + * @return string + */ function xss_clean($str, $is_image = FALSE) { $CI =& get_instance(); @@ -55,14 +56,14 @@ if ( ! function_exists('xss_clean')) // ------------------------------------------------------------------------ -/** - * Sanitize Filename - * - * @param string - * @return string - */ if ( ! function_exists('sanitize_filename')) { + /** + * Sanitize Filename + * + * @param string + * @return string + */ function sanitize_filename($filename) { $CI =& get_instance(); @@ -72,14 +73,17 @@ if ( ! function_exists('sanitize_filename')) // -------------------------------------------------------------------- -/** - * Hash encode a string - * - * @param string - * @return string - */ if ( ! function_exists('do_hash')) { + /** + * Hash encode a string + * + * @todo Remove in version 3.1+. + * @deprecated 3.0.0 Use PHP's native hash() instead. + * @param string $str + * @param string $type = 'sha1' + * @return string + */ function do_hash($str, $type = 'sha1') { if ( ! in_array(strtolower($type), hash_algos())) @@ -93,33 +97,34 @@ if ( ! function_exists('do_hash')) // ------------------------------------------------------------------------ -/** - * Strip Image Tags - * - * @param string - * @return string - */ if ( ! function_exists('strip_image_tags')) { + /** + * Strip Image Tags + * + * @param string + * @return string + */ function strip_image_tags($str) { - return preg_replace(array('#<img\s+.*?src\s*=\s*["\'](.+?)["\'].*?\>#', '#<img\s+.*?src\s*=\s*(.+?).*?\>#'), '\\1', $str); + $CI =& get_instance(); + return $CI->security->strip_image_tags($str); } } // ------------------------------------------------------------------------ -/** - * Convert PHP tags to entities - * - * @param string - * @return string - */ if ( ! function_exists('encode_php_tags')) { + /** + * Convert PHP tags to entities + * + * @param string + * @return string + */ function encode_php_tags($str) { - return str_replace(array('<?php', '<?PHP', '<?', '?>'), array('<?php', '<?PHP', '<?', '?>'), $str); + return str_replace(array('<?', '?>'), array('<?', '?>'), $str); } } diff --git a/system/helpers/smiley_helper.php b/system/helpers/smiley_helper.php index 8dba74e73..4b491758e 100644 --- a/system/helpers/smiley_helper.php +++ b/system/helpers/smiley_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Smiley Helpers @@ -37,125 +38,111 @@ // ------------------------------------------------------------------------ -/** - * Smiley Javascript - * - * Returns the javascript required for the smiley insertion. Optionally takes - * an array of aliases to loosely couple the smiley array to the view. - * - * @param mixed alias name or array of alias->field_id pairs - * @param string field_id if alias name was passed in - * @return array - */ if ( ! function_exists('smiley_js')) { + /** + * Smiley Javascript + * + * Returns the javascript required for the smiley insertion. Optionally takes + * an array of aliases to loosely couple the smiley array to the view. + * + * @param mixed alias name or array of alias->field_id pairs + * @param string field_id if alias name was passed in + * @param bool + * @return array + */ function smiley_js($alias = '', $field_id = '', $inline = TRUE) { static $do_setup = TRUE; - $r = ''; - if ($alias != '' && ! is_array($alias)) + if ($alias !== '' && ! is_array($alias)) { $alias = array($alias => $field_id); } if ($do_setup === TRUE) { - $do_setup = FALSE; - - $m = array(); + $do_setup = FALSE; + $m = array(); - if (is_array($alias)) + if (is_array($alias)) + { + foreach ($alias as $name => $id) { - foreach ($alias as $name => $id) - { - $m[] = '"'.$name.'" : "'.$id.'"'; - } + $m[] = '"'.$name.'" : "'.$id.'"'; } + } - $m = '{'.implode(',', $m).'}'; + $m = '{'.implode(',', $m).'}'; - $r .= <<<EOF - var smiley_map = {$m}; + $r .= <<<EOF + var smiley_map = {$m}; - function insert_smiley(smiley, field_id) { - var el = document.getElementById(field_id), newStart; + function insert_smiley(smiley, field_id) { + var el = document.getElementById(field_id), newStart; - if ( ! el && smiley_map[field_id]) { - el = document.getElementById(smiley_map[field_id]); + if ( ! el && smiley_map[field_id]) { + el = document.getElementById(smiley_map[field_id]); - if ( ! el) - return false; - } + if ( ! el) + return false; + } - el.focus(); - smiley = " " + smiley; + el.focus(); + smiley = " " + smiley; - if ('selectionStart' in el) { - newStart = el.selectionStart + smiley.length; + if ('selectionStart' in el) { + newStart = el.selectionStart + smiley.length; - el.value = el.value.substr(0, el.selectionStart) + - smiley + - el.value.substr(el.selectionEnd, el.value.length); - el.setSelectionRange(newStart, newStart); - } - else if (document.selection) { - document.selection.createRange().text = smiley; - } + el.value = el.value.substr(0, el.selectionStart) + + smiley + + el.value.substr(el.selectionEnd, el.value.length); + el.setSelectionRange(newStart, newStart); + } + else if (document.selection) { + document.selection.createRange().text = smiley; } + } EOF; } - else + elseif (is_array($alias)) { - if (is_array($alias)) + foreach ($alias as $name => $id) { - foreach ($alias as $name => $id) - { - $r .= 'smiley_map["'.$name.'"] = "'.$id.'";'."\n"; - } + $r .= 'smiley_map["'.$name.'"] = "'.$id."\";\n"; } } - if ($inline) - { - return '<script type="text/javascript" charset="utf-8">/*<![CDATA[ */'.$r.'// ]]></script>'; - } - else - { - return $r; - } + return ($inline) ? '<script type="text/javascript" charset="utf-8">/*<![CDATA[ */'.$r.'// ]]></script>' : $r; } } // ------------------------------------------------------------------------ -/** - * Get Clickable Smileys - * - * Returns an array of image tag links that can be clicked to be inserted - * into a form field. - * - * @param string the URL to the folder containing the smiley images - * @return array - */ + if ( ! function_exists('get_clickable_smileys')) { - function get_clickable_smileys($image_url, $alias = '', $smileys = NULL) + /** + * Get Clickable Smileys + * + * Returns an array of image tag links that can be clicked to be inserted + * into a form field. + * + * @param string the URL to the folder containing the smiley images + * @param array + * @return array + */ + function get_clickable_smileys($image_url, $alias = '') { // For backward compatibility with js_insert_smiley - if (is_array($alias)) { $smileys = $alias; } - - if ( ! is_array($smileys)) + elseif (FALSE === ($smileys = _get_smiley_array())) { - if (FALSE === ($smileys = _get_smiley_array())) - { - return $smileys; - } + return FALSE; } // Add a trailing slash to the file path if needed @@ -165,7 +152,7 @@ if ( ! function_exists('get_clickable_smileys')) foreach ($smileys as $key => $val) { // Keep duplicates from being used, which can happen if the - // mapping array contains multiple identical replacements. For example: + // mapping array contains multiple identical replacements. For example: // :-) and :) might be replaced with the same image so both smileys // will be in the array. if (isset($used[$smileys[$key][0]])) @@ -173,8 +160,7 @@ if ( ! function_exists('get_clickable_smileys')) continue; } - $link[] = "<a href=\"javascript:void(0);\" onclick=\"insert_smiley('".$key."', '".$alias."')\"><img src=\"".$image_url.$smileys[$key][0]."\" width=\"".$smileys[$key][1]."\" height=\"".$smileys[$key][2]."\" alt=\"".$smileys[$key][3]."\" style=\"border:0;\" /></a>"; - + $link[] = '<a href="javascript:void(0);" onclick="insert_smiley(\''.$key.'\', \''.$alias.'\')"><img src="'.$image_url.$smileys[$key][0].'" alt="'.$smileys[$key][3].'" style="width: '.$smileys[$key][1].'; height: '.$smileys[$key][2].'; border: 0;" /></a>'; $used[$smileys[$key][0]] = TRUE; } @@ -184,38 +170,31 @@ if ( ! function_exists('get_clickable_smileys')) // ------------------------------------------------------------------------ -/** - * Parse Smileys - * - * Takes a string as input and swaps any contained smileys for the actual image - * - * @param string the text to be parsed - * @param string the URL to the folder containing the smiley images - * @return string - */ if ( ! function_exists('parse_smileys')) { + /** + * Parse Smileys + * + * Takes a string as input and swaps any contained smileys for the actual image + * + * @param string the text to be parsed + * @param string the URL to the folder containing the smiley images + * @param array + * @return string + */ function parse_smileys($str = '', $image_url = '', $smileys = NULL) { - if ($image_url == '') + if ($image_url === '' OR ( ! is_array($smileys) && FALSE === ($smileys = _get_smiley_array()))) { return $str; } - if ( ! is_array($smileys)) - { - if (FALSE === ($smileys = _get_smiley_array())) - { - return $str; - } - } - // Add a trailing slash to the file path if needed - $image_url = preg_replace("/(.+?)\/*$/", "\\1/", $image_url); + $image_url = rtrim($image_url, '/').'/'; foreach ($smileys as $key => $val) { - $str = str_replace($key, "<img src=\"".$image_url.$smileys[$key][0]."\" width=\"".$smileys[$key][1]."\" height=\"".$smileys[$key][2]."\" alt=\"".$smileys[$key][3]."\" style=\"border:0;\" />", $str); + $str = str_replace($key, '<img src="'.$image_url.$smileys[$key][0].'" alt="'.$smileys[$key][3].'" style="width: '.$smileys[$key][1].'; height: '.$smileys[$key][2].'; border: 0;" />', $str); } return $str; @@ -224,15 +203,15 @@ if ( ! function_exists('parse_smileys')) // ------------------------------------------------------------------------ -/** - * Get Smiley Array - * - * Fetches the config/smiley.php file - * - * @return mixed - */ if ( ! function_exists('_get_smiley_array')) { + /** + * Get Smiley Array + * + * Fetches the config/smiley.php file + * + * @return mixed + */ function _get_smiley_array() { if (defined('ENVIRONMENT') && file_exists(APPPATH.'config/'.ENVIRONMENT.'/smileys.php')) @@ -244,40 +223,7 @@ if ( ! function_exists('_get_smiley_array')) include(APPPATH.'config/smileys.php'); } - if (isset($smileys) && is_array($smileys)) - { - return $smileys; - } - - return FALSE; - } -} - -// ------------------------------------------------------------------------ - -/** - * JS Insert Smiley - * - * Generates the javascript function needed to insert smileys into a form field - * - * DEPRECATED as of version 1.7.2, use smiley_js instead - * - * @param string form name - * @param string field name - * @return string - */ -if ( ! function_exists('js_insert_smiley')) -{ - function js_insert_smiley($form_name = '', $form_field = '') - { - return <<<EOF -<script type="text/javascript"> - function insert_smiley(smiley) - { - document.{$form_name}.{$form_field}.value += " " + smiley; - } -</script> -EOF; + return (isset($smileys) && is_array($smileys)) ? $smileys : FALSE; } } diff --git a/system/helpers/string_helper.php b/system/helpers/string_helper.php index aed35c157..9fc24559a 100644 --- a/system/helpers/string_helper.php +++ b/system/helpers/string_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter String Helpers @@ -37,22 +38,25 @@ // ------------------------------------------------------------------------ -/** - * Trim Slashes - * - * Removes any leading/trailing slashes from a string: - * - * /this/that/theother/ - * - * becomes: - * - * this/that/theother - * - * @param string - * @return string - */ if ( ! function_exists('trim_slashes')) { + /** + * Trim Slashes + * + * Removes any leading/trailing slashes from a string: + * + * /this/that/theother/ + * + * becomes: + * + * this/that/theother + * + * @todo Remove in version 3.1+. + * @deprecated 3.0.0 This is just an alias for PHP's native trim() + * + * @param string + * @return string + */ function trim_slashes($str) { return trim($str, '/'); @@ -61,28 +65,26 @@ if ( ! function_exists('trim_slashes')) // ------------------------------------------------------------------------ -/** - * Strip Slashes - * - * Removes slashes contained in a string or in an array - * - * @param mixed string or array - * @return mixed string or array - */ if ( ! function_exists('strip_slashes')) { + /** + * Strip Slashes + * + * Removes slashes contained in a string or in an array + * + * @param mixed string or array + * @return mixed string or array + */ function strip_slashes($str) { - if (is_array($str)) + if ( ! is_array($str)) { - foreach ($str as $key => $val) - { - $str[$key] = strip_slashes($val); - } + return stripslashes($str); } - else + + foreach ($str as $key => $val) { - $str = stripslashes($str); + $str[$key] = strip_slashes($val); } return $str; @@ -91,16 +93,16 @@ if ( ! function_exists('strip_slashes')) // ------------------------------------------------------------------------ -/** - * Strip Quotes - * - * Removes single and double quotes from a string - * - * @param string - * @return string - */ if ( ! function_exists('strip_quotes')) { + /** + * Strip Quotes + * + * Removes single and double quotes from a string + * + * @param string + * @return string + */ function strip_quotes($str) { return str_replace(array('"', "'"), '', $str); @@ -109,16 +111,16 @@ if ( ! function_exists('strip_quotes')) // ------------------------------------------------------------------------ -/** - * Quotes to Entities - * - * Converts single and double quotes to entities - * - * @param string - * @return string - */ if ( ! function_exists('quotes_to_entities')) { + /** + * Quotes to Entities + * + * Converts single and double quotes to entities + * + * @param string + * @return string + */ function quotes_to_entities($str) { return str_replace(array("\'","\"","'",'"'), array("'",""","'","""), $str); @@ -127,23 +129,23 @@ if ( ! function_exists('quotes_to_entities')) // ------------------------------------------------------------------------ -/** - * Reduce Double Slashes - * - * Converts double slashes in a string to a single slash, - * except those found in http:// - * - * http://www.some-site.com//index.php - * - * becomes: - * - * http://www.some-site.com/index.php - * - * @param string - * @return string - */ if ( ! function_exists('reduce_double_slashes')) { + /** + * Reduce Double Slashes + * + * Converts double slashes in a string to a single slash, + * except those found in http:// + * + * http://www.some-site.com//index.php + * + * becomes: + * + * http://www.some-site.com/index.php + * + * @param string + * @return string + */ function reduce_double_slashes($str) { return preg_replace('#(^|[^:])//+#', '\\1/', $str); @@ -152,131 +154,116 @@ if ( ! function_exists('reduce_double_slashes')) // ------------------------------------------------------------------------ -/** - * Reduce Multiples - * - * Reduces multiple instances of a particular character. Example: - * - * Fred, Bill,, Joe, Jimmy - * - * becomes: - * - * Fred, Bill, Joe, Jimmy - * - * @param string - * @param string the character you wish to reduce - * @param bool TRUE/FALSE - whether to trim the character from the beginning/end - * @return string - */ if ( ! function_exists('reduce_multiples')) { + /** + * Reduce Multiples + * + * Reduces multiple instances of a particular character. Example: + * + * Fred, Bill,, Joe, Jimmy + * + * becomes: + * + * Fred, Bill, Joe, Jimmy + * + * @param string + * @param string the character you wish to reduce + * @param bool TRUE/FALSE - whether to trim the character from the beginning/end + * @return string + */ function reduce_multiples($str, $character = ',', $trim = FALSE) { $str = preg_replace('#'.preg_quote($character, '#').'{2,}#', $character, $str); - - if ($trim === TRUE) - { - return trim($str, $character); - } - - return $str; + return ($trim === TRUE) ? trim($str, $character) : $str; } } // ------------------------------------------------------------------------ -/** - * Create a Random String - * - * Useful for generating passwords or hashes. - * - * @param string type of random string. basic, alpha, alunum, numeric, nozero, unique, md5, encrypt and sha1 - * @param int number of characters - * @return string - */ if ( ! function_exists('random_string')) { + /** + * Create a Random String + * + * Useful for generating passwords or hashes. + * + * @param string type of random string. basic, alpha, alunum, numeric, nozero, unique, md5, encrypt and sha1 + * @param int number of characters + * @return string + */ function random_string($type = 'alnum', $len = 8) { - switch($type) + switch ($type) { - case 'basic' : return mt_rand(); - break; - case 'alnum' : - case 'numeric' : - case 'nozero' : - case 'alpha' : - - switch ($type) - { - case 'alpha' : $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - break; - case 'alnum' : $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - break; - case 'numeric' : $pool = '0123456789'; - break; - case 'nozero' : $pool = '123456789'; - break; - } - - $str = substr(str_shuffle(str_repeat($pool, ceil($len/strlen($pool)))),0,$len); - - return $str; - break; - case 'unique' : - case 'md5' : - - return md5(uniqid(mt_rand())); - break; - case 'encrypt' : - case 'sha1' : - - $CI =& get_instance(); - $CI->load->helper('security'); - - return do_hash(uniqid(mt_rand(), TRUE), 'sha1'); - break; + case 'basic': + return mt_rand(); + case 'alnum': + case 'numeric': + case 'nozero': + case 'alpha': + switch ($type) + { + case 'alpha': + $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + break; + case 'alnum': + $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + break; + case 'numeric': + $pool = '0123456789'; + break; + case 'nozero': + $pool = '123456789'; + break; + } + return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len); + case 'unique': // todo: remove in 3.1+ + case 'md5': + return md5(uniqid(mt_rand())); + case 'encrypt': // todo: remove in 3.1+ + case 'sha1': + return sha1(uniqid(mt_rand(), TRUE)); } } } // ------------------------------------------------------------------------ -/** - * Add's _1 to a string or increment the ending number to allow _2, _3, etc - * - * @param string required - * @param string What should the duplicate number be appended with - * @param string Which number should be used for the first dupe increment - * @return string - */ if ( ! function_exists('increment_string')) { + /** + * Add's _1 to a string or increment the ending number to allow _2, _3, etc + * + * @param string required + * @param string What should the duplicate number be appended with + * @param string Which number should be used for the first dupe increment + * @return string + */ function increment_string($str, $separator = '_', $first = 1) { preg_match('/(.+)'.$separator.'([0-9]+)$/', $str, $match); - return isset($match[2]) ? $match[1].$separator.($match[2] + 1) : $str.$separator.$first; } } // ------------------------------------------------------------------------ -/** - * Alternator - * - * Allows strings to be alternated. See docs... - * - * @param string (as many parameters as needed) - * @return string - */ if ( ! function_exists('alternator')) { - function alternator() + /** + * Alternator + * + * Allows strings to be alternated. See docs... + * + * @param string (as many parameters as needed) + * @return string + */ + function alternator($args) { static $i; - if (func_num_args() == 0) + if (func_num_args() === 0) { $i = 0; return ''; @@ -288,15 +275,18 @@ if ( ! function_exists('alternator')) // ------------------------------------------------------------------------ -/** - * Repeater function - * - * @param string - * @param int number of repeats - * @return string - */ if ( ! function_exists('repeater')) { + /** + * Repeater function + * + * @todo Remove in version 3.1+. + * @deprecated 3.0.0 This is just an alias for PHP's native str_repeat() + * + * @param string $data String to repeat + * @param int $num Number of repeats + * @return string + */ function repeater($data, $num = 1) { return ($num > 0) ? str_repeat($data, $num) : ''; diff --git a/system/helpers/text_helper.php b/system/helpers/text_helper.php index cc501c334..cce659231 100644 --- a/system/helpers/text_helper.php +++ b/system/helpers/text_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Text Helpers @@ -37,28 +38,28 @@ // ------------------------------------------------------------------------ -/** - * Word Limiter - * - * Limits a string to X number of words. - * - * @param string - * @param int - * @param string the end character. Usually an ellipsis - * @return string - */ if ( ! function_exists('word_limiter')) { + /** + * Word Limiter + * + * Limits a string to X number of words. + * + * @param string + * @param int + * @param string the end character. Usually an ellipsis + * @return string + */ function word_limiter($str, $limit = 100, $end_char = '…') { - if (trim($str) == '') + if (trim($str) === '') { return $str; } preg_match('/^\s*+(?:\S++\s*+){1,'.(int) $limit.'}/', $str, $matches); - if (strlen($str) == strlen($matches[0])) + if (strlen($str) === strlen($matches[0])) { $end_char = ''; } @@ -69,19 +70,19 @@ if ( ! function_exists('word_limiter')) // ------------------------------------------------------------------------ -/** - * Character Limiter - * - * Limits the string based on the character count. Preserves complete words - * so the character count may not be exactly as specified. - * - * @param string - * @param int - * @param string the end character. Usually an ellipsis - * @return string - */ if ( ! function_exists('character_limiter')) { + /** + * Character Limiter + * + * Limits the string based on the character count. Preserves complete words + * so the character count may not be exactly as specified. + * + * @param string + * @param int + * @param string the end character. Usually an ellipsis + * @return string + */ function character_limiter($str, $n = 500, $end_char = '…') { if (strlen($str) < $n) @@ -89,14 +90,15 @@ if ( ! function_exists('character_limiter')) return $str; } - $str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str)); + // a bit complicated, but faster than preg_replace with \s+ + $str = preg_replace('/ {2,}/', ' ', str_replace(array("\r", "\n", "\t", "\x0B", "\x0C"), ' ', $str)); if (strlen($str) <= $n) { return $str; } - $out = ""; + $out = ''; foreach (explode(' ', trim($str)) as $val) { $out .= $val.' '; @@ -104,7 +106,7 @@ if ( ! function_exists('character_limiter')) if (strlen($out) >= $n) { $out = trim($out); - return (strlen($out) == strlen($str)) ? $out : $out.$end_char; + return (strlen($out) === strlen($str)) ? $out : $out.$end_char; } } } @@ -112,23 +114,20 @@ if ( ! function_exists('character_limiter')) // ------------------------------------------------------------------------ -/** - * High ASCII to Entities - * - * Converts High ascii text and MS Word special characters to character entities - * - * @param string - * @return string - */ if ( ! function_exists('ascii_to_entities')) { + /** + * High ASCII to Entities + * + * Converts high ASCII text and MS Word special characters to character entities + * + * @param string $str + * @return string + */ function ascii_to_entities($str) { - $count = 1; - $out = ''; - $temp = array(); - - for ($i = 0, $s = strlen($str); $i < $s; $i++) + $out = ''; + for ($i = 0, $s = strlen($str), $count = 1, $temp = array(); $i < $s; $i++) { $ordinal = ord($str[$i]); @@ -138,7 +137,7 @@ if ( ! function_exists('ascii_to_entities')) If the $temp array has a value but we have moved on, then it seems only fair that we output that entity and restart $temp before continuing. -Paul */ - if (count($temp) == 1) + if (count($temp) === 1) { $out .= '&#'.array_shift($temp).';'; $count = 1; @@ -148,16 +147,18 @@ if ( ! function_exists('ascii_to_entities')) } else { - if (count($temp) == 0) + if (count($temp) === 0) { $count = ($ordinal < 224) ? 2 : 3; } $temp[] = $ordinal; - if (count($temp) == $count) + if (count($temp) === $count) { - $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64); + $number = ($count === 3) + ? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64) + : (($temp[0] % 32) * 64) + ($temp[1] % 64); $out .= '&#'.$number.';'; $count = 1; @@ -172,25 +173,24 @@ if ( ! function_exists('ascii_to_entities')) // ------------------------------------------------------------------------ -/** - * Entities to ASCII - * - * Converts character entities back to ASCII - * - * @param string - * @param bool - * @return string - */ if ( ! function_exists('entities_to_ascii')) { + /** + * Entities to ASCII + * + * Converts character entities back to ASCII + * + * @param string + * @param bool + * @return string + */ function entities_to_ascii($str, $all = TRUE) { if (preg_match_all('/\&#(\d+)\;/', $str, $matches)) { - for ($i = 0, $s = count($matches['0']); $i < $s; $i++) + for ($i = 0, $s = count($matches[0]); $i < $s; $i++) { - $digits = $matches['1'][$i]; - + $digits = $matches[1][$i]; $out = ''; if ($digits < 128) @@ -200,25 +200,24 @@ if ( ! function_exists('entities_to_ascii')) } elseif ($digits < 2048) { - $out .= chr(192 + (($digits - ($digits % 64)) / 64)); - $out .= chr(128 + ($digits % 64)); + $out .= chr(192 + (($digits - ($digits % 64)) / 64)).chr(128 + ($digits % 64)); } else { - $out .= chr(224 + (($digits - ($digits % 4096)) / 4096)); - $out .= chr(128 + ((($digits % 4096) - ($digits % 64)) / 64)); - $out .= chr(128 + ($digits % 64)); + $out .= chr(224 + (($digits - ($digits % 4096)) / 4096)) + .chr(128 + ((($digits % 4096) - ($digits % 64)) / 64)) + .chr(128 + ($digits % 64)); } - $str = str_replace($matches['0'][$i], $out, $str); + $str = str_replace($matches[0][$i], $out, $str); } } if ($all) { - $str = str_replace(array("&", "<", ">", """, "'", "-"), - array("&","<",">","\"", "'", "-"), - $str); + return str_replace(array('&', '<', '>', '"', ''', '-'), + array('&', '<', '>', '"', "'", '-'), + $str); } return $str; @@ -227,20 +226,20 @@ if ( ! function_exists('entities_to_ascii')) // ------------------------------------------------------------------------ -/** - * Word Censoring Function - * - * Supply a string and an array of disallowed words and any - * matched words will be converted to #### or to the replacement - * word you've submitted. - * - * @param string the text string - * @param string the array of censoered words - * @param string the optional replacement value - * @return string - */ if ( ! function_exists('word_censor')) { + /** + * Word Censoring Function + * + * Supply a string and an array of disallowed words and any + * matched words will be converted to #### or to the replacement + * word you've submitted. + * + * @param string the text string + * @param string the array of censoered words + * @param string the optional replacement value + * @return string + */ function word_censor($str, $censored, $replacement = '') { if ( ! is_array($censored)) @@ -258,7 +257,7 @@ if ( ! function_exists('word_censor')) foreach ($censored as $badword) { - if ($replacement != '') + if ($replacement !== '') { $str = preg_replace("/({$delim})(".str_replace('\*', '\w*?', preg_quote($badword, '/')).")({$delim})/i", "\\1{$replacement}\\3", $str); } @@ -274,39 +273,45 @@ if ( ! function_exists('word_censor')) // ------------------------------------------------------------------------ -/** - * Code Highlighter - * - * Colorizes code strings - * - * @param string the text string - * @return string - */ if ( ! function_exists('highlight_code')) { + /** + * Code Highlighter + * + * Colorizes code strings + * + * @param string the text string + * @return string + */ function highlight_code($str) { - // The highlight string function encodes and highlights - // brackets so we need them to start raw - $str = str_replace(array('<', '>'), array('<', '>'), $str); - - // Replace any existing PHP tags to temporary markers so they don't accidentally - // break the string out of PHP, and thus, thwart the highlighting. - $str = str_replace(array('<?', '?>', '<%', '%>', '\\', '</script>'), - array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), + /* The highlight string function encodes and highlights + * brackets so we need them to start raw. + * + * Also replace any existing PHP tags to temporary markers + * so they don't accidentally break the string out of PHP, + * and thus, thwart the highlighting. + */ + $str = str_replace(array('<', '>', '<?', '?>', '<%', '%>', '\\', '</script>'), + array('<', '>', 'phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), $str); // The highlight_string function requires that the text be surrounded // by PHP tags, which we will remove later - $str = '<?php '.$str.' ?>'; // <? - - // All the magic happens here, baby! - $str = highlight_string($str, TRUE); + $str = highlight_string('<?php '.$str.' ?>', TRUE); // Remove our artificially added PHP, and the syntax highlighting that came with it - $str = preg_replace('/<span style="color: #([A-Z0-9]+)"><\?php( | )/i', '<span style="color: #$1">', $str); - $str = preg_replace('/(<span style="color: #[A-Z0-9]+">.*?)\?><\/span>\n<\/span>\n<\/code>/is', "$1</span>\n</span>\n</code>", $str); - $str = preg_replace('/<span style="color: #[A-Z0-9]+"\><\/span>/i', '', $str); + $str = preg_replace(array( + '/<span style="color: #([A-Z0-9]+)"><\?php( | )/i', + '/(<span style="color: #[A-Z0-9]+">.*?)\?><\/span>\n<\/span>\n<\/code>/is', + '/<span style="color: #[A-Z0-9]+"\><\/span>/i' + ), + array( + '<span style="color: #$1">', + "$1</span>\n</span>\n</code>", + '' + ), + $str); // Replace our markers back to PHP tags. return str_replace(array('phptagopen', 'phptagclose', 'asptagopen', 'asptagclose', 'backslashtmp', 'scriptclose'), @@ -317,29 +322,29 @@ if ( ! function_exists('highlight_code')) // ------------------------------------------------------------------------ -/** - * Phrase Highlighter - * - * Highlights a phrase within a text string - * - * @param string the text string - * @param string the phrase you'd like to highlight - * @param string the openging tag to precede the phrase with - * @param string the closing tag to end the phrase with - * @return string - */ if ( ! function_exists('highlight_phrase')) { + /** + * Phrase Highlighter + * + * Highlights a phrase within a text string + * + * @param string the text string + * @param string the phrase you'd like to highlight + * @param string the openging tag to precede the phrase with + * @param string the closing tag to end the phrase with + * @return string + */ function highlight_phrase($str, $phrase, $tag_open = '<strong>', $tag_close = '</strong>') { - if ($str == '') + if ($str === '') { return ''; } - if ($phrase != '') + if ($phrase !== '') { - return preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open."\\1".$tag_close, $str); + return preg_replace('/('.preg_quote($phrase, '/').')/i', $tag_open.'\\1'.$tag_close, $str); } return $str; @@ -348,28 +353,33 @@ if ( ! function_exists('highlight_phrase')) // ------------------------------------------------------------------------ -/** - * Convert Accented Foreign Characters to ASCII - * - * @param string the text string - * @return string - */ if ( ! function_exists('convert_accented_characters')) { + /** + * Convert Accented Foreign Characters to ASCII + * + * @param string the text string + * @return string + */ function convert_accented_characters($str) { - if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php')) - { - include(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php'); - } - elseif (is_file(APPPATH.'config/foreign_chars.php')) - { - include(APPPATH.'config/foreign_chars.php'); - } + global $foreign_characters; - if ( ! isset($foreign_characters)) + if ( ! isset($foreign_characters) OR ! is_array($foreign_characters)) { - return $str; + if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php')) + { + include(APPPATH.'config/'.ENVIRONMENT.'/foreign_chars.php'); + } + elseif (is_file(APPPATH.'config/foreign_chars.php')) + { + include(APPPATH.'config/foreign_chars.php'); + } + + if ( ! isset($foreign_characters) OR ! is_array($foreign_characters)) + { + return $str; + } } return preg_replace(array_keys($foreign_characters), array_values($foreign_characters), $str); @@ -378,27 +388,29 @@ if ( ! function_exists('convert_accented_characters')) // ------------------------------------------------------------------------ -/** - * Word Wrap - * - * Wraps text at the specified character. Maintains the integrity of words. - * Anything placed between {unwrap}{/unwrap} will not be word wrapped, nor - * will URLs. - * - * @param string the text string - * @param int the number of characters to wrap at - * @return string - */ if ( ! function_exists('word_wrap')) { - function word_wrap($str, $charlim = '76') + /** + * Word Wrap + * + * Wraps text at the specified character. Maintains the integrity of words. + * Anything placed between {unwrap}{/unwrap} will not be word wrapped, nor + * will URLs. + * + * @param string $str the text string + * @param int $charlim = 76 the number of characters to wrap at + * @return string + */ + function word_wrap($str, $charlim = 76) { - // Se the character limit + // Set the character limit if ( ! is_numeric($charlim)) + { $charlim = 76; + } // Reduce multiple spaces - $str = preg_replace("| +|", " ", $str); + $str = preg_replace('| +|', ' ', $str); // Standardize newlines if (strpos($str, "\r") !== FALSE) @@ -409,22 +421,22 @@ if ( ! function_exists('word_wrap')) // If the current word is surrounded by {unwrap} tags we'll // strip the entire chunk and replace it with a marker. $unwrap = array(); - if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches)) + if (preg_match_all('|(\{unwrap\}.+?\{/unwrap\})|s', $str, $matches)) { - for ($i = 0; $i < count($matches['0']); $i++) + for ($i = 0, $c = count($matches[0]); $i < $c; $i++) { - $unwrap[] = $matches['1'][$i]; - $str = str_replace($matches['1'][$i], "{{unwrapped".$i."}}", $str); + $unwrap[] = $matches[1][$i]; + $str = str_replace($matches[1][$i], '{{unwrapped'.$i.'}}', $str); } } // Use PHP's native function to do the initial wordwrap. // We set the cut flag to FALSE so that any individual words that are - // too long get left alone. In the next step we'll deal with them. + // too long get left alone. In the next step we'll deal with them. $str = wordwrap($str, $charlim, "\n", FALSE); // Split the string into individual lines of text and cycle through them - $output = ""; + $output = ''; foreach (explode("\n", $str) as $line) { // Is the line within the allowed character count? @@ -439,28 +451,26 @@ if ( ! function_exists('word_wrap')) while ((strlen($line)) > $charlim) { // If the over-length word is a URL we won't wrap it - if (preg_match("!\[url.+\]|://|wwww.!", $line)) + if (preg_match('!\[url.+\]|://|wwww.!', $line)) { break; } // Trim the word down - $temp .= substr($line, 0, $charlim-1); - $line = substr($line, $charlim-1); + $temp .= substr($line, 0, $charlim - 1); + $line = substr($line, $charlim - 1); } // If $temp contains data it means we had to split up an over-length // word into smaller chunks so we'll add it back to our current line - if ($temp != '') + if ($temp !== '') { - $output .= $temp."\n".$line; + $output .= $temp."\n".$line."\n"; } else { - $output .= $line; + $output .= $line."\n"; } - - $output .= "\n"; } // Put our markers back @@ -468,32 +478,30 @@ if ( ! function_exists('word_wrap')) { foreach ($unwrap as $key => $val) { - $output = str_replace("{{unwrapped".$key."}}", $val, $output); + $output = str_replace('{{unwrapped'.$key.'}}', $val, $output); } } - // Remove the unwrap tags - $output = str_replace(array('{unwrap}', '{/unwrap}'), '', $output); - - return $output; + // Remove the unwrap tags and return + return str_replace(array('{unwrap}', '{/unwrap}'), '', $output); } } // ------------------------------------------------------------------------ -/** - * Ellipsize String - * - * This function will strip tags from a string, split it at its max_length and ellipsize - * - * @param string string to ellipsize - * @param int max length of string - * @param mixed int (1|0) or float, .5, .2, etc for position to split - * @param string ellipsis ; Default '...' - * @return string ellipsized string - */ if ( ! function_exists('ellipsize')) { + /** + * Ellipsize String + * + * This function will strip tags from a string, split it at its max_length and ellipsize + * + * @param string string to ellipsize + * @param int max length of string + * @param mixed int (1|0) or float, .5, .2, etc for position to split + * @param string ellipsis ; Default '...' + * @return string ellipsized string + */ function ellipsize($str, $max_length, $position = 1, $ellipsis = '…') { // Strip tags @@ -506,7 +514,6 @@ if ( ! function_exists('ellipsize')) } $beg = substr($str, 0, floor($max_length * $position)); - $position = ($position > 1) ? 1 : $position; if ($position === 1) diff --git a/system/helpers/typography_helper.php b/system/helpers/typography_helper.php index 7a3db5d6b..48f1f1147 100644 --- a/system/helpers/typography_helper.php +++ b/system/helpers/typography_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Typography Helpers @@ -37,14 +38,14 @@ // ------------------------------------------------------------------------ -/** - * Convert newlines to HTML line breaks except within PRE tags - * - * @param string - * @return string - */ if ( ! function_exists('nl2br_except_pre')) { + /** + * Convert newlines to HTML line breaks except within PRE tags + * + * @param string + * @return string + */ function nl2br_except_pre($str) { $CI =& get_instance(); @@ -55,38 +56,36 @@ if ( ! function_exists('nl2br_except_pre')) // ------------------------------------------------------------------------ -/** - * Auto Typography Wrapper Function - * - * @param string - * @param bool whether to allow javascript event handlers - * @param bool whether to reduce multiple instances of double newlines to two - * @return string - */ if ( ! function_exists('auto_typography')) { - function auto_typography($str, $strip_js_event_handlers = TRUE, $reduce_linebreaks = FALSE) + /** + * Auto Typography Wrapper Function + * + * @param string $str + * @param bool $reduce_linebreaks = FALSE whether to reduce multiple instances of double newlines to two + * @return string + */ + function auto_typography($str, $reduce_linebreaks = FALSE) { $CI =& get_instance(); $CI->load->library('typography'); - return $CI->typography->auto_typography($str, $strip_js_event_handlers, $reduce_linebreaks); + return $CI->typography->auto_typography($str, $reduce_linebreaks); } } - // -------------------------------------------------------------------- -/** - * HTML Entities Decode - * - * This function is a replacement for html_entity_decode() - * - * @param string - * @param string - * @return string - */ if ( ! function_exists('entity_decode')) { + /** + * HTML Entities Decode + * + * This function is a replacement for html_entity_decode() + * + * @param string + * @param string + * @return string + */ function entity_decode($str, $charset = NULL) { global $SEC; diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php index 5576c2748..0aa358a0b 100644 --- a/system/helpers/url_helper.php +++ b/system/helpers/url_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter URL Helpers @@ -37,17 +38,17 @@ // ------------------------------------------------------------------------ -/** - * Site URL - * - * Create a local URL based on your basepath. Segments can be passed via the - * first parameter either as a string or an array. - * - * @param string - * @return string - */ if ( ! function_exists('site_url')) { + /** + * Site URL + * + * Create a local URL based on your basepath. Segments can be passed via the + * first parameter either as a string or an array. + * + * @param string + * @return string + */ function site_url($uri = '') { $CI =& get_instance(); @@ -57,18 +58,18 @@ if ( ! function_exists('site_url')) // ------------------------------------------------------------------------ -/** - * Base URL - * - * Create a local URL based on your basepath. - * Segments can be passed in as a string or an array, same as site_url - * or a URL to a file can be passed in, e.g. to an image file. - * - * @param string - * @return string - */ if ( ! function_exists('base_url')) { + /** + * Base URL + * + * Create a local URL based on your basepath. + * Segments can be passed in as a string or an array, same as site_url + * or a URL to a file can be passed in, e.g. to an image file. + * + * @param string + * @return string + */ function base_url($uri = '') { $CI =& get_instance(); @@ -78,16 +79,16 @@ if ( ! function_exists('base_url')) // ------------------------------------------------------------------------ -/** - * Current URL - * - * Returns the full URL (including segments) of the page where this - * function is placed - * - * @return string - */ if ( ! function_exists('current_url')) { + /** + * Current URL + * + * Returns the full URL (including segments) of the page where this + * function is placed + * + * @return string + */ function current_url() { $CI =& get_instance(); @@ -96,15 +97,16 @@ if ( ! function_exists('current_url')) } // ------------------------------------------------------------------------ -/** - * URL String - * - * Returns the URI segments. - * - * @return string - */ + if ( ! function_exists('uri_string')) { + /** + * URL String + * + * Returns the URI segments. + * + * @return string + */ function uri_string() { $CI =& get_instance(); @@ -114,15 +116,15 @@ if ( ! function_exists('uri_string')) // ------------------------------------------------------------------------ -/** - * Index page - * - * Returns the "index_page" from your config file - * - * @return string - */ if ( ! function_exists('index_page')) { + /** + * Index page + * + * Returns the "index_page" from your config file + * + * @return string + */ function index_page() { $CI =& get_instance(); @@ -132,18 +134,18 @@ if ( ! function_exists('index_page')) // ------------------------------------------------------------------------ -/** - * Anchor Link - * - * Creates an anchor based on the local URL. - * - * @param string the URL - * @param string the link title - * @param mixed any attributes - * @return string - */ if ( ! function_exists('anchor')) { + /** + * Anchor Link + * + * Creates an anchor based on the local URL. + * + * @param string the URL + * @param string the link title + * @param mixed any attributes + * @return string + */ function anchor($uri = '', $title = '', $attributes = '') { $title = (string) $title; @@ -157,14 +159,14 @@ if ( ! function_exists('anchor')) $site_url = site_url($uri); } - if ($title == '') + if ($title === '') { $title = $site_url; } - if ($attributes != '') + if ($attributes !== '') { - $attributes = _parse_attributes($attributes); + $attributes = _stringify_attributes($attributes); } return '<a href="'.$site_url.'"'.$attributes.'>'.$title.'</a>'; @@ -173,98 +175,105 @@ if ( ! function_exists('anchor')) // ------------------------------------------------------------------------ -/** - * Anchor Link - Pop-up version - * - * Creates an anchor based on the local URL. The link - * opens a new window based on the attributes specified. - * - * @param string the URL - * @param string the link title - * @param mixed any attributes - * @return string - */ if ( ! function_exists('anchor_popup')) { + /** + * Anchor Link - Pop-up version + * + * Creates an anchor based on the local URL. The link + * opens a new window based on the attributes specified. + * + * @param string the URL + * @param string the link title + * @param mixed any attributes + * @return string + */ function anchor_popup($uri = '', $title = '', $attributes = FALSE) { $title = (string) $title; $site_url = preg_match('!^\w+://! i', $uri) ? $uri : site_url($uri); - if ($title == '') + if ($title === '') { $title = $site_url; } if ($attributes === FALSE) { - return "<a href='javascript:void(0);' onclick=\"window.open('".$site_url."', '_blank');\">".$title.'</a>'; + return '<a href="'.$site_url.'" onclick="window.open(\''.$site_url."', '_blank'); return false;\">".$title.'</a>'; } if ( ! is_array($attributes)) { - $attributes = array(); + $attributes = array($attributes); + + // Ref: http://www.w3schools.com/jsref/met_win_open.asp + $window_name = '_blank'; + } + elseif ( ! empty($attributes['window_name'])) + { + $window_name = $attributes['window_name']; + unset($attributes['window_name']); } - foreach (array('width' => '800', 'height' => '600', 'scrollbars' => 'yes', 'status' => 'yes', 'resizable' => 'yes', 'screenx' => '0', 'screeny' => '0', ) as $key => $val) + foreach (array('width' => '800', 'height' => '600', 'scrollbars' => 'yes', 'status' => 'yes', 'resizable' => 'yes', 'screenx' => '0', 'screeny' => '0') as $key => $val) { $atts[$key] = isset($attributes[$key]) ? $attributes[$key] : $val; unset($attributes[$key]); } - if ($attributes != '') - { - $attributes = _parse_attributes($attributes); - } + $attributes = _stringify_attributes($attributes); - return "<a href='javascript:void(0);' onclick=\"window.open('".$site_url."', '_blank', '"._parse_attributes($atts, TRUE)."');\"".$attributes.'>'.$title.'</a>'; + return '<a href="'.$site_url + .'" onclick="window.open(\''.$site_url."', '".$window_name."', '"._stringify_attributes($atts, TRUE)."'); return false;\"" + .$attributes.'>'.$title.'</a>'; } } // ------------------------------------------------------------------------ -/** - * Mailto Link - * - * @param string the email address - * @param string the link title - * @param mixed any attributes - * @return string - */ if ( ! function_exists('mailto')) { + /** + * Mailto Link + * + * @param string the email address + * @param string the link title + * @param mixed any attributes + * @return string + */ function mailto($email, $title = '', $attributes = '') { $title = (string) $title; - if ($title == '') + if ($title === '') { $title = $email; } - return '<a href="mailto:'.$email.'"'._parse_attributes($attributes).'>'.$title.'</a>'; + return '<a href="mailto:'.$email.'"'._stringify_attributes($attributes).'>'.$title.'</a>'; } } // ------------------------------------------------------------------------ -/** - * Encoded Mailto Link - * - * Create a spam-protected mailto link written in Javascript - * - * @param string the email address - * @param string the link title - * @param mixed any attributes - * @return string - */ if ( ! function_exists('safe_mailto')) { + /** + * Encoded Mailto Link + * + * Create a spam-protected mailto link written in Javascript + * + * @param string the email address + * @param string the link title + * @param mixed any attributes + * @return string + */ function safe_mailto($email, $title = '', $attributes = '') { $title = (string) $title; - if ($title == '') + if ($title === '') { $title = $email; } @@ -278,7 +287,7 @@ if ( ! function_exists('safe_mailto')) $x[] = '"'; - if ($attributes != '') + if ($attributes !== '') { if (is_array($attributes)) { @@ -344,7 +353,7 @@ if ( ! function_exists('safe_mailto')) for ($i = 0, $c = count($x); $i < $c; $i++) { ?>l[<?php echo $i; ?>]='<?php echo $x[$i]; ?>';<?php } ?> for (var i = l.length-1; i >= 0; i=i-1){ - if (l[i].substring(0, 1) == '|') document.write("&#"+unescape(l[i].substring(1))+";"); + if (l[i].substring(0, 1) === '|') document.write("&#"+unescape(l[i].substring(1))+";"); else document.write(unescape(l[i]));} //]]> </script><?php @@ -357,21 +366,21 @@ if ( ! function_exists('safe_mailto')) // ------------------------------------------------------------------------ -/** - * Auto-linker - * - * Automatically links URL and Email addresses. - * Note: There's a bit of extra code here to deal with - * URLs or emails that end in a period. We'll strip these - * off and add them after the link. - * - * @param string the string - * @param string the type: email, url, or both - * @param bool whether to create pop-up links - * @return string - */ if ( ! function_exists('auto_link')) { + /** + * Auto-linker + * + * Automatically links URL and Email addresses. + * Note: There's a bit of extra code here to deal with + * URLs or emails that end in a period. We'll strip these + * off and add them after the link. + * + * @param string the string + * @param string the type: email, url, or both + * @param bool whether to create pop-up links + * @return string + */ function auto_link($str, $type = 'both', $popup = FALSE) { if ($type !== 'email' && preg_match_all('#(^|\s|\(|\b)((http(s?)://)|(www\.))(\w+[^\s\)\<]+)#i', $str, $matches)) @@ -380,40 +389,43 @@ if ( ! function_exists('auto_link')) for ($i = 0, $c = count($matches[0]); $i < $c; $i++) { - if (preg_match('|\.$|', $matches[6][$i])) + if (preg_match('/(\.|\,)$/i', $matches[6][$i], $m)) { - $period = '.'; + $punct = $m[1]; $matches[6][$i] = substr($matches[6][$i], 0, -1); } else { - $period = ''; + $punct = ''; } $str = str_replace($matches[0][$i], $matches[1][$i].'<a href="http'.$matches[4][$i].'://' .$matches[5][$i].$matches[6][$i].'"'.$pop.'>http' .$matches[4][$i].'://'.$matches[5][$i] - .$matches[6][$i].'</a>'.$period, + .$matches[6][$i].'</a>'.$punct, $str); } } - if ($type !== 'url' && preg_match_all('/([a-zA-Z0-9_\.\-\+]+)@([a-zA-Z0-9\-]+)\.([a-zA-Z0-9\-\.]*)/i', $str, $matches)) + if ($type !== 'url' && preg_match_all('/([a-zA-Z0-9_\.\-\+]+)@([a-zA-Z0-9\-]+)\.([a-zA-Z0-9\-\.]+)/i', $str, $matches)) { for ($i = 0, $c = count($matches); $i < $c; $i++) { - if (preg_match('|\.$|', $matches[3][$i])) + if (preg_match('/(\.|\,)$/i', $matches[3][$i], $m)) { - $period = '.'; + $punct = $m[1]; $matches[3][$i] = substr($matches[3][$i], 0, -1); } else { - $period = ''; + $punct = ''; } - $str = str_replace($matches[0][$i], safe_mailto($matches[1][$i].'@'.$matches[2][$i].'.'.$matches[3][$i]).$period, $str); + if (filter_var(($m = $matches[1][$i].'@'.$matches[2][$i].'.'.$matches[3][$i]), FILTER_VALIDATE_EMAIL) !== FALSE) + { + $str = str_replace($matches[0][$i], safe_mailto($m).$punct, $str); + } } } @@ -423,19 +435,19 @@ if ( ! function_exists('auto_link')) // ------------------------------------------------------------------------ -/** - * Prep URL - * - * Simply adds the http:// part if no scheme is included - * - * @param string the URL - * @return string - */ if ( ! function_exists('prep_url')) { + /** + * Prep URL + * + * Simply adds the http:// part if no scheme is included + * + * @param string the URL + * @return string + */ function prep_url($str = '') { - if ($str === 'http://' OR $str == '') + if ($str === 'http://' OR $str === '') { return ''; } @@ -453,20 +465,22 @@ if ( ! function_exists('prep_url')) // ------------------------------------------------------------------------ -/** - * Create URL Title - * - * Takes a "title" string as input and creates a - * human-friendly URL string with a "separator" string - * as the word separator. - * - * @param string the string - * @param string the separator - * @param bool - * @return string - */ if ( ! function_exists('url_title')) { + /** + * Create URL Title + * + * Takes a "title" string as input and creates a + * human-friendly URL string with a "separator" string + * as the word separator. + * + * @todo Remove old 'dash' and 'underscore' usage in 3.1+. + * @param string $str Input string + * @param string $separator Word separator + * (usually '-' or '_') + * @param bool $lowercase Wether to transform the output string to lowercase + * @return string + */ function url_title($str, $separator = '-', $lowercase = FALSE) { if ($separator === 'dash') @@ -478,7 +492,7 @@ if ( ! function_exists('url_title')) $separator = '_'; } - $q_separator = preg_quote($separator); + $q_separator = preg_quote($separator, '#'); $trans = array( '&.+?;' => '', @@ -504,20 +518,22 @@ if ( ! function_exists('url_title')) // ------------------------------------------------------------------------ -/** - * Header Redirect - * - * Header redirect in two flavors - * For very fine grained control over headers, you could use the Output - * Library's set_header() function. - * - * @param string the URL - * @param string the method: location or refresh - * @return string - */ if ( ! function_exists('redirect')) { - function redirect($uri = '', $method = 'auto', $http_response_code = 302) + /** + * Header Redirect + * + * Header redirect in two flavors + * For very fine grained control over headers, you could use the Output + * Library's set_header() function. + * + * @param string $uri URL + * @param string $method Redirect method + * 'auto', 'location' or 'refresh' + * @param int $code HTTP Response status code + * @return void + */ + function redirect($uri = '', $method = 'auto', $code = NULL) { if ( ! preg_match('#^https?://#i', $uri)) { @@ -525,65 +541,31 @@ if ( ! function_exists('redirect')) } // IIS environment likely? Use 'refresh' for better compatibility - if (DIRECTORY_SEPARATOR !== '/' && $method === 'auto') + if ($method === 'auto' && isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== FALSE) { $method = 'refresh'; } + elseif ($method !== 'refresh' && (empty($code) OR ! is_numeric($code))) + { + // Reference: http://en.wikipedia.org/wiki/Post/Redirect/Get + $code = (isset($_SERVER['REQUEST_METHOD'], $_SERVER['SERVER_PROTOCOL']) + && $_SERVER['REQUEST_METHOD'] === 'POST' + && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.1') + ? 303 : 302; + } - switch($method) + switch ($method) { case 'refresh': header('Refresh:0;url='.$uri); break; default: - header('Location: '.$uri, TRUE, $http_response_code); + header('Location: '.$uri, TRUE, $code); break; } exit; } } -// ------------------------------------------------------------------------ - -/** - * Parse out the attributes - * - * Some of the functions use this - * - * @param array - * @param bool - * @return string - */ -if ( ! function_exists('_parse_attributes')) -{ - function _parse_attributes($attributes, $javascript = FALSE) - { - if (is_string($attributes)) - { - return ($attributes != '') ? ' '.$attributes : ''; - } - - $att = ''; - foreach ($attributes as $key => $val) - { - if ($javascript == TRUE) - { - $att .= $key.'='.$val.','; - } - else - { - $att .= ' '.$key.'="'.$val.'"'; - } - } - - if ($javascript == TRUE && $att != '') - { - return substr($att, 0, -1); - } - - return $att; - } -} - /* End of file url_helper.php */ /* Location: ./system/helpers/url_helper.php */
\ No newline at end of file diff --git a/system/helpers/xml_helper.php b/system/helpers/xml_helper.php index 67fd34b97..c3dfdcddb 100644 --- a/system/helpers/xml_helper.php +++ b/system/helpers/xml_helper.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter XML Helpers @@ -37,15 +38,15 @@ // ------------------------------------------------------------------------ -/** - * Convert Reserved XML characters to Entities - * - * @param string - * @param bool - * @return string - */ if ( ! function_exists('xml_convert')) { + /** + * Convert Reserved XML characters to Entities + * + * @param string + * @param bool + * @return string + */ function xml_convert($str, $protect_all = FALSE) { $temp = '__TEMP_AMPERSANDS__'; @@ -54,7 +55,7 @@ if ( ! function_exists('xml_convert')) // ampersands won't get messed up $str = preg_replace('/&#(\d+);/', $temp.'\\1;', $str); - if ($protect_all == TRUE) + if ($protect_all === TRUE) { $str = preg_replace('/&(\w+);/', $temp.'\\1;', $str); } @@ -66,7 +67,7 @@ if ( ! function_exists('xml_convert')) // Decode the temp markers back to entities $str = preg_replace('/'.$temp.'(\d+);/', '&#\\1;', $str); - if ($protect_all == TRUE) + if ($protect_all === TRUE) { return preg_replace('/'.$temp.'(\w+);/', '&\\1;', $str); } diff --git a/system/language/english/calendar_lang.php b/system/language/english/calendar_lang.php index 2d477e6c8..288eb91d8 100644 --- a/system/language/english/calendar_lang.php +++ b/system/language/english/calendar_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,53 +24,53 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); -$lang['cal_su'] = "Su"; -$lang['cal_mo'] = "Mo"; -$lang['cal_tu'] = "Tu"; -$lang['cal_we'] = "We"; -$lang['cal_th'] = "Th"; -$lang['cal_fr'] = "Fr"; -$lang['cal_sa'] = "Sa"; -$lang['cal_sun'] = "Sun"; -$lang['cal_mon'] = "Mon"; -$lang['cal_tue'] = "Tue"; -$lang['cal_wed'] = "Wed"; -$lang['cal_thu'] = "Thu"; -$lang['cal_fri'] = "Fri"; -$lang['cal_sat'] = "Sat"; -$lang['cal_sunday'] = "Sunday"; -$lang['cal_monday'] = "Monday"; -$lang['cal_tuesday'] = "Tuesday"; -$lang['cal_wednesday'] = "Wednesday"; -$lang['cal_thursday'] = "Thursday"; -$lang['cal_friday'] = "Friday"; -$lang['cal_saturday'] = "Saturday"; -$lang['cal_jan'] = "Jan"; -$lang['cal_feb'] = "Feb"; -$lang['cal_mar'] = "Mar"; -$lang['cal_apr'] = "Apr"; -$lang['cal_may'] = "May"; -$lang['cal_jun'] = "Jun"; -$lang['cal_jul'] = "Jul"; -$lang['cal_aug'] = "Aug"; -$lang['cal_sep'] = "Sep"; -$lang['cal_oct'] = "Oct"; -$lang['cal_nov'] = "Nov"; -$lang['cal_dec'] = "Dec"; -$lang['cal_january'] = "January"; -$lang['cal_february'] = "February"; -$lang['cal_march'] = "March"; -$lang['cal_april'] = "April"; -$lang['cal_mayl'] = "May"; -$lang['cal_june'] = "June"; -$lang['cal_july'] = "July"; -$lang['cal_august'] = "August"; -$lang['cal_september'] = "September"; -$lang['cal_october'] = "October"; -$lang['cal_november'] = "November"; -$lang['cal_december'] = "December"; - +$lang['cal_su'] = 'Su'; +$lang['cal_mo'] = 'Mo'; +$lang['cal_tu'] = 'Tu'; +$lang['cal_we'] = 'We'; +$lang['cal_th'] = 'Th'; +$lang['cal_fr'] = 'Fr'; +$lang['cal_sa'] = 'Sa'; +$lang['cal_sun'] = 'Sun'; +$lang['cal_mon'] = 'Mon'; +$lang['cal_tue'] = 'Tue'; +$lang['cal_wed'] = 'Wed'; +$lang['cal_thu'] = 'Thu'; +$lang['cal_fri'] = 'Fri'; +$lang['cal_sat'] = 'Sat'; +$lang['cal_sunday'] = 'Sunday'; +$lang['cal_monday'] = 'Monday'; +$lang['cal_tuesday'] = 'Tuesday'; +$lang['cal_wednesday'] = 'Wednesday'; +$lang['cal_thursday'] = 'Thursday'; +$lang['cal_friday'] = 'Friday'; +$lang['cal_saturday'] = 'Saturday'; +$lang['cal_jan'] = 'Jan'; +$lang['cal_feb'] = 'Feb'; +$lang['cal_mar'] = 'Mar'; +$lang['cal_apr'] = 'Apr'; +$lang['cal_may'] = 'May'; +$lang['cal_jun'] = 'Jun'; +$lang['cal_jul'] = 'Jul'; +$lang['cal_aug'] = 'Aug'; +$lang['cal_sep'] = 'Sep'; +$lang['cal_oct'] = 'Oct'; +$lang['cal_nov'] = 'Nov'; +$lang['cal_dec'] = 'Dec'; +$lang['cal_january'] = 'January'; +$lang['cal_february'] = 'February'; +$lang['cal_march'] = 'March'; +$lang['cal_april'] = 'April'; +$lang['cal_mayl'] = 'May'; +$lang['cal_june'] = 'June'; +$lang['cal_july'] = 'July'; +$lang['cal_august'] = 'August'; +$lang['cal_september'] = 'September'; +$lang['cal_october'] = 'October'; +$lang['cal_november'] = 'November'; +$lang['cal_december'] = 'December'; /* End of file calendar_lang.php */ /* Location: ./system/language/english/calendar_lang.php */
\ No newline at end of file diff --git a/system/language/english/date_lang.php b/system/language/english/date_lang.php index 533563700..db1e9e0ff 100644 --- a/system/language/english/date_lang.php +++ b/system/language/english/date_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,21 +24,22 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); -$lang['date_year'] = "Year"; -$lang['date_years'] = "Years"; -$lang['date_month'] = "Month"; -$lang['date_months'] = "Months"; -$lang['date_week'] = "Week"; -$lang['date_weeks'] = "Weeks"; -$lang['date_day'] = "Day"; -$lang['date_days'] = "Days"; -$lang['date_hour'] = "Hour"; -$lang['date_hours'] = "Hours"; -$lang['date_minute'] = "Minute"; -$lang['date_minutes'] = "Minutes"; -$lang['date_second'] = "Second"; -$lang['date_seconds'] = "Seconds"; +$lang['date_year'] = 'Year'; +$lang['date_years'] = 'Years'; +$lang['date_month'] = 'Month'; +$lang['date_months'] = 'Months'; +$lang['date_week'] = 'Week'; +$lang['date_weeks'] = 'Weeks'; +$lang['date_day'] = 'Day'; +$lang['date_days'] = 'Days'; +$lang['date_hour'] = 'Hour'; +$lang['date_hours'] = 'Hours'; +$lang['date_minute'] = 'Minute'; +$lang['date_minutes'] = 'Minutes'; +$lang['date_second'] = 'Second'; +$lang['date_seconds'] = 'Seconds'; $lang['UM12'] = '(UTC -12:00) Baker/Howland Island'; $lang['UM11'] = '(UTC -11:00) Niue'; @@ -81,6 +82,5 @@ $lang['UP1275'] = '(UTC +12:45) Chatham Islands Standard Time'; $lang['UP13'] = '(UTC +13:00) Samoa Time Zone, Phoenix Islands Time, Tonga'; $lang['UP14'] = '(UTC +14:00) Line Islands'; - /* End of file date_lang.php */ /* Location: ./system/language/english/date_lang.php */
\ No newline at end of file diff --git a/system/language/english/db_lang.php b/system/language/english/db_lang.php index a135d1aac..50ce6bbd6 100644 --- a/system/language/english/db_lang.php +++ b/system/language/english/db_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); $lang['db_invalid_connection_str'] = 'Unable to determine the database settings based on the connection string you submitted.'; $lang['db_unable_to_connect'] = 'Unable to connect to your database server using the provided settings.'; @@ -40,8 +41,8 @@ $lang['db_field_param_missing'] = 'To fetch fields requires the name of the tabl $lang['db_unsupported_function'] = 'This feature is not available for the database you are using.'; $lang['db_transaction_failure'] = 'Transaction failure: Rollback performed.'; $lang['db_unable_to_drop'] = 'Unable to drop the specified database.'; -$lang['db_unsuported_feature'] = 'Unsupported feature of the database platform you are using.'; -$lang['db_unsuported_compression'] = 'The file compression format you chose is not supported by your server.'; +$lang['db_unsupported_feature'] = 'Unsupported feature of the database platform you are using.'; +$lang['db_unsupported_compression'] = 'The file compression format you chose is not supported by your server.'; $lang['db_filepath_error'] = 'Unable to write data to the file path you have submitted.'; $lang['db_invalid_cache_path'] = 'The cache path you submitted is not valid or writable.'; $lang['db_table_name_required'] = 'A table name is required for that operation.'; diff --git a/system/language/english/email_lang.php b/system/language/english/email_lang.php index 23296a244..646a49647 100644 --- a/system/language/english/email_lang.php +++ b/system/language/english/email_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,26 +24,26 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); -$lang['email_must_be_array'] = "The email validation method must be passed an array."; -$lang['email_invalid_address'] = "Invalid email address: %s"; -$lang['email_attachment_missing'] = "Unable to locate the following email attachment: %s"; -$lang['email_attachment_unreadable'] = "Unable to open this attachment: %s"; -$lang['email_no_recipients'] = "You must include recipients: To, Cc, or Bcc"; -$lang['email_send_failure_phpmail'] = "Unable to send email using PHP mail(). Your server might not be configured to send mail using this method."; -$lang['email_send_failure_sendmail'] = "Unable to send email using PHP Sendmail. Your server might not be configured to send mail using this method."; -$lang['email_send_failure_smtp'] = "Unable to send email using PHP SMTP. Your server might not be configured to send mail using this method."; -$lang['email_sent'] = "Your message has been successfully sent using the following protocol: %s"; -$lang['email_no_socket'] = "Unable to open a socket to Sendmail. Please check settings."; -$lang['email_no_hostname'] = "You did not specify a SMTP hostname."; -$lang['email_smtp_error'] = "The following SMTP error was encountered: %s"; -$lang['email_no_smtp_unpw'] = "Error: You must assign a SMTP username and password."; -$lang['email_failed_smtp_login'] = "Failed to send AUTH LOGIN command. Error: %s"; -$lang['email_smtp_auth_un'] = "Failed to authenticate username. Error: %s"; -$lang['email_smtp_auth_pw'] = "Failed to authenticate password. Error: %s"; -$lang['email_smtp_data_failure'] = "Unable to send data: %s"; -$lang['email_exit_status'] = "Exit status code: %s"; - +$lang['email_must_be_array'] = 'The email validation method must be passed an array.'; +$lang['email_invalid_address'] = 'Invalid email address: %s'; +$lang['email_attachment_missing'] = 'Unable to locate the following email attachment: %s'; +$lang['email_attachment_unreadable'] = 'Unable to open this attachment: %s'; +$lang['email_no_recipients'] = 'You must include recipients: To, Cc, or Bcc'; +$lang['email_send_failure_phpmail'] = 'Unable to send email using PHP mail(). Your server might not be configured to send mail using this method.'; +$lang['email_send_failure_sendmail'] = 'Unable to send email using PHP Sendmail. Your server might not be configured to send mail using this method.'; +$lang['email_send_failure_smtp'] = 'Unable to send email using PHP SMTP. Your server might not be configured to send mail using this method.'; +$lang['email_sent'] = 'Your message has been successfully sent using the following protocol: %s'; +$lang['email_no_socket'] = 'Unable to open a socket to Sendmail. Please check settings.'; +$lang['email_no_hostname'] = 'You did not specify a SMTP hostname.'; +$lang['email_smtp_error'] = 'The following SMTP error was encountered: %s'; +$lang['email_no_smtp_unpw'] = 'Error: You must assign a SMTP username and password.'; +$lang['email_failed_smtp_login'] = 'Failed to send AUTH LOGIN command. Error: %s'; +$lang['email_smtp_auth_un'] = 'Failed to authenticate username. Error: %s'; +$lang['email_smtp_auth_pw'] = 'Failed to authenticate password. Error: %s'; +$lang['email_smtp_data_failure'] = 'Unable to send data: %s'; +$lang['email_exit_status'] = 'Exit status code: %s'; /* End of file email_lang.php */ /* Location: ./system/language/english/email_lang.php */
\ No newline at end of file diff --git a/system/language/english/form_validation_lang.php b/system/language/english/form_validation_lang.php index 6cf0b46f4..52ca21f92 100644 --- a/system/language/english/form_validation_lang.php +++ b/system/language/english/form_validation_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,33 +24,34 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); -$lang['required'] = "The %s field is required."; -$lang['isset'] = "The %s field must have a value."; -$lang['valid_email'] = "The %s field must contain a valid email address."; -$lang['valid_emails'] = "The %s field must contain all valid email addresses."; -$lang['valid_url'] = "The %s field must contain a valid URL."; -$lang['valid_ip'] = "The %s field must contain a valid IP."; -$lang['min_length'] = "The %s field must be at least %s characters in length."; -$lang['max_length'] = "The %s field cannot exceed %s characters in length."; -$lang['exact_length'] = "The %s field must be exactly %s characters in length."; -$lang['alpha'] = "The %s field may only contain alphabetical characters."; -$lang['alpha_numeric'] = "The %s field may only contain alpha-numeric characters."; -$lang['alpha_dash'] = "The %s field may only contain alpha-numeric characters, underscores, and dashes."; -$lang['numeric'] = "The %s field must contain only numbers."; -$lang['is_numeric'] = "The %s field must contain only numeric characters."; -$lang['integer'] = "The %s field must contain an integer."; -$lang['regex_match'] = "The %s field is not in the correct format."; -$lang['matches'] = "The %s field does not match the %s field."; -$lang['is_unique'] = "The %s field must contain a unique value."; -$lang['is_natural'] = "The %s field must contain only positive numbers."; -$lang['is_natural_no_zero'] = "The %s field must contain a number greater than zero."; -$lang['decimal'] = "The %s field must contain a decimal number."; -$lang['less_than'] = "The %s field must contain a number less than %s."; -$lang['less_than_equal_to'] = "The %s field must contain a number less than or equal to %s."; -$lang['greater_than'] = "The %s field must contain a number greater than %s."; -$lang['greater_than_equal_to'] = "The %s field must contain a number greater than or equal to %s."; - +$lang['required'] = 'The %s field is required.'; +$lang['isset'] = 'The %s field must have a value.'; +$lang['valid_email'] = 'The %s field must contain a valid email address.'; +$lang['valid_emails'] = 'The %s field must contain all valid email addresses.'; +$lang['valid_url'] = 'The %s field must contain a valid URL.'; +$lang['valid_ip'] = 'The %s field must contain a valid IP.'; +$lang['min_length'] = 'The %s field must be at least %s characters in length.'; +$lang['max_length'] = 'The %s field cannot exceed %s characters in length.'; +$lang['exact_length'] = 'The %s field must be exactly %s characters in length.'; +$lang['alpha'] = 'The %s field may only contain alphabetical characters.'; +$lang['alpha_numeric'] = 'The %s field may only contain alpha-numeric characters.'; +$lang['alpha_dash'] = 'The %s field may only contain alpha-numeric characters, underscores, and dashes.'; +$lang['numeric'] = 'The %s field must contain only numbers.'; +$lang['is_numeric'] = 'The %s field must contain only numeric characters.'; +$lang['integer'] = 'The %s field must contain an integer.'; +$lang['regex_match'] = 'The %s field is not in the correct format.'; +$lang['matches'] = 'The %s field does not match the %s field.'; +$lang['differs'] = 'The %s field must differ from the %s field.'; +$lang['is_unique'] = 'The %s field must contain a unique value.'; +$lang['is_natural'] = 'The %s field must only contain digits.'; +$lang['is_natural_no_zero'] = 'The %s field must only contain digits and must be greater than zero.'; +$lang['decimal'] = 'The %s field must contain a decimal number.'; +$lang['less_than'] = 'The %s field must contain a number less than %s.'; +$lang['less_than_equal_to'] = 'The %s field must contain a number less than or equal to %s.'; +$lang['greater_than'] = 'The %s field must contain a number greater than %s.'; +$lang['greater_than_equal_to'] = 'The %s field must contain a number greater than or equal to %s.'; /* End of file form_validation_lang.php */ -/* Location: ./system/language/english/form_validation_lang.php */ +/* Location: ./system/language/english/form_validation_lang.php */
\ No newline at end of file diff --git a/system/language/english/ftp_lang.php b/system/language/english/ftp_lang.php index 4e39e43bf..090a88c28 100644 --- a/system/language/english/ftp_lang.php +++ b/system/language/english/ftp_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,20 +24,20 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); -$lang['ftp_no_connection'] = "Unable to locate a valid connection ID. Please make sure you are connected before peforming any file routines."; -$lang['ftp_unable_to_connect'] = "Unable to connect to your FTP server using the supplied hostname."; -$lang['ftp_unable_to_login'] = "Unable to login to your FTP server. Please check your username and password."; -$lang['ftp_unable_to_makdir'] = "Unable to create the directory you have specified."; -$lang['ftp_unable_to_changedir'] = "Unable to change directories."; -$lang['ftp_unable_to_chmod'] = "Unable to set file permissions. Please check your path. Note: This feature is only available in PHP 5 or higher."; -$lang['ftp_unable_to_upload'] = "Unable to upload the specified file. Please check your path."; -$lang['ftp_unable_to_download'] = "Unable to download the specified file. Please check your path."; -$lang['ftp_no_source_file'] = "Unable to locate the source file. Please check your path."; -$lang['ftp_unable_to_rename'] = "Unable to rename the file."; -$lang['ftp_unable_to_delete'] = "Unable to delete the file."; -$lang['ftp_unable_to_move'] = "Unable to move the file. Please make sure the destination directory exists."; - +$lang['ftp_no_connection'] = 'Unable to locate a valid connection ID. Please make sure you are connected before peforming any file routines.'; +$lang['ftp_unable_to_connect'] = 'Unable to connect to your FTP server using the supplied hostname.'; +$lang['ftp_unable_to_login'] = 'Unable to login to your FTP server. Please check your username and password.'; +$lang['ftp_unable_to_makdir'] = 'Unable to create the directory you have specified.'; +$lang['ftp_unable_to_changedir'] = 'Unable to change directories.'; +$lang['ftp_unable_to_chmod'] = 'Unable to set file permissions. Please check your path. Note: This feature is only available in PHP 5 or higher.'; +$lang['ftp_unable_to_upload'] = 'Unable to upload the specified file. Please check your path.'; +$lang['ftp_unable_to_download'] = 'Unable to download the specified file. Please check your path.'; +$lang['ftp_no_source_file'] = 'Unable to locate the source file. Please check your path.'; +$lang['ftp_unable_to_rename'] = 'Unable to rename the file.'; +$lang['ftp_unable_to_delete'] = 'Unable to delete the file.'; +$lang['ftp_unable_to_move'] = 'Unable to move the file. Please make sure the destination directory exists.'; /* End of file ftp_lang.php */ /* Location: ./system/language/english/ftp_lang.php */
\ No newline at end of file diff --git a/system/language/english/imglib_lang.php b/system/language/english/imglib_lang.php index 67ca94277..296c4af68 100644 --- a/system/language/english/imglib_lang.php +++ b/system/language/english/imglib_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,26 +24,26 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); -$lang['imglib_source_image_required'] = "You must specify a source image in your preferences."; -$lang['imglib_gd_required'] = "The GD image library is required for this feature."; -$lang['imglib_gd_required_for_props'] = "Your server must support the GD image library in order to determine the image properties."; -$lang['imglib_unsupported_imagecreate'] = "Your server does not support the GD function required to process this type of image."; -$lang['imglib_gif_not_supported'] = "GIF images are often not supported due to licensing restrictions. You may have to use JPG or PNG images instead."; -$lang['imglib_jpg_not_supported'] = "JPG images are not supported."; -$lang['imglib_png_not_supported'] = "PNG images are not supported."; -$lang['imglib_jpg_or_png_required'] = "The image resize protocol specified in your preferences only works with JPEG or PNG image types."; -$lang['imglib_copy_error'] = "An error was encountered while attempting to replace the file. Please make sure your file directory is writable."; -$lang['imglib_rotate_unsupported'] = "Image rotation does not appear to be supported by your server."; -$lang['imglib_libpath_invalid'] = "The path to your image library is not correct. Please set the correct path in your image preferences."; -$lang['imglib_image_process_failed'] = "Image processing failed. Please verify that your server supports the chosen protocol and that the path to your image library is correct."; -$lang['imglib_rotation_angle_required'] = "An angle of rotation is required to rotate the image."; -$lang['imglib_writing_failed_gif'] = "GIF image."; -$lang['imglib_invalid_path'] = "The path to the image is not correct."; -$lang['imglib_copy_failed'] = "The image copy routine failed."; -$lang['imglib_missing_font'] = "Unable to find a font to use."; -$lang['imglib_save_failed'] = "Unable to save the image. Please make sure the image and file directory are writable."; - +$lang['imglib_source_image_required'] = 'You must specify a source image in your preferences.'; +$lang['imglib_gd_required'] = 'The GD image library is required for this feature.'; +$lang['imglib_gd_required_for_props'] = 'Your server must support the GD image library in order to determine the image properties.'; +$lang['imglib_unsupported_imagecreate'] = 'Your server does not support the GD function required to process this type of image.'; +$lang['imglib_gif_not_supported'] = 'GIF images are often not supported due to licensing restrictions. You may have to use JPG or PNG images instead.'; +$lang['imglib_jpg_not_supported'] = 'JPG images are not supported.'; +$lang['imglib_png_not_supported'] = 'PNG images are not supported.'; +$lang['imglib_jpg_or_png_required'] = 'The image resize protocol specified in your preferences only works with JPEG or PNG image types.'; +$lang['imglib_copy_error'] = 'An error was encountered while attempting to replace the file. Please make sure your file directory is writable.'; +$lang['imglib_rotate_unsupported'] = 'Image rotation does not appear to be supported by your server.'; +$lang['imglib_libpath_invalid'] = 'The path to your image library is not correct. Please set the correct path in your image preferences.'; +$lang['imglib_image_process_failed'] = 'Image processing failed. Please verify that your server supports the chosen protocol and that the path to your image library is correct.'; +$lang['imglib_rotation_angle_required'] = 'An angle of rotation is required to rotate the image.'; +$lang['imglib_writing_failed_gif'] = 'GIF image.'; +$lang['imglib_invalid_path'] = 'The path to the image is not correct.'; +$lang['imglib_copy_failed'] = 'The image copy routine failed.'; +$lang['imglib_missing_font'] = 'Unable to find a font to use.'; +$lang['imglib_save_failed'] = 'Unable to save the image. Please make sure the image and file directory are writable.'; /* End of file imglib_lang.php */ /* Location: ./system/language/english/imglib_lang.php */
\ No newline at end of file diff --git a/system/language/english/migration_lang.php b/system/language/english/migration_lang.php index 2085cee2a..689a72952 100644 --- a/system/language/english/migration_lang.php +++ b/system/language/english/migration_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,15 +24,16 @@ * @since Version 3.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); -$lang['migration_none_found'] = "No migrations were found."; -$lang['migration_not_found'] = "This migration could not be found."; -$lang['migration_multiple_version'] = "This are multiple migrations with the same version number: %d."; -$lang['migration_class_doesnt_exist'] = "The migration class \"%s\" could not be found."; -$lang['migration_missing_up_method'] = "The migration class \"%s\" is missing an 'up' method."; -$lang['migration_missing_down_method'] = "The migration class \"%s\" is missing a 'down' method."; -$lang['migration_invalid_filename'] = "Migration \"%s\" has an invalid filename."; - +$lang['migration_none_found'] = 'No migrations were found.'; +$lang['migration_not_found'] = 'No migration could be found with the version number: %d.'; +$lang['migration_sequence_gap'] = 'There is a gap in the migration sequence near version number: %d.'; +$lang['migration_multiple_version'] = 'There are multiple migrations with the same version number: %d.'; +$lang['migration_class_doesnt_exist'] = 'The migration class "%s" could not be found.'; +$lang['migration_missing_up_method'] = 'The migration class "%s" is missing an "up" method.'; +$lang['migration_missing_down_method'] = 'The migration class "%s" is missing a "down" method.'; +$lang['migration_invalid_filename'] = 'Migration "%s" has an invalid filename.'; /* End of file migration_lang.php */ /* Location: ./system/language/english/migration_lang.php */
\ No newline at end of file diff --git a/system/language/english/number_lang.php b/system/language/english/number_lang.php index 0c19ec614..019013a49 100644 --- a/system/language/english/number_lang.php +++ b/system/language/english/number_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,12 +24,13 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); -$lang['terabyte_abbr'] = "TB"; -$lang['gigabyte_abbr'] = "GB"; -$lang['megabyte_abbr'] = "MB"; -$lang['kilobyte_abbr'] = "KB"; -$lang['bytes'] = "Bytes"; +$lang['terabyte_abbr'] = 'TB'; +$lang['gigabyte_abbr'] = 'GB'; +$lang['megabyte_abbr'] = 'MB'; +$lang['kilobyte_abbr'] = 'KB'; +$lang['bytes'] = 'Bytes'; /* End of file number_lang.php */ /* Location: ./system/language/english/number_lang.php */
\ No newline at end of file diff --git a/system/language/english/profiler_lang.php b/system/language/english/profiler_lang.php index 11d791272..6ffcd9349 100644 --- a/system/language/english/profiler_lang.php +++ b/system/language/english/profiler_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); $lang['profiler_database'] = 'DATABASE'; $lang['profiler_controller_info'] = 'CLASS/METHOD'; diff --git a/system/language/english/unit_test_lang.php b/system/language/english/unit_test_lang.php index 3a8e14403..ed452615f 100644 --- a/system/language/english/unit_test_lang.php +++ b/system/language/english/unit_test_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); $lang['ut_test_name'] = 'Test Name'; $lang['ut_test_datatype'] = 'Test Datatype'; @@ -45,6 +46,5 @@ $lang['ut_resource'] = 'Resource'; $lang['ut_null'] = 'Null'; $lang['ut_notes'] = 'Notes'; - /* End of file unit_test_lang.php */ /* Location: ./system/language/english/unit_test_lang.php */
\ No newline at end of file diff --git a/system/language/english/upload_lang.php b/system/language/english/upload_lang.php index 4fa8394ec..88f9ac372 100644 --- a/system/language/english/upload_lang.php +++ b/system/language/english/upload_lang.php @@ -5,9 +5,9 @@ * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE - * + * * Licensed under the Open Software License version 3.0 - * + * * This source file is subject to the Open Software License (OSL 3.0) that is * bundled with this package in the files license.txt / license.rst. It is * also available through the world wide web at this URL: @@ -24,24 +24,24 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); -$lang['upload_userfile_not_set'] = "Unable to find a post variable called userfile."; -$lang['upload_file_exceeds_limit'] = "The uploaded file exceeds the maximum allowed size in your PHP configuration file."; -$lang['upload_file_exceeds_form_limit'] = "The uploaded file exceeds the maximum size allowed by the submission form."; -$lang['upload_file_partial'] = "The file was only partially uploaded."; -$lang['upload_no_temp_directory'] = "The temporary folder is missing."; -$lang['upload_unable_to_write_file'] = "The file could not be written to disk."; -$lang['upload_stopped_by_extension'] = "The file upload was stopped by extension."; -$lang['upload_no_file_selected'] = "You did not select a file to upload."; -$lang['upload_invalid_filetype'] = "The filetype you are attempting to upload is not allowed."; -$lang['upload_invalid_filesize'] = "The file you are attempting to upload is larger than the permitted size."; -$lang['upload_invalid_dimensions'] = "The image you are attempting to upload exceeds the maximum height or width."; -$lang['upload_destination_error'] = "A problem was encountered while attempting to move the uploaded file to the final destination."; -$lang['upload_no_filepath'] = "The upload path does not appear to be valid."; -$lang['upload_no_file_types'] = "You have not specified any allowed file types."; -$lang['upload_bad_filename'] = "The file name you submitted already exists on the server."; -$lang['upload_not_writable'] = "The upload destination folder does not appear to be writable."; - +$lang['upload_userfile_not_set'] = 'Unable to find a post variable called userfile.'; +$lang['upload_file_exceeds_limit'] = 'The uploaded file exceeds the maximum allowed size in your PHP configuration file.'; +$lang['upload_file_exceeds_form_limit'] = 'The uploaded file exceeds the maximum size allowed by the submission form.'; +$lang['upload_file_partial'] = 'The file was only partially uploaded.'; +$lang['upload_no_temp_directory'] = 'The temporary folder is missing.'; +$lang['upload_unable_to_write_file'] = 'The file could not be written to disk.'; +$lang['upload_stopped_by_extension'] = 'The file upload was stopped by extension.'; +$lang['upload_no_file_selected'] = 'You did not select a file to upload.'; +$lang['upload_invalid_filetype'] = 'The filetype you are attempting to upload is not allowed.'; +$lang['upload_invalid_filesize'] = 'The file you are attempting to upload is larger than the permitted size.'; +$lang['upload_invalid_dimensions'] = 'The image you are attempting to upload exceeds the maximum height or width.'; +$lang['upload_destination_error'] = 'A problem was encountered while attempting to move the uploaded file to the final destination.'; +$lang['upload_no_filepath'] = 'The upload path does not appear to be valid.'; +$lang['upload_no_file_types'] = 'You have not specified any allowed file types.'; +$lang['upload_bad_filename'] = 'The file name you submitted already exists on the server.'; +$lang['upload_not_writable'] = 'The upload destination folder does not appear to be writable.'; /* End of file upload_lang.php */ /* Location: ./system/language/english/upload_lang.php */
\ No newline at end of file diff --git a/system/libraries/Cache/Cache.php b/system/libraries/Cache/Cache.php index f98241617..e76fdc557 100644 --- a/system/libraries/Cache/Cache.php +++ b/system/libraries/Cache/Cache.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 2.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Caching Class @@ -36,32 +37,62 @@ */ class CI_Cache extends CI_Driver_Library { - protected $valid_drivers = array( - 'cache_apc', - 'cache_file', - 'cache_memcached', - 'cache_dummy', - 'cache_wincache' - ); + /** + * Valid cache drivers + * + * @var array + */ + protected $valid_drivers = array( + 'cache_apc', + 'cache_dummy', + 'cache_file', + 'cache_memcached', + 'cache_redis', + 'cache_wincache' + ); + + /** + * Path of cache files (if file-based cache) + * + * @var string + */ + protected $_cache_path = NULL; + + /** + * Reference to the driver + * + * @var mixed + */ + protected $_adapter = 'dummy'; - protected $_cache_path = NULL; // Path of cache files (if file-based cache) - protected $_adapter = 'dummy'; - protected $_backup_driver; + /** + * Fallback driver + * + * @var string + */ + protected $_backup_driver = 'dummy'; + + /** + * Cache key prefix + * + * @var string + */ + public $key_prefix = ''; /** * Constructor * * Initialize class properties based on the configuration array. * - * @param array + * @param array $config = array() * @return void */ public function __construct($config = array()) { $default_config = array( - 'adapter', - 'memcached' - ); + 'adapter', + 'memcached' + ); foreach ($default_config as $key) { @@ -73,11 +104,26 @@ class CI_Cache extends CI_Driver_Library { } } - if (isset($config['backup'])) + isset($config['key_prefix']) && $this->key_prefix = $config['key_prefix']; + + if (isset($config['backup']) && in_array('cache_'.$config['backup'], $this->valid_drivers)) { - if (in_array('cache_'.$config['backup'], $this->valid_drivers)) + $this->_backup_driver = $config['backup']; + } + + // If the specified adapter isn't available, check the backup. + if ( ! $this->is_supported($this->_adapter)) + { + if ( ! $this->is_supported($this->_backup_driver)) { - $this->_backup_driver = $config['backup']; + // Backup isn't supported either. Default to 'Dummy' driver. + log_message('error', 'Cache adapter "'.$this->_adapter.'" and backup "'.$this->_backup_driver.'" are both unavailable. Cache is now using "Dummy" adapter.'); + $this->_adapter = 'dummy'; + } + else + { + // Backup is supported. Set it to primary. + $this->_adapter = $this->_backup_driver; } } } @@ -90,12 +136,12 @@ class CI_Cache extends CI_Driver_Library { * Look for a value in the cache. If it exists, return the data * if not, return FALSE * - * @param string - * @return mixed value that is stored/FALSE on failure + * @param string $id + * @return mixed value matching $id or FALSE on failure */ public function get($id) { - return $this->{$this->_adapter}->get($id); + return $this->{$this->_adapter}->get($this->key_prefix.$id); } // ------------------------------------------------------------------------ @@ -103,14 +149,14 @@ class CI_Cache extends CI_Driver_Library { /** * Cache Save * - * @param string Unique Key - * @param mixed Data to store - * @param int Length of time (in seconds) to cache the data - * @return bool true on success/false on failure + * @param string $id Cache ID + * @param mixed $data Data to store + * @param int $ttl = 60 Cache TTL (in seconds) + * @return bool TRUE on success, FALSE on failure */ public function save($id, $data, $ttl = 60) { - return $this->{$this->_adapter}->save($id, $data, $ttl); + return $this->{$this->_adapter}->save($this->key_prefix.$id, $data, $ttl); } // ------------------------------------------------------------------------ @@ -118,12 +164,12 @@ class CI_Cache extends CI_Driver_Library { /** * Delete from Cache * - * @param mixed unique identifier of the item in the cache - * @return bool true on success/false on failure + * @param string $id Cache ID + * @return bool TRUE on success, FALSE on failure */ public function delete($id) { - return $this->{$this->_adapter}->delete($id); + return $this->{$this->_adapter}->delete($this->key_prefix.$id); } // ------------------------------------------------------------------------ @@ -131,7 +177,7 @@ class CI_Cache extends CI_Driver_Library { /** * Clean the cache * - * @return bool false on failure/true on success + * @return bool TRUE on success, FALSE on failure */ public function clean() { @@ -143,8 +189,8 @@ class CI_Cache extends CI_Driver_Library { /** * Cache Info * - * @param string user/filehits - * @return mixed array on success, false on failure + * @param string $type = 'user' user/filehits + * @return mixed array containing cache info on success OR FALSE on failure */ public function cache_info($type = 'user') { @@ -156,12 +202,12 @@ class CI_Cache extends CI_Driver_Library { /** * Get Cache Metadata * - * @param mixed key to get cache metadata on - * @return mixed return value from child method + * @param string $id key to get cache metadata on + * @return mixed cache item metadata */ public function get_metadata($id) { - return $this->{$this->_adapter}->get_metadata($id); + return $this->{$this->_adapter}->get_metadata($this->key_prefix.$id); } // ------------------------------------------------------------------------ @@ -169,7 +215,7 @@ class CI_Cache extends CI_Driver_Library { /** * Is the requested driver supported in this environment? * - * @param string The driver to test. + * @param string $driver The driver to test * @return array */ public function is_supported($driver) @@ -184,26 +230,6 @@ class CI_Cache extends CI_Driver_Library { return $support[$driver]; } - // ------------------------------------------------------------------------ - - /** - * __get() - * - * @param child - * @return object - */ - public function __get($child) - { - $obj = parent::__get($child); - - if ( ! $this->is_supported($child)) - { - $this->_adapter = $this->_backup_driver; - } - - return $obj; - } - } /* End of file Cache.php */ diff --git a/system/libraries/Cache/drivers/Cache_apc.php b/system/libraries/Cache/drivers/Cache_apc.php index 59ab67533..46e633463 100644 --- a/system/libraries/Cache/drivers/Cache_apc.php +++ b/system/libraries/Cache/drivers/Cache_apc.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 2.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter APC Caching Class @@ -75,7 +76,7 @@ class CI_Cache_apc extends CI_Driver { * Delete from Cache * * @param mixed unique identifier of the item in the cache - * @param bool true on success/false on failure + * @return bool true on success/false on failure */ public function delete($id) { diff --git a/system/libraries/Cache/drivers/Cache_dummy.php b/system/libraries/Cache/drivers/Cache_dummy.php index e8b791c5b..a3bdc3c80 100644 --- a/system/libraries/Cache/drivers/Cache_dummy.php +++ b/system/libraries/Cache/drivers/Cache_dummy.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 2.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Dummy Caching Class @@ -70,7 +71,7 @@ class CI_Cache_dummy extends CI_Driver { * Delete from Cache * * @param mixed unique identifier of the item in the cache - * @param bool TRUE, simulating success + * @return bool TRUE, simulating success */ public function delete($id) { diff --git a/system/libraries/Cache/drivers/Cache_file.php b/system/libraries/Cache/drivers/Cache_file.php index dd27aa90e..5d370380e 100644 --- a/system/libraries/Cache/drivers/Cache_file.php +++ b/system/libraries/Cache/drivers/Cache_file.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -18,15 +18,16 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 2.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** - * CodeIgniter Memcached Caching Class + * CodeIgniter File Caching Class * * @package CodeIgniter * @subpackage Libraries @@ -36,14 +37,24 @@ */ class CI_Cache_file extends CI_Driver { + /** + * Directory in which to save cache files + * + * @var string + */ protected $_cache_path; + /** + * Initialize file-based cache + * + * @return void + */ public function __construct() { $CI =& get_instance(); $CI->load->helper('file'); $path = $CI->config->item('cache_path'); - $this->_cache_path = ($path == '') ? APPPATH.'cache/' : $path; + $this->_cache_path = ($path === '') ? APPPATH.'cache/' : $path; } // ------------------------------------------------------------------------ @@ -61,9 +72,9 @@ class CI_Cache_file extends CI_Driver { return FALSE; } - $data = unserialize(read_file($this->_cache_path.$id)); + $data = unserialize(file_get_contents($this->_cache_path.$id)); - if (time() > $data['time'] + $data['ttl']) + if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl']) { unlink($this->_cache_path.$id); return FALSE; @@ -86,10 +97,10 @@ class CI_Cache_file extends CI_Driver { public function save($id, $data, $ttl = 60) { $contents = array( - 'time' => time(), - 'ttl' => $ttl, - 'data' => $data - ); + 'time' => time(), + 'ttl' => $ttl, + 'data' => $data + ); if (write_file($this->_cache_path.$id, serialize($contents))) { @@ -155,19 +166,19 @@ class CI_Cache_file extends CI_Driver { return FALSE; } - $data = unserialize(read_file($this->_cache_path.$id)); + $data = unserialize(file_get_contents($this->_cache_path.$id)); if (is_array($data)) { $mtime = filemtime($this->_cache_path.$id); - if ( ! isset($data['data']['ttl'])) + if ( ! isset($data['ttl'])) { return FALSE; } return array( - 'expire' => $mtime + $data['data']['ttl'], + 'expire' => $mtime + $data['ttl'], 'mtime' => $mtime ); } diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php index 4cd5f3d6f..fae002347 100644 --- a/system/libraries/Cache/drivers/Cache_memcached.php +++ b/system/libraries/Cache/drivers/Cache_memcached.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 2.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Memcached Caching Class @@ -36,15 +37,25 @@ */ class CI_Cache_memcached extends CI_Driver { - protected $_memcached; // Holds the memcached object + /** + * Holds the memcached object + * + * @var object + */ + protected $_memcached; + /** + * Memcached configuration + * + * @var array + */ protected $_memcache_conf = array( - 'default' => array( - 'default_host' => '127.0.0.1', - 'default_port' => 11211, - 'default_weight' => 1 - ) - ); + 'default' => array( + 'default_host' => '127.0.0.1', + 'default_port' => 11211, + 'default_weight' => 1 + ) + ); /** * Fetch from cache @@ -67,7 +78,7 @@ class CI_Cache_memcached extends CI_Driver { * @param string unique identifier * @param mixed data being cached * @param int time to live - * @return bool true on success, false on failure + * @return bool true on success, false on failure */ public function save($id, $data, $ttl = 60) { @@ -89,7 +100,7 @@ class CI_Cache_memcached extends CI_Driver { * Delete from Cache * * @param mixed key to be deleted. - * @return bool true on success, false on failure + * @return bool true on success, false on failure */ public function delete($id) { @@ -202,7 +213,7 @@ class CI_Cache_memcached extends CI_Driver { $cache_server['weight'] = $this->_memcache_conf['default']['default_weight']; } - if (get_class($this->_memcached) == 'Memcache') + if (get_class($this->_memcached) === 'Memcache') { // Third parameter is persistance and defaults to TRUE. $this->_memcached->addServer( diff --git a/system/libraries/Cache/drivers/Cache_redis.php b/system/libraries/Cache/drivers/Cache_redis.php new file mode 100644 index 000000000..60033344b --- /dev/null +++ b/system/libraries/Cache/drivers/Cache_redis.php @@ -0,0 +1,237 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 3.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * CodeIgniter Redis Caching Class + * + * @package CodeIgniter + * @subpackage Libraries + * @category Core + * @author Anton Lindqvist <anton@qvister.se> + * @link + */ +class CI_Cache_redis extends CI_Driver +{ + /** + * Default config + * + * @static + * @var array + */ + protected static $_default_config = array( + 'host' => '127.0.0.1', + 'password' => NULL, + 'port' => 6379, + 'timeout' => 0 + ); + + /** + * Redis connection + * + * @var Redis + */ + protected $_redis; + + // ------------------------------------------------------------------------ + + /** + * Get cache + * + * @param string Cache key identifier + * @return mixed + */ + public function get($key) + { + return $this->_redis->get($key); + } + + // ------------------------------------------------------------------------ + + /** + * Save cache + * + * @param string Cache key identifier + * @param mixed Data to save + * @param int Time to live + * @return bool + */ + public function save($key, $value, $ttl = NULL) + { + return ($ttl) + ? $this->_redis->setex($key, $ttl, $value) + : $this->_redis->set($key, $value); + } + + // ------------------------------------------------------------------------ + + /** + * Delete from cache + * + * @param string Cache key + * @return bool + */ + public function delete($key) + { + return ($this->_redis->delete($key) === 1); + } + + // ------------------------------------------------------------------------ + + /** + * Clean cache + * + * @return bool + * @see Redis::flushDB() + */ + public function clean() + { + return $this->_redis->flushDB(); + } + + // ------------------------------------------------------------------------ + + /** + * Get cache driver info + * + * @param string Not supported in Redis. + * Only included in order to offer a + * consistent cache API. + * @return array + * @see Redis::info() + */ + public function cache_info($type = NULL) + { + return $this->_redis->info(); + } + + // ------------------------------------------------------------------------ + + /** + * Get cache metadata + * + * @param string Cache key + * @return array + */ + public function get_metadata($key) + { + $value = $this->get($key); + + if ($value) + { + return array( + 'expire' => time() + $this->_redis->ttl($key), + 'data' => $value + ); + } + + return FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Check if Redis driver is supported + * + * @return bool + */ + public function is_supported() + { + if (extension_loaded('redis')) + { + $this->_setup_redis(); + return TRUE; + } + else + { + log_message('error', 'The Redis extension must be loaded to use Redis cache.'); + return FALSE; + } + } + + // ------------------------------------------------------------------------ + + /** + * Setup Redis config and connection + * + * Loads Redis config file if present. Will halt execution + * if a Redis connection can't be established. + * + * @return bool + * @see Redis::connect() + */ + protected function _setup_redis() + { + $config = array(); + $CI =& get_instance(); + + if ($CI->config->load('redis', TRUE, TRUE)) + { + $config += $CI->config->item('redis'); + } + + $config = array_merge(self::$_default_config, $config); + + $this->_redis = new Redis(); + + try + { + $this->_redis->connect($config['host'], $config['port'], $config['timeout']); + } + catch (RedisException $e) + { + show_error('Redis connection refused. ' . $e->getMessage()); + } + + if (isset($config['password'])) + { + $this->_redis->auth($config['password']); + } + } + + // ------------------------------------------------------------------------ + + /** + + * Class destructor + * + * Closes the connection to Redis if present. + * + * @return void + */ + public function __destruct() + { + if ($this->_redis) + { + $this->_redis->close(); + } + } + +} + +/* End of file Cache_redis.php */ +/* Location: ./system/libraries/Cache/drivers/Cache_redis.php */
\ No newline at end of file diff --git a/system/libraries/Cache/drivers/Cache_wincache.php b/system/libraries/Cache/drivers/Cache_wincache.php index b32e66a46..383b3afdd 100644 --- a/system/libraries/Cache/drivers/Cache_wincache.php +++ b/system/libraries/Cache/drivers/Cache_wincache.php @@ -1,8 +1,8 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * - * An open source application development framework for PHP 5.1.6 or newer + * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 3.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Wincache Caching Class @@ -78,7 +79,7 @@ class CI_Cache_wincache extends CI_Driver { * Delete from Cache * * @param mixed unique identifier of the item in the cache - * @param bool true on success/false on failure + * @return bool true on success/false on failure */ public function delete($id) { diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php index b6f145d95..caa496a5e 100644 --- a/system/libraries/Calendar.php +++ b/system/libraries/Calendar.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Calendar Class @@ -38,22 +39,70 @@ */ class CI_Calendar { + /** + * Reference to CodeIgniter instance + * + * @var object + */ protected $CI; - public $lang; + + /** + * Current local time + * + * @var int + */ public $local_time; + + /** + * Calendar layout template + * + * @var string + */ public $template = ''; + + /** + * Day of the week to start the calendar on + * + * @var string + */ public $start_day = 'sunday'; + + /** + * How to display months + * + * @var string + */ public $month_type = 'long'; + + /** + * How to display names of days + * + * @var string + */ public $day_type = 'abr'; - public $show_next_prev = FALSE; - public $next_prev_url = ''; /** - * Constructor + * Whether to show next/prev month links + * + * @var bool + */ + public $show_next_prev = FALSE; + + /** + * Url base to use for next/prev month links + * + * @var bool + */ + public $next_prev_url = ''; + + /** + * Class constructor * - * Loads the calendar language file and sets the default time reference + * Loads the calendar language file and sets the default time reference. * - * @param array + * @uses CI_Lang::$is_loaded + * + * @param array $config Calendar options * @return void */ public function __construct($config = array()) @@ -109,7 +158,7 @@ class CI_Calendar { public function generate($year = '', $month = '', $data = array()) { // Set and validate the supplied month/year - if ($year == '') + if (empty($year)) { $year = date('Y', $this->local_time); } @@ -122,7 +171,7 @@ class CI_Calendar { $year = '20'.$year; } - if ($month == '') + if (empty($month)) { $month = date('m', $this->local_time); } @@ -141,7 +190,7 @@ class CI_Calendar { // Set the starting day of the week $start_days = array('sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday' => 3, 'thursday' => 4, 'friday' => 5, 'saturday' => 6); - $start_day = ( ! isset($start_days[$this->start_day])) ? 0 : $start_days[$this->start_day]; + $start_day = isset($start_days[$this->start_day]) ? $start_days[$this->start_day] : 0; // Set the starting day number $local_date = mktime(12, 0, 0, $month, 1, $year); @@ -168,7 +217,7 @@ class CI_Calendar { $out = $this->temp['table_open']."\n\n".$this->temp['heading_row_start']."\n"; // "previous" month link - if ($this->show_next_prev == TRUE) + if ($this->show_next_prev === TRUE) { // Add a trailing slash to the URL if needed $this->next_prev_url = preg_replace('/(.+?)\/*$/', '\\1/', $this->next_prev_url); @@ -178,7 +227,7 @@ class CI_Calendar { } // Heading containing the month/year - $colspan = ($this->show_next_prev == TRUE) ? 5 : 7; + $colspan = ($this->show_next_prev === TRUE) ? 5 : 7; $this->temp['heading_title_cell'] = str_replace('{colspan}', $colspan, str_replace('{heading}', $this->get_month_name($month).' '.$year, $this->temp['heading_title_cell'])); @@ -186,7 +235,7 @@ class CI_Calendar { $out .= $this->temp['heading_title_cell']."\n"; // "next" month link - if ($this->show_next_prev == TRUE) + if ($this->show_next_prev === TRUE) { $adjusted_date = $this->adjust_date($month + 1, $year); $out .= str_replace('{next_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->temp['heading_next_cell']); @@ -244,9 +293,7 @@ class CI_Calendar { $out .= "\n".$this->temp['cal_row_end']."\n"; } - $out .= "\n".$this->temp['table_close']; - - return $out; + return $out .= "\n".$this->temp['table_close']; } // -------------------------------------------------------------------- @@ -262,7 +309,7 @@ class CI_Calendar { */ public function get_month_name($month) { - if ($this->month_type == 'short') + if ($this->month_type === 'short') { $month_names = array('01' => 'cal_jan', '02' => 'cal_feb', '03' => 'cal_mar', '04' => 'cal_apr', '05' => 'cal_may', '06' => 'cal_jun', '07' => 'cal_jul', '08' => 'cal_aug', '09' => 'cal_sep', '10' => 'cal_oct', '11' => 'cal_nov', '12' => 'cal_dec'); } @@ -271,14 +318,9 @@ class CI_Calendar { $month_names = array('01' => 'cal_january', '02' => 'cal_february', '03' => 'cal_march', '04' => 'cal_april', '05' => 'cal_mayl', '06' => 'cal_june', '07' => 'cal_july', '08' => 'cal_august', '09' => 'cal_september', '10' => 'cal_october', '11' => 'cal_november', '12' => 'cal_december'); } - $month = $month_names[$month]; - - if ($this->CI->lang->line($month) === FALSE) - { - return ucfirst(substr($month, 4)); - } - - return $this->CI->lang->line($month); + return ($this->CI->lang->line($month_names[$month]) === FALSE) + ? ucfirst(substr($month_names[$month], 4)) + : $this->CI->lang->line($month_names[$month]); } // -------------------------------------------------------------------- @@ -294,16 +336,16 @@ class CI_Calendar { */ public function get_day_names($day_type = '') { - if ($day_type != '') + if ($day_type !== '') { $this->day_type = $day_type; } - if ($this->day_type == 'long') + if ($this->day_type === 'long') { $day_names = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); } - elseif ($this->day_type == 'short') + elseif ($this->day_type === 'short') { $day_names = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'); } @@ -382,7 +424,7 @@ class CI_Calendar { // Is the year a leap year? if ($month == 2) { - if ($year % 400 == 0 OR ($year % 4 == 0 && $year % 100 != 0)) + if ($year % 400 === 0 OR ($year % 4 === 0 && $year % 100 !== 0)) { return 29; } @@ -402,29 +444,29 @@ class CI_Calendar { */ public function default_template() { - return array ( - 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">', - 'heading_row_start' => '<tr>', - 'heading_previous_cell' => '<th><a href="{previous_url}"><<</a></th>', - 'heading_title_cell' => '<th colspan="{colspan}">{heading}</th>', - 'heading_next_cell' => '<th><a href="{next_url}">>></a></th>', - 'heading_row_end' => '</tr>', - 'week_row_start' => '<tr>', - 'week_day_cell' => '<td>{week_day}</td>', - 'week_row_end' => '</tr>', - 'cal_row_start' => '<tr>', - 'cal_cell_start' => '<td>', - 'cal_cell_start_today' => '<td>', - 'cal_cell_content' => '<a href="{content}">{day}</a>', - 'cal_cell_content_today' => '<a href="{content}"><strong>{day}</strong></a>', - 'cal_cell_no_content' => '{day}', - 'cal_cell_no_content_today' => '<strong>{day}</strong>', - 'cal_cell_blank' => ' ', - 'cal_cell_end' => '</td>', - 'cal_cell_end_today' => '</td>', - 'cal_row_end' => '</tr>', - 'table_close' => '</table>' - ); + return array( + 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">', + 'heading_row_start' => '<tr>', + 'heading_previous_cell' => '<th><a href="{previous_url}"><<</a></th>', + 'heading_title_cell' => '<th colspan="{colspan}">{heading}</th>', + 'heading_next_cell' => '<th><a href="{next_url}">>></a></th>', + 'heading_row_end' => '</tr>', + 'week_row_start' => '<tr>', + 'week_day_cell' => '<td>{week_day}</td>', + 'week_row_end' => '</tr>', + 'cal_row_start' => '<tr>', + 'cal_cell_start' => '<td>', + 'cal_cell_start_today' => '<td>', + 'cal_cell_content' => '<a href="{content}">{day}</a>', + 'cal_cell_content_today' => '<a href="{content}"><strong>{day}</strong></a>', + 'cal_cell_no_content' => '{day}', + 'cal_cell_no_content_today' => '<strong>{day}</strong>', + 'cal_cell_blank' => ' ', + 'cal_cell_end' => '</td>', + 'cal_cell_end_today' => '</td>', + 'cal_row_end' => '</tr>', + 'table_close' => '</table>' + ); } // -------------------------------------------------------------------- @@ -441,7 +483,7 @@ class CI_Calendar { { $this->temp = $this->default_template(); - if ($this->template == '') + if ($this->template === '') { return; } diff --git a/system/libraries/Cart.php b/system/libraries/Cart.php index ca7be555e..035a6a42b 100644 --- a/system/libraries/Cart.php +++ b/system/libraries/Cart.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Shopping Cart Class @@ -36,19 +37,54 @@ */ class CI_Cart { - // These are the regular expression rules that we use to validate the product ID and product name - public $product_id_rules = '\.a-z0-9_-'; // alpha-numeric, dashes, underscores, or periods - public $product_name_rules = '\.\:\-_ a-z0-9'; // alpha-numeric, dashes, underscores, colons or periods - public $product_name_safe = TRUE; // only allow safe product names + /** + * These are the regular expression rules that we use to validate the product ID and product name + * alpha-numeric, dashes, underscores, or periods + * + * @var string + */ + public $product_id_rules = '\.a-z0-9_-'; + + /** + * These are the regular expression rules that we use to validate the product ID and product name + * alpha-numeric, dashes, underscores, colons or periods + * + * @var string + */ + public $product_name_rules = '\.\:\-_ a-z0-9'; + /** + * only allow safe product names + * + * @var bool + */ + public $product_name_safe = TRUE; + + // -------------------------------------------------------------------------- // Protected variables. Do not change! + // -------------------------------------------------------------------------- + + /** + * Reference to CodeIgniter instance + * + * @var object + */ protected $CI; + + /** + * Contents of the cart + * + * @var array + */ protected $_cart_contents = array(); /** * Shopping Class Constructor * * The constructor loads the Session class, used to store the shopping cart contents. + * + * @param array + * @return void */ public function __construct($params = array()) { @@ -146,7 +182,7 @@ class CI_Cart { // -------------------------------------------------------------------- // Does the $items array contain an id, quantity, price, and name? These are required - if ( ! isset($items['id']) OR ! isset($items['qty']) OR ! isset($items['price']) OR ! isset($items['name'])) + if ( ! isset($items['id'], $items['qty'], $items['price'], $items['name'])) { log_message('error', 'The cart array must contain a product ID, quantity, price, and name.'); return FALSE; @@ -158,7 +194,7 @@ class CI_Cart { $items['qty'] = (float) $items['qty']; // If the quantity is zero or blank there's nothing for us to do - if ( ! is_numeric($items['qty']) OR $items['qty'] == 0) + if ($items['qty'] == 0) { return FALSE; } @@ -189,15 +225,6 @@ class CI_Cart { // Prep the price. Remove leading zeros and anything that isn't a number or decimal point. $items['price'] = (float) $items['price']; - // Is the price a valid number? - if ( ! is_numeric($items['price'])) - { - log_message('error', 'An invalid price was submitted for product ID: '.$items['id']); - return FALSE; - } - - // -------------------------------------------------------------------- - // We now need to create a unique identifier for the item being inserted into the cart. // Every time something is added to the cart it is stored in the master cart array. // Each row in the cart array, however, must have a unique index that identifies not only @@ -210,7 +237,7 @@ class CI_Cart { // This becomes the unique "row ID" if (isset($items['options']) && count($items['options']) > 0) { - $rowid = md5($items['id'].implode('', $items['options'])); + $rowid = md5($items['id'].serialize($items['options'])); } else { @@ -245,7 +272,6 @@ class CI_Cart { * product ID and quantity for each item. * * @param array - * @param string * @return bool */ public function update($items = array()) @@ -308,7 +334,7 @@ class CI_Cart { protected function _update($items = array()) { // Without these array indexes there is nothing we can do - if ( ! isset($items['qty']) OR ! isset($items['rowid']) OR ! isset($this->_cart_contents[$items['rowid']])) + if ( ! isset($items['qty'], $items['rowid'], $this->_cart_contents[$items['rowid']])) { return FALSE; } @@ -316,12 +342,6 @@ class CI_Cart { // Prep the quantity $items['qty'] = (float) $items['qty']; - // Is the quantity a number? - if ( ! is_numeric($items['qty'])) - { - return FALSE; - } - // Is the quantity zero? If so we will remove the item from the cart. // If the quantity is greater than zero we are updating if ($items['qty'] == 0) @@ -350,7 +370,7 @@ class CI_Cart { foreach ($this->_cart_contents as $key => $val) { // We make sure the array contains the proper indexes - if ( ! is_array($val) OR ! isset($val['price']) OR ! isset($val['qty'])) + if ( ! is_array($val) OR ! isset($val['price'], $val['qty'])) { continue; } @@ -360,7 +380,7 @@ class CI_Cart { $this->_cart_contents[$key]['subtotal'] = ($this->_cart_contents[$key]['price'] * $this->_cart_contents[$key]['qty']); } - // Is our cart empty? If so we delete it from the session + // Is our cart empty? If so we delete it from the session if (count($this->_cart_contents) <= 2) { $this->CI->session->unset_userdata('cart_contents'); @@ -396,6 +416,7 @@ class CI_Cart { * * Removes an item from the cart * + * @param int * @return bool */ public function remove($rowid) @@ -427,6 +448,7 @@ class CI_Cart { * * Returns the entire cart array * + * @param bool * @return array */ public function contents($newest_first = FALSE) @@ -444,16 +466,34 @@ class CI_Cart { // -------------------------------------------------------------------- /** + * Get cart item + * + * Returns the details of a specific item in the cart + * + * @param string $row_id + * @return array + */ + public function get_item($row_id) + { + return (in_array($row_id, array('total_items', 'cart_total'), TRUE) OR ! isset($this->_cart_contents[$row_id])) + ? FALSE + : $this->_cart_contents[$row_id]; + } + + // -------------------------------------------------------------------- + + /** * Has options * * Returns TRUE if the rowid passed to this function correlates to an item * that has options associated with it. * + * @param string $row_id = '' * @return bool */ - public function has_options($rowid = '') + public function has_options($row_id = '') { - return (isset($this->_cart_contents[$rowid]['options']) && count($this->_cart_contents[$rowid]['options']) !== 0) ? TRUE : FALSE; + return (isset($this->_cart_contents[$row_id]['options']) && count($this->_cart_contents[$row_id]['options']) !== 0); } // -------------------------------------------------------------------- @@ -463,12 +503,12 @@ class CI_Cart { * * Returns the an array of options, for a particular product row ID * - * @param int + * @param string $row_id = '' * @return array */ - public function product_options($rowid = '') + public function product_options($row_id = '') { - return isset($this->_cart_contents[$rowid]['options']) ? $this->_cart_contents[$rowid]['options'] : array(); + return isset($this->_cart_contents[$row_id]['options']) ? $this->_cart_contents[$row_id]['options'] : array(); } // -------------------------------------------------------------------- @@ -483,15 +523,7 @@ class CI_Cart { */ public function format_number($n = '') { - if ($n == '') - { - return ''; - } - - // Remove anything that isn't a number or decimal point. - $n = (float) $n; - - return number_format($n, 2, '.', ','); + return ($n === '') ? '' : number_format( (float) $n, 2, '.', ','); } // -------------------------------------------------------------------- diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php index f409f47d4..621d22631 100644 --- a/system/libraries/Driver.php +++ b/system/libraries/Driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Driver Library Class @@ -39,13 +40,45 @@ */ class CI_Driver_Library { - protected $valid_drivers = array(); - protected static $lib_name; + /** + * Array of drivers that are available to use with the driver class + * + * @var array + */ + protected $valid_drivers = array(); + + /** + * Name of the current class - usually the driver class + * + * @var string + */ + protected $lib_name; - // The first time a child is used it won't exist, so we instantiate it - // subsequents calls will go straight to the proper child. + /** + * Get magic method + * + * The first time a child is used it won't exist, so we instantiate it + * subsequents calls will go straight to the proper child. + * + * @param string Child class name + * @return object Child class + */ public function __get($child) { + // Try to load the driver + return $this->load_driver($child); + } + + /** + * Load driver + * + * Separate load_driver call to support explicit driver load by library or user + * + * @param string Child class name + * @return object Child class + */ + public function load_driver($child) + { if ( ! isset($this->lib_name)) { $this->lib_name = get_class($this); @@ -100,6 +133,8 @@ class CI_Driver_Library { } +// -------------------------------------------------------------------------- + /** * CodeIgniter Driver Class * @@ -114,11 +149,33 @@ class CI_Driver_Library { */ class CI_Driver { + /** + * Instance of the parent class + * + * @var object + */ protected $_parent; + /** + * List of methods in the parent class + * + * @var array + */ protected $_methods = array(); + + /** + * List of properties in the parent class + * + * @var array + */ protected $_properties = array(); + /** + * Array of methods and properties for the parent class(es) + * + * @static + * @var array + */ protected static $_reflections = array(); /** diff --git a/system/libraries/Email.php b/system/libraries/Email.php index 48c3bf3ab..92ccde60c 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Email Class @@ -38,74 +39,364 @@ */ class CI_Email { + /** + * Used as the User-Agent and X-Mailer headers' value. + * + * @var string + */ public $useragent = 'CodeIgniter'; + + /** + * Path to the Sendmail binary. + * + * @var string + */ public $mailpath = '/usr/sbin/sendmail'; // Sendmail path + + /** + * Which method to use for sending e-mails. + * + * @var string 'mail', 'sendmail' or 'smtp' + */ public $protocol = 'mail'; // mail/sendmail/smtp - public $smtp_host = ''; // SMTP Server. Example: mail.earthlink.net - public $smtp_user = ''; // SMTP Username - public $smtp_pass = ''; // SMTP Password - public $smtp_port = 25; // SMTP Port - public $smtp_timeout = 5; // SMTP Timeout in seconds - public $smtp_crypto = ''; // SMTP Encryption. Can be null, tls or ssl. - public $wordwrap = TRUE; // TRUE/FALSE Turns word-wrap on/off - public $wrapchars = 76; // Number of characters to wrap at. - public $mailtype = 'text'; // text/html Defines email formatting - public $charset = 'utf-8'; // Default char set: iso-8859-1 or us-ascii + + /** + * STMP Server host + * + * @var string + */ + public $smtp_host = ''; + + /** + * SMTP Username + * + * @var string + */ + public $smtp_user = ''; + + /** + * SMTP Password + * + * @var string + */ + public $smtp_pass = ''; + + /** + * SMTP Server port + * + * @var int + */ + public $smtp_port = 25; + + /** + * SMTP connection timeout in seconds + * + * @var int + */ + public $smtp_timeout = 5; + + /** + * SMTP Encryption + * + * @var string NULL, 'tls' or 'ssl' + */ + public $smtp_crypto = NULL; + + /** + * Whether to apply word-wrapping to the message body. + * + * @var bool + */ + public $wordwrap = TRUE; + + /** + * Number of characters to wrap at. + * + * @see CI_Email::$wordwrap + * @var int + */ + public $wrapchars = 76; + + /** + * Message format. + * + * @var string 'text' or 'html' + */ + public $mailtype = 'text'; + + /** + * Character set (default: utf-8) + * + * @var string + */ + public $charset = 'utf-8'; + + /** + * Multipart message + * + * @var string 'mixed' (in the body) or 'related' (separate) + */ public $multipart = 'mixed'; // "mixed" (in the body) or "related" (separate) - public $alt_message = ''; // Alternative message for HTML emails - public $validate = FALSE; // TRUE/FALSE. Enables email validation + + /** + * Alternative message (for HTML messages only) + * + * @var string + */ + public $alt_message = ''; + + /** + * Whether to validate e-mail addresses. + * + * @var bool + */ + public $validate = FALSE; + + /** + * X-Priority header value. + * + * @var int 1-5 + */ public $priority = 3; // Default priority (1 - 5) + + /** + * Newline character sequence. + * Use "\r\n" to comply with RFC 822. + * + * @link http://www.ietf.org/rfc/rfc822.txt + * @var string "\r\n" or "\n" + */ public $newline = "\n"; // Default newline. "\r\n" or "\n" (Use "\r\n" to comply with RFC 822) - public $crlf = "\n"; // The RFC 2045 compliant CRLF for quoted-printable is "\r\n". Apparently some servers, - // even on the receiving end think they need to muck with CRLFs, so using "\n", while - // distasteful, is the only thing that seems to work for all environments. - public $dsn = FALSE; // Delivery Status Notification - public $send_multipart = TRUE; // TRUE/FALSE - Yahoo does not like multipart alternative, so this is an override. Set to FALSE for Yahoo. - public $bcc_batch_mode = FALSE; // TRUE/FALSE - Turns on/off Bcc batch feature - public $bcc_batch_size = 200; // If bcc_batch_mode = TRUE, sets max number of Bccs in each batch + /** + * CRLF character sequence + * + * RFC 2045 specifies that for 'quoted-printable' encoding, + * "\r\n" must be used. However, it appears that some servers + * (even on the receiving end) don't handle it properly and + * switching to "\n", while improper, is the only solution + * that seems to work for all environments. + * + * @link http://www.ietf.org/rfc/rfc822.txt + * @var string + */ + public $crlf = "\n"; + + /** + * Whether to use Delivery Status Notification. + * + * @var bool + */ + public $dsn = FALSE; + + /** + * Whether to send multipart alternatives. + * Yahoo! doesn't seem to like these. + * + * @var bool + */ + public $send_multipart = TRUE; + + /** + * Whether to send messages to BCC recipients in batches. + * + * @var bool + */ + public $bcc_batch_mode = FALSE; + + /** + * BCC Batch max number size. + * + * @see CI_Email::$bcc_batch_mode + * @var int + */ + public $bcc_batch_size = 200; + + // -------------------------------------------------------------------- + + /** + * Whether PHP is running in safe mode. Initialized by the class constructor. + * + * @var bool + */ protected $_safe_mode = FALSE; + + /** + * Subject header + * + * @var string + */ protected $_subject = ''; + + /** + * Message body + * + * @var string + */ protected $_body = ''; + + /** + * Final message body to be sent. + * + * @var string + */ protected $_finalbody = ''; + + /** + * multipart/alternative boundary + * + * @var string + */ protected $_alt_boundary = ''; + + /** + * Attachment boundary + * + * @var string + */ protected $_atc_boundary = ''; + + /** + * Final headers to send + * + * @var string + */ protected $_header_str = ''; + + /** + * SMTP Connection socket placeholder + * + * @var resource + */ protected $_smtp_connect = ''; + + /** + * Mail encoding + * + * @var string '8bit' or '7bit' + */ protected $_encoding = '8bit'; - protected $_IP = FALSE; + + /** + * Whether to perform SMTP authentication + * + * @var bool + */ protected $_smtp_auth = FALSE; + + /** + * Whether to send a Reply-To header + * + * @var bool + */ protected $_replyto_flag = FALSE; + + /** + * Debug messages + * + * @see CI_Email::print_debugger() + * @var string + */ protected $_debug_msg = array(); + + /** + * Recipients + * + * @var string[] + */ protected $_recipients = array(); + + /** + * CC Recipients + * + * @var string[] + */ protected $_cc_array = array(); + + /** + * BCC Recipients + * + * @var string[] + */ protected $_bcc_array = array(); + + /** + * Message headers + * + * @var string[] + */ protected $_headers = array(); - protected $_attach_name = array(); - protected $_attach_type = array(); - protected $_attach_disp = array(); + + /** + * Attachment data + * + * @var array + */ + protected $_attachments = array(); + + /** + * Valid $protocol values + * + * @see CI_Email::$protocol + * @var string[] + */ protected $_protocols = array('mail', 'sendmail', 'smtp'); - protected $_base_charsets = array('us-ascii', 'iso-2022-'); // 7-bit charsets (excluding language suffix) + + /** + * Base charsets + * + * Character sets valid for 7-bit encoding, + * excluding language suffix. + * + * @var string[] + */ + protected $_base_charsets = array('us-ascii', 'iso-2022-'); + + /** + * Bit depths + * + * Valid mail encodings + * + * @see CI_Email::$_encoding + * @var string[] + */ protected $_bit_depths = array('7bit', '8bit'); + + /** + * $priority translations + * + * Actual values to send with the X-Priority header + * + * @var string[] + */ protected $_priorities = array('1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)'); + // -------------------------------------------------------------------- + /** * Constructor - Sets Email Preferences * * The constructor can be passed an array of config values + * + * @param array $config = array() + * @return void */ public function __construct($config = array()) { + $this->charset = config_item('charset'); + if (count($config) > 0) { $this->initialize($config); } else { - $this->_smtp_auth = ! ($this->smtp_user == '' && $this->smtp_pass == ''); + $this->_smtp_auth = ! ($this->smtp_user === '' && $this->smtp_pass === ''); $this->_safe_mode = (bool) @ini_get('safe_mode'); } + $this->charset = strtoupper($this->charset); + log_message('debug', 'Email Class Initialized'); } @@ -137,7 +428,7 @@ class CI_Email { } $this->clear(); - $this->_smtp_auth = ! ($this->smtp_user == '' && $this->smtp_pass == ''); + $this->_smtp_auth = ! ($this->smtp_user === '' && $this->smtp_pass === ''); $this->_safe_mode = (bool) @ini_get('safe_mode'); return $this; @@ -164,14 +455,12 @@ class CI_Email { $this->_headers = array(); $this->_debug_msg = array(); - $this->_set_header('User-Agent', $this->useragent); - $this->_set_header('Date', $this->_set_date()); + $this->set_header('User-Agent', $this->useragent); + $this->set_header('Date', $this->_set_date()); if ($clear_attachments !== FALSE) { - $this->_attach_name = array(); - $this->_attach_type = array(); - $this->_attach_disp = array(); + $this->_attachments = array(); } return $this; @@ -182,11 +471,12 @@ class CI_Email { /** * Set FROM * - * @param string - * @param string + * @param string $from + * @param string $name + * @param string $return_path = NULL Return-Path * @return object */ - public function from($from, $name = '') + public function from($from, $name = '', $return_path = NULL) { if (preg_match('/\<(.*)\>/', $from, $match)) { @@ -196,10 +486,14 @@ class CI_Email { if ($this->validate) { $this->validate_email($this->_str_to_array($from)); + if ($return_path) + { + $this->validate_email($this->_str_to_array($return_path)); + } } // prepare the display name - if ($name != '') + if ($name !== '') { // only use Q encoding if there are characters that would require it if ( ! preg_match('/[\200-\377]/', $name)) @@ -209,12 +503,14 @@ class CI_Email { } else { - $name = $this->_prep_q_encoding($name, TRUE); + $name = $this->_prep_q_encoding($name); } } - $this->_set_header('From', $name.' <'.$from.'>'); - $this->_set_header('Return-Path', '<'.$from.'>'); + $this->set_header('From', $name.' <'.$from.'>'); + + isset($return_path) OR $return_path = $from; + $this->set_header('Return-Path', '<'.$return_path.'>'); return $this; } @@ -240,17 +536,17 @@ class CI_Email { $this->validate_email($this->_str_to_array($replyto)); } - if ($name == '') + if ($name === '') { $name = $replyto; } - if (strncmp($name, '"', 1) !== 0) + if (strpos($name, '"') !== 0) { $name = '"'.$name.'"'; } - $this->_set_header('Reply-To', $name.' <'.$replyto.'>'); + $this->set_header('Reply-To', $name.' <'.$replyto.'>'); $this->_replyto_flag = TRUE; return $this; @@ -276,19 +572,10 @@ class CI_Email { if ($this->_get_protocol() !== 'mail') { - $this->_set_header('To', implode(', ', $to)); + $this->set_header('To', implode(', ', $to)); } - switch ($this->_get_protocol()) - { - case 'smtp': - $this->_recipients = $to; - break; - case 'sendmail': - case 'mail': - $this->_recipients = implode(', ', $to); - break; - } + $this->_recipients = $to; return $this; } @@ -303,15 +590,14 @@ class CI_Email { */ public function cc($cc) { - $cc = $this->_str_to_array($cc); - $cc = $this->clean_email($cc); + $cc = $this->clean_email($this->_str_to_array($cc)); if ($this->validate) { $this->validate_email($cc); } - $this->_set_header('Cc', implode(', ', $cc)); + $this->set_header('Cc', implode(', ', $cc)); if ($this->_get_protocol() === 'smtp') { @@ -332,14 +618,13 @@ class CI_Email { */ public function bcc($bcc, $limit = '') { - if ($limit != '' && is_numeric($limit)) + if ($limit !== '' && is_numeric($limit)) { $this->bcc_batch_mode = TRUE; $this->bcc_batch_size = $limit; } - $bcc = $this->_str_to_array($bcc); - $bcc = $this->clean_email($bcc); + $bcc = $this->clean_email($this->_str_to_array($bcc)); if ($this->validate) { @@ -352,7 +637,7 @@ class CI_Email { } else { - $this->_set_header('Bcc', implode(', ', $bcc)); + $this->set_header('Bcc', implode(', ', $bcc)); } return $this; @@ -369,7 +654,7 @@ class CI_Email { public function subject($subject) { $subject = $this->_prep_q_encoding($subject); - $this->_set_header('Subject', $subject); + $this->set_header('Subject', $subject); return $this; } @@ -404,14 +689,20 @@ class CI_Email { /** * Assign file attachments * - * @param string + * @param string $filename + * @param string $disposition = 'attachment' + * @param string $newname = NULL + * @param string $mime = '' * @return object */ public function attach($filename, $disposition = '', $newname = NULL, $mime = '') { - $this->_attach_name[] = array($filename, $newname); - $this->_attach_disp[] = empty($disposition) ? 'attachment' : $disposition; // Can also be 'inline' Not sure if it matters - $this->_attach_type[] = $mime; + $this->_attachments[] = array( + 'name' => array($filename, $newname), + 'disposition' => empty($disposition) ? 'attachment' : $disposition, // Can also be 'inline' Not sure if it matters + 'type' => $mime + ); + return $this; } @@ -424,7 +715,7 @@ class CI_Email { * @param string * @return void */ - protected function _set_header($header, $value) + public function set_header($header, $value) { $this->_headers[$header] = $value; } @@ -441,15 +732,11 @@ class CI_Email { { if ( ! is_array($email)) { - if (strpos($email, ',') !== FALSE) - { - $email = preg_split('/[\s,]/', $email, -1, PREG_SPLIT_NO_EMPTY); - } - else - { - $email = (array) trim($email); - } + return (strpos($email, ',') !== FALSE) + ? preg_split('/[\s,]/', $email, -1, PREG_SPLIT_NO_EMPTY) + : (array) trim($email); } + return $email; } @@ -477,7 +764,7 @@ class CI_Email { */ public function set_mailtype($type = 'text') { - $this->mailtype = ($type == 'html') ? 'html' : 'text'; + $this->mailtype = ($type === 'html') ? 'html' : 'text'; return $this; } @@ -574,7 +861,7 @@ class CI_Email { protected function _get_message_id() { $from = str_replace(array('>', '<'), '', $this->_headers['Return-Path']); - return '<'.uniqid('').strstr($from, '@').'>'; + return '<'.uniqid('').strstr($from, '@').'>'; } // -------------------------------------------------------------------- @@ -590,7 +877,7 @@ class CI_Email { $this->protocol = strtolower($this->protocol); in_array($this->protocol, $this->_protocols, TRUE) OR $this->protocol = 'mail'; - if ($return == TRUE) + if ($return === TRUE) { return $this->protocol; } @@ -610,13 +897,13 @@ class CI_Email { foreach ($this->_base_charsets as $charset) { - if (strncmp($charset, $this->charset, strlen($charset)) === 0) + if (strpos($charset, $this->charset) === 0) { $this->_encoding = '7bit'; } } - if ($return == TRUE) + if ($return === TRUE) { return $this->_encoding; } @@ -631,15 +918,11 @@ class CI_Email { */ protected function _get_content_type() { - if ($this->mailtype === 'html' && count($this->_attach_name) === 0) + if ($this->mailtype === 'html') { - return 'html'; + return (count($this->_attachments) === 0) ? 'html' : 'html-attach'; } - elseif ($this->mailtype === 'html' && count($this->_attach_name) > 0) - { - return 'html-attach'; - } - elseif ($this->mailtype === 'text' && count($this->_attach_name) > 0) + elseif ($this->mailtype === 'text' && count($this->_attachments) > 0) { return 'plain-attach'; } @@ -659,7 +942,7 @@ class CI_Email { protected function _set_date() { $timezone = date('Z'); - $operator = (strncmp($timezone, '-', 1) === 0) ? '-' : '+'; + $operator = ($timezone[0] === '-') ? '-' : '+'; $timezone = abs($timezone); $timezone = floor($timezone/3600) * 100 + ($timezone % 3600) / 60; @@ -714,9 +997,9 @@ class CI_Email { * @param string * @return bool */ - public function valid_email($address) + public function valid_email($email) { - return (bool) preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix', $address); + return (bool) filter_var($email, FILTER_VALIDATE_EMAIL); } // -------------------------------------------------------------------- @@ -731,7 +1014,7 @@ class CI_Email { { if ( ! is_array($email)) { - return (preg_match('/\<(.*)\>/', $email, $match)) ? $match[1] : $email; + return preg_match('/\<(.*)\>/', $email, $match) ? $match[1] : $email; } $clean_email = array(); @@ -749,8 +1032,8 @@ class CI_Email { /** * Build alternative plain text message * - * This public function provides the raw message for use - * in plain-text headers of HTML-formatted emails. + * Provides the raw message for use in plain-text headers of + * HTML-formatted emails. * If the user hasn't specified his own alternative message * it creates one by stripping the HTML * @@ -758,12 +1041,14 @@ class CI_Email { */ protected function _get_alt_message() { - if ($this->alt_message != '') + if ( ! empty($this->alt_message)) { - return $this->word_wrap($this->alt_message, '76'); + return ($this->wordwrap) + ? $this->word_wrap($this->alt_message, 76) + : $this->alt_message; } - $body = (preg_match('/\<body.*?\>(.*)\<\/body\>/si', $this->_body, $match)) ? $match[1] : $this->_body; + $body = preg_match('/\<body.*?\>(.*)\<\/body\>/si', $this->_body, $match) ? $match[1] : $this->_body; $body = str_replace("\t", '', preg_replace('#<!--(.*)--\>#', '', trim(strip_tags($body)))); for ($i = 20; $i >= 3; $i--) @@ -771,7 +1056,12 @@ class CI_Email { $body = str_replace(str_repeat("\n", $i), "\n\n", $body); } - return $this->word_wrap($body, 76); + // Reduce multiple spaces + $body = preg_replace('| +|', ' ', $body); + + return ($this->wordwrap) + ? $this->word_wrap($body, 76) + : $body; } // -------------------------------------------------------------------- @@ -780,45 +1070,45 @@ class CI_Email { * Word Wrap * * @param string - * @param int + * @param int line-length limit * @return string */ - public function word_wrap($str, $charlim = '') + public function word_wrap($str, $charlim = NULL) { - // Se the character limit - if ($charlim == '') + // Set the character limit, if not already present + if (empty($charlim)) { - $charlim = ($this->wrapchars == "") ? 76 : $this->wrapchars; + $charlim = empty($this->wrapchars) ? 76 : $this->wrapchars; } - // Reduce multiple spaces - $str = preg_replace("| +|", " ", $str); - // Standardize newlines if (strpos($str, "\r") !== FALSE) { $str = str_replace(array("\r\n", "\r"), "\n", $str); } + // Reduce multiple spaces at end of line + $str = preg_replace('| +\n|', "\n", $str); + // If the current word is surrounded by {unwrap} tags we'll // strip the entire chunk and replace it with a marker. $unwrap = array(); - if (preg_match_all("|(\{unwrap\}.+?\{/unwrap\})|s", $str, $matches)) + if (preg_match_all('|(\{unwrap\}.+?\{/unwrap\})|s', $str, $matches)) { for ($i = 0, $c = count($matches[0]); $i < $c; $i++) { $unwrap[] = $matches[1][$i]; - $str = str_replace($matches[1][$i], "{{unwrapped".$i."}}", $str); + $str = str_replace($matches[1][$i], '{{unwrapped'.$i.'}}', $str); } } // Use PHP's native public function to do the initial wordwrap. // We set the cut flag to FALSE so that any individual words that are - // too long get left alone. In the next step we'll deal with them. + // too long get left alone. In the next step we'll deal with them. $str = wordwrap($str, $charlim, "\n", FALSE); // Split the string into individual lines of text and cycle through them - $output = ""; + $output = ''; foreach (explode("\n", $str) as $line) { // Is the line within the allowed character count? @@ -833,7 +1123,7 @@ class CI_Email { do { // If the over-length word is a URL we won't wrap it - if (preg_match("!\[url.+\]|://|wwww.!", $line)) + if (preg_match('!\[url.+\]|://|wwww.!', $line)) { break; } @@ -846,7 +1136,7 @@ class CI_Email { // If $temp contains data it means we had to split up an over-length // word into smaller chunks so we'll add it back to our current line - if ($temp != '') + if ($temp !== '') { $output .= $temp.$this->newline; } @@ -859,7 +1149,7 @@ class CI_Email { { foreach ($unwrap as $key => $val) { - $output = str_replace("{{unwrapped".$key."}}", $val, $output); + $output = str_replace('{{unwrapped'.$key.'}}', $val, $output); } } @@ -875,11 +1165,11 @@ class CI_Email { */ protected function _build_headers() { - $this->_set_header('X-Sender', $this->clean_email($this->_headers['From'])); - $this->_set_header('X-Mailer', $this->useragent); - $this->_set_header('X-Priority', $this->_priorities[$this->priority - 1]); - $this->_set_header('Message-ID', $this->_get_message_id()); - $this->_set_header('Mime-Version', '1.0'); + $this->set_header('X-Sender', $this->clean_email($this->_headers['From'])); + $this->set_header('X-Mailer', $this->useragent); + $this->set_header('X-Priority', $this->_priorities[$this->priority - 1]); + $this->set_header('Message-ID', $this->_get_message_id()); + $this->set_header('Mime-Version', '1.0'); } // -------------------------------------------------------------------- @@ -898,15 +1188,15 @@ class CI_Email { } reset($this->_headers); - $this->_header_str = ""; + $this->_header_str = ''; foreach ($this->_headers as $key => $val) { $val = trim($val); - if ($val != "") + if ($val !== '') { - $this->_header_str .= $key.": ".$val.$this->newline; + $this->_header_str .= $key.': '.$val.$this->newline; } } @@ -940,8 +1230,8 @@ class CI_Email { { case 'plain' : - $hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline - . "Content-Transfer-Encoding: " . $this->_get_encoding(); + $hdr .= 'Content-Type: text/plain; charset='.$this->charset.$this->newline + .'Content-Transfer-Encoding: '.$this->_get_encoding(); if ($this->_get_protocol() === 'mail') { @@ -959,26 +1249,25 @@ class CI_Email { if ($this->send_multipart === FALSE) { - $hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline - . "Content-Transfer-Encoding: quoted-printable"; + $hdr .= 'Content-Type: text/html; charset='.$this->charset.$this->newline + .'Content-Transfer-Encoding: quoted-printable'; } else { - $hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline . $this->newline; + $hdr .= 'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"'.$this->newline.$this->newline; - $body .= $this->_get_mime_message() . $this->newline . $this->newline - . "--" . $this->_alt_boundary . $this->newline + $body .= $this->_get_mime_message().$this->newline.$this->newline + .'--'.$this->_alt_boundary.$this->newline - . "Content-Type: text/plain; charset=" . $this->charset . $this->newline - . "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline - . $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline + .'Content-Type: text/plain; charset='.$this->charset.$this->newline + .'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline + .$this->_get_alt_message().$this->newline.$this->newline.'--'.$this->_alt_boundary.$this->newline - . "Content-Type: text/html; charset=" . $this->charset . $this->newline - . "Content-Transfer-Encoding: quoted-printable" . $this->newline . $this->newline; + .'Content-Type: text/html; charset='.$this->charset.$this->newline + .'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline; } - $this->_finalbody = $body . $this->_prep_quoted_printable($this->_body) . $this->newline . $this->newline; - + $this->_finalbody = $body.$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline; if ($this->_get_protocol() === 'mail') { @@ -986,72 +1275,72 @@ class CI_Email { } else { - $this->_finalbody = $hdr . $this->_finalbody; + $this->_finalbody = $hdr.$this->_finalbody; } - if ($this->send_multipart !== FALSE) { - $this->_finalbody .= "--" . $this->_alt_boundary . "--"; + $this->_finalbody .= '--'.$this->_alt_boundary.'--'; } return; case 'plain-attach' : - $hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline . $this->newline; + $hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"'.$this->newline.$this->newline; if ($this->_get_protocol() === 'mail') { $this->_header_str .= $hdr; } - $body .= $this->_get_mime_message() . $this->newline . $this->newline - . "--" . $this->_atc_boundary . $this->newline + $body .= $this->_get_mime_message().$this->newline.$this->newline + .'--'.$this->_atc_boundary.$this->newline - . "Content-Type: text/plain; charset=" . $this->charset . $this->newline - . "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline + .'Content-Type: text/plain; charset='.$this->charset.$this->newline + .'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline - . $this->_body . $this->newline . $this->newline; + .$this->_body.$this->newline.$this->newline; break; case 'html-attach' : - $hdr .= "Content-Type: multipart/".$this->multipart."; boundary=\"" . $this->_atc_boundary."\"" . $this->newline . $this->newline; + $hdr .= 'Content-Type: multipart/'.$this->multipart.'; boundary="'.$this->_atc_boundary.'"'.$this->newline.$this->newline; if ($this->_get_protocol() === 'mail') { $this->_header_str .= $hdr; } - $body .= $this->_get_mime_message() . $this->newline . $this->newline - . "--" . $this->_atc_boundary . $this->newline + $body .= $this->_get_mime_message().$this->newline.$this->newline + .'--'.$this->_atc_boundary.$this->newline - . "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline .$this->newline - . "--" . $this->_alt_boundary . $this->newline + .'Content-Type: multipart/alternative; boundary="'.$this->_alt_boundary.'"'.$this->newline.$this->newline + .'--'.$this->_alt_boundary.$this->newline - . "Content-Type: text/plain; charset=" . $this->charset . $this->newline - . "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline - . $this->_get_alt_message() . $this->newline . $this->newline . "--" . $this->_alt_boundary . $this->newline + .'Content-Type: text/plain; charset='.$this->charset.$this->newline + .'Content-Transfer-Encoding: '.$this->_get_encoding().$this->newline.$this->newline + .$this->_get_alt_message().$this->newline.$this->newline.'--'.$this->_alt_boundary.$this->newline - . "Content-Type: text/html; charset=" . $this->charset . $this->newline - . "Content-Transfer-Encoding: quoted-printable" . $this->newline . $this->newline + .'Content-Type: text/html; charset='.$this->charset.$this->newline + .'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline - . $this->_prep_quoted_printable($this->_body) . $this->newline . $this->newline - . "--" . $this->_alt_boundary . "--" . $this->newline . $this->newline; + .$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline + .'--'.$this->_alt_boundary.'--'.$this->newline.$this->newline; break; } $attachment = array(); - for ($i = 0, $c = count($this->_attach_name), $z = 0; $i < $c; $i++) + for ($i = 0, $c = count($this->_attachments), $z = 0; $i < $c; $i++) { - $filename = $this->_attach_name[$i][0]; - $basename = (is_null($this->_attach_name[$i][1])) ? basename($filename) : $this->_attach_name[$i][1]; - $ctype = $this->_attach_type[$i]; + $filename = $this->_attachments[$i]['name'][0]; + $basename = is_null($this->_attachments[$i]['name'][1]) + ? basename($filename) : $this->_attachments[$i]['name'][1]; + $ctype = $this->_attachments[$i]['type']; $file_content = ''; - if ($this->_attach_type[$i] == '') + if ($ctype === '') { if ( ! file_exists($filename)) { @@ -1073,19 +1362,20 @@ class CI_Email { } else { - $file_content =& $this->_attach_content[$i]; + $file_content =& $this->_attachments[$i]['name'][0]; } - $attachment[$z++] = "--".$this->_atc_boundary.$this->newline - . "Content-type: ".$ctype."; " - . "name=\"".$basename."\"".$this->newline - . "Content-Disposition: ".$this->_attach_disp[$i].";".$this->newline - . "Content-Transfer-Encoding: base64".$this->newline; + + $attachment[$z++] = '--'.$this->_atc_boundary.$this->newline + .'Content-type: '.$ctype.'; ' + .'name="'.$basename.'"'.$this->newline + .'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline + .'Content-Transfer-Encoding: base64'.$this->newline; $attachment[$z++] = chunk_split(base64_encode($file_content)); } - $body .= implode($this->newline, $attachment).$this->newline."--".$this->_atc_boundary."--"; - $this->_finalbody = ($this->_get_protocol() === 'mail') ? $body : $hdr . $body; + $body .= implode($this->newline, $attachment).$this->newline.'--'.$this->_atc_boundary.'--'; + $this->_finalbody = ($this->_get_protocol() === 'mail') ? $body : $hdr.$body; return; } @@ -1098,21 +1388,32 @@ class CI_Email { * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt * * @param string - * @param int * @return string */ - protected function _prep_quoted_printable($str, $charlim = '') + protected function _prep_quoted_printable($str) { - // Set the character limit - // Don't allow over 76, as that will make servers and MUAs barf - // all over quoted-printable data - if ($charlim == '' OR $charlim > 76) + // We are intentionally wrapping so mail servers will encode characters + // properly and MUAs will behave, so {unwrap} must go! + $str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str); + + // RFC 2045 specifies CRLF as "\r\n". + // However, many developers choose to override that and violate + // the RFC rules due to (apparently) a bug in MS Exchange, + // which only works with "\n". + if ($this->crlf === "\r\n") { - $charlim = 76; + if (is_php('5.3')) + { + return quoted_printable_encode($str); + } + elseif (function_exists('imap_8bit')) + { + return imap_8bit($str); + } } // Reduce multiple spaces & remove nulls - $str = preg_replace(array("| +|", '/\x00+/'), array(' ', ''), $str); + $str = preg_replace(array('| +|', '/\x00+/'), array(' ', ''), $str); // Standardize newlines if (strpos($str, "\r") !== FALSE) @@ -1120,10 +1421,6 @@ class CI_Email { $str = str_replace(array("\r\n", "\r"), "\n", $str); } - // We are intentionally wrapping so mail servers will encode characters - // properly and MUAs will behave, so {unwrap} must go! - $str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str); - $escape = '='; $output = ''; @@ -1153,7 +1450,7 @@ class CI_Email { // If we're at the character limit, add the line to the output, // reset our temp variable, and keep on chuggin' - if ((strlen($temp) + strlen($char)) >= $charlim) + if ((strlen($temp) + strlen($char)) >= 76) { $output .= $temp.$escape.$this->crlf; $temp = ''; @@ -1176,68 +1473,75 @@ class CI_Email { /** * Prep Q Encoding * - * Performs "Q Encoding" on a string for use in email headers. It's related - * but not identical to quoted-printable, so it has its own method + * Performs "Q Encoding" on a string for use in email headers. + * It's related but not identical to quoted-printable, so it has its + * own method. * * @param string - * @param bool set to TRUE for processing From: headers * @return string */ - protected function _prep_q_encoding($str, $from = FALSE) + protected function _prep_q_encoding($str) { - $str = str_replace(array("\r", "\n"), array('', ''), $str); - - // Line length must not exceed 76 characters, so we adjust for - // a space, 7 extra characters =??Q??=, and the charset that we will add to each line - $limit = 75 - 7 - strlen($this->charset); - - // these special characters must be converted too - $convert = array('_', '=', '?'); + $str = str_replace(array("\r", "\n"), '', $str); - if ($from === TRUE) + if ($this->charset === 'UTF-8') { - $convert[] = ','; - $convert[] = ';'; + if (MB_ENABLED === TRUE) + { + return mb_encode_mimeheader($str, $this->charset, 'Q', $this->crlf); + } + elseif (extension_loaded('iconv')) + { + $output = @iconv_mime_encode('', $str, + array( + 'scheme' => 'Q', + 'line-length' => 76, + 'input-charset' => $this->charset, + 'output-charset' => $this->charset, + 'line-break-chars' => $this->crlf + ) + ); + + // There are reports that iconv_mime_encode() might fail and return FALSE + if ($output !== FALSE) + { + // iconv_mime_encode() will always put a header field name. + // We've passed it an empty one, but it still prepends our + // encoded string with ': ', so we need to strip it. + return substr($output, 2); + } + + $chars = iconv_strlen($str, 'UTF-8'); + } } - $output = ''; - $temp = ''; + // We might already have this set for UTF-8 + isset($chars) OR $chars = strlen($str); - for ($i = 0, $length = strlen($str); $i < $length; $i++) + $output = '=?'.$this->charset.'?Q?'; + for ($i = 0, $length = strlen($output), $iconv = extension_loaded('iconv'); $i < $chars; $i++) { - // Grab the next character - $char = $str[$i]; - $ascii = ord($char); + $chr = ($this->charset === 'UTF-8' && $iconv === TRUE) + ? '='.implode('=', str_split(strtoupper(bin2hex(iconv_substr($str, $i, 1, $this->charset))), 2)) + : '='.strtoupper(bin2hex($str[$i])); - // convert ALL non-printable ASCII characters and our specials - if ($ascii < 32 OR $ascii > 126 OR in_array($char, $convert)) + // RFC 2045 sets a limit of 76 characters per line. + // We'll append ?= to the end of each line though. + if ($length + ($l = strlen($chr)) > 74) { - $char = '='.dechex($ascii); + $output .= '?='.$this->crlf // EOL + .' =?'.$this->charset.'?Q?'.$chr; // New line + $length = 6 + strlen($this->charset) + $l; // Reset the length for the new line } - - // handle regular spaces a bit more compactly than =20 - if ($ascii === 32) - { - $char = '_'; - } - - // If we're at the character limit, add the line to the output, - // reset our temp variable, and keep on chuggin' - if ((strlen($temp) + strlen($char)) >= $limit) + else { - $output .= $temp.$this->crlf; - $temp = ''; + $output .= $chr; + $length += $l; } - - // Add the character to our temporary line - $temp .= $char; } - $str = $output.$temp; - - // wrap each line with the shebang, charset, and transfer encoding - // the preceding space on successive lines is required for header "folding" - return trim(preg_replace('/^(.*)$/m', ' =?'.$this->charset.'?Q?$1?=', $str)); + // End the header + return $output.'?='; } // -------------------------------------------------------------------- @@ -1245,11 +1549,12 @@ class CI_Email { /** * Send Email * + * @param bool $auto_clear = TRUE * @return bool */ - public function send() + public function send($auto_clear = TRUE) { - if ($this->_replyto_flag == FALSE) + if ($this->_replyto_flag === FALSE) { $this->reply_to($this->_headers['From']); } @@ -1266,11 +1571,25 @@ class CI_Email { if ($this->bcc_batch_mode && count($this->_bcc_array) > $this->bcc_batch_size) { - return $this->batch_bcc_send(); + $result = $this->batch_bcc_send(); + + if ($result && $auto_clear) + { + $this->clear(); + } + + return $result; } $this->_build_message(); - return $this->_spool_email(); + $result = $this->_spool_email(); + + if ($result && $auto_clear) + { + $this->clear(); + } + + return $result; } // -------------------------------------------------------------------- @@ -1293,7 +1612,7 @@ class CI_Email { $set .= ', '.$this->_bcc_array[$i]; } - if ($i == $float) + if ($i === $float) { $chunk[] = substr($set, 1); $float += $this->bcc_batch_size; @@ -1314,7 +1633,7 @@ class CI_Email { if ($this->protocol !== 'smtp') { - $this->_set_header('Bcc', implode(', ', $bcc)); + $this->set_header('Bcc', implode(', ', $bcc)); } else { @@ -1335,7 +1654,7 @@ class CI_Email { */ protected function _unwrap_specials() { - $this->_finalbody = preg_replace_callback("/\{unwrap\}(.*?)\{\/unwrap\}/si", array($this, '_remove_nl_callback'), $this->_finalbody); + $this->_finalbody = preg_replace_callback('/\{unwrap\}(.*?)\{\/unwrap\}/si', array($this, '_remove_nl_callback'), $this->_finalbody); } // -------------------------------------------------------------------- @@ -1343,6 +1662,7 @@ class CI_Email { /** * Strip line-breaks via callback * + * @param string $matches * @return string */ protected function _remove_nl_callback($matches) @@ -1366,10 +1686,10 @@ class CI_Email { { $this->_unwrap_specials(); - $method = '_send_with_' . $this->_get_protocol(); + $method = '_send_with_'.$this->_get_protocol(); if ( ! $this->$method()) { - $this->_set_error_message('lang:email_send_failure_' . ($this->_get_protocol() === 'mail' ? 'phpmail' : $this->_get_protocol())); + $this->_set_error_message('lang:email_send_failure_'.($this->_get_protocol() === 'mail' ? 'phpmail' : $this->_get_protocol())); return FALSE; } @@ -1386,7 +1706,12 @@ class CI_Email { */ protected function _send_with_mail() { - if ($this->_safe_mode == TRUE) + if (is_array($this->_recipients)) + { + $this->_recipients = implode(', ', $this->_recipients); + } + + if ($this->_safe_mode === TRUE) { return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str); } @@ -1394,7 +1719,7 @@ class CI_Email { { // most documentation of sendmail using the "-f" flag lacks a space after it, however // we've encountered servers that seem to require it to be in place. - return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, "-f ".$this->clean_email($this->_headers['From'])); + return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$this->clean_email($this->_headers['Return-Path'])); } } @@ -1407,11 +1732,14 @@ class CI_Email { */ protected function _send_with_sendmail() { - $fp = @popen($this->mailpath . " -oi -f ".$this->clean_email($this->_headers['From'])." -t", 'w'); - - if ($fp === FALSE OR $fp === NULL) + // is popen() enabled? + if ( ! function_usable('popen') + OR FALSE === ($fp = @popen( + $this->mailpath.' -oi -f '.$this->clean_email($this->_headers['From']) + .' -t -r '.$this->clean_email($this->_headers['Return-Path']) + , 'w')) + ) // server probably has popen disabled, so nothing we can do to get a verbose error. { - // server probably has popen disabled, so nothing we can do to get a verbose error. return FALSE; } @@ -1439,7 +1767,7 @@ class CI_Email { */ protected function _send_with_smtp() { - if ($this->smtp_host == '') + if ($this->smtp_host === '') { $this->_set_error_message('lang:email_no_hostname'); return FALSE; @@ -1461,7 +1789,7 @@ class CI_Email { { foreach ($this->_cc_array as $val) { - if ($val != "") + if ($val !== '') { $this->_send_command('to', $val); } @@ -1472,7 +1800,7 @@ class CI_Email { { foreach ($this->_bcc_array as $val) { - if ($val != "") + if ($val !== '') { $this->_send_command('to', $val); } @@ -1482,7 +1810,7 @@ class CI_Email { $this->_send_command('data'); // perform dot transformation on any lines that begin with a dot - $this->_send_data($this->_header_str . preg_replace('/^\./m', '..$1', $this->_finalbody)); + $this->_send_data($this->_header_str.preg_replace('/^\./m', '..$1', $this->_finalbody)); $this->_send_data('.'); @@ -1490,7 +1818,7 @@ class CI_Email { $this->_set_error_message($reply); - if (strncmp($reply, '250', 3) !== 0) + if (strpos($reply, '250') !== 0) { $this->_set_error_message('lang:email_smtp_error', $reply); return FALSE; @@ -1505,28 +1833,27 @@ class CI_Email { /** * SMTP Connect * - * @param string * @return string */ protected function _smtp_connect() { - $ssl = ($this->smtp_crypto == 'ssl') ? 'ssl://' : NULL; + $ssl = ($this->smtp_crypto === 'ssl') ? 'ssl://' : NULL; $this->_smtp_connect = fsockopen($ssl.$this->smtp_host, - $this->smtp_port, - $errno, - $errstr, - $this->smtp_timeout); + $this->smtp_port, + $errno, + $errstr, + $this->smtp_timeout); if ( ! is_resource($this->_smtp_connect)) { - $this->_set_error_message('lang:email_smtp_error', $errno." ".$errstr); + $this->_set_error_message('lang:email_smtp_error', $errno.' '.$errstr); return FALSE; } $this->_set_error_message($this->_get_smtp_data()); - if ($this->smtp_crypto == 'tls') + if ($this->smtp_crypto === 'tls') { $this->_send_command('hello'); $this->_send_command('starttls'); @@ -1558,27 +1885,29 @@ class CI_Email { { case 'hello' : - if ($this->_smtp_auth OR $this->_get_encoding() == '8bit') - $this->_send_data('EHLO '.$this->_get_hostname()); - else - $this->_send_data('HELO '.$this->_get_hostname()); + if ($this->_smtp_auth OR $this->_get_encoding() === '8bit') + { + $this->_send_data('EHLO '.$this->_get_hostname()); + } + else + { + $this->_send_data('HELO '.$this->_get_hostname()); + } $resp = 250; break; case 'starttls' : $this->_send_data('STARTTLS'); - $resp = 220; break; case 'from' : $this->_send_data('MAIL FROM:<'.$data.'>'); - $resp = 250; break; - case 'to' : - + case 'to' : + if ($this->dsn) { $this->_send_data('RCPT TO:<'.$data.'> NOTIFY=SUCCESS,DELAY,FAILURE ORCPT=rfc822;'.$data); @@ -1587,33 +1916,32 @@ class CI_Email { { $this->_send_data('RCPT TO:<'.$data.'>'); } + $resp = 250; break; case 'data' : $this->_send_data('DATA'); - $resp = 354; break; case 'quit' : $this->_send_data('QUIT'); - $resp = 221; break; } $reply = $this->_get_smtp_data(); - $this->_debug_msg[] = "<pre>".$cmd.": ".$reply."</pre>"; + $this->_debug_msg[] = '<pre>'.$cmd.': '.$reply.'</pre>'; - if (substr($reply, 0, 3) != $resp) + if ((int) substr($reply, 0, 3) !== $resp) { $this->_set_error_message('lang:email_smtp_error', $reply); return FALSE; } - if ($cmd == 'quit') + if ($cmd === 'quit') { fclose($this->_smtp_connect); } @@ -1624,7 +1952,7 @@ class CI_Email { // -------------------------------------------------------------------- /** - * SMTP Authenticate + * SMTP Authenticate * * @return bool */ @@ -1635,7 +1963,7 @@ class CI_Email { return TRUE; } - if ($this->smtp_user == '' && $this->smtp_pass == '') + if ($this->smtp_user === '' && $this->smtp_pass === '') { $this->_set_error_message('lang:email_no_smtp_unpw'); return FALSE; @@ -1645,7 +1973,7 @@ class CI_Email { $reply = $this->_get_smtp_data(); - if (strncmp($reply, '334', 3) !== 0) + if (strpos($reply, '334') !== 0) { $this->_set_error_message('lang:email_failed_smtp_login', $reply); return FALSE; @@ -1655,7 +1983,7 @@ class CI_Email { $reply = $this->_get_smtp_data(); - if (strncmp($reply, '334', 3) !== 0) + if (strpos($reply, '334') !== 0) { $this->_set_error_message('lang:email_smtp_auth_un', $reply); return FALSE; @@ -1665,7 +1993,7 @@ class CI_Email { $reply = $this->_get_smtp_data(); - if (strncmp($reply, '235', 3) !== 0) + if (strpos($reply, '235') !== 0) { $this->_set_error_message('lang:email_smtp_auth_pw', $reply); return FALSE; @@ -1679,11 +2007,12 @@ class CI_Email { /** * Send SMTP data * + * @param string $data * @return bool */ protected function _send_data($data) { - if ( ! fwrite($this->_smtp_connect, $data . $this->newline)) + if ( ! fwrite($this->_smtp_connect, $data.$this->newline)) { $this->_set_error_message('lang:email_smtp_data_failure', $data); return FALSE; @@ -1701,13 +2030,13 @@ class CI_Email { */ protected function _get_smtp_data() { - $data = ""; + $data = ''; while ($str = fgets($this->_smtp_connect, 512)) { $data .= $str; - if ($str[3] == " ") + if ($str[3] === ' ') { break; } @@ -1731,47 +2060,6 @@ class CI_Email { // -------------------------------------------------------------------- /** - * Get IP - * - * @return string - */ - protected function _get_ip() - { - if ($this->_IP !== FALSE) - { - return $this->_IP; - } - - $cip = ( ! empty($_SERVER['HTTP_CLIENT_IP'])) ? $_SERVER['HTTP_CLIENT_IP'] : FALSE; - $rip = ( ! empty($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : FALSE; - if ($cip) $this->_IP = $cip; - elseif ($rip) $this->_IP = $rip; - else - { - $fip = ( ! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE; - if ($fip) - { - $this->_IP = $fip; - } - } - - if (strpos($this->_IP, ',') !== FALSE) - { - $x = explode(',', $this->_IP); - $this->_IP = end($x); - } - - if ( ! preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $this->_IP)) - { - $this->_IP = '0.0.0.0'; - } - - return $this->_IP; - } - - // -------------------------------------------------------------------- - - /** * Get Debug Message * * @return string @@ -1796,7 +2084,8 @@ class CI_Email { /** * Set Message * - * @param string + * @param string $msg + * @param string $val = '' * @return void */ protected function _set_error_message($msg, $val = '') @@ -1804,13 +2093,13 @@ class CI_Email { $CI =& get_instance(); $CI->lang->load('email'); - if (substr($msg, 0, 5) !== 'lang:' OR FALSE === ($line = $CI->lang->line(substr($msg, 5)))) + if (sscanf($msg, 'lang:%s', $line) !== 1 OR FALSE === ($line = $CI->lang->line($line))) { - $this->_debug_msg[] = str_replace('%s', $val, $msg)."<br />"; + $this->_debug_msg[] = str_replace('%s', $val, $msg).'<br />'; } else { - $this->_debug_msg[] = str_replace('%s', $val, $line)."<br />"; + $this->_debug_msg[] = str_replace('%s', $val, $line).'<br />'; } } @@ -1824,100 +2113,26 @@ class CI_Email { */ protected function _mime_types($ext = '') { - $mimes = array( - 'hqx' => 'application/mac-binhex40', - 'cpt' => 'application/mac-compactpro', - 'doc' => 'application/msword', - 'bin' => 'application/macbinary', - 'dms' => 'application/octet-stream', - 'lha' => 'application/octet-stream', - 'lzh' => 'application/octet-stream', - 'exe' => 'application/octet-stream', - 'class' => 'application/octet-stream', - 'psd' => 'application/octet-stream', - 'so' => 'application/octet-stream', - 'sea' => 'application/octet-stream', - 'dll' => 'application/octet-stream', - 'oda' => 'application/oda', - 'pdf' => 'application/pdf', - 'ai' => 'application/postscript', - 'eps' => 'application/postscript', - 'ps' => 'application/postscript', - 'smi' => 'application/smil', - 'smil' => 'application/smil', - 'mif' => 'application/vnd.mif', - 'xls' => 'application/vnd.ms-excel', - 'ppt' => 'application/vnd.ms-powerpoint', - 'wbxml' => 'application/vnd.wap.wbxml', - 'wmlc' => 'application/vnd.wap.wmlc', - 'dcr' => 'application/x-director', - 'dir' => 'application/x-director', - 'dxr' => 'application/x-director', - 'dvi' => 'application/x-dvi', - 'gtar' => 'application/x-gtar', - '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' => 'application/x-tar', - 'xhtml' => 'application/xhtml+xml', - 'xht' => 'application/xhtml+xml', - 'zip' => 'application/zip', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mpga' => 'audio/mpeg', - 'mp2' => 'audio/mpeg', - 'mp3' => 'audio/mpeg', - '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' => 'audio/x-wav', - 'bmp' => 'image/bmp', - 'gif' => 'image/gif', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'jpe' => 'image/jpeg', - 'png' => 'image/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' => 'text/plain', - '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', - 'word' => 'application/msword', - 'xl' => 'application/excel', - 'eml' => 'message/rfc822' - ); - - return isset($mimes[strtolower($ext)]) ? $mimes[strtolower($ext)] : 'application/x-unknown-content-type'; + static $mimes; + + $ext = strtolower($ext); + + if ( ! is_array($mimes)) + { + $mimes =& get_mimes(); + } + + if (isset($mimes[$ext])) + { + return is_array($mimes[$ext]) + ? current($mimes[$ext]) + : $mimes[$ext]; + } + + return 'application/x-unknown-content-type'; } } /* End of file Email.php */ -/* Location: ./system/libraries/Email.php */ +/* Location: ./system/libraries/Email.php */
\ No newline at end of file diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php index 54b5bf737..cdb0a6452 100644 --- a/system/libraries/Encrypt.php +++ b/system/libraries/Encrypt.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Encryption Class @@ -38,12 +39,46 @@ */ class CI_Encrypt { + /** + * Reference to the user's encryption key + * + * @var string + */ public $encryption_key = ''; + + /** + * Type of hash operation + * + * @var string + */ protected $_hash_type = 'sha1'; + + /** + * Flag for the existance of mcrypt + * + * @var bool + */ protected $_mcrypt_exists = FALSE; + + /** + * Current cipher to be used with mcrypt + * + * @var string + */ protected $_mcrypt_cipher; + + /** + * Method for encrypting/decrypting data + * + * @var int + */ protected $_mcrypt_mode; + /** + * Initialize Encryption class + * + * @return void + */ public function __construct() { $this->_mcrypt_exists = function_exists('mcrypt_encrypt'); @@ -63,15 +98,14 @@ class CI_Encrypt { */ public function get_key($key = '') { - if ($key == '') + if ($key === '') { - if ($this->encryption_key != '') + if ($this->encryption_key !== '') { return $this->encryption_key; } - $CI =& get_instance(); - $key = $CI->config->item('encryption_key'); + $key = config_item('encryption_key'); if ($key === FALSE) { @@ -132,7 +166,7 @@ class CI_Encrypt { */ public function decode($string, $key = '') { - if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string)) + if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string) OR base64_encode(base64_decode($string)) !== $string) { return FALSE; } @@ -180,6 +214,7 @@ class CI_Encrypt { $dec = base64_decode($string); if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE) { + $this->set_mode($current_mode); return FALSE; } @@ -349,7 +384,8 @@ class CI_Encrypt { * * Function description * - * @param string + * @param string $data + * @param string $key * @return string */ protected function _remove_cipher_noise($data, $key) @@ -414,7 +450,7 @@ class CI_Encrypt { */ protected function _get_cipher() { - if ($this->_mcrypt_cipher == '') + if ($this->_mcrypt_cipher === NULL) { return $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256; } @@ -431,7 +467,7 @@ class CI_Encrypt { */ protected function _get_mode() { - if ($this->_mcrypt_mode == '') + if ($this->_mcrypt_mode === NULL) { return $this->_mcrypt_mode = MCRYPT_MODE_CBC; } @@ -449,7 +485,7 @@ class CI_Encrypt { */ public function set_hash($type = 'sha1') { - $this->_hash_type = ($type !== 'sha1' && $type !== 'md5') ? 'sha1' : $type; + $this->_hash_type = in_array($type, hash_algos()) ? $type : 'sha1'; } // -------------------------------------------------------------------- @@ -462,7 +498,7 @@ class CI_Encrypt { */ public function hash($str) { - return ($this->_hash_type === 'sha1') ? sha1($str) : md5($str); + return hash($this->_hash_type, $str); } } diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php index 22bc7ddf3..b0ba8bbcb 100644 --- a/system/libraries/Form_validation.php +++ b/system/libraries/Form_validation.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Form Validation Class @@ -36,17 +37,82 @@ */ class CI_Form_validation { + /** + * Reference to the CodeIgniter instance + * + * @var object + */ protected $CI; + + /** + * Validation data for the current form submission + * + * @var array + */ protected $_field_data = array(); + + /** + * Validation rules for the current form + * + * @var array + */ protected $_config_rules = array(); + + /** + * Array of validation errors + * + * @var array + */ protected $_error_array = array(); + + /** + * Array of custom error messages + * + * @var array + */ protected $_error_messages = array(); + + /** + * Start tag for error wrapping + * + * @var string + */ protected $_error_prefix = '<p>'; + + /** + * End tag for error wrapping + * + * @var string + */ protected $_error_suffix = '</p>'; + + /** + * Custom error message + * + * @var string + */ protected $error_string = ''; + + /** + * Whether the form data has been validated as safe + * + * @var bool + */ protected $_safe_form_data = FALSE; + + /** + * Custom data to validate + * + * @var array + */ protected $validation_data = array(); + /** + * Initialize Form_Validation class + * + * @param array $rules + * @return void + */ public function __construct($rules = array()) { $this->CI =& get_instance(); @@ -69,12 +135,6 @@ class CI_Form_validation { // Automatically load the form helper $this->CI->load->helper('form'); - // Set the character encoding in MB. - if (MB_ENABLED === TRUE) - { - mb_internal_encoding($this->CI->config->item('charset')); - } - log_message('debug', 'Form Validation Class Initialized'); } @@ -86,8 +146,9 @@ class CI_Form_validation { * This function takes an array of field names and validation * rules as input, validates the info, and stores it * - * @param mixed - * @param string + * @param mixed $field + * @param string $label + * @param mixed $rules * @return object */ public function set_rules($field, $label = '', $rules = '') @@ -121,27 +182,31 @@ class CI_Form_validation { return $this; } + // Convert an array of rules to a string + if (is_array($rules)) + { + $rules = implode('|', $rules); + } + // No fields? Nothing to do... - if ( ! is_string($field) OR ! is_string($rules) OR $field == '') + if ( ! is_string($field) OR ! is_string($rules) OR $field === '') { return $this; } // If the field label wasn't passed we use the field name - $label = ($label == '') ? $field : $label; + $label = ($label === '') ? $field : $label; // Is the field name an array? If it is an array, we break it apart // into its components so that we can fetch the corresponding POST data later + $indexes = array(); if (preg_match_all('/\[(.*?)\]/', $field, $matches)) { - // Note: Due to a bug in current() that affects some versions - // of PHP we can not pass function call directly into it - $x = explode('[', $field); - $indexes[] = current($x); + sscanf($field, '%[^[][', $indexes[0]); for ($i = 0, $c = count($matches[0]); $i < $c; $i++) { - if ($matches[1][$i] != '') + if ($matches[1][$i] !== '') { $indexes[] = $matches[1][$i]; } @@ -151,19 +216,18 @@ class CI_Form_validation { } else { - $indexes = array(); $is_array = FALSE; } // Build our master array $this->_field_data[$field] = array( - 'field' => $field, - 'label' => $label, - 'rules' => $rules, - 'is_array' => $is_array, - 'keys' => $indexes, - 'postdata' => NULL, - 'error' => '' + 'field' => $field, + 'label' => $label, + 'rules' => $rules, + 'is_array' => $is_array, + 'keys' => $indexes, + 'postdata' => NULL, + 'error' => '' ); return $this; @@ -241,6 +305,8 @@ class CI_Form_validation { * Gets the error message associated with a particular field * * @param string the field name + * @param string the html start tag + * @param strign the html end tag * @return string */ public function error($field = '', $prefix = '', $suffix = '') @@ -250,12 +316,12 @@ class CI_Form_validation { return ''; } - if ($prefix == '') + if ($prefix === '') { $prefix = $this->_error_prefix; } - if ($suffix == '') + if ($suffix === '') { $suffix = $this->_error_suffix; } @@ -296,12 +362,12 @@ class CI_Form_validation { return ''; } - if ($prefix == '') + if ($prefix === '') { $prefix = $this->_error_prefix; } - if ($suffix == '') + if ($suffix === '') { $suffix = $this->_error_suffix; } @@ -310,7 +376,7 @@ class CI_Form_validation { $str = ''; foreach ($this->_error_array as $val) { - if ($val != '') + if ($val !== '') { $str .= $prefix.$val.$suffix."\n"; } @@ -326,6 +392,7 @@ class CI_Form_validation { * * This function does all the work. * + * @param string $group * @return bool */ public function run($group = '') @@ -348,9 +415,9 @@ class CI_Form_validation { } // Is there a validation rule for the particular URI being accessed? - $uri = ($group == '') ? trim($this->CI->uri->ruri_string(), '/') : $group; + $uri = ($group === '') ? trim($this->CI->uri->ruri_string(), '/') : $group; - if ($uri != '' && isset($this->_config_rules[$uri])) + if ($uri !== '' && isset($this->_config_rules[$uri])) { $this->set_rules($this->_config_rules[$uri]); } @@ -370,20 +437,31 @@ class CI_Form_validation { // Load the language file containing error messages $this->CI->lang->load('form_validation'); - // Cycle through the rules for each field, match the - // corresponding $_POST item and test for errors + // Cycle through the rules for each field and match the corresponding $validation_data item foreach ($this->_field_data as $field => $row) { - // Fetch the data from the corresponding $_POST or validation array and cache it in the _field_data array. + // Fetch the data from the validation_data array item and cache it in the _field_data array. // Depending on whether the field name is an array or a string will determine where we get it from. if ($row['is_array'] === TRUE) { $this->_field_data[$field]['postdata'] = $this->_reduce_array($validation_array, $row['keys']); } - elseif ( ! empty($validation_array[$field])) + elseif (isset($validation_array[$field]) && $validation_array[$field] !== '') { $this->_field_data[$field]['postdata'] = $validation_array[$field]; } + } + + // Execute validation rules + // Note: A second foreach (for now) is required in order to avoid false-positives + // for rules like 'matches', which correlate to other validation fields. + foreach ($this->_field_data as $field => $row) + { + // Don't try to validate if we have no rules set + if (empty($row['rules'])) + { + continue; + } $this->_execute($row, explode('|', $row['rules']), $this->_field_data[$field]['postdata']); } @@ -496,8 +574,7 @@ class CI_Form_validation { { foreach ($postdata as $key => $val) { - $this->_execute($row, $rules, $val, $cycles); - $cycles++; + $this->_execute($row, $rules, $val, $key); } return; @@ -527,16 +604,13 @@ class CI_Form_validation { // Set the message type $type = in_array('required', $rules) ? 'required' : 'isset'; - if ( ! isset($this->_error_messages[$type])) + if (isset($this->_error_messages[$type])) { - if (FALSE === ($line = $this->CI->lang->line($type))) - { - $line = 'The field was not set'; - } + $line = $this->_error_messages[$type]; } - else + elseif (FALSE === ($line = $this->CI->lang->line($type))) { - $line = $this->_error_messages[$type]; + $line = 'The field was not set'; } // Build the error message @@ -563,7 +637,7 @@ class CI_Form_validation { // We set the $postdata variable with the current data in our master array so that // each cycle of the loop is dealing with the processed data from the last cycle - if ($row['is_array'] == TRUE && is_array($this->_field_data[$row['field']]['postdata'])) + if ($row['is_array'] === TRUE && is_array($this->_field_data[$row['field']]['postdata'])) { // We shouldn't need this safety, but just in case there isn't an array index // associated with this cycle we'll bail out @@ -577,7 +651,12 @@ class CI_Form_validation { } else { - $postdata = $this->_field_data[$row['field']]['postdata']; + // If we get an array field, but it's not expected - then it is most likely + // somebody messing with the form on the client side, so we'll just consider + // it an empty field + $postdata = is_array($this->_field_data[$row['field']]['postdata']) + ? NULL + : $this->_field_data[$row['field']]['postdata']; } // Is the rule a callback? @@ -591,11 +670,7 @@ class CI_Form_validation { // Strip the parameter (if exists) from the rule // Rules can contain a parameter: max_length[5] $param = FALSE; - if (preg_match('/(.*?)\[(.*)\]/', $rule, $match)) - { - $rule = $match[1]; - $param = $match[2]; - } + sscanf($rule, '%[^[][%[^]]', $rule, $param); // Call the function that corresponds to the rule if ($callback === TRUE) @@ -714,11 +789,8 @@ class CI_Form_validation { { // Do we need to translate the field name? // We look for the prefix lang: to determine this - if (strpos($fieldname, 'lang:') === 0) + if (sscanf($fieldname, 'lang:%s', $line) === 1) { - // Grab the variable - $line = substr($fieldname, 5); - // Were we able to translate the field name? If not we use $line if (FALSE === ($fieldname = $this->CI->lang->line($line))) { @@ -768,6 +840,7 @@ class CI_Form_validation { * * @param string * @param string + * @param bool * @return string */ public function set_select($field = '', $value = '', $default = FALSE) @@ -785,7 +858,7 @@ class CI_Form_validation { return ''; } } - elseif (($field == '' OR $value == '') OR ($field != $value)) + elseif (($field === '' OR $value === '') OR ($field !== $value)) { return ''; } @@ -803,6 +876,7 @@ class CI_Form_validation { * * @param string * @param string + * @param bool * @return string */ public function set_radio($field = '', $value = '', $default = FALSE) @@ -820,7 +894,7 @@ class CI_Form_validation { return ''; } } - elseif (($field == '' OR $value == '') OR ($field != $value)) + elseif (($field === '' OR $value === '') OR ($field !== $value)) { return ''; } @@ -838,6 +912,7 @@ class CI_Form_validation { * * @param string * @param string + * @param bool * @return string */ public function set_checkbox($field = '', $value = '', $default = FALSE) @@ -878,19 +953,29 @@ class CI_Form_validation { /** * Match one field to another * - * @param string - * @param string field + * @param string $str string to compare against + * @param string $field * @return bool */ public function matches($str, $field) { - $validation_array = empty($this->validation_data) ? $_POST : $this->validation_data; - if ( ! isset($validation_array[$field])) - { - return FALSE; - } + return isset($this->_field_data[$field], $this->_field_data[$field]['postdata']) + ? ($str === $this->_field_data[$field]['postdata']) + : FALSE; + } - return ($str === $validation_array[$field]); + // -------------------------------------------------------------------- + + /** + * Differs from another field + * + * @param string + * @param string field + * @return bool + */ + public function differs($str, $field) + { + return ! (isset($this->_field_data[$field]) && $this->_field_data[$field]['postdata'] === $str); } // -------------------------------------------------------------------- @@ -907,7 +992,7 @@ class CI_Form_validation { */ public function is_unique($str, $field) { - list($table, $field) = explode('.', $field); + sscanf($field, '%[^.].%[^.]', $table, $field); if (isset($this->CI->db)) { $query = $this->CI->db->limit(1)->get_where($table, array($field => $str)); @@ -922,19 +1007,23 @@ class CI_Form_validation { * Minimum Length * * @param string - * @param int + * @param string * @return bool */ public function min_length($str, $val) { - if (preg_match('/[^0-9]/', $val)) + if ( ! is_numeric($val)) { return FALSE; } + else + { + $val = (int) $val; + } return (MB_ENABLED === TRUE) ? ($val <= mb_strlen($str)) - : ($val <= strlen(str)); + : ($val <= strlen($str)); } // -------------------------------------------------------------------- @@ -943,15 +1032,19 @@ class CI_Form_validation { * Max Length * * @param string - * @param int + * @param string * @return bool */ public function max_length($str, $val) { - if (preg_match('/[^0-9]/', $val)) + if ( ! is_numeric($val)) { return FALSE; } + else + { + $val = (int) $val; + } return (MB_ENABLED === TRUE) ? ($val >= mb_strlen($str)) @@ -964,19 +1057,23 @@ class CI_Form_validation { * Exact Length * * @param string - * @param int + * @param string * @return bool */ public function exact_length($str, $val) { - if (preg_match('/[^0-9]/', $val)) + if ( ! is_numeric($val)) { return FALSE; } + else + { + $val = (int) $val; + } return (MB_ENABLED === TRUE) - ? (mb_strlen($str) == $val) - : (strlen($str) == $val); + ? (mb_strlen($str) === $val) + : (strlen($str) === $val); } // -------------------------------------------------------------------- @@ -989,7 +1086,7 @@ class CI_Form_validation { */ public function valid_email($str) { - return (bool) preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix', $str); + return (bool) filter_var($str, FILTER_VALIDATE_EMAIL); } // -------------------------------------------------------------------- @@ -1024,11 +1121,12 @@ class CI_Form_validation { * Validate IP Address * * @param string + * @param string 'ipv4' or 'ipv6' to validate a specific IP format * @return bool */ - public function valid_ip($ip) + public function valid_ip($ip, $which = '') { - return $this->CI->input->valid_ip($ip); + return $this->CI->input->valid_ip($ip, $which); } // -------------------------------------------------------------------- @@ -1041,7 +1139,7 @@ class CI_Form_validation { */ public function alpha($str) { - return (bool) preg_match('/^[a-z]+$/i', $str); + return ctype_alpha($str); } // -------------------------------------------------------------------- @@ -1054,7 +1152,7 @@ class CI_Form_validation { */ public function alpha_numeric($str) { - return (bool) preg_match('/^[a-z0-9]+$/i', $str); + return ctype_alnum((string) $str); } // -------------------------------------------------------------------- @@ -1116,6 +1214,7 @@ class CI_Form_validation { * Greater than * * @param string + * @param int * @return bool */ public function greater_than($str, $min) @@ -1129,6 +1228,7 @@ class CI_Form_validation { * Equal to or Greater than * * @param string + * @param int * @return bool */ public function greater_than_equal_to($str, $min) @@ -1142,6 +1242,7 @@ class CI_Form_validation { * Less than * * @param string + * @param int * @return bool */ public function less_than($str, $max) @@ -1155,6 +1256,7 @@ class CI_Form_validation { * Equal to or Less than * * @param string + * @param int * @return bool */ public function less_than_equal_to($str, $max) @@ -1172,7 +1274,7 @@ class CI_Form_validation { */ public function is_natural($str) { - return (bool) preg_match('/^[0-9]+$/', $str); + return ctype_digit((string) $str); } // -------------------------------------------------------------------- @@ -1185,7 +1287,7 @@ class CI_Form_validation { */ public function is_natural_no_zero($str) { - return ($str != 0 && preg_match('/^[0-9]+$/', $str)); + return ($str != 0 && ctype_digit((string) $str)); } // -------------------------------------------------------------------- @@ -1201,7 +1303,7 @@ class CI_Form_validation { */ public function valid_base64($str) { - return (bool) ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str); + return ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str); } // -------------------------------------------------------------------- @@ -1217,6 +1319,11 @@ class CI_Form_validation { */ public function prep_for_form($data = '') { + if ($this->_safe_form_data === FALSE OR empty($data)) + { + return $data; + } + if (is_array($data)) { foreach ($data as $key => $val) @@ -1227,11 +1334,6 @@ class CI_Form_validation { return $data; } - if ($this->_safe_form_data == FALSE OR $data === '') - { - return $data; - } - return str_replace(array("'", '"', '<', '>'), array(''', '"', '<', '>'), stripslashes($data)); } @@ -1245,7 +1347,7 @@ class CI_Form_validation { */ public function prep_url($str = '') { - if ($str === 'http://' OR $str == '') + if ($str === 'http://' OR $str === '') { return ''; } @@ -1268,7 +1370,7 @@ class CI_Form_validation { */ public function strip_image_tags($str) { - return $this->CI->input->strip_image_tags($str); + return $this->CI->security->strip_image_tags($str); } // -------------------------------------------------------------------- @@ -1294,7 +1396,7 @@ class CI_Form_validation { */ public function encode_php_tags($str) { - return str_replace(array('<?php', '<?PHP', '<?', '?>'), array('<?php', '<?PHP', '<?', '?>'), $str); + return str_replace(array('<?', '?>'), array('<?', '?>'), $str); } // -------------------------------------------------------------------- diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php index 8aa1650d2..60c03b5ad 100644 --- a/system/libraries/Ftp.php +++ b/system/libraries/Ftp.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * FTP Class @@ -36,15 +37,65 @@ */ class CI_FTP { + /** + * FTP Server hostname + * + * @var string + */ public $hostname = ''; + + /** + * FTP Username + * + * @var string + */ public $username = ''; + + /** + * FTP Password + * + * @var string + */ public $password = ''; + + /** + * FTP Server port + * + * @var int + */ public $port = 21; + + /** + * Passive mode flag + * + * @var bool + */ public $passive = TRUE; + + /** + * Debug flag + * + * Specifies whether to display error messages. + * + * @var bool + */ public $debug = FALSE; + + /** + * Connection + * + * @var resource + */ public $conn_id = FALSE; + // -------------------------------------------------------------------- + /** + * Constructor + * + * @param array $config + * @return void + */ public function __construct($config = array()) { if (count($config) > 0) @@ -60,7 +111,7 @@ class CI_FTP { /** * Initialize preferences * - * @param array + * @param array $config * @return void */ public function initialize($config = array()) @@ -82,7 +133,7 @@ class CI_FTP { /** * FTP Connect * - * @param array the connection values + * @param array $config Connection values * @return bool */ public function connect($config = array()) @@ -94,7 +145,7 @@ class CI_FTP { if (FALSE === ($this->conn_id = @ftp_connect($this->hostname, $this->port))) { - if ($this->debug == TRUE) + if ($this->debug === TRUE) { $this->_error('ftp_unable_to_connect'); } @@ -103,7 +154,7 @@ class CI_FTP { if ( ! $this->_login()) { - if ($this->debug == TRUE) + if ($this->debug === TRUE) { $this->_error('ftp_unable_to_login'); } @@ -111,7 +162,7 @@ class CI_FTP { } // Set passive mode if needed - if ($this->passive == TRUE) + if ($this->passive === TRUE) { ftp_pasv($this->conn_id, TRUE); } @@ -142,7 +193,7 @@ class CI_FTP { { if ( ! is_resource($this->conn_id)) { - if ($this->debug == TRUE) + if ($this->debug === TRUE) { $this->_error('ftp_no_connection'); } @@ -162,13 +213,13 @@ class CI_FTP { * so we do it by trying to change to a particular directory. * Internally, this parameter is only used by the "mirror" function below. * - * @param string - * @param bool + * @param string $path + * @param bool $supress_debug * @return bool */ public function changedir($path = '', $supress_debug = FALSE) { - if ($path == '' OR ! $this->_is_conn()) + if ($path === '' OR ! $this->_is_conn()) { return FALSE; } @@ -177,7 +228,7 @@ class CI_FTP { if ($result === FALSE) { - if ($this->debug == TRUE && $supress_debug == FALSE) + if ($this->debug === TRUE && $supress_debug === FALSE) { $this->_error('ftp_unable_to_changedir'); } @@ -192,13 +243,13 @@ class CI_FTP { /** * Create a directory * - * @param string - * @param int + * @param string $path + * @param int $permissions * @return bool */ public function mkdir($path = '', $permissions = NULL) { - if ($path == '' OR ! $this->_is_conn()) + if ($path === '' OR ! $this->_is_conn()) { return FALSE; } @@ -207,7 +258,7 @@ class CI_FTP { if ($result === FALSE) { - if ($this->debug == TRUE) + if ($this->debug === TRUE) { $this->_error('ftp_unable_to_makdir'); } @@ -228,10 +279,10 @@ class CI_FTP { /** * Upload a file to the server * - * @param string - * @param string - * @param string - * @param int + * @param string $locpath + * @param string $rempath + * @param string $mode + * @param int $permissions * @return bool */ public function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL) @@ -261,7 +312,7 @@ class CI_FTP { if ($result === FALSE) { - if ($this->debug == TRUE) + if ($this->debug === TRUE) { $this->_error('ftp_unable_to_upload'); } @@ -282,9 +333,9 @@ class CI_FTP { /** * Download a file from a remote server to the local server * - * @param string - * @param string - * @param string + * @param string $rempath + * @param string $locpath + * @param string $mode * @return bool */ public function download($rempath, $locpath, $mode = 'auto') @@ -308,7 +359,7 @@ class CI_FTP { if ($result === FALSE) { - if ($this->debug == TRUE) + if ($this->debug === TRUE) { $this->_error('ftp_unable_to_download'); } @@ -323,9 +374,9 @@ class CI_FTP { /** * Rename (or move) a file * - * @param string - * @param string - * @param bool + * @param string $old_file + * @param string $new_file + * @param bool $move * @return bool */ public function rename($old_file, $new_file, $move = FALSE) @@ -339,9 +390,9 @@ class CI_FTP { if ($result === FALSE) { - if ($this->debug == TRUE) + if ($this->debug === TRUE) { - $this->_error('ftp_unable_to_' . ($move == FALSE ? 'rename' : 'move')); + $this->_error('ftp_unable_to_' . ($move === FALSE ? 'rename' : 'move')); } return FALSE; } @@ -354,8 +405,8 @@ class CI_FTP { /** * Move a file * - * @param string - * @param string + * @param string $old_file + * @param string $new_file * @return bool */ public function move($old_file, $new_file) @@ -368,7 +419,7 @@ class CI_FTP { /** * Rename (or move) a file * - * @param string + * @param string $filepath * @return bool */ public function delete_file($filepath) @@ -382,7 +433,7 @@ class CI_FTP { if ($result === FALSE) { - if ($this->debug == TRUE) + if ($this->debug === TRUE) { $this->_error('ftp_unable_to_delete'); } @@ -398,7 +449,7 @@ class CI_FTP { * Delete a folder and recursively delete everything (including sub-folders) * containted within it. * - * @param string + * @param string $filepath * @return bool */ public function delete_dir($filepath) @@ -430,7 +481,7 @@ class CI_FTP { if ($result === FALSE) { - if ($this->debug == TRUE) + if ($this->debug === TRUE) { $this->_error('ftp_unable_to_delete'); } @@ -445,8 +496,8 @@ class CI_FTP { /** * Set file permissions * - * @param string the file path - * @param string the permissions + * @param string $path File path + * @param int $perm Permissions * @return bool */ public function chmod($path, $perm) @@ -460,7 +511,7 @@ class CI_FTP { if ($result === FALSE) { - if ($this->debug == TRUE) + if ($this->debug === TRUE) { $this->_error('ftp_unable_to_chmod'); } @@ -475,6 +526,7 @@ class CI_FTP { /** * FTP List files in the specified directory * + * @param string $path * @return array */ public function list_files($path = '.') @@ -497,8 +549,8 @@ class CI_FTP { * Whatever the directory structure of the original file path will be * recreated on the server. * - * @param string path to source with trailing slash - * @param string path to destination - include the base folder with trailing slash + * @param string $locpath Path to source with trailing slash + * @param string $rempath Path to destination - include the base folder with trailing slash * @return bool */ public function mirror($locpath, $rempath) @@ -539,13 +591,12 @@ class CI_FTP { return FALSE; } - // -------------------------------------------------------------------- /** * Extract the file extension * - * @param string + * @param string $filename * @return string */ protected function _getext($filename) @@ -564,7 +615,7 @@ class CI_FTP { /** * Set the upload type * - * @param string + * @param string $ext Filename extension * @return string */ protected function _settype($ext) @@ -611,7 +662,7 @@ class CI_FTP { /** * Display error message * - * @param string + * @param string $line * @return void */ protected function _error($line) diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php index 1ab8b23e0..7f937f99b 100644 --- a/system/libraries/Image_lib.php +++ b/system/libraries/Image_lib.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Image Manipulation class @@ -36,56 +37,336 @@ */ class CI_Image_lib { - public $image_library = 'gd2'; // Can be: imagemagick, netpbm, gd, gd2 + /** + * PHP extension/library to use for image manipulation + * Can be: imagemagick, netpbm, gd, gd2 + * + * @var string + */ + public $image_library = 'gd2'; + + /** + * Path to the graphic library (if applicable) + * + * @var string + */ public $library_path = ''; - public $dynamic_output = FALSE; // Whether to send to browser or write to disk + + /** + * Whether to send to browser or write to disk + * + * @var bool + */ + public $dynamic_output = FALSE; + + /** + * Path to original image + * + * @var string + */ public $source_image = ''; - public $new_image = ''; - public $width = ''; - public $height = ''; - public $quality = '90'; + + /** + * Path to the modified image + * + * @var string + */ + public $new_image = ''; + + /** + * Image width + * + * @var int + */ + public $width = ''; + + /** + * Image height + * + * @var int + */ + public $height = ''; + + /** + * Quality percentage of new image + * + * @var int + */ + public $quality = 90; + + /** + * Whether to create a thumbnail + * + * @var bool + */ public $create_thumb = FALSE; + + /** + * String to add to thumbnail version of image + * + * @var string + */ public $thumb_marker = '_thumb'; - public $maintain_ratio = TRUE; // Whether to maintain aspect ratio when resizing or use hard values - public $master_dim = 'auto'; // auto, height, or width. Determines what to use as the master dimension + + /** + * Whether to maintain aspect ratio when resizing or use hard values + * + * @var bool + */ + public $maintain_ratio = TRUE; + + /** + * auto, height, or width. Determines what to use as the master dimension + * + * @var string + */ + public $master_dim = 'auto'; + + /** + * Angle at to rotate image + * + * @var string + */ public $rotation_angle = ''; - public $x_axis = ''; - public $y_axis = ''; + /** + * X Coordinate for manipulation of the current image + * + * @var int + */ + public $x_axis = ''; + + /** + * Y Coordinate for manipulation of the current image + * + * @var int + */ + public $y_axis = ''; + + // -------------------------------------------------------------------------- // Watermark Vars - public $wm_text = ''; // Watermark text if graphic is not used - public $wm_type = 'text'; // Type of watermarking. Options: text/overlay + // -------------------------------------------------------------------------- + + /** + * Watermark text if graphic is not used + * + * @var string + */ + public $wm_text = ''; + + /** + * Type of watermarking. Options: text/overlay + * + * @var string + */ + public $wm_type = 'text'; + + /** + * Default transparency for watermark + * + * @var int + */ public $wm_x_transp = 4; + + /** + * Default transparency for watermark + * + * @var int + */ public $wm_y_transp = 4; - public $wm_overlay_path = ''; // Watermark image path - public $wm_font_path = ''; // TT font - public $wm_font_size = 17; // Font size (different versions of GD will either use points or pixels) - public $wm_vrt_alignment = 'B'; // Vertical alignment: T M B - public $wm_hor_alignment = 'C'; // Horizontal alignment: L R C - public $wm_padding = 0; // Padding around text - public $wm_hor_offset = 0; // Lets you push text to the right - public $wm_vrt_offset = 0; // Lets you push text down - protected $wm_font_color = '#ffffff'; // Text color - protected $wm_shadow_color = ''; // Dropshadow color - public $wm_shadow_distance = 2; // Dropshadow distance - public $wm_opacity = 50; // Image opacity: 1 - 100 Only works with image + /** + * Watermark image path + * + * @var string + */ + public $wm_overlay_path = ''; + + /** + * TT font + * + * @var string + */ + public $wm_font_path = ''; + + /** + * Font size (different versions of GD will either use points or pixels) + * + * @var int + */ + public $wm_font_size = 17; + + /** + * Vertical alignment: T M B + * + * @var string + */ + public $wm_vrt_alignment = 'B'; + + /** + * Horizontal alignment: L R C + * + * @var string + */ + public $wm_hor_alignment = 'C'; + + /** + * Padding around text + * + * @var int + */ + public $wm_padding = 0; + + /** + * Lets you push text to the right + * + * @var int + */ + public $wm_hor_offset = 0; + + /** + * Lets you push text down + * + * @var int + */ + public $wm_vrt_offset = 0; + + /** + * Text color + * + * @var string + */ + protected $wm_font_color = '#ffffff'; + + /** + * Dropshadow color + * + * @var string + */ + protected $wm_shadow_color = ''; + + /** + * Dropshadow distance + * + * @var int + */ + public $wm_shadow_distance = 2; + + /** + * Image opacity: 1 - 100 Only works with image + * + * @var int + */ + public $wm_opacity = 50; + + // -------------------------------------------------------------------------- // Private Vars + // -------------------------------------------------------------------------- + + /** + * Source image folder + * + * @var string + */ public $source_folder = ''; + + /** + * Destination image folder + * + * @var string + */ public $dest_folder = ''; - public $mime_type = ''; - public $orig_width = ''; + + /** + * Image mime-type + * + * @var string + */ + public $mime_type = ''; + + /** + * Original image width + * + * @var int + */ + public $orig_width = ''; + + /** + * Original image height + * + * @var int + */ public $orig_height = ''; - public $image_type = ''; - public $size_str = ''; + + /** + * Image format + * + * @var string + */ + public $image_type = ''; + + /** + * Size of current image + * + * @var string + */ + public $size_str = ''; + + /** + * Full path to source image + * + * @var string + */ public $full_src_path = ''; + + /** + * Full path to destination image + * + * @var string + */ public $full_dst_path = ''; - public $create_fnc = 'imagecreatetruecolor'; - public $copy_fnc = 'imagecopyresampled'; - public $error_msg = array(); + + /** + * Name of function to create image + * + * @var string + */ + public $create_fnc = 'imagecreatetruecolor'; + + /** + * Name of function to copy image + * + * @var string + */ + public $copy_fnc = 'imagecopyresampled'; + + /** + * Error messages + * + * @var array + */ + public $error_msg = array(); + + /** + * Whether to have a drop shadow on watermark + * + * @var bool + */ protected $wm_use_drop_shadow = FALSE; + + /** + * Whether to use truetype fonts + * + * @var bool + */ public $wm_use_truetype = FALSE; + /** + * Initialize Image Library + * + * @param array $props + * @return void + */ public function __construct($props = array()) { if (count($props) > 0) @@ -116,7 +397,7 @@ class CI_Image_lib { $this->image_library = 'gd2'; $this->dynamic_output = FALSE; - $this->quality = '90'; + $this->quality = 90; $this->create_thumb = FALSE; $this->thumb_marker = '_thumb'; $this->maintain_ratio = TRUE; @@ -186,7 +467,7 @@ class CI_Image_lib { } // Is there a source image? If not, there's no reason to continue - if ($this->source_image == '') + if ($this->source_image === '') { $this->set_error('imglib_source_image_required'); return FALSE; @@ -239,7 +520,7 @@ class CI_Image_lib { * it means we are altering the original. We'll * set the destination filename and path accordingly. */ - if ($this->new_image == '') + if ($this->new_image === '') { $this->dest_image = $this->source_image; $this->dest_folder = $this->source_folder; @@ -282,7 +563,7 @@ class CI_Image_lib { * We'll also split the destination image name * so we can insert the thumbnail marker if needed. */ - if ($this->create_thumb === FALSE OR $this->thumb_marker == '') + if ($this->create_thumb === FALSE OR $this->thumb_marker === '') { $this->thumb_marker = ''; } @@ -301,7 +582,7 @@ class CI_Image_lib { * might not be in correct proportion with the source * image's width/height. We'll recalculate it here. */ - if ($this->maintain_ratio === TRUE && ($this->width != 0 OR $this->height != 0)) + if ($this->maintain_ratio === TRUE && ($this->width !== 0 OR $this->height !== 0)) { $this->image_reproportion(); } @@ -311,12 +592,12 @@ class CI_Image_lib { * If the destination width/height was not submitted we * will use the values from the actual file */ - if ($this->width == '') + if ($this->width === '') { $this->width = $this->orig_width; } - if ($this->height == '') + if ($this->height === '') { $this->height = $this->orig_height; } @@ -324,31 +605,31 @@ class CI_Image_lib { // Set the quality $this->quality = trim(str_replace('%', '', $this->quality)); - if ($this->quality == '' OR $this->quality == 0 OR ! preg_match('/^[0-9]+$/', $this->quality)) + if ($this->quality === '' OR $this->quality === 0 OR ! ctype_digit($this->quality)) { $this->quality = 90; } // Set the x/y coordinates - $this->x_axis = ($this->x_axis == '' OR ! preg_match('/^[0-9]+$/', $this->x_axis)) ? 0 : $this->x_axis; - $this->y_axis = ($this->y_axis == '' OR ! preg_match('/^[0-9]+$/', $this->y_axis)) ? 0 : $this->y_axis; + is_numeric($this->x_axis) OR $this->x_axis = 0; + is_numeric($this->y_axis) OR $this->y_axis = 0; // Watermark-related Stuff... - if ($this->wm_overlay_path != '') + if ($this->wm_overlay_path !== '') { $this->wm_overlay_path = str_replace('\\', '/', realpath($this->wm_overlay_path)); } - if ($this->wm_shadow_color != '') + if ($this->wm_shadow_color !== '') { $this->wm_use_drop_shadow = TRUE; } - elseif ($this->wm_use_drop_shadow == TRUE && $this->wm_shadow_color == '') + elseif ($this->wm_use_drop_shadow === TRUE && $this->wm_shadow_color === '') { $this->wm_use_drop_shadow = FALSE; } - if ($this->wm_font_path != '') + if ($this->wm_font_path !== '') { $this->wm_use_truetype = TRUE; } @@ -403,14 +684,14 @@ class CI_Image_lib { // Allowed rotation values $degs = array(90, 180, 270, 'vrt', 'hor'); - if ($this->rotation_angle == '' OR ! in_array($this->rotation_angle, $degs)) + if ($this->rotation_angle === '' OR ! in_array($this->rotation_angle, $degs)) { $this->set_error('imglib_rotation_angle_required'); return FALSE; } // Reassign the width and height - if ($this->rotation_angle == 90 OR $this->rotation_angle == 270) + if ($this->rotation_angle === 90 OR $this->rotation_angle === 270) { $this->width = $this->orig_height; $this->height = $this->orig_width; @@ -449,9 +730,9 @@ class CI_Image_lib { // If the target width/height match the source, AND if the new file name is not equal to the old file name // we'll simply make a copy of the original with the new name... assuming dynamic rendering is off. - if ($this->dynamic_output === FALSE && $this->orig_width == $this->width && $this->orig_height == $this->height) + if ($this->dynamic_output === FALSE && $this->orig_width === $this->width && $this->orig_height === $this->height) { - if ($this->source_image != $this->new_image && @copy($this->full_src_path, $this->full_dst_path)) + if ($this->source_image !== $this->new_image && @copy($this->full_src_path, $this->full_dst_path)) { @chmod($this->full_dst_path, FILE_WRITE_MODE); } @@ -460,7 +741,7 @@ class CI_Image_lib { } // Let's set up our values based on the action - if ($action == 'crop') + if ($action === 'crop') { // Reassign the source width/height if cropping $this->orig_width = $this->width; @@ -470,7 +751,7 @@ class CI_Image_lib { if ($this->gd_version() !== FALSE) { $gd_version = str_replace('0', '', $this->gd_version()); - $v2_override = ($gd_version == 2) ? TRUE : FALSE; + $v2_override = ($gd_version === 2); } } else @@ -492,7 +773,7 @@ class CI_Image_lib { * it appears that this is no longer the issue that it was in 2004, so we've removed it, retaining it in the comment * below should that ever prove inaccurate. * - * if ($this->image_library === 'gd2' && function_exists('imagecreatetruecolor') && $v2_override == FALSE) + * if ($this->image_library === 'gd2' && function_exists('imagecreatetruecolor') && $v2_override === FALSE) */ if ($this->image_library === 'gd2' && function_exists('imagecreatetruecolor')) { @@ -507,7 +788,7 @@ class CI_Image_lib { $dst_img = $create($this->width, $this->height); - if ($this->image_type == 3) // png we can actually preserve transparency + if ($this->image_type === 3) // png we can actually preserve transparency { imagealphablending($dst_img, FALSE); imagesavealpha($dst_img, TRUE); @@ -516,7 +797,7 @@ class CI_Image_lib { $copy($dst_img, $src_img, 0, 0, $this->x_axis, $this->y_axis, $this->width, $this->height, $this->orig_width, $this->orig_height); // Show the image - if ($this->dynamic_output == TRUE) + if ($this->dynamic_output === TRUE) { $this->image_display_gd($dst_img); } @@ -548,7 +829,7 @@ class CI_Image_lib { public function image_process_imagemagick($action = 'resize') { // Do we have a vaild library path? - if ($this->library_path == '') + if ($this->library_path === '') { $this->set_error('imglib_libpath_invalid'); return FALSE; @@ -562,11 +843,11 @@ class CI_Image_lib { // Execute the command $cmd = $this->library_path.' -quality '.$this->quality; - if ($action == 'crop') + if ($action === 'crop') { $cmd .= ' -crop '.$this->width.'x'.$this->height.'+'.$this->x_axis.'+'.$this->y_axis.' "'.$this->full_src_path.'" "'.$this->full_dst_path .'" 2>&1'; } - elseif ($action == 'rotate') + elseif ($action === 'rotate') { $angle = ($this->rotation_angle === 'hor' OR $this->rotation_angle === 'vrt') ? '-flop' : '-rotate '.$this->rotation_angle; @@ -575,11 +856,22 @@ class CI_Image_lib { } else // Resize { - $cmd .= ' -resize '.$this->width.'x'.$this->height.' "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1'; + if($this->maintain_ratio === TRUE) + { + $cmd .= ' -resize '.$this->width.'x'.$this->height.' "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1'; + } + else + { + $cmd .= ' -resize '.$this->width.'x'.$this->height.'\! "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1'; + } } $retval = 1; - @exec($cmd, $output, $retval); + // exec() might be disabled + if (function_usable('exec')) + { + @exec($cmd, $output, $retval); + } // Did it work? if ($retval > 0) @@ -606,7 +898,7 @@ class CI_Image_lib { */ public function image_process_netpbm($action = 'resize') { - if ($this->library_path == '') + if ($this->library_path === '') { $this->set_error('imglib_libpath_invalid'); return FALSE; @@ -616,36 +908,36 @@ class CI_Image_lib { switch ($this->image_type) { case 1 : - $cmd_in = 'giftopnm'; - $cmd_out = 'ppmtogif'; + $cmd_in = 'giftopnm'; + $cmd_out = 'ppmtogif'; break; case 2 : - $cmd_in = 'jpegtopnm'; - $cmd_out = 'ppmtojpeg'; + $cmd_in = 'jpegtopnm'; + $cmd_out = 'ppmtojpeg'; break; case 3 : - $cmd_in = 'pngtopnm'; - $cmd_out = 'ppmtopng'; + $cmd_in = 'pngtopnm'; + $cmd_out = 'ppmtopng'; break; } - if ($action == 'crop') + if ($action === 'crop') { $cmd_inner = 'pnmcut -left '.$this->x_axis.' -top '.$this->y_axis.' -width '.$this->width.' -height '.$this->height; } - elseif ($action == 'rotate') + elseif ($action === 'rotate') { switch ($this->rotation_angle) { - case 90 : $angle = 'r270'; + case 90: $angle = 'r270'; break; - case 180 : $angle = 'r180'; + case 180: $angle = 'r180'; break; - case 270 : $angle = 'r90'; + case 270: $angle = 'r90'; break; - case 'vrt' : $angle = 'tb'; + case 'vrt': $angle = 'tb'; break; - case 'hor' : $angle = 'lr'; + case 'hor': $angle = 'lr'; break; } @@ -659,7 +951,11 @@ class CI_Image_lib { $cmd = $this->library_path.$cmd_in.' '.$this->full_src_path.' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp'; $retval = 1; - @exec($cmd, $output, $retval); + // exec() might be disabled + if (function_usable('exec')) + { + @exec($cmd, $output, $retval); + } // Did it work? if ($retval > 0) @@ -671,7 +967,7 @@ class CI_Image_lib { // With NetPBM we have to create a temporary image. // If you try manipulating the original it fails so // we have to rename the temp file. - copy ($this->dest_folder.'netpbm.tmp', $this->full_dst_path); + copy($this->dest_folder.'netpbm.tmp', $this->full_dst_path); unlink($this->dest_folder.'netpbm.tmp'); @chmod($this->full_dst_path, FILE_WRITE_MODE); @@ -704,7 +1000,7 @@ class CI_Image_lib { $dst_img = imagerotate($src_img, $this->rotation_angle, $white); // Show the image - if ($this->dynamic_output == TRUE) + if ($this->dynamic_output === TRUE) { $this->image_display_gd($dst_img); } @@ -778,7 +1074,7 @@ class CI_Image_lib { } // Show the image - if ($this->dynamic_output == TRUE) + if ($this->dynamic_output === TRUE) { $this->image_display_gd($src_img); } @@ -804,7 +1100,6 @@ class CI_Image_lib { * This is a wrapper function that chooses the type * of watermarking based on the specified preference. * - * @param string * @return bool */ public function watermark() @@ -850,10 +1145,10 @@ class CI_Image_lib { $this->wm_vrt_alignment = strtoupper($this->wm_vrt_alignment[0]); $this->wm_hor_alignment = strtoupper($this->wm_hor_alignment[0]); - if ($this->wm_vrt_alignment == 'B') + if ($this->wm_vrt_alignment === 'B') $this->wm_vrt_offset = $this->wm_vrt_offset * -1; - if ($this->wm_hor_alignment == 'R') + if ($this->wm_hor_alignment === 'R') $this->wm_hor_offset = $this->wm_hor_offset * -1; // Set the base x and y axis values @@ -881,7 +1176,7 @@ class CI_Image_lib { } // Build the finalized image - if ($wm_img_type == 3 && function_exists('imagealphablending')) + if ($wm_img_type === 3 && function_exists('imagealphablending')) { @imagealphablending($src_img, TRUE); } @@ -904,7 +1199,7 @@ class CI_Image_lib { } // Output the image - if ($this->dynamic_output == TRUE) + if ($this->dynamic_output === TRUE) { $this->image_display_gd($src_img); } @@ -933,7 +1228,7 @@ class CI_Image_lib { return FALSE; } - if ($this->wm_use_truetype == TRUE && ! file_exists($this->wm_font_path)) + if ($this->wm_use_truetype === TRUE && ! file_exists($this->wm_font_path)) { $this->set_error('imglib_missing_font'); return FALSE; @@ -949,18 +1244,18 @@ class CI_Image_lib { // invert the offset. Note: The horizontal // offset flips itself automatically - if ($this->wm_vrt_alignment == 'B') + if ($this->wm_vrt_alignment === 'B') $this->wm_vrt_offset = $this->wm_vrt_offset * -1; - if ($this->wm_hor_alignment == 'R') + if ($this->wm_hor_alignment === 'R') $this->wm_hor_offset = $this->wm_hor_offset * -1; // Set font width and height // These are calculated differently depending on // whether we are using the true type font or not - if ($this->wm_use_truetype == TRUE) + if ($this->wm_use_truetype === TRUE) { - if ($this->wm_font_size == '') + if ($this->wm_font_size === '') { $this->wm_font_size = 17; } @@ -979,11 +1274,11 @@ class CI_Image_lib { $x_axis = $this->wm_hor_offset + $this->wm_padding; $y_axis = $this->wm_vrt_offset + $this->wm_padding; - if ($this->wm_use_drop_shadow == FALSE) + if ($this->wm_use_drop_shadow === FALSE) $this->wm_shadow_distance = 0; - $this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1)); - $this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1)); + $this->wm_vrt_alignment = strtoupper($this->wm_vrt_alignment[0]); + $this->wm_hor_alignment = strtoupper($this->wm_hor_alignment[0]); // Set verticle alignment if ($this->wm_vrt_alignment === 'M') @@ -1034,10 +1329,17 @@ class CI_Image_lib { imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color); imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color); } + + // We can preserve transparency for PNG images + if ($this->image_type === 3) + { + imagealphablending($src_img, FALSE); + imagesavealpha($src_img, TRUE); + } } // Output the final image - if ($this->dynamic_output == TRUE) + if ($this->dynamic_output === TRUE) { $this->image_display_gd($src_img); } @@ -1060,14 +1362,15 @@ class CI_Image_lib { * based on the type of image being processed * * @param string + * @param string * @return resource */ public function image_create_gd($path = '', $image_type = '') { - if ($path == '') + if ($path === '') $path = $this->full_src_path; - if ($image_type == '') + if ($image_type === '') $image_type = $this->image_type; @@ -1122,49 +1425,49 @@ class CI_Image_lib { { switch ($this->image_type) { - case 1 : - if ( ! function_exists('imagegif')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported')); - return FALSE; - } + case 1: + if ( ! function_exists('imagegif')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported')); + return FALSE; + } - if ( ! @imagegif($resource, $this->full_dst_path)) - { - $this->set_error('imglib_save_failed'); - return FALSE; - } - break; - case 2 : - if ( ! function_exists('imagejpeg')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported')); - return FALSE; - } + if ( ! @imagegif($resource, $this->full_dst_path)) + { + $this->set_error('imglib_save_failed'); + return FALSE; + } + break; + case 2: + if ( ! function_exists('imagejpeg')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported')); + return FALSE; + } - if ( ! @imagejpeg($resource, $this->full_dst_path, $this->quality)) - { - $this->set_error('imglib_save_failed'); - return FALSE; - } - break; - case 3 : - if ( ! function_exists('imagepng')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported')); - return FALSE; - } + if ( ! @imagejpeg($resource, $this->full_dst_path, $this->quality)) + { + $this->set_error('imglib_save_failed'); + return FALSE; + } + break; + case 3: + if ( ! function_exists('imagepng')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported')); + return FALSE; + } - if ( ! @imagepng($resource, $this->full_dst_path)) - { - $this->set_error('imglib_save_failed'); - return FALSE; - } - break; - default : - $this->set_error(array('imglib_unsupported_imagecreate')); - return FALSE; - break; + if ( ! @imagepng($resource, $this->full_dst_path)) + { + $this->set_error('imglib_save_failed'); + return FALSE; + } + break; + default: + $this->set_error(array('imglib_unsupported_imagecreate')); + return FALSE; + break; } return TRUE; @@ -1187,13 +1490,13 @@ class CI_Image_lib { switch ($this->image_type) { - case 1 : imagegif($resource); + case 1 : imagegif($resource); break; - case 2 : imagejpeg($resource, '', $this->quality); + case 2 : imagejpeg($resource, '', $this->quality); break; - case 3 : imagepng($resource); + case 3 : imagepng($resource); break; - default : echo 'Unable to display the image'; + default: echo 'Unable to display the image'; break; } } @@ -1214,14 +1517,14 @@ class CI_Image_lib { */ public function image_reproportion() { - if (($this->width == 0 && $this->height == 0) OR $this->orig_width == 0 OR $this->orig_height == 0 - OR ( ! preg_match('/^[0-9]+$/', $this->width) && ! preg_match('/^[0-9]+$/', $this->height)) - OR ! preg_match('/^[0-9]+$/', $this->orig_width) OR ! preg_match('/^[0-9]+$/', $this->orig_height)) + if (($this->width === 0 && $this->height === 0) OR $this->orig_width === 0 OR $this->orig_height === 0 + OR ( ! ctype_digit((string) $this->width) && ! ctype_digit((string) $this->height)) + OR ! ctype_digit((string) $this->orig_width) OR ! ctype_digit((string) $this->orig_height)) { return; } - // Sanitize so we don't call preg_match() anymore + // Sanitize $this->width = (int) $this->width; $this->height = (int) $this->height; @@ -1261,6 +1564,7 @@ class CI_Image_lib { * A helper function that gets info about the file * * @param string + * @param bool * @return mixed */ public function get_image_properties($path = '', $return = FALSE) @@ -1268,7 +1572,7 @@ class CI_Image_lib { // For now we require GD but we should // find a way to determine this using IM or NetPBM - if ($path == '') + if ($path === '') { $path = $this->full_src_path; } @@ -1283,7 +1587,7 @@ class CI_Image_lib { $types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png'); $mime = (isset($types[$vals[2]])) ? 'image/'.$types[$vals[2]] : 'image/jpg'; - if ($return == TRUE) + if ($return === TRUE) { return array( 'width' => $vals[0], @@ -1333,20 +1637,22 @@ class CI_Image_lib { foreach ($allowed as $item) { - if ( ! isset($vals[$item]) OR $vals[$item] == '') + if (empty($vals[$item])) + { $vals[$item] = 0; + } } - if ($vals['width'] == 0 OR $vals['height'] == 0) + if ($vals['width'] === 0 OR $vals['height'] === 0) { return $vals; } - if ($vals['new_width'] == 0) + if ($vals['new_width'] === 0) { $vals['new_width'] = ceil($vals['width']*$vals['new_height']/$vals['height']); } - elseif ($vals['new_height'] == 0) + elseif ($vals['new_height'] === 0) { $vals['new_height'] = ceil($vals['new_width']*$vals['height']/$vals['width']); } @@ -1432,15 +1738,14 @@ class CI_Image_lib { { foreach ($msg as $val) { - - $msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val); + $msg = ($CI->lang->line($val) === FALSE) ? $val : $CI->lang->line($val); $this->error_msg[] = $msg; log_message('error', $msg); } } else { - $msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg); + $msg = ($CI->lang->line($msg) === FALSE) ? $msg : $CI->lang->line($msg); $this->error_msg[] = $msg; log_message('error', $msg); } @@ -1452,6 +1757,7 @@ class CI_Image_lib { * Show error messages * * @param string + * @param string * @return string */ public function display_errors($open = '<p>', $close = '</p>') diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php index 629a3adfe..9a15cddaa 100644 --- a/system/libraries/Javascript.php +++ b/system/libraries/Javascript.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Javascript Class @@ -36,8 +37,21 @@ */ class CI_Javascript { + /** + * JavaScript location + * + * @var string + */ protected $_javascript_location = 'js'; + // -------------------------------------------------------------------- + + /** + * Constructor + * + * @param array $params + * @return void + */ public function __construct($params = array()) { $defaults = array('js_library_driver' => 'jquery', 'autoload' => TRUE); @@ -312,8 +326,7 @@ class CI_Javascript { * * Outputs a javascript library mouseup event * - * @param string The element to attach the event to - * @param string The code to execute + * @param string $js Code to execute * @return string */ public function ready($js) @@ -394,9 +407,10 @@ class CI_Javascript { * * Outputs a javascript library animate event * - * @param string - element - * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds - * @param string - Javascript callback function + * @param string $element = 'this' + * @param array $params = array() + * @param mixed $speed 'slow', 'normal', 'fast', or time in milliseconds + * @param string $extra * @return string */ public function animate($element = 'this', $params = array(), $speed = '', $extra = '') @@ -546,10 +560,11 @@ class CI_Javascript { * * Outputs a javascript library toggle class event * - * @param string - element + * @param string $element = 'this' + * @param string $class = '' * @return string */ - public function toggleClass($element = 'this', $class='') + public function toggleClass($element = 'this', $class = '') { return $this->js->_toggleClass($element, $class); } @@ -579,7 +594,8 @@ class CI_Javascript { * * gather together all script needing to be output * - * @param string The element to attach the event to + * @param string $view_var + * @param bool $script_tags * @return string */ public function compile($view_var = 'script_foot', $script_tags = TRUE) @@ -587,6 +603,8 @@ class CI_Javascript { $this->js->_compile($view_var, $script_tags); } + // -------------------------------------------------------------------- + /** * Clear Compile * @@ -606,7 +624,8 @@ class CI_Javascript { * * Outputs a <script> tag with the source as an external js file * - * @param string The element to attach the event to + * @param string $external_file + * @param bool $relative * @return string */ public function external($external_file = '', $relative = FALSE) @@ -615,12 +634,12 @@ class CI_Javascript { { $this->_javascript_location = $external_file; } - elseif ($this->CI->config->item('javascript_location') != '') + elseif ($this->CI->config->item('javascript_location') !== '') { $this->_javascript_location = $this->CI->config->item('javascript_location'); } - if ($relative === TRUE OR strncmp($external_file, 'http://', 7) === 0 OR strncmp($external_file, 'https://', 8) === 0) + if ($relative === TRUE OR strpos($external_file, 'http://') === 0 OR strpos($external_file, 'https://') === 0) { $str = $this->_open_script($external_file); } @@ -667,7 +686,7 @@ class CI_Javascript { protected function _open_script($src = '') { return '<script type="text/javascript" charset="'.strtolower($this->CI->config->item('charset')).'"' - .($src == '' ? '>' : ' src="'.$src.'">'); + .($src === '' ? '>' : ' src="'.$src.'">'); } // -------------------------------------------------------------------- @@ -723,7 +742,7 @@ class CI_Javascript { { if (is_object($result)) { - $json_result = $result->result_array(); + $json_result = is_callable(array($result, 'result_array')) ? $result->result_array() : (array) $result; } elseif (is_array($result)) { @@ -799,7 +818,8 @@ class CI_Javascript { * * Ensures a standard json value and escapes values * - * @param mixed + * @param mixed $result + * @param bool $is_key = FALSE * @return string */ protected function _prep_args($result, $is_key = FALSE) diff --git a/system/libraries/Migration.php b/system/libraries/Migration.php index a18fcb9f1..e96791cef 100644 --- a/system/libraries/Migration.php +++ b/system/libraries/Migration.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 3.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Migration Class @@ -39,14 +40,68 @@ */ class CI_Migration { + /** + * Whether the library is enabled + * + * @var bool + */ protected $_migration_enabled = FALSE; + + /** + * Migration numbering type + * + * @var bool + */ + protected $_migration_type = 'sequential'; + + /** + * Path to migration classes + * + * @var string + */ protected $_migration_path = NULL; + + /** + * Current migration version + * + * @var mixed + */ protected $_migration_version = 0; + + /** + * Database table with migration info + * + * @var string + */ protected $_migration_table = 'migrations'; + + /** + * Whether to automatically run migrations + * + * @var bool + */ protected $_migration_auto_latest = FALSE; + /** + * Migration basename regex + * + * @var bool + */ + protected $_migration_regex = NULL; + + /** + * Error message + * + * @var string + */ protected $_error_string = ''; + /** + * Initialize Migration Class + * + * @param array $config + * @return void + */ public function __construct($config = array()) { # Only run this constructor on main library load @@ -57,7 +112,7 @@ class CI_Migration { foreach ($config as $key => $val) { - $this->{'_' . $key} = $val; + $this->{'_'.$key} = $val; } log_message('debug', 'Migrations class initialized'); @@ -69,7 +124,7 @@ class CI_Migration { } // If not set, set it - $this->_migration_path != '' OR $this->_migration_path = APPPATH.'migrations/'; + $this->_migration_path !== '' OR $this->_migration_path = APPPATH.'migrations/'; // Add trailing slash if not set $this->_migration_path = rtrim($this->_migration_path, '/').'/'; @@ -86,11 +141,22 @@ class CI_Migration { show_error('Migrations configuration file (migration.php) must have "migration_table" set.'); } + // Migration basename regex + $this->_migration_regex = ($this->_migration_type === 'timestamp') + ? '/^\d{14}_(\w+)$/' + : '/^\d{3}_(\w+)$/'; + + // Make sure a valid migration numbering type was set. + if ( ! in_array($this->_migration_type, array('sequential', 'timestamp'))) + { + show_error('An invalid migration numbering type was specified: '.$this->_migration_type); + } + // If the migrations table is missing, make it if ( ! $this->db->table_exists($this->_migration_table)) { $this->dbforge->add_field(array( - 'version' => array('type' => 'INT', 'constraint' => 3), + 'version' => array('type' => 'BIGINT', 'constraint' => 20), )); $this->dbforge->create_table($this->_migration_table, TRUE); @@ -113,118 +179,86 @@ class CI_Migration { * Calls each migration step required to get to the schema version of * choice * - * @param int Target schema version + * @param int $target_version Target schema version * @return mixed TRUE if already latest, FALSE if failed, int if upgraded */ public function version($target_version) { - $start = $current_version = $this->_get_version(); - $stop = $target_version; + $current_version = (int) $this->_get_version(); + $target_version = (int) $target_version; + + $migrations = $this->find_migrations(); + + if ($target_version > 0 && ! isset($migrations[$target_version])) + { + $this->_error_string = sprintf($this->lang->line('migration_not_found'), $target_version); + return FALSE; + } if ($target_version > $current_version) { // Moving Up - ++$start; - ++$stop; - $step = 1; + $method = 'up'; } else { - // Moving Down - $step = -1; + // Moving Down, apply in reverse order + $method = 'down'; + krsort($migrations); } - $method = $step === 1 ? 'up' : 'down'; - $migrations = array(); - - // We now prepare to actually DO the migrations - // But first let's make sure that everything is the way it should be - for ($i = $start; $i != $stop; $i += $step) + if (empty($migrations)) { - $f = glob(sprintf($this->_migration_path.'%03d_*.php', $i)); + return TRUE; + } - // Only one migration per step is permitted - if (count($f) > 1) - { - $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $i); - return FALSE; - } + $previous = FALSE; - // Migration step not found - if (count($f) === 0) + // Validate all available migrations, and run the ones within our target range + foreach ($migrations as $number => $file) + { + // Check for sequence gaps + if ($this->_migration_type === 'sequential' && $previous !== FALSE && abs($number - $previous) > 1) { - // If trying to migrate up to a version greater than the last - // existing one, migrate to the last one. - if ($step === 1) - { - break; - } - - // If trying to migrate down but we're missing a step, - // something must definitely be wrong. - $this->_error_string = sprintf($this->lang->line('migration_not_found'), $i); + $this->_error_string = sprintf($this->lang->line('migration_sequence_gap'), $number); return FALSE; } - $file = basename($f[0]); - $name = basename($f[0], '.php'); + include $file; + $class = 'Migration_'.ucfirst(strtolower($this->_get_migration_name(basename($file, '.php')))); - // Filename validations - if (preg_match('/^\d{3}_(\w+)$/', $name, $match)) + // Validate the migration file structure + if ( ! class_exists($class)) { - $match[1] = strtolower($match[1]); - - // Cannot repeat a migration at different steps - if (in_array($match[1], $migrations)) - { - $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $match[1]); - return FALSE; - } - - include $f[0]; - $class = 'Migration_'.ucfirst($match[1]); - - if ( ! class_exists($class)) - { - $this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class); - return FALSE; - } - - if ( ! is_callable(array($class, $method))) - { - $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class); - return FALSE; - } - - $migrations[] = $match[1]; + $this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class); + return FALSE; } - else + elseif ( ! is_callable(array($class, $method))) { - $this->_error_string = sprintf($this->lang->line('migration_invalid_filename'), $file); + $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class); return FALSE; } - } - - log_message('debug', 'Current migration: '.$current_version); - $version = $i + ($step === 1 ? -1 : 0); + $previous = $number; - // If there is nothing to do so quit - if ($migrations === array()) - { - return TRUE; + // Run migrations that are inside the target range + if ( + ($method === 'up' && $number > $current_version && $number <= $target_version) OR + ($method === 'down' && $number <= $current_version && $number > $target_version) + ) + { + log_message('debug', 'Migrating '.$method.' from version '.$current_version.' to version '.$number); + call_user_func(array(new $class, $method)); + $current_version = $number; + $this->_update_version($current_version); + } } - log_message('debug', 'Migrating from '.$method.' to version '.$version); - - // Loop through the migrations - foreach ($migrations AS $migration) + // This is necessary when moving down, since the the last migration applied + // will be the down() method for the next migration up from the target + if ($current_version <> $target_version) { - // Run the migration class - $class = 'Migration_'.ucfirst(strtolower($migration)); - call_user_func(array(new $class, $method)); - - $current_version += $step; + $current_version = $target_version; $this->_update_version($current_version); } @@ -238,21 +272,23 @@ class CI_Migration { /** * Set's the schema to the latest migration * - * @return mixed true if already latest, false if failed, int if upgraded + * @return mixed TRUE if already latest, FALSE if failed, int if upgraded */ public function latest() { - if ( ! $migrations = $this->find_migrations()) + $migrations = $this->find_migrations(); + + if (empty($migrations)) { $this->_error_string = $this->lang->line('migration_none_found'); - return false; + return FALSE; } $last_migration = basename(end($migrations)); // Calculate the last migration step from existing migration // filenames and procceed to the standard version migration - return $this->version((int) substr($last_migration, 0, 3)); + return $this->version($this->_get_migration_number($last_migration)); } // -------------------------------------------------------------------- @@ -260,7 +296,7 @@ class CI_Migration { /** * Set's the schema to the migration version set in config * - * @return mixed true if already current, false if failed, int if upgraded + * @return mixed TRUE if already current, FALSE if failed, int if upgraded */ public function current() { @@ -282,27 +318,66 @@ class CI_Migration { // -------------------------------------------------------------------- /** - * Set's the schema to the latest migration + * Retrieves list of available migration scripts * - * @return mixed true if already latest, false if failed, int if upgraded + * @return array list of migration file paths sorted by version */ - protected function find_migrations() + public function find_migrations() { - // Load all *_*.php files in the migrations path - $files = glob($this->_migration_path.'*_*.php'); + $migrations = array(); - for ($i = 0, $c = count($files); $i < $c; $i++) + // Load all *_*.php files in the migrations path + foreach (glob($this->_migration_path.'*_*.php') as $file) { - // Mark wrongly formatted files as false for later filtering - if ( ! preg_match('/^\d{3}_(\w+)$/', basename($files[$i], '.php'))) + $name = basename($file, '.php'); + + // Filter out non-migration files + if (preg_match($this->_migration_regex, $name)) { - $files[$i] = FALSE; + $number = $this->_get_migration_number($name); + + // There cannot be duplicate migration numbers + if (isset($migrations[$number])) + { + $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $number); + show_error($this->_error_string); + } + + $migrations[$number] = $file; } } - sort($files); + ksort($migrations); + return $migrations; + } + + // -------------------------------------------------------------------- + + /** + * Extracts the migration number from a filename + * + * @param string $migration + * @return int Numeric portion of a migration filename + */ + protected function _get_migration_number($migration) + { + return sscanf($migration, '%d', $number) + ? $number : 0; + } + + // -------------------------------------------------------------------- - return $files; + /** + * Extracts the migration class name from a filename + * + * @param string $migration + * @return string text portion of a migration filename + */ + protected function _get_migration_name($migration) + { + $parts = explode('_', $migration); + array_shift($parts); + return implode('_', $parts); } // -------------------------------------------------------------------- @@ -323,13 +398,13 @@ class CI_Migration { /** * Stores the current schema version * - * @param int Migration reached + * @param int $migration Migration reached * @return void Outputs a report of the migration */ - protected function _update_version($migrations) + protected function _update_version($migration) { return $this->db->update($this->_migration_table, array( - 'version' => $migrations + 'version' => $migration )); } @@ -338,13 +413,14 @@ class CI_Migration { /** * Enable the use of CI super-global * - * @param $var + * @param string $var * @return mixed */ public function __get($var) { return get_instance()->$var; } + } /* End of file Migration.php */ diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php index 0fe73d69f..ae8dba072 100644 --- a/system/libraries/Pagination.php +++ b/system/libraries/Pagination.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Pagination Class @@ -36,43 +37,270 @@ */ class CI_Pagination { - protected $base_url = ''; // The page we are linking to - protected $prefix = ''; // A custom prefix added to the path. - protected $suffix = ''; // A custom suffix added to the path. - protected $total_rows = 0; // Total number of items (database results) - protected $per_page = 10; // Max number of items you want shown per page - protected $num_links = 2; // Number of "digit" links to show before/after the currently viewed page - protected $cur_page = 0; // The current page being viewed - protected $use_page_numbers = FALSE; // Use page number for segment instead of offset - protected $first_link = '‹ First'; - protected $next_link = '>'; - protected $prev_link = '<'; - protected $last_link = 'Last ›'; - protected $uri_segment = 3; - protected $full_tag_open = ''; - protected $full_tag_close = ''; - protected $first_tag_open = ''; - protected $first_tag_close = ' '; - protected $last_tag_open = ' '; - protected $last_tag_close = ''; - protected $first_url = ''; // Alternative URL for the First Page. - protected $cur_tag_open = ' <strong>'; - protected $cur_tag_close = '</strong>'; - protected $next_tag_open = ' '; - protected $next_tag_close = ' '; - protected $prev_tag_open = ' '; - protected $prev_tag_close = ''; - protected $num_tag_open = ' '; - protected $num_tag_close = ''; + /** + * Base URL + * + * The page that we're linking to + * + * @var string + */ + protected $base_url = ''; + + /** + * Prefix + * + * @var string + */ + protected $prefix = ''; + + /** + * Suffix + * + * @var string + */ + protected $suffix = ''; + + /** + * Total number of items + * + * @var int + */ + protected $total_rows = 0; + + /** + * Items per page + * + * @var int + */ + protected $per_page = 10; + + /** + * Number of links to show + * + * Relates to "digit" type links shown before/after + * the currently viewed page. + * + * @var int + */ + protected $num_links = 2; + + /** + * Current page + * + * @var int + */ + protected $cur_page = 0; + + /** + * Use page numbers flag + * + * Whether to use actual page numbers instead of an offset + * + * @var bool + */ + protected $use_page_numbers = FALSE; + + /** + * First link + * + * @var string + */ + protected $first_link = '‹ First'; + + /** + * Next link + * + * @var string + */ + protected $next_link = '>'; + + /** + * Previous link + * + * @var string + */ + protected $prev_link = '<'; + + /** + * Last link + * + * @var string + */ + protected $last_link = 'Last ›'; + + /** + * URI Segment + * + * @var int + */ + protected $uri_segment = 3; + + /** + * Full tag open + * + * @var string + */ + protected $full_tag_open = ''; + + /** + * Full tag close + * + * @var string + */ + protected $full_tag_close = ''; + + /** + * First tag open + * + * @var string + */ + protected $first_tag_open = ''; + + /** + * First tag close + * + * @var string + */ + protected $first_tag_close = ''; + + /** + * Last tag open + * + * @var string + */ + protected $last_tag_open = ''; + + /** + * Last tag close + * + * @var string + */ + protected $last_tag_close = ''; + + /** + * First URL + * + * An alternative URL for the first page + * + * @var string + */ + protected $first_url = ''; + + /** + * Current tag open + * + * @var string + */ + protected $cur_tag_open = '<strong>'; + + /** + * Current tag close + * + * @var string + */ + protected $cur_tag_close = '</strong>'; + + /** + * Next tag open + * + * @var string + */ + protected $next_tag_open = ''; + + /** + * Next tag close + * + * @var string + */ + protected $next_tag_close = ''; + + /** + * Previous tag open + * + * @var string + */ + protected $prev_tag_open = ''; + + /** + * Previous tag close + * + * @var string + */ + protected $prev_tag_close = ''; + + /** + * Number tag open + * + * @var string + */ + protected $num_tag_open = ''; + + /** + * Number tag close + * + * @var string + */ + protected $num_tag_close = ''; + + /** + * Page query string flag + * + * @var bool + */ protected $page_query_string = FALSE; + + /** + * Query string segment + * + * @var string + */ protected $query_string_segment = 'per_page'; - protected $display_pages = TRUE; - protected $anchor_class = ''; + + /** + * Display pages flag + * + * @var bool + */ + protected $display_pages = TRUE; + + /** + * Attributes + * + * @var string + */ + protected $_attributes = ''; + + /** + * Link types + * + * "rel" attribute + * + * @see CI_Pagination::_attr_rel() + * @var array + */ + protected $_link_types = array(); + + /** + * Reuse query string flag + * + * @var bool + */ + protected $reuse_query_string = FALSE; + + /** + * Data page attribute + * + * @var string + */ + protected $data_page_attr = 'data-ci-pagination-page'; + + // -------------------------------------------------------------------- /** * Constructor * - * @param array initialization parameters + * @param array $params Initialization parameters + * @return void */ public function __construct($params = array()) { @@ -85,11 +313,29 @@ class CI_Pagination { /** * Initialize Preferences * - * @param array initialization parameters + * @param array $params Initialization parameters * @return void */ public function initialize($params = array()) { + $attributes = array(); + + if (isset($params['attributes']) && is_array($params['attributes'])) + { + $attributes = $params['attributes']; + unset($params['attributes']); + } + + // Deprecated legacy support for the anchor_class option + // Should be removed in CI 3.1+ + if (isset($params['anchor_class'])) + { + empty($params['anchor_class']) OR $attributes['class'] = $params['anchor_class']; + unset($params['anchor_class']); + } + + $this->_parse_attributes($attributes); + if (count($params) > 0) { foreach ($params as $key => $val) @@ -100,11 +346,6 @@ class CI_Pagination { } } } - - if ($this->anchor_class != '') - { - $this->anchor_class = 'class="'.$this->anchor_class.'" '; - } } // -------------------------------------------------------------------- @@ -117,7 +358,7 @@ class CI_Pagination { public function create_links() { // If our item count or per-page total is zero there is no need to continue. - if ($this->total_rows == 0 OR $this->per_page == 0) + if ($this->total_rows === 0 OR $this->per_page === 0) { return ''; } @@ -138,9 +379,9 @@ class CI_Pagination { $CI =& get_instance(); // See if we are using a prefix or suffix on links - if ($this->prefix != '' OR $this->suffix != '') + if ($this->prefix !== '' OR $this->suffix !== '') { - $this->cur_page = (int) str_replace(array($this->prefix, $this->suffix), '', $CI->uri->segment($this->uri_segment)); + $this->cur_page = (int) str_replace(array($this->prefix, $this->suffix), '', $CI->uri->rsegment($this->uri_segment)); } if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE) @@ -150,13 +391,13 @@ class CI_Pagination { $this->cur_page = (int) $CI->input->get($this->query_string_segment); } } - elseif ( ! $this->cur_page && $CI->uri->segment($this->uri_segment) != $base_page) + elseif ( ! $this->cur_page && $CI->uri->segment($this->uri_segment) !== $base_page) { - $this->cur_page = (int) $CI->uri->segment($this->uri_segment); + $this->cur_page = (int) $CI->uri->rsegment($this->uri_segment); } // Set current page to 1 if it's not valid or if using page numbers instead of offset - if ( ! is_numeric($this->cur_page) OR ($this->use_page_numbers && $this->cur_page == 0)) + if ( ! is_numeric($this->cur_page) OR ($this->use_page_numbers && $this->cur_page === 0)) { $this->cur_page = $base_page; } @@ -186,7 +427,7 @@ class CI_Pagination { if ( ! $this->use_page_numbers) { - $this->cur_page = floor(($this->cur_page/$this->per_page) + 1); + $this->cur_page = (int) floor(($this->cur_page/$this->per_page) + 1); } // Calculate the start and end numbers. These determine @@ -198,7 +439,8 @@ class CI_Pagination { // string. If post, add a trailing slash to the base URL if needed if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE) { - $this->base_url = rtrim($this->base_url).'&'.$this->query_string_segment.'='; + $segment = (strpos($this->base_url, '?')) ? '&' : '?'; + $this->base_url = rtrim($this->base_url).$segment.$this->query_string_segment.'='; } else { @@ -207,27 +449,56 @@ class CI_Pagination { // And here we go... $output = ''; + $query_string = ''; + + // Add anything in the query string back to the links + // Note: Nothing to do with query_string_segment or any other query string options + if ($this->reuse_query_string === TRUE) + { + $get = $CI->input->get(); + + // Unset the controll, method, old-school routing options + unset($get['c'], $get['m'], $get[$this->query_string_segment]); + + if ( ! $get) $get = array(); + + // Put everything else onto the end + $query_string = (strpos($this->base_url, '&') !== FALSE ? '&' : '?') . http_build_query($get, '', '&'); + + // Add this after the suffix to put it into more links easily + $this->suffix .= $query_string; + } // Render the "First" link if ($this->first_link !== FALSE && $this->cur_page > ($this->num_links + 1)) { - $first_url = ($this->first_url == '') ? $this->base_url : $this->first_url; - $output .= $this->first_tag_open.'<a '.$this->anchor_class.'href="'.$first_url.'">'.$this->first_link.'</a>'.$this->first_tag_close; + $first_url = ($this->first_url === '') ? $this->base_url : $this->first_url; + + // Take the general parameters, and squeeze this pagination-page attr in there for JS fw's + $attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, 1); + + $output .= $this->first_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('start').'>' + .$this->first_link.'</a>'.$this->first_tag_close; } // Render the "previous" link - if ($this->prev_link !== FALSE && $this->cur_page != 1) + if ($this->prev_link !== FALSE && $this->cur_page !== 1) { $i = ($this->use_page_numbers) ? $uri_page_number - 1 : $uri_page_number - $this->per_page; - if ($i == $base_page && $this->first_url != '') + // Take the general parameters, and squeeze this pagination-page attr in there for JS fw's + $attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i); + + if ($i === $base_page && $this->first_url !== '') { - $output .= $this->prev_tag_open.'<a '.$this->anchor_class.'href="'.$this->first_url.'">'.$this->prev_link.'</a>'.$this->prev_tag_close; + $output .= $this->prev_tag_open.'<a href="'.$this->first_url.$query_string.'"'.$attributes.$this->_attr_rel('prev').'>' + .$this->prev_link.'</a>'.$this->prev_tag_close; } else { - $i = ($i == $base_page) ? '' : $this->prefix.$i.$this->suffix; - $output .= $this->prev_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$i.'">'.$this->prev_link.'</a>'.$this->prev_tag_close; + $append = ($i === $base_page) ? $query_string : $this->prefix.$i.$this->suffix; + $output .= $this->prev_tag_open.'<a href="'.$this->base_url.$append.'"'.$attributes.$this->_attr_rel('prev').'>' + .$this->prev_link.'</a>'.$this->prev_tag_close; } } @@ -240,25 +511,28 @@ class CI_Pagination { { $i = ($this->use_page_numbers) ? $loop : ($loop * $this->per_page) - $this->per_page; + // Take the general parameters, and squeeze this pagination-page attr in there for JS fw's + $attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i); + if ($i >= $base_page) { - if ($this->cur_page == $loop) + if ($this->cur_page === $loop) { $output .= $this->cur_tag_open.$loop.$this->cur_tag_close; // Current page } else { - $n = ($i == $base_page) ? '' : $i; - - if ($n == '' && $this->first_url != '') + $n = ($i === $base_page) ? '' : $i; + if ($n === '' && ! empty($this->first_url)) { - $output .= $this->num_tag_open.'<a '.$this->anchor_class.'href="'.$this->first_url.'">'.$loop.'</a>'.$this->num_tag_close; + $output .= $this->num_tag_open.'<a href="'.$this->first_url.$query_string.'"'.$attributes.$this->_attr_rel('start').'>' + .$loop.'</a>'.$this->num_tag_close; } else { - $n = ($n == '') ? '' : $this->prefix.$n.$this->suffix; - - $output .= $this->num_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$n.'">'.$loop.'</a>'.$this->num_tag_close; + $append = ($n === '') ? $query_string : $this->prefix.$n.$this->suffix; + $output .= $this->num_tag_open.'<a href="'.$this->base_url.$append.'"'.$attributes.$this->_attr_rel('start').'>' + .$loop.'</a>'.$this->num_tag_close; } } } @@ -270,7 +544,11 @@ class CI_Pagination { { $i = ($this->use_page_numbers) ? $this->cur_page + 1 : $this->cur_page * $this->per_page; - $output .= $this->next_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$this->prefix.$i.$this->suffix.'">'.$this->next_link.'</a>'.$this->next_tag_close; + // Take the general parameters, and squeeze this pagination-page attr in there for JS fw's + $attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i); + + $output .= $this->next_tag_open.'<a href="'.$this->base_url.$this->prefix.$i.$this->suffix.'"'.$attributes + .$this->_attr_rel('next').'>'.$this->next_link.'</a>'.$this->next_tag_close; } // Render the "Last" link @@ -278,7 +556,11 @@ class CI_Pagination { { $i = ($this->use_page_numbers) ? $num_pages : ($num_pages * $this->per_page) - $this->per_page; - $output .= $this->last_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$this->prefix.$i.$this->suffix.'">'.$this->last_link.'</a>'.$this->last_tag_close; + // Take the general parameters, and squeeze this pagination-page attr in there for JS fw's + $attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i); + + $output .= $this->last_tag_open.'<a href="'.$this->base_url.$this->prefix.$i.$this->suffix.'"'.$attributes.'>' + .$this->last_link.'</a>'.$this->last_tag_close; } // Kill double slashes. Note: Sometimes we can end up with a double slash @@ -289,6 +571,49 @@ class CI_Pagination { return $this->full_tag_open.$output.$this->full_tag_close; } + // -------------------------------------------------------------------- + + /** + * Parse attributes + * + * @param array $attributes + * @return void + */ + protected function _parse_attributes($attributes) + { + isset($attributes['rel']) OR $attributes['rel'] = TRUE; + $this->_link_types = ($attributes['rel']) + ? array('start' => 'start', 'prev' => 'prev', 'next' => 'next') + : array(); + unset($attributes['rel']); + + $this->_attributes = ''; + foreach ($attributes as $key => $value) + { + $this->_attributes .= ' '.$key.'="'.$value.'"'; + } + } + + // -------------------------------------------------------------------- + + /** + * Add "rel" attribute + * + * @link http://www.w3.org/TR/html5/links.html#linkTypes + * @param string $type + * @return string + */ + protected function _attr_rel($type) + { + if (isset($this->_link_types[$type])) + { + unset($this->_link_types[$type]); + return ' rel="'.$type.'"'; + } + + return ''; + } + } /* End of file Pagination.php */ diff --git a/system/libraries/Parser.php b/system/libraries/Parser.php index d1b5b764b..faa94b7c9 100644 --- a/system/libraries/Parser.php +++ b/system/libraries/Parser.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Parser Class @@ -36,11 +37,41 @@ */ class CI_Parser { + /** + * Left delimeter character for psuedo vars + * + * @var string + */ public $l_delim = '{'; + + /** + * Right delimeter character for psuedo vars + * + * @var string + */ public $r_delim = '}'; - public $object; + + /** + * Reference to CodeIgniter instance + * + * @var object + */ protected $CI; + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @return void + */ + public function __construct() + { + $this->CI =& get_instance(); + } + + // -------------------------------------------------------------------- + /** * Parse a template * @@ -54,7 +85,6 @@ class CI_Parser { */ public function parse($template, $data, $return = FALSE) { - $this->CI =& get_instance(); $template = $this->CI->load->view($template, $data, TRUE); return $this->_parse($template, $data, $return); @@ -93,24 +123,19 @@ class CI_Parser { */ protected function _parse($template, $data, $return = FALSE) { - if ($template == '') + if ($template === '') { return FALSE; } foreach ($data as $key => $val) { - if (is_array($val)) - { - $template = $this->_parse_pair($key, $val, $template); - } - else - { - $template = $this->_parse_single($key, (string)$val, $template); - } + $template = is_array($val) + ? $this->_parse_pair($key, $val, $template) + : $template = $this->_parse_single($key, (string) $val, $template); } - if ($return == FALSE) + if ($return === FALSE) { $this->CI->output->append_output($template); } @@ -173,14 +198,9 @@ class CI_Parser { $temp = $match[1]; foreach ($row as $key => $val) { - if ( ! is_array($val)) - { - $temp = $this->_parse_single($key, $val, $temp); - } - else - { - $temp = $this->_parse_pair($key, $val, $temp); - } + $temp = is_array($val) + ? $this->_parse_pair($key, $val, $temp) + : $this->_parse_single($key, $val, $temp); } $str .= $temp; diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php index 6320ab50d..1c97e3481 100644 --- a/system/libraries/Profiler.php +++ b/system/libraries/Profiler.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Profiler Class @@ -42,23 +43,47 @@ */ class CI_Profiler { + /** + * List of profiler sections available to show + * + * @var array + */ protected $_available_sections = array( - 'benchmarks', - 'get', - 'memory_usage', - 'post', - 'uri_string', - 'controller_info', - 'queries', - 'http_headers', - 'session_data', - 'config' - ); + 'benchmarks', + 'get', + 'memory_usage', + 'post', + 'uri_string', + 'controller_info', + 'queries', + 'http_headers', + 'session_data', + 'config' + ); + /** + * Number of queries to show before making the additional queries togglable + * + * @var int + */ protected $_query_toggle_count = 25; + /** + * Reference to the CodeIgniter singleton + * + * @var object + */ protected $CI; + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * Initialize Profiler + * + * @param array $config Parameters + */ public function __construct($config = array()) { $this->CI =& get_instance(); @@ -89,11 +114,17 @@ class CI_Profiler { * * Sets the private _compile_* properties to enable/disable Profiler sections * - * @param mixed + * @param mixed $config * @return void */ public function set_sections($config) { + if (isset($config['query_toggle_count'])) + { + $this->_query_toggle_count = (int) $config['query_toggle_count']; + unset($config['query_toggle_count']); + } + foreach ($config as $method => $enable) { if (in_array($method, $this->_available_sections)) @@ -162,11 +193,24 @@ class CI_Profiler { $dbs = array(); // Let's determine which databases are currently connected to - foreach (get_object_vars($this->CI) as $CI_object) + foreach (get_object_vars($this->CI) as $name => $cobject) { - if (is_object($CI_object) && is_subclass_of(get_class($CI_object), 'CI_DB')) + if (is_object($cobject)) { - $dbs[] = $CI_object; + if ($cobject instanceof CI_DB) + { + $dbs[get_class($this->CI).':$'.$name] = $cobject; + } + elseif ($cobject instanceof CI_Model) + { + foreach (get_object_vars($cobject) as $mname => $mobject) + { + if ($mobject instanceof CI_DB) + { + $dbs[get_class($cobject).':$'.$mname] = $mobject; + } + } + } } } @@ -191,13 +235,13 @@ class CI_Profiler { $output = "\n\n"; $count = 0; - foreach ($dbs as $db) + foreach ($dbs as $name => $db) { $hide_queries = (count($db->queries) > $this->_query_toggle_count) ? ' display:none' : ''; $show_hide_js = '(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_queries_db_'.$count.'\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_hide').'\'?\''.$this->CI->lang->line('profiler_section_show').'\':\''.$this->CI->lang->line('profiler_section_hide').'\';">'.$this->CI->lang->line('profiler_section_hide').'</span>)'; - if ($hide_queries != '') + if ($hide_queries !== '') { $show_hide_js = '(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_queries_db_'.$count.'\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)'; } @@ -205,7 +249,7 @@ class CI_Profiler { $output .= '<fieldset style="border:1px solid #0000FF;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">' ."\n" .'<legend style="color:#0000FF;"> '.$this->CI->lang->line('profiler_database') - .': '.$db->database.' '.$this->CI->lang->line('profiler_queries') + .': '.$db->database.' ('.$name.') '.$this->CI->lang->line('profiler_queries') .': '.count($db->queries).' '.$show_hide_js."</legend>\n\n\n" .'<table style="width:100%;'.$hide_queries.'" id="ci_profiler_queries_db_'.$count."\">\n"; @@ -293,7 +337,7 @@ class CI_Profiler { ."\n" .'<legend style="color:#009900;"> '.$this->CI->lang->line('profiler_post_data')." </legend>\n"; - if (count($_POST) == 0) + if (count($_POST) === 0) { $output .= '<div style="color:#009900;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->lang->line('profiler_no_post').'</div>'; } @@ -343,7 +387,7 @@ class CI_Profiler { ."\n" .'<legend style="color:#000;"> '.$this->CI->lang->line('profiler_uri_string')." </legend>\n" .'<div style="color:#000;font-weight:normal;padding:4px 0 4px 0;">' - .($this->CI->uri->uri_string == '' ? $this->CI->lang->line('profiler_no_uri') : $this->CI->uri->uri_string) + .($this->CI->uri->uri_string === '' ? $this->CI->lang->line('profiler_no_uri') : $this->CI->uri->uri_string) .'</div></fieldset>'; } @@ -380,7 +424,7 @@ class CI_Profiler { ."\n" .'<legend style="color:#5a0099;"> '.$this->CI->lang->line('profiler_memory_usage')." </legend>\n" .'<div style="color:#5a0099;font-weight:normal;padding:4px 0 4px 0;">' - .((function_exists('memory_get_usage') && ($usage = memory_get_usage()) != '') ? number_format($usage).' bytes' : $this->CI->lang->line('profiler_no_memory')) + .(($usage = memory_get_usage()) != '' ? number_format($usage).' bytes' : $this->CI->lang->line('profiler_no_memory')) .'</div></fieldset>'; } @@ -505,6 +549,7 @@ class CI_Profiler { return $output.'</div>'; } + } /* End of file Profiler.php */ diff --git a/system/libraries/Session.php b/system/libraries/Session.php deleted file mode 100644 index 3515764ce..000000000 --- a/system/libraries/Session.php +++ /dev/null @@ -1,819 +0,0 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); -/** - * CodeIgniter - * - * An open source application development framework for PHP 5.2.4 or newer - * - * NOTICE OF LICENSE - * - * Licensed under the Open Software License version 3.0 - * - * This source file is subject to the Open Software License (OSL 3.0) that is - * bundled with this package in the files license.txt / license.rst. It is - * also available through the world wide web at this URL: - * http://opensource.org/licenses/OSL-3.0 - * If you did not receive a copy of the license and are unable to obtain it - * through the world wide web, please send an email to - * licensing@ellislab.com so we can send you a copy immediately. - * - * @package CodeIgniter - * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) - * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) - * @link http://codeigniter.com - * @since Version 1.0 - * @filesource - */ - -/** - * Session Class - * - * @package CodeIgniter - * @subpackage Libraries - * @category Sessions - * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/libraries/sessions.html - */ -class CI_Session { - - public $sess_encrypt_cookie = FALSE; - public $sess_use_database = FALSE; - public $sess_table_name = ''; - public $sess_expiration = 7200; - public $sess_expire_on_close = FALSE; - public $sess_match_ip = FALSE; - public $sess_match_useragent = TRUE; - public $sess_cookie_name = 'ci_session'; - public $cookie_prefix = ''; - public $cookie_path = ''; - public $cookie_domain = ''; - public $cookie_secure = FALSE; - public $cookie_httponly = FALSE; - public $sess_time_to_update = 300; - public $encryption_key = ''; - public $flashdata_key = 'flash'; - public $time_reference = 'time'; - public $gc_probability = 5; - public $userdata = array(); - public $CI; - public $now; - - /** - * Session Constructor - * - * The constructor runs the session routines automatically - * whenever the class is instantiated. - */ - public function __construct($params = array()) - { - log_message('debug', 'Session Class Initialized'); - - // Set the super object to a local variable for use throughout the class - $this->CI =& get_instance(); - - // Set all the session preferences, which can either be set - // manually via the $params array above or via the config file - foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key) - { - $this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key); - } - - if ($this->encryption_key == '') - { - show_error('In order to use the Session class you are required to set an encryption key in your config file.'); - } - - // Load the string helper so we can use the strip_slashes() function - $this->CI->load->helper('string'); - - // Do we need encryption? If so, load the encryption class - if ($this->sess_encrypt_cookie == TRUE) - { - $this->CI->load->library('encrypt'); - } - - // Are we using a database? If so, load it - if ($this->sess_use_database === TRUE && $this->sess_table_name != '') - { - $this->CI->load->database(); - } - - // Set the "now" time. Can either be GMT or server time, based on the - // config prefs. We use this to set the "last activity" time - $this->now = $this->_get_time(); - - // Set the session length. If the session expiration is - // set to zero we'll set the expiration two years from now. - if ($this->sess_expiration == 0) - { - $this->sess_expiration = (60*60*24*365*2); - } - - // Set the cookie name - $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name; - - // Run the Session routine. If a session doesn't exist we'll - // create a new one. If it does, we'll update it. - if ( ! $this->sess_read()) - { - $this->sess_create(); - } - else - { - $this->sess_update(); - } - - // Delete 'old' flashdata (from last request) - $this->_flashdata_sweep(); - - // Mark all new flashdata as old (data will be deleted before next request) - $this->_flashdata_mark(); - - // Delete expired sessions if necessary - $this->_sess_gc(); - - log_message('debug', 'Session routines successfully run'); - } - - // -------------------------------------------------------------------- - - /** - * Fetch the current session data if it exists - * - * @return bool - */ - public function sess_read() - { - // Fetch the cookie - $session = $this->CI->input->cookie($this->sess_cookie_name); - - // No cookie? Goodbye cruel world!... - if ($session === FALSE) - { - log_message('debug', 'A session cookie was not found.'); - return FALSE; - } - - // Decrypt the cookie data - if ($this->sess_encrypt_cookie == TRUE) - { - $session = $this->CI->encrypt->decode($session); - } - else - { - // encryption was not used, so we need to check the md5 hash - $hash = substr($session, strlen($session)-32); // get last 32 chars - $session = substr($session, 0, strlen($session)-32); - - // Does the md5 hash match? This is to prevent manipulation of session data in userspace - if ($hash !== md5($session.$this->encryption_key)) - { - log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.'); - $this->sess_destroy(); - return FALSE; - } - } - - // Unserialize the session array - $session = $this->_unserialize($session); - - // Is the session data we unserialized an array with the correct format? - if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity'])) - { - $this->sess_destroy(); - return FALSE; - } - - // Is the session current? - if (($session['last_activity'] + $this->sess_expiration) < $this->now) - { - $this->sess_destroy(); - return FALSE; - } - - // Does the IP match? - if ($this->sess_match_ip == TRUE && $session['ip_address'] !== $this->CI->input->ip_address()) - { - $this->sess_destroy(); - return FALSE; - } - - // Does the User Agent Match? - if ($this->sess_match_useragent == TRUE && trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120))) - { - $this->sess_destroy(); - return FALSE; - } - - // Is there a corresponding session in the DB? - if ($this->sess_use_database === TRUE) - { - $this->CI->db->where('session_id', $session['session_id']); - - if ($this->sess_match_ip == TRUE) - { - $this->CI->db->where('ip_address', $session['ip_address']); - } - - if ($this->sess_match_useragent == TRUE) - { - $this->CI->db->where('user_agent', $session['user_agent']); - } - - $query = $this->CI->db->limit(1)->get($this->sess_table_name); - - // No result? Kill it! - if ($query->num_rows() === 0) - { - $this->sess_destroy(); - return FALSE; - } - - // Is there custom data? If so, add it to the main session array - $row = $query->row(); - if (isset($row->user_data) && $row->user_data != '') - { - $custom_data = $this->_unserialize($row->user_data); - - if (is_array($custom_data)) - { - foreach ($custom_data as $key => $val) - { - $session[$key] = $val; - } - } - } - } - - // Session is valid! - $this->userdata = $session; - unset($session); - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Write the session data - * - * @return void - */ - public function sess_write() - { - // Are we saving custom data to the DB? If not, all we do is update the cookie - if ($this->sess_use_database === FALSE) - { - $this->_set_cookie(); - return; - } - - // set the custom userdata, the session data we will set in a second - $custom_userdata = $this->userdata; - $cookie_userdata = array(); - - // Before continuing, we need to determine if there is any custom data to deal with. - // Let's determine this by removing the default indexes to see if there's anything left in the array - // and set the session data while we're at it - foreach (array('session_id','ip_address','user_agent','last_activity') as $val) - { - unset($custom_userdata[$val]); - $cookie_userdata[$val] = $this->userdata[$val]; - } - - // Did we find any custom data? If not, we turn the empty array into a string - // since there's no reason to serialize and store an empty array in the DB - if (count($custom_userdata) === 0) - { - $custom_userdata = ''; - } - else - { - // Serialize the custom data array so we can store it - $custom_userdata = $this->_serialize($custom_userdata); - } - - // Run the update query - $this->CI->db->where('session_id', $this->userdata['session_id']); - $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata)); - - // Write the cookie. Notice that we manually pass the cookie data array to the - // _set_cookie() function. Normally that function will store $this->userdata, but - // in this case that array contains custom data, which we do not want in the cookie. - $this->_set_cookie($cookie_userdata); - } - - // -------------------------------------------------------------------- - - /** - * Create a new session - * - * @return void - */ - public function sess_create() - { - $sessid = ''; - do - { - $sessid .= mt_rand(0, mt_getrandmax()); - } - while (strlen($sessid) < 32); - - // To make the session ID even more secure we'll combine it with the user's IP - $sessid .= $this->CI->input->ip_address(); - - $this->userdata = array( - 'session_id' => md5(uniqid($sessid, TRUE)), - 'ip_address' => $this->CI->input->ip_address(), - 'user_agent' => substr($this->CI->input->user_agent(), 0, 120), - 'last_activity' => $this->now, - 'user_data' => '' - ); - - // Save the data to the DB if needed - if ($this->sess_use_database === TRUE) - { - $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata)); - } - - // Write the cookie - $this->_set_cookie(); - } - - // -------------------------------------------------------------------- - - /** - * Update an existing session - * - * @return void - */ - public function sess_update() - { - // We only update the session every five minutes by default - if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) - { - return; - } - - // _set_cookie() will handle this for us if we aren't using database sessions - // by pushing all userdata to the cookie. - $cookie_data = NULL; - - /* Changing the session ID during an AJAX call causes problems, - * so we'll only update our last_activity - */ - if ($this->CI->input->is_ajax_request()) - { - $this->userdata['last_activity'] = $this->now; - - // Update the session ID and last_activity field in the DB if needed - if ($this->sess_use_database === TRUE) - { - // set cookie explicitly to only have our session data - $cookie_data = array(); - foreach (array('session_id','ip_address','user_agent','last_activity') as $val) - { - $cookie_data[$val] = $this->userdata[$val]; - } - - $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, - array('last_activity' => $this->userdata['last_activity']), - array('session_id' => $this->userdata['session_id']))); - } - - return $this->_set_cookie($cookie_data); - } - - // Save the old session id so we know which record to - // update in the database if we need it - $old_sessid = $this->userdata['session_id']; - $new_sessid = ''; - do - { - $new_sessid .= mt_rand(0, mt_getrandmax()); - } - while (strlen($new_sessid) < 32); - - // To make the session ID even more secure we'll combine it with the user's IP - $new_sessid .= $this->CI->input->ip_address(); - - // Turn it into a hash and update the session data array - $this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE)); - $this->userdata['last_activity'] = $this->now; - - // Update the session ID and last_activity field in the DB if needed - if ($this->sess_use_database === TRUE) - { - // set cookie explicitly to only have our session data - $cookie_data = array(); - foreach (array('session_id','ip_address','user_agent','last_activity') as $val) - { - $cookie_data[$val] = $this->userdata[$val]; - } - - $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid))); - } - - // Write the cookie - $this->_set_cookie($cookie_data); - } - - // -------------------------------------------------------------------- - - /** - * Destroy the current session - * - * @return void - */ - public function sess_destroy() - { - // Kill the session DB row - if ($this->sess_use_database === TRUE && isset($this->userdata['session_id'])) - { - $this->CI->db->where('session_id', $this->userdata['session_id']); - $this->CI->db->delete($this->sess_table_name); - } - - // Kill the cookie - setcookie( - $this->sess_cookie_name, - addslashes(serialize(array())), - ($this->now - 31500000), - $this->cookie_path, - $this->cookie_domain, - 0 - ); - } - - // -------------------------------------------------------------------- - - /** - * Fetch a specific item from the session array - * - * @param string - * @return string - */ - public function userdata($item) - { - return isset($this->userdata[$item]) ? $this->userdata[$item] : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Fetch all session data - * - * @return array - */ - public function all_userdata() - { - return $this->userdata; - } - - // -------------------------------------------------------------------------- - - /** - * Fetch all flashdata - * - * @return array - */ - public function all_flashdata() - { - $out = array(); - - // loop through all userdata - foreach ($this->all_userdata() as $key => $val) - { - // if it contains flashdata, add it - if (strpos($key, 'flash:old:') !== FALSE) - { - $out[$key] = $val; - } - } - return $out; - } - - // -------------------------------------------------------------------- - - /** - * Add or change data in the "userdata" array - * - * @param mixed - * @param string - * @return void - */ - public function set_userdata($newdata = array(), $newval = '') - { - if (is_string($newdata)) - { - $newdata = array($newdata => $newval); - } - - if (count($newdata) > 0) - { - foreach ($newdata as $key => $val) - { - $this->userdata[$key] = $val; - } - } - - $this->sess_write(); - } - - // -------------------------------------------------------------------- - - /** - * Delete a session variable from the "userdata" array - * - * @return void - */ - public function unset_userdata($newdata = array()) - { - if (is_string($newdata)) - { - $newdata = array($newdata => ''); - } - - if (count($newdata) > 0) - { - foreach ($newdata as $key => $val) - { - unset($this->userdata[$key]); - } - } - - $this->sess_write(); - } - - // ------------------------------------------------------------------------ - - /** - * Add or change flashdata, only available - * until the next request - * - * @param mixed - * @param string - * @return void - */ - public function set_flashdata($newdata = array(), $newval = '') - { - if (is_string($newdata)) - { - $newdata = array($newdata => $newval); - } - - if (count($newdata) > 0) - { - foreach ($newdata as $key => $val) - { - $this->set_userdata($this->flashdata_key.':new:'.$key, $val); - } - } - } - - // ------------------------------------------------------------------------ - - /** - * Keeps existing flashdata available to next request. - * - * @param string - * @return void - */ - public function keep_flashdata($key) - { - // 'old' flashdata gets removed. Here we mark all - // flashdata as 'new' to preserve it from _flashdata_sweep() - // Note the function will return FALSE if the $key - // provided cannot be found - $value = $this->userdata($this->flashdata_key.':old:'.$key); - - $this->set_userdata($this->flashdata_key.':new:'.$key, $value); - } - - // ------------------------------------------------------------------------ - - /** - * Fetch a specific flashdata item from the session array - * - * @param string - * @return string - */ - public function flashdata($key) - { - return $this->userdata($this->flashdata_key.':old:'.$key); - } - - // ------------------------------------------------------------------------ - - /** - * Identifies flashdata as 'old' for removal - * when _flashdata_sweep() runs. - * - * @return void - */ - protected function _flashdata_mark() - { - $userdata = $this->all_userdata(); - foreach ($userdata as $name => $value) - { - $parts = explode(':new:', $name); - if (is_array($parts) && count($parts) === 2) - { - $this->set_userdata($this->flashdata_key.':old:'.$parts[1], $value); - $this->unset_userdata($name); - } - } - } - - // ------------------------------------------------------------------------ - - /** - * Removes all flashdata marked as 'old' - * - * @return void - */ - protected function _flashdata_sweep() - { - $userdata = $this->all_userdata(); - foreach ($userdata as $key => $value) - { - if (strpos($key, ':old:')) - { - $this->unset_userdata($key); - } - } - - } - - // -------------------------------------------------------------------- - - /** - * Get the "now" time - * - * @return string - */ - protected function _get_time() - { - return (strtolower($this->time_reference) === 'gmt') - ? mktime(gmdate('H'), gmdate('i'), gmdate('s'), gmdate('m'), gmdate('d'), gmdate('Y')) - : time(); - } - - // -------------------------------------------------------------------- - - /** - * Write the session cookie - * - * @return void - */ - protected function _set_cookie($cookie_data = NULL) - { - if (is_null($cookie_data)) - { - $cookie_data = $this->userdata; - } - - // Serialize the userdata for the cookie - $cookie_data = $this->_serialize($cookie_data); - - if ($this->sess_encrypt_cookie == TRUE) - { - $cookie_data = $this->CI->encrypt->encode($cookie_data); - } - else - { - // if encryption is not used, we provide an md5 hash to prevent userside tampering - $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key); - } - - $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); - - // Set the cookie - setcookie( - $this->sess_cookie_name, - $cookie_data, - $expire, - $this->cookie_path, - $this->cookie_domain, - $this->cookie_secure, - $this->cookie_httponly - ); - } - - // -------------------------------------------------------------------- - - /** - * Serialize an array - * - * This function first converts any slashes found in the array to a temporary - * marker, so when it gets unserialized the slashes will be preserved - * - * @param array - * @return string - */ - protected function _serialize($data) - { - if (is_array($data)) - { - array_walk_recursive($data, array(&$this, '_escape_slashes')); - } - elseif (is_string($data)) - { - $data = str_replace('\\', '{{slash}}', $data); - } - return serialize($data); - } - - /** - * Escape slashes - * - * This function converts any slashes found into a temporary marker - * - * @param string - * @param string - * @return void - */ - protected function _escape_slashes(&$val, $key) - { - if (is_string($val)) - { - $val = str_replace('\\', '{{slash}}', $val); - } - } - - // -------------------------------------------------------------------- - - /** - * Unserialize - * - * This function unserializes a data string, then converts any - * temporary slash markers back to actual slashes - * - * @param array - * @return string - */ - protected function _unserialize($data) - { - $data = @unserialize(strip_slashes(trim($data))); - - if (is_array($data)) - { - array_walk_recursive($data, array(&$this, '_unescape_slashes')); - return $data; - } - - return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data; - } - - // -------------------------------------------------------------------- - - /** - * Unescape slashes - * - * This function converts any slash markers back into actual slashes - * - * @param string - * @param string - * @return void - */ - protected function _unescape_slashes(&$val, $key) - { - if (is_string($val)) - { - $val= str_replace('{{slash}}', '\\', $val); - } - } - - // -------------------------------------------------------------------- - - /** - * Garbage collection - * - * This deletes expired session rows from database - * if the probability percentage is met - * - * @return void - */ - protected function _sess_gc() - { - if ($this->sess_use_database != TRUE) - { - return; - } - - srand(time()); - if ((rand() % 100) < $this->gc_probability) - { - $expire = $this->now - $this->sess_expiration; - - $this->CI->db->where('last_activity < '.$expire); - $this->CI->db->delete($this->sess_table_name); - - log_message('debug', 'Session garbage collection performed.'); - } - } - -} - -/* End of file Session.php */ -/* Location: ./system/libraries/Session.php */
\ No newline at end of file diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php new file mode 100755 index 000000000..96e65f154 --- /dev/null +++ b/system/libraries/Session/Session.php @@ -0,0 +1,744 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * CodeIgniter Session Class + * + * The user interface defined by EllisLabs, now with puggable drivers to manage different storage mechanisms. + * By default, the cookie session driver will load, but the 'sess_driver' config/param item (see above) can be + * used to specify the 'native' driver, or any other you might create. + * Once loaded, this driver setup is a drop-in replacement for the former CI_Session library, taking its place as the + * 'session' member of the global controller framework (e.g.: $CI->session or $this->session). + * In keeping with the CI_Driver methodology, multiple drivers may be loaded, although this might be a bit confusing. + * The CI_Session library class keeps track of the most recently loaded driver as "current" to call for driver methods. + * Ideally, one driver is loaded and all calls go directly through the main library interface. However, any methods + * called through the specific driver will switch the "current" driver to itself before invoking the library method + * (which will then call back into the driver for low-level operations). So, alternation between two drivers can be + * achieved by specifying which driver to use for each call (e.g.: $this->session->native->set_userdata('foo', 'bar'); + * $this->session->cookie->userdata('foo'); $this->session->native->unset_userdata('foo');). Notice in the previous + * example that the _native_ userdata value 'foo' would be set to 'bar', which would NOT be returned by the call for + * the _cookie_ userdata 'foo', nor would the _cookie_ value be unset by the call to unset the _native_ 'foo' value. + * + * @package CodeIgniter + * @subpackage Libraries + * @category Sessions + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/libraries/sessions.html + */ +class CI_Session extends CI_Driver_Library { + + /** + * Initialization parameters + * + * @var array + */ + public $params = array(); + + /** + * Current driver in use + * + * @var string + */ + protected $current = NULL; + + /** + * User data + * + * @var array + */ + protected $userdata = array(); + + // ------------------------------------------------------------------------ + + const FLASHDATA_KEY = 'flash'; + const FLASHDATA_NEW = ':new:'; + const FLASHDATA_OLD = ':old:'; + const FLASHDATA_EXP = ':exp:'; + const EXPIRATION_KEY = '__expirations'; + const TEMP_EXP_DEF = 300; + + // ------------------------------------------------------------------------ + + /** + * CI_Session constructor + * + * The constructor loads the configured driver ('sess_driver' in config.php or as a parameter), running + * routines in its constructor, and manages flashdata aging. + * + * @param array Configuration parameters + * @return void + */ + public function __construct(array $params = array()) + { + $CI =& get_instance(); + + // No sessions under CLI + if ($CI->input->is_cli_request()) + { + return; + } + + log_message('debug', 'CI_Session Class Initialized'); + + // Get valid drivers list + $this->valid_drivers = array( + 'Session_native', + 'Session_cookie' + ); + $key = 'sess_valid_drivers'; + $drivers = isset($params[$key]) ? $params[$key] : $CI->config->item($key); + if ($drivers) + { + is_array($drivers) OR $drivers = array($drivers); + + // Add driver names to valid list + foreach ($drivers as $driver) + { + if ( ! in_array(strtolower($driver), array_map('strtolower', $this->valid_drivers))) + { + $this->valid_drivers[] = $driver; + } + } + } + + // Get driver to load + $key = 'sess_driver'; + $driver = isset($params[$key]) ? $params[$key] : $CI->config->item($key); + if ( ! $driver) + { + $driver = 'cookie'; + } + + if ( ! in_array('session_'.strtolower($driver), array_map('strtolower', $this->valid_drivers))) + { + $this->valid_drivers[] = 'Session_'.$driver; + } + + // Save a copy of parameters in case drivers need access + $this->params = $params; + + // Load driver and get array reference + $this->load_driver($driver); + + // Delete 'old' flashdata (from last request) + $this->_flashdata_sweep(); + + // Mark all new flashdata as old (data will be deleted before next request) + $this->_flashdata_mark(); + + // Delete expired tempdata + $this->_tempdata_sweep(); + + log_message('debug', 'CI_Session routines successfully run'); + } + + // ------------------------------------------------------------------------ + + /** + * Loads session storage driver + * + * @param string Driver classname + * @return object Loaded driver object + */ + public function load_driver($driver) + { + // Save reference to most recently loaded driver as library default and sync userdata + $this->current = parent::load_driver($driver); + $this->userdata =& $this->current->get_userdata(); + return $this->current; + } + + // ------------------------------------------------------------------------ + + /** + * Select default session storage driver + * + * @param string Driver classname + * @return void + */ + public function select_driver($driver) + { + // Validate driver name + $lowername = strtolower(str_replace('CI_', '', $driver)); + if (in_array($lowername, array_map('strtolower', $this->valid_drivers))) + { + // See if driver is loaded + $child = str_replace($this->lib_name.'_', '', $driver); + if (isset($this->$child)) + { + // See if driver is already current + if ($this->$child !== $this->current) + { + // Make driver current and sync userdata + $this->current = $this->$child; + $this->userdata =& $this->current->get_userdata(); + } + } + else + { + // Load new driver + $this->load_driver($child); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Destroy the current session + * + * @return void + */ + public function sess_destroy() + { + // Just call destroy on driver + $this->current->sess_destroy(); + } + + // ------------------------------------------------------------------------ + + /** + * Regenerate the current session + * + * @param bool Destroy session data flag (default: false) + * @return void + */ + public function sess_regenerate($destroy = FALSE) + { + // Call regenerate on driver and resync userdata + $this->current->sess_regenerate($destroy); + $this->userdata =& $this->current->get_userdata(); + } + + // ------------------------------------------------------------------------ + + /** + * Fetch a specific item from the session array + * + * @param string Item key + * @return string Item value or NULL if not found + */ + public function userdata($item) + { + return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL; + } + + // ------------------------------------------------------------------------ + + /** + * Fetch all session data + * + * @return array User data array + */ + public function all_userdata() + { + return isset($this->userdata) ? $this->userdata : NULL; + } + + // ------------------------------------------------------------------------ + + /** + * Fetch all flashdata + * + * @return array Flash data array + */ + public function all_flashdata() + { + $out = array(); + + // loop through all userdata + foreach ($this->all_userdata() as $key => $val) + { + // if it contains flashdata, add it + if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_OLD) !== FALSE) + { + $key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_OLD, '', $key); + $out[$key] = $val; + } + } + return $out; + } + + // ------------------------------------------------------------------------ + + /** + * Add or change data in the "userdata" array + * + * @param mixed Item name or array of items + * @param string Item value or empty string + * @return void + */ + public function set_userdata($newdata = array(), $newval = '') + { + // Wrap params as array if singular + if (is_string($newdata)) + { + $newdata = array($newdata => $newval); + } + + // Set each name/value pair + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + $this->userdata[$key] = $val; + } + } + + // Tell driver data changed + $this->current->sess_save(); + } + + // ------------------------------------------------------------------------ + + /** + * Delete a session variable from the "userdata" array + * + * @param mixed Item name or array of item names + * @return void + */ + public function unset_userdata($newdata = array()) + { + // Wrap single name as array + if (is_string($newdata)) + { + $newdata = array($newdata => ''); + } + + // Unset each item name + if (count($newdata) > 0) + { + foreach (array_keys($newdata) as $key) + { + unset($this->userdata[$key]); + } + } + + // Tell driver data changed + $this->current->sess_save(); + } + + // ------------------------------------------------------------------------ + + /** + * Determine if an item exists + * + * @param string Item name + * @return bool + */ + public function has_userdata($item) + { + return isset($this->userdata[$item]); + } + + // ------------------------------------------------------------------------ + + /** + * Add or change flashdata, only available until the next request + * + * @param mixed Item name or array of items + * @param string Item value or empty string + * @return void + */ + public function set_flashdata($newdata = array(), $newval = '') + { + // Wrap item as array if singular + if (is_string($newdata)) + { + $newdata = array($newdata => $newval); + } + + // Prepend each key name and set value + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key; + $this->set_userdata($flashdata_key, $val); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Keeps existing flashdata available to next request. + * + * @param string Item key + * @return void + */ + public function keep_flashdata($key) + { + // 'old' flashdata gets removed. Here we mark all flashdata as 'new' to preserve it from _flashdata_sweep() + // Note the function will return NULL if the $key provided cannot be found + $old_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key; + $value = $this->userdata($old_flashdata_key); + + $new_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key; + $this->set_userdata($new_flashdata_key, $value); + } + + // ------------------------------------------------------------------------ + + /** + * Fetch a specific flashdata item from the session array + * + * @param string Item key + * @return string + */ + public function flashdata($key) + { + // Prepend key and retrieve value + $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key; + return $this->userdata($flashdata_key); + } + + // ------------------------------------------------------------------------ + + /** + * Add or change tempdata, only available until expiration + * + * @param mixed Item name or array of items + * @param string Item value or empty string + * @param int Item lifetime in seconds or 0 for default + * @return void + */ + public function set_tempdata($newdata = array(), $newval = '', $expire = 0) + { + // Set expiration time + $expire = time() + ($expire ? $expire : self::TEMP_EXP_DEF); + + // Wrap item as array if singular + if (is_string($newdata)) + { + $newdata = array($newdata => $newval); + } + + // Get or create expiration list + $expirations = $this->userdata(self::EXPIRATION_KEY); + if ( ! $expirations) + { + $expirations = array(); + } + + // Prepend each key name and set value + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key; + $expirations[$tempdata_key] = $expire; + $this->set_userdata($tempdata_key, $val); + } + } + + // Update expiration list + $this->set_userdata(self::EXPIRATION_KEY, $expirations); + } + + // ------------------------------------------------------------------------ + + /** + * Delete a temporary session variable from the "userdata" array + * + * @param mixed Item name or array of item names + * @return void + */ + public function unset_tempdata($newdata = array()) + { + // Get expirations list + $expirations = $this->userdata(self::EXPIRATION_KEY); + if (empty($expirations)) + { + // Nothing to do + return; + } + + // Wrap single name as array + if (is_string($newdata)) + { + $newdata = array($newdata => ''); + } + + // Prepend each item name and unset + if (count($newdata) > 0) + { + foreach (array_keys($newdata) as $key) + { + $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key; + unset($expirations[$tempdata_key]); + $this->unset_userdata($tempdata_key); + } + } + + // Update expiration list + $this->set_userdata(self::EXPIRATION_KEY, $expirations); + } + + // ------------------------------------------------------------------------ + + /** + * Fetch a specific tempdata item from the session array + * + * @param string Item key + * @return string + */ + public function tempdata($key) + { + // Prepend key and return value + $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key; + return $this->userdata($tempdata_key); + } + + // ------------------------------------------------------------------------ + + /** + * Identifies flashdata as 'old' for removal + * when _flashdata_sweep() runs. + * + * @return void + */ + protected function _flashdata_mark() + { + foreach ($this->all_userdata() as $name => $value) + { + $parts = explode(self::FLASHDATA_NEW, $name); + if (count($parts) === 2) + { + $new_name = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$parts[1]; + $this->set_userdata($new_name, $value); + $this->unset_userdata($name); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Removes all flashdata marked as 'old' + * + * @return void + */ + protected function _flashdata_sweep() + { + $userdata = $this->all_userdata(); + foreach (array_keys($userdata) as $key) + { + if (strpos($key, self::FLASHDATA_OLD)) + { + $this->unset_userdata($key); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Removes all expired tempdata + * + * @return void + */ + protected function _tempdata_sweep() + { + // Get expirations list + $expirations = $this->userdata(self::EXPIRATION_KEY); + if (empty($expirations)) + { + // Nothing to do + return; + } + + // Unset expired elements + $now = time(); + $userdata = $this->all_userdata(); + foreach (array_keys($userdata) as $key) + { + if (strpos($key, self::FLASHDATA_EXP) && $expirations[$key] < $now) + { + unset($expirations[$key]); + $this->unset_userdata($key); + } + } + + // Update expiration list + $this->set_userdata(self::EXPIRATION_KEY, $expirations); + } + +} + +// ------------------------------------------------------------------------ + +/** + * CI_Session_driver Class + * + * Extend this class to make a new CI_Session driver. + * A CI_Session driver basically manages an array of name/value pairs with some sort of storage mechanism. + * To make a new driver, derive from (extend) CI_Session_driver. Overload the initialize method and read or create + * session data. Then implement a save handler to write changed data to storage (sess_save), a destroy handler + * to remove deleted data (sess_destroy), and an access handler to expose the data (get_userdata). + * Put your driver in the libraries/Session/drivers folder anywhere in the loader paths. This includes the + * application directory, the system directory, or any path you add with $CI->load->add_package_path(). + * Your driver must be named CI_Session_<name>, and your filename must be Session_<name>.php, + * preferably also capitalized. (e.g.: CI_Session_foo in libraries/Session/drivers/Session_foo.php) + * Then specify the driver by setting 'sess_driver' in your config file or as a parameter when loading the CI_Session + * object. (e.g.: $config['sess_driver'] = 'foo'; OR $CI->load->driver('session', array('sess_driver' => 'foo')); ) + * Already provided are the Native driver, which manages the native PHP $_SESSION array, and + * the Cookie driver, which manages the data in a browser cookie, with optional extra storage in a database table. + * + * @package CodeIgniter + * @subpackage Libraries + * @category Sessions + * @author EllisLab Dev Team + */ +abstract class CI_Session_driver extends CI_Driver { + + /** + * CI Singleton + * + * @see get_instance() + * @var object + */ + protected $CI; + + // ------------------------------------------------------------------------ + + /** + * Constructor + * + * Gets the CI singleton, so that individual drivers + * don't have to do it separately. + * + * @return void + */ + public function __construct() + { + $this->CI =& get_instance(); + } + + // ------------------------------------------------------------------------ + + /** + * Decorate + * + * Decorates the child with the parent driver lib's methods and properties + * + * @param object Parent library object + * @return void + */ + public function decorate($parent) + { + // Call base class decorate first + parent::decorate($parent); + + // Call initialize method now that driver has access to $this->_parent + $this->initialize(); + } + + // ------------------------------------------------------------------------ + + /** + * __call magic method + * + * Handles access to the parent driver library's methods + * + * @param string Library method name + * @param array Method arguments (default: none) + * @return mixed + */ + public function __call($method, $args = array()) + { + // Make sure the parent library uses this driver + $this->_parent->select_driver(get_class($this)); + return parent::__call($method, $args); + } + + // ------------------------------------------------------------------------ + + /** + * Initialize driver + * + * @return void + */ + protected function initialize() + { + // Overload this method to implement initialization + } + + // ------------------------------------------------------------------------ + + /** + * Save the session data + * + * Data in the array has changed - perform any storage synchronization + * necessary. The child class MUST implement this abstract method! + * + * @return void + */ + abstract public function sess_save(); + + // ------------------------------------------------------------------------ + + /** + * Destroy the current session + * + * Clean up storage for this session - it has been terminated. + * The child class MUST implement this abstract method! + * + * @return void + */ + abstract public function sess_destroy(); + + // ------------------------------------------------------------------------ + + /** + * Regenerate the current session + * + * Regenerate the session ID. + * The child class MUST implement this abstract method! + * + * @param bool Destroy session data flag (default: false) + * @return void + */ + abstract public function sess_regenerate($destroy = FALSE); + + // ------------------------------------------------------------------------ + + /** + * Get a reference to user data array + * + * Give array access to the main CI_Session object. + * The child class MUST implement this abstract method! + * + * @return array Reference to userdata + */ + abstract public function &get_userdata(); + +} + +/* End of file Session.php */ +/* Location: ./system/libraries/Session/Session.php */
\ No newline at end of file diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php new file mode 100755 index 000000000..3c4848265 --- /dev/null +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -0,0 +1,845 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * Cookie-based session management driver + * + * This is the classic CI_Session functionality, as written by EllisLab, abstracted out to a driver. + * + * @package CodeIgniter + * @subpackage Libraries + * @category Sessions + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/libraries/sessions.html + */ +class CI_Session_cookie extends CI_Session_driver { + + /** + * Whether to encrypt the session cookie + * + * @var bool + */ + public $sess_encrypt_cookie = FALSE; + + /** + * Whether to use to the database for session storage + * + * @var bool + */ + public $sess_use_database = FALSE; + + /** + * Name of the database table in which to store sessions + * + * @var string + */ + public $sess_table_name = ''; + + /** + * Length of time (in seconds) for sessions to expire + * + * @var int + */ + public $sess_expiration = 7200; + + /** + * Whether to kill session on close of browser window + * + * @var bool + */ + public $sess_expire_on_close = FALSE; + + /** + * Whether to match session on ip address + * + * @var bool + */ + public $sess_match_ip = FALSE; + + /** + * Whether to match session on user-agent + * + * @var bool + */ + public $sess_match_useragent = TRUE; + + /** + * Name of session cookie + * + * @var string + */ + public $sess_cookie_name = 'ci_session'; + + /** + * Session cookie prefix + * + * @var string + */ + public $cookie_prefix = ''; + + /** + * Session cookie path + * + * @var string + */ + public $cookie_path = ''; + + /** + * Session cookie domain + * + * @var string + */ + public $cookie_domain = ''; + + /** + * Whether to set the cookie only on HTTPS connections + * + * @var bool + */ + public $cookie_secure = FALSE; + + /** + * Whether cookie should be allowed only to be sent by the server + * + * @var bool + */ + public $cookie_httponly = FALSE; + + /** + * Interval at which to update session + * + * @var int + */ + public $sess_time_to_update = 300; + + /** + * Key with which to encrypt the session cookie + * + * @var string + */ + public $encryption_key = ''; + + /** + * Timezone to use for the current time + * + * @var string + */ + public $time_reference = 'local'; + + /** + * Session data + * + * @var array + */ + public $userdata = array(); + + /** + * Current time + * + * @var int + */ + public $now; + + /** + * Default userdata keys + * + * @var array + */ + protected $defaults = array( + 'session_id' => NULL, + 'ip_address' => NULL, + 'user_agent' => NULL, + 'last_activity' => NULL + ); + + /** + * Data needs DB update flag + * + * @var bool + */ + protected $data_dirty = FALSE; + + /** + * Initialize session driver object + * + * @return void + */ + protected function initialize() + { + // Set all the session preferences, which can either be set + // manually via the $params array or via the config file + $prefs = array( + 'sess_encrypt_cookie', + 'sess_use_database', + 'sess_table_name', + 'sess_expiration', + 'sess_expire_on_close', + 'sess_match_ip', + 'sess_match_useragent', + 'sess_cookie_name', + 'cookie_path', + 'cookie_domain', + 'cookie_secure', + 'cookie_httponly', + 'sess_time_to_update', + 'time_reference', + 'cookie_prefix', + 'encryption_key' + ); + + foreach ($prefs as $key) + { + $this->$key = isset($this->_parent->params[$key]) + ? $this->_parent->params[$key] + : $this->CI->config->item($key); + } + + if ($this->encryption_key === '') + { + show_error('In order to use the Cookie Session driver you are required to set an encryption key in your config file.'); + } + + // Do we need encryption? If so, load the encryption class + if ($this->sess_encrypt_cookie === TRUE) + { + $this->CI->load->library('encrypt'); + } + + // Check for database + if ($this->sess_use_database === TRUE && $this->sess_table_name !== '') + { + // Load database driver + $this->CI->load->database(); + + // Register shutdown function + register_shutdown_function(array($this, '_update_db')); + } + + // Set the "now" time. Can either be GMT or server time, based on the config prefs. + // We use this to set the "last activity" time + $this->now = $this->_get_time(); + + // Set the session length. If the session expiration is + // set to zero we'll set the expiration two years from now. + if ($this->sess_expiration === 0) + { + $this->sess_expiration = (60*60*24*365*2); + } + + // Set the cookie name + $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name; + + // Run the Session routine. If a session doesn't exist we'll + // create a new one. If it does, we'll update it. + if ( ! $this->_sess_read()) + { + $this->_sess_create(); + } + else + { + $this->_sess_update(); + } + + // Delete expired sessions if necessary + $this->_sess_gc(); + } + + // ------------------------------------------------------------------------ + + /** + * Write the session data + * + * @return void + */ + public function sess_save() + { + // Check for database + if ($this->sess_use_database === TRUE) + { + // Mark custom data as dirty so we know to update the DB + $this->data_dirty = TRUE; + } + + // Write the cookie + $this->_set_cookie(); + } + + // ------------------------------------------------------------------------ + + /** + * Destroy the current session + * + * @return void + */ + public function sess_destroy() + { + // Kill the session DB row + if ($this->sess_use_database === TRUE && isset($this->userdata['session_id'])) + { + $this->CI->db->delete($this->sess_table_name, array('session_id' => $this->userdata['session_id'])); + $this->data_dirty = FALSE; + } + + // Kill the cookie + $this->_setcookie($this->sess_cookie_name, '', ($this->now - 31500000), + $this->cookie_path, $this->cookie_domain, 0); + + // Kill session data + $this->userdata = array(); + } + + // ------------------------------------------------------------------------ + + /** + * Regenerate the current session + * + * Regenerate the session id + * + * @param bool Destroy session data flag (default: false) + * @return void + */ + public function sess_regenerate($destroy = FALSE) + { + // Check destroy flag + if ($destroy) + { + // Destroy old session and create new one + $this->sess_destroy(); + $this->_sess_create(); + } + else + { + // Just force an update to recreate the id + $this->_sess_update(TRUE); + } + } + + // ------------------------------------------------------------------------ + + /** + * Get a reference to user data array + * + * @return array Reference to userdata + */ + public function &get_userdata() + { + return $this->userdata; + } + + // ------------------------------------------------------------------------ + + /** + * Fetch the current session data if it exists + * + * @return bool + */ + protected function _sess_read() + { + // Fetch the cookie + $session = $this->CI->input->cookie($this->sess_cookie_name); + + // No cookie? Goodbye cruel world!... + if ($session === NULL) + { + log_message('debug', 'A session cookie was not found.'); + return FALSE; + } + + $len = strlen($session) - 40; + + if ($len < 0) + { + log_message('debug', 'The session cookie was not signed.'); + return FALSE; + } + + // Check cookie authentication + $hmac = substr($session, $len); + $session = substr($session, 0, $len); + + if ($hmac !== hash_hmac('sha1', $session, $this->encryption_key)) + { + log_message('error', 'The session cookie data did not match what was expected.'); + $this->sess_destroy(); + return FALSE; + } + + // Check for encryption + if ($this->sess_encrypt_cookie === TRUE) + { + // Decrypt the cookie data + $session = $this->CI->encrypt->decode($session); + } + + // Unserialize the session array + $session = $this->_unserialize($session); + + // Is the session data we unserialized an array with the correct format? + if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity'])) + { + $this->sess_destroy(); + return FALSE; + } + + // Is the session current? + if (($session['last_activity'] + $this->sess_expiration) < $this->now OR $session['last_activity'] > $this->now) + { + $this->sess_destroy(); + return FALSE; + } + + // Does the IP match? + if ($this->sess_match_ip === TRUE && $session['ip_address'] !== $this->CI->input->ip_address()) + { + $this->sess_destroy(); + return FALSE; + } + + // Does the User Agent Match? + if ($this->sess_match_useragent === TRUE && + trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120))) + { + $this->sess_destroy(); + return FALSE; + } + + // Is there a corresponding session in the DB? + if ($this->sess_use_database === TRUE) + { + $this->CI->db->where('session_id', $session['session_id']); + + if ($this->sess_match_ip === TRUE) + { + $this->CI->db->where('ip_address', $session['ip_address']); + } + + if ($this->sess_match_useragent === TRUE) + { + $this->CI->db->where('user_agent', $session['user_agent']); + } + + // Is caching in effect? Turn it off + $db_cache = $this->CI->db->cache_on; + $this->CI->db->cache_off(); + + $query = $this->CI->db->limit(1)->get($this->sess_table_name); + + // Was caching in effect? + if ($db_cache) + { + // Turn it back on + $this->CI->db->cache_on(); + } + + // No result? Kill it! + if ($query->num_rows() === 0) + { + $this->sess_destroy(); + return FALSE; + } + + // Is there custom data? If so, add it to the main session array + $row = $query->row(); + if ( ! empty($row->user_data)) + { + $custom_data = $this->_unserialize($row->user_data); + + if (is_array($custom_data)) + { + $session = $session + $custom_data; + } + } + } + + // Session is valid! + $this->userdata = $session; + return TRUE; + } + + // ------------------------------------------------------------------------ + + /** + * Create a new session + * + * @return void + */ + protected function _sess_create() + { + // Initialize userdata + $this->userdata = array( + 'session_id' => $this->_make_sess_id(), + 'ip_address' => $this->CI->input->ip_address(), + 'user_agent' => substr($this->CI->input->user_agent(), 0, 120), + 'last_activity' => $this->now, + ); + + // Check for database + if ($this->sess_use_database === TRUE) + { + // Add empty user_data field and save the data to the DB + $this->CI->db->set('user_data', '')->insert($this->sess_table_name, $this->userdata); + } + + // Write the cookie + $this->_set_cookie(); + } + + // ------------------------------------------------------------------------ + + /** + * Update an existing session + * + * @param bool Force update flag (default: false) + * @return void + */ + protected function _sess_update($force = FALSE) + { + // We only update the session every five minutes by default (unless forced) + if ( ! $force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) + { + return; + } + + // Update last activity to now + $this->userdata['last_activity'] = $this->now; + + // Save the old session id so we know which DB record to update + $old_sessid = $this->userdata['session_id']; + + // Changing the session ID during an AJAX call causes problems + if ( ! $this->CI->input->is_ajax_request()) + { + // Get new id + $this->userdata['session_id'] = $this->_make_sess_id(); + } + + // Check for database + if ($this->sess_use_database === TRUE) + { + $this->CI->db->where('session_id', $old_sessid); + + if ($this->sess_match_ip === TRUE) + { + $this->CI->db->where('ip_address', $this->CI->input->ip_address()); + } + + if ($this->sess_match_useragent === TRUE) + { + $this->CI->db->where('user_agent', trim(substr($this->CI->input->user_agent(), 0, 120))); + } + + // Update the session ID and last_activity field in the DB + $this->CI->db->update($this->sess_table_name, + array( + 'last_activity' => $this->now, + 'session_id' => $this->userdata['session_id'] + ) + ); + } + + // Write the cookie + $this->_set_cookie(); + } + + // ------------------------------------------------------------------------ + + /** + * Update database with current data + * + * This gets called from the shutdown function and also + * registered with PHP to run at the end of the request + * so it's guaranteed to update even when a fatal error + * occurs. The first call makes the update and clears the + * dirty flag so it won't happen twice. + * + * @return void + */ + public function _update_db() + { + // Check for database and dirty flag and unsaved + if ($this->sess_use_database === TRUE && $this->data_dirty === TRUE) + { + // Set up activity and data fields to be set + // If we don't find custom data, user_data will remain an empty string + $set = array( + 'last_activity' => $this->userdata['last_activity'], + 'user_data' => '' + ); + + // Get the custom userdata, leaving out the defaults + // (which get stored in the cookie) + $userdata = array_diff_key($this->userdata, $this->defaults); + + // Did we find any custom data? + if ( ! empty($userdata)) + { + // Serialize the custom data array so we can store it + $set['user_data'] = $this->_serialize($userdata); + } + + // Run the update query + // Any time we change the session id, it gets updated immediately, + // so our where clause below is always safe + $this->CI->db->where('session_id', $this->userdata['session_id']); + + if ($this->sess_match_ip === TRUE) + { + $this->CI->db->where('ip_address', $this->CI->input->ip_address()); + } + + if ($this->sess_match_useragent === TRUE) + { + $this->CI->db->where('user_agent', trim(substr($this->CI->input->user_agent(), 0, 120))); + } + + $this->CI->db->update($this->sess_table_name, $set); + + // Clear dirty flag to prevent double updates + $this->data_dirty = FALSE; + + log_message('debug', 'CI_Session Data Saved To DB'); + } + } + + // ------------------------------------------------------------------------ + + /** + * Generate a new session id + * + * @return string Hashed session id + */ + protected function _make_sess_id() + { + $new_sessid = ''; + do + { + $new_sessid .= mt_rand(0, mt_getrandmax()); + } + while (strlen($new_sessid) < 32); + + // To make the session ID even more secure we'll combine it with the user's IP + $new_sessid .= $this->CI->input->ip_address(); + + // Turn it into a hash and return + return md5(uniqid($new_sessid, TRUE)); + } + + // ------------------------------------------------------------------------ + + /** + * Get the "now" time + * + * @return int Time + */ + protected function _get_time() + { + if ($this->time_reference === 'local' OR $this->time_reference === date_default_timezone_get()) + { + return time(); + } + + $datetime = new DateTime('now', new DateTimeZone($this->time_reference)); + sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second); + + return mktime($hour, $minute, $second, $month, $day, $year); + } + + // ------------------------------------------------------------------------ + + /** + * Write the session cookie + * + * @return void + */ + protected function _set_cookie() + { + // Get userdata (only defaults if database) + $cookie_data = ($this->sess_use_database === TRUE) + ? array_intersect_key($this->userdata, $this->defaults) + : $this->userdata; + + // Serialize the userdata for the cookie + $cookie_data = $this->_serialize($cookie_data); + + if ($this->sess_encrypt_cookie === TRUE) + { + $cookie_data = $this->CI->encrypt->encode($cookie_data); + } + + // Require message authentication + $cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key); + + $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); + + // Set the cookie + $this->_setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain, + $this->cookie_secure, $this->cookie_httponly); + } + + // ------------------------------------------------------------------------ + + /** + * Set a cookie with the system + * + * This abstraction of the setcookie call allows overriding for unit testing + * + * @param string Cookie name + * @param string Cookie value + * @param int Expiration time + * @param string Cookie path + * @param string Cookie domain + * @param bool Secure connection flag + * @param bool HTTP protocol only flag + * @return void + */ + protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = FALSE, $httponly = FALSE) + { + setcookie($name, $value, $expire, $path, $domain, $secure, $httponly); + } + + // ------------------------------------------------------------------------ + + /** + * Serialize an array + * + * This function first converts any slashes found in the array to a temporary + * marker, so when it gets unserialized the slashes will be preserved + * + * @param mixed Data to serialize + * @return string Serialized data + */ + protected function _serialize($data) + { + if (is_array($data)) + { + array_walk_recursive($data, array(&$this, '_escape_slashes')); + } + elseif (is_string($data)) + { + $data = str_replace('\\', '{{slash}}', $data); + } + + return serialize($data); + } + + // ------------------------------------------------------------------------ + + /** + * Escape slashes + * + * This function converts any slashes found into a temporary marker + * + * @param string Value + * @param string Key + * @return void + */ + protected function _escape_slashes(&$val, $key) + { + if (is_string($val)) + { + $val = str_replace('\\', '{{slash}}', $val); + } + } + + // ------------------------------------------------------------------------ + + /** + * Unserialize + * + * This function unserializes a data string, then converts any + * temporary slash markers back to actual slashes + * + * @param mixed Data to unserialize + * @return mixed Unserialized data + */ + protected function _unserialize($data) + { + $data = @unserialize(trim($data)); + + if (is_array($data)) + { + array_walk_recursive($data, array(&$this, '_unescape_slashes')); + return $data; + } + + return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data; + } + + // ------------------------------------------------------------------------ + + /** + * Unescape slashes + * + * This function converts any slash markers back into actual slashes + * + * @param string Value + * @param string Key + * @return void + */ + protected function _unescape_slashes(&$val, $key) + { + if (is_string($val)) + { + $val= str_replace('{{slash}}', '\\', $val); + } + } + + // ------------------------------------------------------------------------ + + /** + * Garbage collection + * + * This deletes expired session rows from database + * if the probability percentage is met + * + * @return void + */ + protected function _sess_gc() + { + if ($this->sess_use_database !== TRUE) + { + return; + } + + $probability = ini_get('session.gc_probability'); + $divisor = ini_get('session.gc_divisor'); + + srand(time()); + if ((mt_rand(0, $divisor) / $divisor) < $probability) + { + $expire = $this->now - $this->sess_expiration; + $this->CI->db->delete($this->sess_table_name, 'last_activity < '.$expire); + + log_message('debug', 'Session garbage collection performed.'); + } + } + +} + +/* End of file Session_cookie.php */ +/* Location: ./system/libraries/Session/drivers/Session_cookie.php */
\ No newline at end of file diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php new file mode 100755 index 000000000..3e700ad5d --- /dev/null +++ b/system/libraries/Session/drivers/Session_native.php @@ -0,0 +1,242 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * Native PHP session management driver + * + * This is the driver that uses the native PHP $_SESSION array through the Session driver library. + * + * @package CodeIgniter + * @subpackage Libraries + * @category Sessions + * @author EllisLab Dev Team + */ +class CI_Session_native extends CI_Session_driver { + + /** + * Initialize session driver object + * + * @return void + */ + protected function initialize() + { + // Get config parameters + $config = array(); + $prefs = array( + 'sess_cookie_name', + 'sess_expire_on_close', + 'sess_expiration', + 'sess_match_ip', + 'sess_match_useragent', + 'sess_time_to_update', + 'cookie_prefix', + 'cookie_path', + 'cookie_domain', + 'cookie_secure', + 'cookie_httponly' + ); + + foreach ($prefs as $key) + { + $config[$key] = isset($this->_parent->params[$key]) + ? $this->_parent->params[$key] + : $this->CI->config->item($key); + } + + // Set session name, if specified + if ($config['sess_cookie_name']) + { + // Differentiate name from cookie driver with '_id' suffix + $name = $config['sess_cookie_name'].'_id'; + if ($config['cookie_prefix']) + { + // Prepend cookie prefix + $name = $config['cookie_prefix'].$name; + } + session_name($name); + } + + // Set expiration, path, and domain + $expire = 7200; + $path = '/'; + $domain = ''; + $secure = (bool) $config['cookie_secure']; + $http_only = (bool) $config['cookie_httponly']; + + if ($config['sess_expiration'] !== FALSE) + { + // Default to 2 years if expiration is "0" + $expire = ($config['sess_expiration'] == 0) ? (60*60*24*365*2) : $config['sess_expiration']; + } + + if ($config['cookie_path']) + { + // Use specified path + $path = $config['cookie_path']; + } + + if ($config['cookie_domain']) + { + // Use specified domain + $domain = $config['cookie_domain']; + } + + session_set_cookie_params($config['sess_expire_on_close'] ? 0 : $expire, $path, $domain, $secure, $http_only); + + // Start session + session_start(); + + // Check session expiration, ip, and agent + $now = time(); + $destroy = FALSE; + if (isset($_SESSION['last_activity']) && (($_SESSION['last_activity'] + $expire) < $now OR $_SESSION['last_activity'] > $now)) + { + // Expired - destroy + $destroy = TRUE; + } + elseif ($config['sess_match_ip'] === TRUE && isset($_SESSION['ip_address']) + && $_SESSION['ip_address'] !== $this->CI->input->ip_address()) + { + // IP doesn't match - destroy + $destroy = TRUE; + } + elseif ($config['sess_match_useragent'] === TRUE && isset($_SESSION['user_agent']) + && $_SESSION['user_agent'] !== trim(substr($this->CI->input->user_agent(), 0, 50))) + { + // Agent doesn't match - destroy + $destroy = TRUE; + } + + // Destroy expired or invalid session + if ($destroy) + { + // Clear old session and start new + $this->sess_destroy(); + session_start(); + } + + // Check for update time + if ($config['sess_time_to_update'] && isset($_SESSION['last_activity']) + && ($_SESSION['last_activity'] + $config['sess_time_to_update']) < $now) + { + // Changing the session ID amidst a series of AJAX calls causes problems + if( ! $this->CI->input->is_ajax_request()) + { + // Regenerate ID, but don't destroy session + $this->sess_regenerate(FALSE); + } + } + + // Set activity time + $_SESSION['last_activity'] = $now; + + // Set matching values as required + if ($config['sess_match_ip'] === TRUE && ! isset($_SESSION['ip_address'])) + { + // Store user IP address + $_SESSION['ip_address'] = $this->CI->input->ip_address(); + } + + if ($config['sess_match_useragent'] === TRUE && ! isset($_SESSION['user_agent'])) + { + // Store user agent string + $_SESSION['user_agent'] = trim(substr($this->CI->input->user_agent(), 0, 50)); + } + + // Make session ID available + $_SESSION['session_id'] = session_id(); + } + + // ------------------------------------------------------------------------ + + /** + * Save the session data + * + * @return void + */ + public function sess_save() + { + // Nothing to do - changes to $_SESSION are automatically saved + } + + // ------------------------------------------------------------------------ + + /** + * Destroy the current session + * + * @return void + */ + public function sess_destroy() + { + // Cleanup session + $_SESSION = array(); + $name = session_name(); + if (isset($_COOKIE[$name])) + { + // Clear session cookie + $params = session_get_cookie_params(); + setcookie($name, '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']); + unset($_COOKIE[$name]); + } + session_destroy(); + } + + // ------------------------------------------------------------------------ + + /** + * Regenerate the current session + * + * Regenerate the session id + * + * @param bool Destroy session data flag (default: FALSE) + * @return void + */ + public function sess_regenerate($destroy = FALSE) + { + // Just regenerate id, passing destroy flag + session_regenerate_id($destroy); + $_SESSION['session_id'] = session_id(); + } + + // ------------------------------------------------------------------------ + + /** + * Get a reference to user data array + * + * @return array Reference to userdata + */ + public function &get_userdata() + { + // Just return reference to $_SESSION + return $_SESSION; + } + +} + +/* End of file Session_native.php */ +/* Location: ./system/libraries/Session/drivers/Session_native.php */
\ No newline at end of file diff --git a/system/libraries/Table.php b/system/libraries/Table.php index 3777d29ff..886fb6581 100644 --- a/system/libraries/Table.php +++ b/system/libraries/Table.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.3.1 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * HTML Table Generating Class @@ -38,13 +39,60 @@ */ class CI_Table { + /** + * Data for table rows + * + * @var array + */ public $rows = array(); + + /** + * Data for table heading + * + * @var array + */ public $heading = array(); + + /** + * Whether or not to automatically create the table header + * + * @var bool + */ public $auto_heading = TRUE; + + /** + * Table caption + * + * @var string + */ public $caption = NULL; + + /** + * Table layout template + * + * @var array + */ public $template = NULL; + + /** + * Newline setting + * + * @var string + */ public $newline = "\n"; + + /** + * Contents of empty cells + * + * @var string + */ public $empty_cells = ''; + + /** + * Callback for custom table layout + * + * @var function + */ public $function = FALSE; /** @@ -93,7 +141,7 @@ class CI_Table { * @param mixed * @return void */ - public function set_heading() + public function set_heading($args = array()) { $args = func_get_args(); $this->heading = $this->_prep_args($args); @@ -122,7 +170,7 @@ class CI_Table { // will want headings from a one-dimensional array $this->auto_heading = FALSE; - if ($col_limit == 0) + if ($col_limit === 0) { return $array; } @@ -172,7 +220,7 @@ class CI_Table { * @param mixed * @return void */ - public function add_row() + public function add_row($args = array()) { $args = func_get_args(); $this->rows[] = $this->_prep_args($args); @@ -251,7 +299,7 @@ class CI_Table { } elseif (is_array($table_data)) { - $set_heading = (count($this->heading) !== 0 OR $this->auto_heading != FALSE); + $set_heading = (count($this->heading) !== 0 OR $this->auto_heading !== FALSE); $this->_set_from_array($table_data, $set_heading); } } @@ -289,7 +337,7 @@ class CI_Table { foreach ($heading as $key => $val) { - if ($key != 'data') + if ($key !== 'data') { $temp = str_replace('<th', '<th '.$key.'="'.$val.'"', $temp); } @@ -420,6 +468,7 @@ class CI_Table { * Set table data from an array * * @param array + * @param bool * @return void */ protected function _set_from_array($data, $set_heading = TRUE) @@ -433,7 +482,7 @@ class CI_Table { foreach ($data as $row) { // If a heading hasn't already been set we'll use the first row of the array as the heading - if ($i++ === 0 && count($data) > 1 && count($this->heading) === 0 && $set_heading == TRUE) + if ($i++ === 0 && count($data) > 1 && count($this->heading) === 0 && $set_heading === TRUE) { $this->heading = $this->_prep_args($row); } @@ -453,7 +502,7 @@ class CI_Table { */ protected function _compile_template() { - if ($this->template == NULL) + if ($this->template === NULL) { $this->template = $this->_default_template(); return; diff --git a/system/libraries/Trackback.php b/system/libraries/Trackback.php index 6761f63a5..d30350340 100644 --- a/system/libraries/Trackback.php +++ b/system/libraries/Trackback.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Trackback Class @@ -38,13 +39,51 @@ */ class CI_Trackback { - public $time_format = 'local'; + /** + * Character set + * + * @var string + */ public $charset = 'UTF-8'; - public $data = array('url' => '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => ''); + + /** + * Trackback data + * + * @var array + */ + public $data = array('url' => '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => ''); + + /** + * Convert ASCII flag + * + * Whether to convert high-ASCII and MS Word + * characters to HTML entities. + * + * @var bool + */ public $convert_ascii = TRUE; - public $response = ''; - public $error_msg = array(); + /** + * Response + * + * @var string + */ + public $response = ''; + + /** + * Error messages list + * + * @var string[] + */ + public $error_msg = array(); + + // -------------------------------------------------------------------- + + /** + * Constructor + * + * @return void + */ public function __construct() { log_message('debug', 'Trackback Class Initialized'); @@ -88,7 +127,7 @@ class CI_Trackback { } // Convert High ASCII Characters - if ($this->convert_ascii == TRUE && in_array($item, array('excerpt', 'title', 'blog_name'))) + if ($this->convert_ascii === TRUE && in_array($item, array('excerpt', 'title', 'blog_name'))) { $$item = $this->convert_ascii($$item); } @@ -106,7 +145,7 @@ class CI_Trackback { { foreach ($ping_url as $url) { - if ($this->process($url, $data) == FALSE) + if ($this->process($url, $data) === FALSE) { $return = FALSE; } @@ -132,7 +171,7 @@ class CI_Trackback { { foreach (array('url', 'title', 'blog_name', 'excerpt') as $val) { - if ( ! isset($_POST[$val]) OR $_POST[$val] == '') + if (empty($_POST[$val])) { $this->set_error('The following required POST variable is missing: '.$val); return FALSE; @@ -140,14 +179,14 @@ class CI_Trackback { $this->data['charset'] = isset($_POST['charset']) ? strtoupper(trim($_POST['charset'])) : 'auto'; - if ($val != 'url' && MB_ENABLED === TRUE) + if ($val !== 'url' && MB_ENABLED === TRUE) { $_POST[$val] = mb_convert_encoding($_POST[$val], $this->charset, $this->data['charset']); } - $_POST[$val] = ($val != 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]); + $_POST[$val] = ($val !== 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]); - if ($val == 'excerpt') + if ($val === 'excerpt') { $_POST['excerpt'] = $this->limit_characters($_POST['excerpt']); } @@ -355,7 +394,7 @@ class CI_Trackback { } } - return preg_match('/^[0-9]+$/', $tb_id) ? $tb_id : FALSE; + return ctype_digit((string) $tb_id) ? $tb_id : FALSE; } // -------------------------------------------------------------------- diff --git a/system/libraries/Typography.php b/system/libraries/Typography.php index 21bbad038..d83bf519b 100644 --- a/system/libraries/Typography.php +++ b/system/libraries/Typography.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Typography Class @@ -36,22 +37,46 @@ */ class CI_Typography { - // Block level elements that should not be wrapped inside <p> tags + /** + * Block level elements that should not be wrapped inside <p> tags + * + * @var string + */ public $block_elements = 'address|blockquote|div|dl|fieldset|form|h\d|hr|noscript|object|ol|p|pre|script|table|ul'; - // Elements that should not have <p> and <br /> tags within them. + /** + * Elements that should not have <p> and <br /> tags within them. + * + * @var string + */ public $skip_elements = 'p|pre|ol|ul|dl|object|table|h\d'; - // Tags we want the parser to completely ignore when splitting the string. + /** + * Tags we want the parser to completely ignore when splitting the string. + * + * @var string + */ public $inline_elements = 'a|abbr|acronym|b|bdo|big|br|button|cite|code|del|dfn|em|i|img|ins|input|label|map|kbd|q|samp|select|small|span|strong|sub|sup|textarea|tt|var'; - // array of block level elements that require inner content to be within another block level element + /** + * array of block level elements that require inner content to be within another block level element + * + * @var array + */ public $inner_block_required = array('blockquote'); - // the last block element parsed + /** + * the last block element parsed + * + * @var string + */ public $last_block_element = ''; - // whether or not to protect quotes within { curly braces } + /** + * whether or not to protect quotes within { curly braces } + * + * @var bool + */ public $protect_braced_quotes = FALSE; /** @@ -71,7 +96,7 @@ class CI_Typography { */ public function auto_typography($str, $reduce_linebreaks = FALSE) { - if ($str == '') + if ($str === '') { return ''; } @@ -149,7 +174,7 @@ class CI_Typography { $process = ($match[1] === '/'); } - if ($match[1] == '') + if ($match[1] === '') { $this->last_block_element = $match[2]; } @@ -320,7 +345,7 @@ class CI_Typography { */ protected function _format_newlines($str) { - if ($str == '' OR (strpos($str, "\n") === FALSE && ! in_array($this->last_block_element, $this->inner_block_required))) + if ($str === '' OR (strpos($str, "\n") === FALSE && ! in_array($this->last_block_element, $this->inner_block_required))) { return $str; } @@ -332,7 +357,7 @@ class CI_Typography { $str = preg_replace("/([^\n])(\n)([^\n])/", '\\1<br />\\2\\3', $str); // Wrap the whole enchilada in enclosing paragraphs - if ($str != "\n") + if ($str !== "\n") { // We trim off the right-side new line so that the closing </p> tag // will be positioned immediately following the string, matching diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php index 0f6e2dfdd..842b4aebd 100644 --- a/system/libraries/Unit_test.php +++ b/system/libraries/Unit_test.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.3.1 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Unit Testing Class @@ -38,13 +39,57 @@ */ class CI_Unit_test { - public $active = TRUE; - public $results = array(); - public $strict = FALSE; - protected $_template = NULL; - protected $_template_rows = NULL; + /** + * Active flag + * + * @var bool + */ + public $active = TRUE; + + /** + * Test results + * + * @var array + */ + public $results = array(); + + /** + * Strict comparison flag + * + * Whether to use === or == when comparing + * + * @var bool + */ + public $strict = FALSE; + + /** + * Template + * + * @var string + */ + protected $_template = NULL; + + /** + * Template rows + * + * @var string + */ + protected $_template_rows = NULL; + + /** + * List of visible test items + * + * @var array + */ protected $_test_items_visible = array(); + // -------------------------------------------------------------------- + + /** + * Constructor + * + * @return void + */ public function __construct() { // These are the default items visible when a test is run. @@ -86,14 +131,15 @@ class CI_Unit_test { * * Runs the supplied tests * - * @param mixed - * @param mixed - * @param string + * @param mixed $test + * @param mixed $expected + * @param string $test_name + * @param string $notes * @return string */ public function run($test, $expected = TRUE, $test_name = 'undefined', $notes = '') { - if ($this->active == FALSE) + if ($this->active === FALSE) { return FALSE; } @@ -106,13 +152,13 @@ class CI_Unit_test { } else { - $result = ($this->strict == TRUE) ? ($test === $expected) : ($test == $expected); + $result = ($this->strict === TRUE) ? ($test === $expected) : ($test == $expected); $extype = gettype($expected); } $back = $this->_backtrace(); - $report[] = array ( + $report = array ( 'test_name' => $test_name, 'test_datatype' => gettype($test), 'res_datatype' => $extype, @@ -124,7 +170,7 @@ class CI_Unit_test { $this->results[] = $report; - return($this->report($this->result($report))); + return $this->report($this->result(array($report))); } // -------------------------------------------------------------------- @@ -134,6 +180,7 @@ class CI_Unit_test { * * Displays a table with the test data * + * @param array $result * @return string */ public function report($result = array()) @@ -155,13 +202,13 @@ class CI_Unit_test { foreach ($res as $key => $val) { - if ($key == $CI->lang->line('ut_result')) + if ($key === $CI->lang->line('ut_result')) { - if ($val == $CI->lang->line('ut_passed')) + if ($val === $CI->lang->line('ut_passed')) { $val = '<span style="color: #0C0;">'.$val.'</span>'; } - elseif ($val == $CI->lang->line('ut_failed')) + elseif ($val === $CI->lang->line('ut_failed')) { $val = '<span style="color: #C00;">'.$val.'</span>'; } @@ -213,6 +260,7 @@ class CI_Unit_test { * * Returns the raw result data * + * @param array $results * @return array */ public function result($results = array()) @@ -236,25 +284,11 @@ class CI_Unit_test { continue; } - if (is_array($val)) - { - foreach ($val as $k => $v) - { - if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$v)))) - { - $v = $line; - } - $temp[$CI->lang->line('ut_'.$k)] = $v; - } - } - else + if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$val)))) { - if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$val)))) - { - $val = $line; - } - $temp[$CI->lang->line('ut_'.$key)] = $val; + $val = $line; } + $temp[$CI->lang->line('ut_'.$key)] = $val; } $retval[] = $temp; @@ -289,15 +323,11 @@ class CI_Unit_test { */ protected function _backtrace() { - if (function_exists('debug_backtrace')) - { - $back = debug_backtrace(); - return array( - 'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''), - 'line' => (isset($back[1]['line']) ? $back[1]['line'] : '') - ); - } - return array('file' => 'Unknown', 'line' => 'Unknown'); + $back = debug_backtrace(); + return array( + 'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''), + 'line' => (isset($back[1]['line']) ? $back[1]['line'] : '') + ); } // -------------------------------------------------------------------- @@ -344,18 +374,26 @@ class CI_Unit_test { } /** - * Helper functions to test boolean true/false + * Helper function to test boolean TRUE * + * @param mixed $test * @return bool */ function is_true($test) { - return (is_bool($test) && $test === TRUE); + return ($test === TRUE); } + +/** + * Helper function to test boolean FALSE + * + * @param mixed $test + * @return bool + */ function is_false($test) { - return (is_bool($test) && $test === FALSE); + return ($test === FALSE); } /* End of file Unit_test.php */ -/* Location: ./system/libraries/Unit_test.php */
\ No newline at end of file +/* Location: ./system/libraries/Unit_test.php */ diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php index 8ad67050d..b3e9f7515 100644 --- a/system/libraries/Upload.php +++ b/system/libraries/Upload.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * File Uploading Class @@ -36,39 +37,210 @@ */ class CI_Upload { + /** + * Maximum file size + * + * @var int + */ public $max_size = 0; + + /** + * Maximum image width + * + * @var int + */ public $max_width = 0; + + /** + * Maximum image height + * + * @var int + */ public $max_height = 0; + + /** + * Maximum filename length + * + * @var int + */ public $max_filename = 0; + + /** + * Maximum duplicate filename increment ID + * + * @var int + */ public $max_filename_increment = 100; + + /** + * Allowed file types + * + * @var string + */ public $allowed_types = ''; + + /** + * Temporary filename + * + * @var string + */ public $file_temp = ''; + + /** + * Filename + * + * @var string + */ public $file_name = ''; + + /** + * Original filename + * + * @var string + */ public $orig_name = ''; + + /** + * File type + * + * @var string + */ public $file_type = ''; - public $file_size = ''; + + /** + * File size + * + * @var int + */ + public $file_size = NULL; + + /** + * Filename extension + * + * @var string + */ public $file_ext = ''; + + /** + * Upload path + * + * @var string + */ public $upload_path = ''; + + /** + * Overwrite flag + * + * @var bool + */ public $overwrite = FALSE; + + /** + * Obfuscate filename flag + * + * @var bool + */ public $encrypt_name = FALSE; + + /** + * Is image flag + * + * @var bool + */ public $is_image = FALSE; - public $image_width = ''; - public $image_height = ''; + + /** + * Image width + * + * @var int + */ + public $image_width = NULL; + + /** + * Image height + * + * @var int + */ + public $image_height = NULL; + + /** + * Image type + * + * @var string + */ public $image_type = ''; + + /** + * Image size string + * + * @var string + */ public $image_size_str = ''; + + /** + * Error messages list + * + * @var array + */ public $error_msg = array(); + + /** + * MIME types list + * + * @var array + */ public $mimes = array(); + + /** + * Remove spaces flag + * + * @var bool + */ public $remove_spaces = TRUE; + + /** + * MIME detection flag + * + * @var bool + */ + public $detect_mime = TRUE; + + /** + * XSS filter flag + * + * @var bool + */ public $xss_clean = FALSE; + + /** + * Temporary filename prefix + * + * @var string + */ public $temp_prefix = 'temp_file_'; + + /** + * Filename sent by the client + * + * @var bool + */ public $client_name = ''; + // -------------------------------------------------------------------- + + /** + * Filename override + * + * @var string + */ protected $_file_name_override = ''; + // -------------------------------------------------------------------- + /** * Constructor * - * @param array + * @param array $props * @return void */ public function __construct($props = array()) @@ -78,6 +250,8 @@ class CI_Upload { $this->initialize($props); } + $this->mimes =& get_mimes(); + log_message('debug', 'Upload Class Initialized'); } @@ -86,7 +260,7 @@ class CI_Upload { /** * Initialize preferences * - * @param array + * @param array $config * @return void */ public function initialize($config = array()) @@ -102,19 +276,19 @@ class CI_Upload { 'file_name' => '', 'orig_name' => '', 'file_type' => '', - 'file_size' => '', + 'file_size' => NULL, 'file_ext' => '', 'upload_path' => '', 'overwrite' => FALSE, 'encrypt_name' => FALSE, 'is_image' => FALSE, - 'image_width' => '', - 'image_height' => '', + 'image_width' => NULL, + 'image_height' => NULL, 'image_type' => '', 'image_size_str' => '', 'error_msg' => array(), - 'mimes' => array(), 'remove_spaces' => TRUE, + 'detect_mime' => TRUE, 'xss_clean' => FALSE, 'temp_prefix' => 'temp_file_', 'client_name' => '' @@ -151,6 +325,7 @@ class CI_Upload { /** * Perform the file upload * + * @param string $field * @return bool */ public function do_upload($field = 'userfile') @@ -208,7 +383,13 @@ class CI_Upload { // Set the uploaded data as class variables $this->file_temp = $_FILES[$field]['tmp_name']; $this->file_size = $_FILES[$field]['size']; - $this->_file_mime_type($_FILES[$field]); + + // Skip MIME type detection? + if ($this->detect_mime !== FALSE) + { + $this->_file_mime_type($_FILES[$field]); + } + $this->file_type = preg_replace('/^(.+?);.*$/', '\\1', $this->file_type); $this->file_type = strtolower(trim(stripslashes($this->file_type), '"')); $this->file_name = $this->_prep_filename($_FILES[$field]['name']); @@ -223,7 +404,7 @@ class CI_Upload { } // if we're overriding, let's now make sure the new name and type is allowed - if ($this->_file_name_override != '') + if ($this->_file_name_override !== '') { $this->file_name = $this->_prep_filename($this->_file_name_override); @@ -276,7 +457,7 @@ class CI_Upload { } // Remove white spaces in the name - if ($this->remove_spaces == TRUE) + if ($this->remove_spaces === TRUE) { $this->file_name = preg_replace('/\s+/', '_', $this->file_name); } @@ -289,7 +470,7 @@ class CI_Upload { */ $this->orig_name = $this->file_name; - if ($this->overwrite == FALSE) + if ($this->overwrite === FALSE) { $this->file_name = $this->set_filename($this->upload_path, $this->file_name); @@ -346,11 +527,12 @@ class CI_Upload { * Returns an associative array containing all of the information * related to the upload, allowing the developer easy access in one array. * - * @return array + * @param string $index + * @return mixed */ - public function data() + public function data($index = NULL) { - return array( + $data = array( 'file_name' => $this->file_name, 'file_type' => $this->file_type, 'file_path' => $this->upload_path, @@ -366,6 +548,13 @@ class CI_Upload { 'image_type' => $this->image_type, 'image_size_str' => $this->image_size_str, ); + + if ( ! empty($index)) + { + return isset($data[$index]) ? $data[$index] : NULL; + } + + return $data; } // -------------------------------------------------------------------- @@ -373,7 +562,7 @@ class CI_Upload { /** * Set Upload Path * - * @param string + * @param string $path * @return void */ public function set_upload_path($path) @@ -391,13 +580,13 @@ class CI_Upload { * existence of a file with the same name. If found, it will append a * number to the end of the filename to avoid overwriting a pre-existing file. * - * @param string - * @param string + * @param string $path + * @param string $filename * @return string */ public function set_filename($path, $filename) { - if ($this->encrypt_name == TRUE) + if ($this->encrypt_name === TRUE) { mt_srand(); $filename = md5(uniqid(mt_rand())).$this->file_ext; @@ -420,7 +609,7 @@ class CI_Upload { } } - if ($new_filename == '') + if ($new_filename === '') { $this->set_error('upload_bad_filename'); return FALSE; @@ -436,7 +625,7 @@ class CI_Upload { /** * Set Maximum File Size * - * @param int + * @param int $n * @return void */ public function set_max_filesize($n) @@ -449,7 +638,7 @@ class CI_Upload { /** * Set Maximum File Name Length * - * @param int + * @param int $n * @return void */ public function set_max_filename($n) @@ -462,7 +651,7 @@ class CI_Upload { /** * Set Maximum Image Width * - * @param int + * @param int $n * @return void */ public function set_max_width($n) @@ -475,7 +664,7 @@ class CI_Upload { /** * Set Maximum Image Height * - * @param int + * @param int $n * @return void */ public function set_max_height($n) @@ -488,7 +677,7 @@ class CI_Upload { /** * Set Allowed File Types * - * @param string + * @param string $types * @return void */ public function set_allowed_types($types) @@ -508,7 +697,7 @@ class CI_Upload { * * Uses GD to determine the width/height/type of image * - * @param string + * @param string $path * @return void */ public function set_image_properties($path = '') @@ -540,12 +729,12 @@ class CI_Upload { * Enables the XSS flag so that the file that was uploaded * will be run through the XSS filter. * - * @param bool + * @param bool $flag * @return void */ public function set_xss_clean($flag = FALSE) { - $this->xss_clean = ($flag == TRUE); + $this->xss_clean = ($flag === TRUE); } // -------------------------------------------------------------------- @@ -582,7 +771,7 @@ class CI_Upload { /** * Verify that the filetype is allowed * - * @param bool + * @param bool $ignore_mime * @return bool */ public function is_allowed_filetype($ignore_mime = FALSE) @@ -641,7 +830,7 @@ class CI_Upload { */ public function is_allowed_filesize() { - return ($this->max_size == 0 OR $this->max_size > $this->file_size); + return ($this->max_size === 0 OR $this->max_size > $this->file_size); } // -------------------------------------------------------------------- @@ -687,13 +876,13 @@ class CI_Upload { */ public function validate_upload_path() { - if ($this->upload_path == '') + if ($this->upload_path === '') { $this->set_error('upload_no_filepath'); return FALSE; } - if (function_exists('realpath') && @realpath($this->upload_path) !== FALSE) + if (@realpath($this->upload_path) !== FALSE) { $this->upload_path = str_replace('\\', '/', realpath($this->upload_path)); } @@ -719,13 +908,13 @@ class CI_Upload { /** * Extract the file extension * - * @param string + * @param string $filename * @return string */ public function get_extension($filename) { $x = explode('.', $filename); - return '.'.end($x); + return (count($x) !== 1) ? '.'.end($x) : ''; } // -------------------------------------------------------------------- @@ -733,7 +922,7 @@ class CI_Upload { /** * Clean the file name for security * - * @param string + * @param string $filename * @return string */ public function clean_file_name($filename) @@ -747,6 +936,8 @@ class CI_Upload { ';', '?', '/', + '!', + '#', '%20', '%22', '%3c', // < @@ -771,7 +962,8 @@ class CI_Upload { /** * Limit the File Name Length * - * @param string + * @param string $filename + * @param int $length * @return string */ public function limit_filename_length($filename, $length) @@ -812,17 +1004,17 @@ class CI_Upload { return FALSE; } - if (function_exists('memory_get_usage') && memory_get_usage() && ini_get('memory_limit') != '') + if (memory_get_usage() && ($memory_limit = ini_get('memory_limit'))) { - $current = ini_get('memory_limit') * 1024 * 1024; + $memory_limit *= 1024 * 1024; // There was a bug/behavioural change in PHP 5.2, where numbers over one million get output // into scientific notation. number_format() ensures this number is an integer // http://bugs.php.net/bug.php?id=43053 - $new_memory = number_format(ceil(filesize($file) + $current), 0, '.', ''); + $memory_limit = number_format(ceil(filesize($file) + $memory_limit), 0, '.', ''); - ini_set('memory_limit', $new_memory); // When an integer is used, the value is measured in bytes. - PHP.net + ini_set('memory_limit', $memory_limit); // When an integer is used, the value is measured in bytes. - PHP.net } // If the file being uploaded is an image, then we should have no problem with XSS attacks (in theory), but @@ -846,10 +1038,8 @@ class CI_Upload { // <a, <body, <head, <html, <img, <plaintext, <pre, <script, <table, <title // title is basically just in SVG, but we filter it anyhow - if ( ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes)) - { - return TRUE; // its an image, no "triggers" detected in the first 256 bytes, we're good - } + // if its an image or no "triggers" detected in the first 256 bytes - we're good + return ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes); } if (($data = @file_get_contents($file)) === FALSE) @@ -866,7 +1056,7 @@ class CI_Upload { /** * Set an error message * - * @param string + * @param string $msg * @return void */ public function set_error($msg) @@ -878,14 +1068,14 @@ class CI_Upload { { foreach ($msg as $val) { - $msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val); + $msg = ($CI->lang->line($val) === FALSE) ? $val : $CI->lang->line($val); $this->error_msg[] = $msg; log_message('error', $msg); } } else { - $msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg); + $msg = ($CI->lang->line($msg) === FALSE) ? $msg : $CI->lang->line($msg); $this->error_msg[] = $msg; log_message('error', $msg); } @@ -896,8 +1086,8 @@ class CI_Upload { /** * Display the error message * - * @param string - * @param string + * @param string $open + * @param string $close * @return string */ public function display_errors($open = '<p>', $close = '</p>') @@ -913,31 +1103,11 @@ class CI_Upload { * This is a list of mime types. We use it to validate * the "allowed types" set by the developer * - * @param string + * @param string $mime * @return string */ public function mimes_types($mime) { - global $mimes; - - if (count($this->mimes) == 0) - { - if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php')) - { - include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'); - } - elseif (is_file(APPPATH.'config/mimes.php')) - { - include(APPPATH.'config/mimes.php'); - } - else - { - return FALSE; - } - - $this->mimes = $mimes; - } - return isset($this->mimes[$mime]) ? $this->mimes[$mime] : FALSE; } @@ -946,15 +1116,17 @@ class CI_Upload { /** * Prep Filename * - * Prevents possible script execution from Apache's handling of files multiple extensions - * http://httpd.apache.org/docs/1.3/mod/mod_mime.html#multipleext + * Prevents possible script execution from Apache's handling + * of files' multiple extensions. + * + * @link http://httpd.apache.org/docs/1.3/mod/mod_mime.html#multipleext * - * @param string + * @param string $filename * @return string */ protected function _prep_filename($filename) { - if (strpos($filename, '.') === FALSE OR $this->allowed_types == '*') + if (strpos($filename, '.') === FALSE OR $this->allowed_types === '*') { return $filename; } @@ -986,7 +1158,7 @@ class CI_Upload { * Detects the (actual) MIME type of the uploaded file, if possible. * The input array is expected to be $_FILES[$field] * - * @param array + * @param array $file * @return void */ protected function _file_mime_type($file) @@ -1001,7 +1173,7 @@ class CI_Upload { */ if (function_exists('finfo_file')) { - $finfo = finfo_open(FILEINFO_MIME); + $finfo = @finfo_open(FILEINFO_MIME); if (is_resource($finfo)) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system { $mime = @finfo_file($finfo, $file['tmp_name']); @@ -1032,9 +1204,11 @@ class CI_Upload { */ if (DIRECTORY_SEPARATOR !== '\\') { - $cmd = 'file --brief --mime ' . escapeshellarg($file['tmp_name']) . ' 2>&1'; + $cmd = function_exists('escapeshellarg') + ? 'file --brief --mime '.escapeshellarg($file['tmp_name']).' 2>&1' + : 'file --brief --mime '.$file['tmp_name'].' 2>&1'; - if (function_exists('exec')) + if (function_usable('exec')) { /* This might look confusing, as $mime is being populated with all of the output when set in the second parameter. * However, we only neeed the last line, which is the actual return value of exec(), and as such - it overwrites @@ -1049,7 +1223,7 @@ class CI_Upload { } } - if ( (bool) @ini_get('safe_mode') === FALSE && function_exists('shell_exec')) + if ( (bool) @ini_get('safe_mode') === FALSE && function_usable('shell_exec')) { $mime = @shell_exec($cmd); if (strlen($mime) > 0) @@ -1063,7 +1237,7 @@ class CI_Upload { } } - if (function_exists('popen')) + if (function_usable('popen')) { $proc = @popen($cmd, 'r'); if (is_resource($proc)) diff --git a/system/libraries/User_agent.php b/system/libraries/User_agent.php index 7d91cc4d9..659371ab5 100644 --- a/system/libraries/User_agent.php +++ b/system/libraries/User_agent.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * User Agent Class @@ -38,25 +39,110 @@ */ class CI_User_agent { - public $agent = NULL; + /** + * Current user-agent + * + * @var string + */ + public $agent = NULL; + + /** + * Flag for if the user-agent belongs to a browser + * + * @var bool + */ + public $is_browser = FALSE; + + /** + * Flag for if the user-agent is a robot + * + * @var bool + */ + public $is_robot = FALSE; + + /** + * Flag for if the user-agent is a mobile browser + * + * @var bool + */ + public $is_mobile = FALSE; - public $is_browser = FALSE; - public $is_robot = FALSE; - public $is_mobile = FALSE; + /** + * Languages accepted by the current user agent + * + * @var array + */ + public $languages = array(); - public $languages = array(); - public $charsets = array(); + /** + * Character sets accepted by the current user agent + * + * @var array + */ + public $charsets = array(); - public $platforms = array(); - public $browsers = array(); - public $mobiles = array(); - public $robots = array(); + /** + * List of platforms to compare against current user agent + * + * @var array + */ + public $platforms = array(); - public $platform = ''; - public $browser = ''; - public $version = ''; - public $mobile = ''; - public $robot = ''; + /** + * List of browsers to compare against current user agent + * + * @var array + */ + public $browsers = array(); + + /** + * List of mobile browsers to compare against current user agent + * + * @var array + */ + public $mobiles = array(); + + /** + * List of robots to compare against current user agent + * + * @var array + */ + public $robots = array(); + + /** + * Current user-agent platform + * + * @var string + */ + public $platform = ''; + + /** + * Current user-agent browser + * + * @var string + */ + public $browser = ''; + + /** + * Current user-agent version + * + * @var string + */ + public $version = ''; + + /** + * Current user-agent mobile name + * + * @var string + */ + public $mobile = ''; + + /** + * Current user-agent robot name + * + * @var string + */ + public $robot = ''; /** * Constructor @@ -246,7 +332,7 @@ class CI_User_agent { { foreach ($this->mobiles as $key => $val) { - if (FALSE !== (strpos(strtolower($this->agent), $key))) + if (FALSE !== (stripos($this->agent, $key))) { $this->is_mobile = TRUE; $this->mobile = $val; @@ -303,6 +389,7 @@ class CI_User_agent { /** * Is Browser * + * @param string $key * @return bool */ public function is_browser($key = NULL) @@ -327,6 +414,7 @@ class CI_User_agent { /** * Is Robot * + * @param string $key * @return bool */ public function is_robot($key = NULL) @@ -351,6 +439,7 @@ class CI_User_agent { /** * Is Mobile * + * @param string $key * @return bool */ public function is_mobile($key = NULL) @@ -379,7 +468,13 @@ class CI_User_agent { */ public function is_referral() { - return ! empty($_SERVER['HTTP_REFERER']); + if (empty($_SERVER['HTTP_REFERER'])) + { + return FALSE; + } + + $referer = parse_url($_SERVER['HTTP_REFERER']); + return ! (empty($referer['host']) && strpos(config_item('base_url'), $referer['host']) !== FALSE); } // -------------------------------------------------------------------- @@ -504,6 +599,7 @@ class CI_User_agent { /** * Test for a particular language * + * @param string $lang * @return bool */ public function accept_lang($lang = 'en') @@ -516,6 +612,7 @@ class CI_User_agent { /** * Test for a particular character set * + * @param string $charset * @return bool */ public function accept_charset($charset = 'utf-8') diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php index fea560c2e..3ef823e29 100644..100755 --- a/system/libraries/Xmlrpc.php +++ b/system/libraries/Xmlrpc.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,14 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +if ( ! function_exists('xml_parser_create')) +{ + show_error('Your PHP installation does not support XML'); +} + +// ------------------------------------------------------------------------ /** * XML-RPC request handler class @@ -34,56 +42,212 @@ * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html */ - -if ( ! function_exists('xml_parser_create')) -{ - show_error('Your PHP installation does not support XML'); -} - -// ------------------------------------------------------------------------ - class CI_Xmlrpc { - public $debug = FALSE; // Debugging on or off + /** + * Debug flag + * + * @var bool + */ + public $debug = FALSE; + + /** + * I4 data type + * + * @var string + */ public $xmlrpcI4 = 'i4'; + + /** + * Integer data type + * + * @var string + */ public $xmlrpcInt = 'int'; + + /** + * Boolean data type + * + * @var string + */ public $xmlrpcBoolean = 'boolean'; + + /** + * Double data type + * + * @var string + */ public $xmlrpcDouble = 'double'; + + /** + * String data type + * + * @var string + */ public $xmlrpcString = 'string'; + + /** + * DateTime format + * + * @var string + */ public $xmlrpcDateTime = 'dateTime.iso8601'; + + /** + * Base64 data type + * + * @var string + */ public $xmlrpcBase64 = 'base64'; + + /** + * Array data type + * + * @var string + */ public $xmlrpcArray = 'array'; + + /** + * Struct data type + * + * @var string + */ public $xmlrpcStruct = 'struct'; + /** + * Data types list + * + * @var array + */ public $xmlrpcTypes = array(); + + /** + * Valid parents list + * + * @var array + */ public $valid_parents = array(); - public $xmlrpcerr = array(); // Response numbers - public $xmlrpcstr = array(); // Response strings + /** + * Response error numbers list + * + * @var array + */ + public $xmlrpcerr = array(); + + /** + * Response error messages list + * + * @var string[] + */ + public $xmlrpcstr = array(); + + /** + * Encoding charset + * + * @var string + */ public $xmlrpc_defencoding = 'UTF-8'; + + /** + * XML-RPC client name + * + * @var string + */ public $xmlrpcName = 'XML-RPC for CodeIgniter'; + + /** + * XML-RPC version + * + * @var string + */ public $xmlrpcVersion = '1.1'; - public $xmlrpcerruser = 800; // Start of user errors - public $xmlrpcerrxml = 100; // Start of XML Parse errors - public $xmlrpc_backslash = ''; // formulate backslashes for escaping regexp + /** + * Start of user errors + * + * @var int + */ + public $xmlrpcerruser = 800; + + /** + * Start of XML parse errors + * + * @var int + */ + public $xmlrpcerrxml = 100; + + /** + * Backslash replacement value + * + * @var string + */ + public $xmlrpc_backslash = ''; + + /** + * XML-RPC Client object + * + * @var object + */ public $client; + + /** + * XML-RPC Method name + * + * @var string + */ public $method; + + /** + * XML-RPC Data + * + * @var array + */ public $data; + + /** + * XML-RPC Message + * + * @var string + */ public $message = ''; - public $error = ''; // Error string for request + + /** + * Request error message + * + * @var string + */ + public $error = ''; + + /** + * XML-RPC result object + * + * @var object + */ public $result; + + /** + * XML-RPC Reponse + * + * @var array + */ public $response = array(); // Response from remote server + /** + * XSS Filter flag + * + * @var bool + */ public $xss_clean = TRUE; + // -------------------------------------------------------------------- /** * Constructor * * Initializes property default values * - * @param array + * @param array $config * @return void */ public function __construct($config = array()) @@ -104,24 +268,24 @@ class CI_Xmlrpc { ); // Array of Valid Parents for Various XML-RPC elements - $this->valid_parents = array('BOOLEAN' => array('VALUE'), - 'I4' => array('VALUE'), - 'INT' => array('VALUE'), - 'STRING' => array('VALUE'), - 'DOUBLE' => array('VALUE'), - 'DATETIME.ISO8601' => array('VALUE'), - 'BASE64' => array('VALUE'), - 'ARRAY' => array('VALUE'), - 'STRUCT' => array('VALUE'), - 'PARAM' => array('PARAMS'), - 'METHODNAME' => array('METHODCALL'), - 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), - 'MEMBER' => array('STRUCT'), - 'NAME' => array('MEMBER'), - 'DATA' => array('ARRAY'), - 'FAULT' => array('METHODRESPONSE'), - 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT') - ); + $this->valid_parents = array('BOOLEAN' => array('VALUE'), + 'I4' => array('VALUE'), + 'INT' => array('VALUE'), + 'STRING' => array('VALUE'), + 'DOUBLE' => array('VALUE'), + 'DATETIME.ISO8601' => array('VALUE'), + 'BASE64' => array('VALUE'), + 'ARRAY' => array('VALUE'), + 'STRUCT' => array('VALUE'), + 'PARAM' => array('PARAMS'), + 'METHODNAME' => array('METHODCALL'), + 'PARAMS' => array('METHODCALL', 'METHODRESPONSE'), + 'MEMBER' => array('STRUCT'), + 'NAME' => array('MEMBER'), + 'DATA' => array('ARRAY'), + 'FAULT' => array('METHODRESPONSE'), + 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT') + ); // XML-RPC Responses @@ -148,7 +312,7 @@ class CI_Xmlrpc { /** * Initialize * - * @param array + * @param array $config * @return void */ public function initialize($config = array()) @@ -170,11 +334,13 @@ class CI_Xmlrpc { /** * Parse server URL * - * @param string url - * @param int port + * @param string $url + * @param int $port + * @param string $proxy + * @param int $proxy_port * @return void */ - public function server($url, $port = 80) + public function server($url, $port = 80, $proxy = FALSE, $proxy_port = 8080) { if (strpos($url, 'http') !== 0) { @@ -190,7 +356,7 @@ class CI_Xmlrpc { $path .= '?'.$parts['query']; } - $this->client = new XML_RPC_Client($path, $parts['host'], $port); + $this->client = new XML_RPC_Client($path, $parts['host'], $port, $proxy, $proxy_port); } // -------------------------------------------------------------------- @@ -198,7 +364,7 @@ class CI_Xmlrpc { /** * Set Timeout * - * @param int seconds + * @param int $seconds * @return void */ public function timeout($seconds = 5) @@ -214,7 +380,7 @@ class CI_Xmlrpc { /** * Set Methods * - * @param string method name + * @param string $function Method name * @return void */ public function method($function) @@ -227,7 +393,7 @@ class CI_Xmlrpc { /** * Take Array of Data and Create Objects * - * @param array + * @param array $incoming * @return void */ public function request($incoming) @@ -251,12 +417,12 @@ class CI_Xmlrpc { /** * Set Debug * - * @param bool + * @param bool $flag * @return void */ public function set_debug($flag = TRUE) { - $this->debug = ($flag == TRUE); + $this->debug = ($flag === TRUE); } // -------------------------------------------------------------------- @@ -264,7 +430,7 @@ class CI_Xmlrpc { /** * Values Parsing * - * @param mixed + * @param mixed $value * @return object */ public function values_parsing($value) @@ -277,7 +443,7 @@ class CI_Xmlrpc { } else { - if (is_array($value[0]) && ($value[1] == 'struct' OR $value[1] == 'array')) + if (is_array($value[0]) && ($value[1] === 'struct' OR $value[1] === 'array')) { while (list($k) = each($value[0])) { @@ -347,8 +513,8 @@ class CI_Xmlrpc { /** * Sends an Error Message for Server Request * - * @param int - * @param string + * @param int $number + * @param string $message * @return object */ public function send_error_message($number, $message) @@ -361,7 +527,7 @@ class CI_Xmlrpc { /** * Send Response for Server Request * - * @param array + * @param array $response * @return object */ public function send_response($response) @@ -382,29 +548,90 @@ class CI_Xmlrpc { */ class XML_RPC_Client extends CI_Xmlrpc { + /** + * Path + * + * @var string + */ public $path = ''; + + /** + * Server hostname + * + * @var string + */ public $server = ''; + + /** + * Server port + * + * @var int + */ public $port = 80; + + /** + * Proxy hostname + * + * @var string + */ + public $proxy = FALSE; + + /** + * Proxy port + * + * @var int + */ + public $proxy_port = 8080; + + /** + * Error number + * + * @var string + */ public $errno = ''; + + /** + * Error message + * + * @var string + */ public $errstring = ''; + + /** + * Timeout in seconds + * + * @var int + */ public $timeout = 5; + + /** + * No Multicall flag + * + * @var bool + */ public $no_multicall = FALSE; + // -------------------------------------------------------------------- + /** * Constructor * - * @param string - * @param object - * @param int + * @param string $path + * @param object $server + * @param int $port + * @param string $proxy + * @param int $proxy_port * @return void */ - public function __construct($path, $server, $port = 80) + public function __construct($path, $server, $port = 80, $proxy = FALSE, $proxy_port = 8080) { parent::__construct(); $this->port = $port; $this->server = $server; $this->path = $path; + $this->proxy = $proxy; + $this->proxy_port = $proxy_port; } // -------------------------------------------------------------------- @@ -412,7 +639,7 @@ class XML_RPC_Client extends CI_Xmlrpc /** * Send message * - * @param mixed + * @param mixed $msg * @return object */ public function send($msg) @@ -431,12 +658,23 @@ class XML_RPC_Client extends CI_Xmlrpc /** * Send payload * - * @param object + * @param object $msg * @return object */ public function sendPayload($msg) { - $fp = @fsockopen($this->server, $this->port,$this->errno, $this->errstr, $this->timeout); + if ($this->proxy === FALSE) + { + $server = $this->server; + $port = $this->port; + } + else + { + $server = $this->proxy; + $port = $this->proxy_port; + } + + $fp = @fsockopen($server, $port, $this->errno, $this->errstring, $this->timeout); if ( ! is_resource($fp)) { @@ -458,7 +696,7 @@ class XML_RPC_Client extends CI_Xmlrpc .'Content-Length: '.strlen($msg->payload).$r.$r .$msg->payload; - if ( ! fputs($fp, $op, strlen($op))) + if ( ! fwrite($fp, $op, strlen($op))) { error_log($this->xmlrpcstr['http_error']); return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']); @@ -480,23 +718,55 @@ class XML_RPC_Client extends CI_Xmlrpc */ class XML_RPC_Response { + + /** + * Value + * + * @var mixed + */ public $val = 0; + + /** + * Error number + * + * @var int + */ public $errno = 0; + + /** + * Error message + * + * @var string + */ public $errstr = ''; + + /** + * Headers list + * + * @var array + */ public $headers = array(); + + /** + * XSS Filter flag + * + * @var bool + */ public $xss_clean = TRUE; + // -------------------------------------------------------------------- + /** * Constructor * - * @param mixed - * @param int - * @param string + * @param mixed $val + * @param int $code + * @param string $fstr * @return void */ public function __construct($val, $code = 0, $fstr = '') { - if ($code != 0) + if ($code !== 0) { // error $this->errno = $code; @@ -636,11 +906,11 @@ class XML_RPC_Response { $kind = $xmlrpc_val->kindOf(); - if ($kind == 'scalar') + if ($kind === 'scalar') { return $xmlrpc_val->scalarval(); } - elseif ($kind == 'array') + elseif ($kind === 'array') { reset($xmlrpc_val->me); $b = current($xmlrpc_val->me); @@ -652,7 +922,7 @@ class XML_RPC_Response } return $arr; } - elseif ($kind == 'struct') + elseif ($kind === 'struct') { reset($xmlrpc_val->me['struct']); $arr = array(); @@ -680,7 +950,7 @@ class XML_RPC_Response $t = 0; if (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $time, $regs)) { - $fnc = ($utc == TRUE) ? 'gmmktime' : 'mktime'; + $fnc = ($utc === TRUE) ? 'gmmktime' : 'mktime'; $t = $fnc($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); } return $t; @@ -697,16 +967,42 @@ class XML_RPC_Response */ class XML_RPC_Message extends CI_Xmlrpc { + + /** + * Payload + * + * @var string + */ public $payload; + + /** + * Method name + * + * @var string + */ public $method_name; + + /** + * Parameter list + * + * @var array + */ public $params = array(); + + /** + * XH? + * + * @var array + */ public $xh = array(); + // -------------------------------------------------------------------- + /** * Constructor * - * @param string method name - * @param array + * @param string $method + * @param array $pars * @return void */ public function __construct($method, $pars = FALSE) @@ -778,7 +1074,7 @@ class XML_RPC_Message extends CI_Xmlrpc } // Check for HTTP 200 Response - if (strncmp($data, 'HTTP', 4) === 0 && ! preg_match('/^HTTP\/[0-9\.]+ 200 /', $data)) + if (strpos($data, 'HTTP') === 0 && ! preg_match('/^HTTP\/[0-9\.]+ 200 /', $data)) { $errstr = substr($data, 0, strpos($data, "\n")-1); return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error'].' ('.$errstr.')'); @@ -873,7 +1169,7 @@ class XML_RPC_Message extends CI_Xmlrpc $errstr_v = $v->me['struct']['faultString']; $errno = $errno_v->scalarval(); - if ($errno == 0) + if ($errno === 0) { // FAULT returned, errno needs to reflect that $errno = -1; @@ -921,9 +1217,9 @@ class XML_RPC_Message extends CI_Xmlrpc if ($this->xh[$the_parser]['isf'] > 1) return; // Evaluate and check for correct nesting of XML elements - if (count($this->xh[$the_parser]['stack']) == 0) + if (count($this->xh[$the_parser]['stack']) === 0) { - if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') + if ($name !== 'METHODRESPONSE' && $name !== 'METHODCALL') { $this->xh[$the_parser]['isf'] = 2; $this->xh[$the_parser]['isf_reason'] = 'Top level XML-RPC element is missing'; @@ -968,7 +1264,7 @@ class XML_RPC_Message extends CI_Xmlrpc case 'DOUBLE': case 'DATETIME.ISO8601': case 'BASE64': - if ($this->xh[$the_parser]['vt'] != 'value') + if ($this->xh[$the_parser]['vt'] !== 'value') { //two data elements inside a value: an error occurred! $this->xh[$the_parser]['isf'] = 2; @@ -1002,7 +1298,7 @@ class XML_RPC_Message extends CI_Xmlrpc // Add current element name to stack, to allow validation of nesting array_unshift($this->xh[$the_parser]['stack'], $name); - $name == 'VALUE' OR $this->xh[$the_parser]['lv'] = 0; + $name === 'VALUE' OR $this->xh[$the_parser]['lv'] = 0; } // -------------------------------------------------------------------- @@ -1045,20 +1341,20 @@ class XML_RPC_Message extends CI_Xmlrpc case 'BASE64': $this->xh[$the_parser]['vt'] = strtolower($name); - if ($name == 'STRING') + if ($name === 'STRING') { $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; } - elseif ($name == 'DATETIME.ISO8601') + elseif ($name === 'DATETIME.ISO8601') { $this->xh[$the_parser]['vt'] = $this->xmlrpcDateTime; $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; } - elseif ($name == 'BASE64') + elseif ($name === 'BASE64') { $this->xh[$the_parser]['value'] = base64_decode($this->xh[$the_parser]['ac']); } - elseif ($name == 'BOOLEAN') + elseif ($name === 'BOOLEAN') { // Translated BOOLEAN values to TRUE AND FALSE $this->xh[$the_parser]['value'] = (bool) $this->xh[$the_parser]['ac']; @@ -1076,7 +1372,7 @@ class XML_RPC_Message extends CI_Xmlrpc // we have an I4/INT // we must check that only 0123456789-<space> are characters here $this->xh[$the_parser]['value'] = preg_match('/^[+-]?[0-9\t ]+$/', $this->xh[$the_parser]['ac']) - ? (int) $this->xh[$the_parset]['ac'] + ? (int) $this->xh[$the_parser]['ac'] : 'ERROR_NON_NUMERIC_FOUND'; } $this->xh[$the_parser]['ac'] = ''; @@ -1093,7 +1389,7 @@ class XML_RPC_Message extends CI_Xmlrpc // build the XML-RPC value out of the data received, and substitute it $temp = new XML_RPC_Values($this->xh[$the_parser]['value'], $this->xh[$the_parser]['vt']); - if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] == 'ARRAY') + if (count($this->xh[$the_parser]['valuestack']) && $this->xh[$the_parser]['valuestack'][0]['type'] === 'ARRAY') { // Array $this->xh[$the_parser]['valuestack'][0]['values'][] = $temp; @@ -1151,9 +1447,9 @@ class XML_RPC_Message extends CI_Xmlrpc if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already // If a value has not been found - if ($this->xh[$the_parser]['lv'] != 3) + if ($this->xh[$the_parser]['lv'] !== 3) { - if ($this->xh[$the_parser]['lv'] == 1) + if ($this->xh[$the_parser]['lv'] === 1) { $this->xh[$the_parser]['lv'] = 2; // Found a value } @@ -1204,7 +1500,7 @@ class XML_RPC_Message extends CI_Xmlrpc { // 'bits' is for the MetaWeblog API image bits // @todo - this needs to be made more general purpose - $array[$key] = ($key == 'bits' OR $this->xss_clean == FALSE) ? $array[$key] : $CI->security->xss_clean($array[$key]); + $array[$key] = ($key === 'bits' OR $this->xss_clean === FALSE) ? $array[$key] : $CI->security->xss_clean($array[$key]); } } @@ -1242,11 +1538,11 @@ class XML_RPC_Message extends CI_Xmlrpc { $kind = $param->kindOf(); - if ($kind == 'scalar') + if ($kind === 'scalar') { return $param->scalarval(); } - elseif ($kind == 'array') + elseif ($kind === 'array') { reset($param->me); $b = current($param->me); @@ -1259,7 +1555,7 @@ class XML_RPC_Message extends CI_Xmlrpc return $arr; } - elseif ($kind == 'struct') + elseif ($kind === 'struct') { reset($param->me['struct']); $arr = array(); @@ -1284,23 +1580,36 @@ class XML_RPC_Message extends CI_Xmlrpc */ class XML_RPC_Values extends CI_Xmlrpc { + /** + * Value data + * + * @var array + */ public $me = array(); + + /** + * Value type + * + * @var int + */ public $mytype = 0; + // -------------------------------------------------------------------- + /** * Constructor * - * @param mixed - * @param string + * @param mixed $val + * @param string $type * @return void */ public function __construct($val = -1, $type = '') { parent::__construct(); - if ($val != -1 OR $type != '') + if ($val !== -1 OR $type !== '') { - $type = $type == '' ? 'string' : $type; + $type = $type === '' ? 'string' : $type; if ($this->xmlrpcTypes[$type] == 1) { @@ -1330,7 +1639,7 @@ class XML_RPC_Values extends CI_Xmlrpc { $typeof = $this->xmlrpcTypes[$type]; - if ($this->mytype == 1) + if ($this->mytype === 1) { echo '<strong>XML_RPC_Values</strong>: scalar can have only one value<br />'; return 0; @@ -1342,12 +1651,12 @@ class XML_RPC_Values extends CI_Xmlrpc return 0; } - if ($type == $this->xmlrpcBoolean) + if ($type === $this->xmlrpcBoolean) { - $val = (int) (strcasecmp($val,'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false'))); + $val = (int) (strcasecmp($val, 'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false'))); } - if ($this->mytype == 2) + if ($this->mytype === 2) { // adding to an array here $ar = $this->me['array']; @@ -1374,7 +1683,7 @@ class XML_RPC_Values extends CI_Xmlrpc */ public function addArray($vals) { - if ($this->mytype != 0) + if ($this->mytype !== 0) { echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />'; return 0; @@ -1395,7 +1704,7 @@ class XML_RPC_Values extends CI_Xmlrpc */ public function addStruct($vals) { - if ($this->mytype != 0) + if ($this->mytype !== 0) { echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />'; return 0; diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php index 6d270c2ea..3c3337bf2 100644 --- a/system/libraries/Xmlrpcs.php +++ b/system/libraries/Xmlrpcs.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); if ( ! function_exists('xml_parser_create')) { @@ -48,12 +49,40 @@ if ( ! class_exists('CI_Xmlrpc')) */ class CI_Xmlrpcs extends CI_Xmlrpc { - public $methods = array(); //array of methods mapped to function names and signatures - public $debug_msg = ''; // Debug Message - public $system_methods = array(); // XML RPC Server methods - public $controller_obj; - public $object = FALSE; + /** + * array of methods mapped to function names and signatures + * + * @var array + */ + public $methods = array(); + + /** + * Debug Message + * + * @var string + */ + public $debug_msg = ''; + /** + * XML RPC Server methods + * + * @var array + */ + public $system_methods = array(); + + /** + * Configuration object + * + * @var object + */ + public $object = FALSE; + + /** + * Initialize XMLRPC class + * + * @param array $config + * @return void + */ public function __construct($config = array()) { parent::__construct(); @@ -180,7 +209,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc // Get Data //------------------------------------- - if ($data == '') + if ($data === '') { $data = $HTTP_RAW_POST_DATA; } @@ -202,7 +231,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc ); xml_set_object($parser, $parser_object); - xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, TRUE); xml_set_element_handler($parser, 'open_tag', 'closing_tag'); xml_set_character_data_handler($parser, 'character_data'); //xml_set_default_handler($parser, 'default_handler'); @@ -275,9 +304,9 @@ class CI_Xmlrpcs extends CI_Xmlrpc $methName = $m->method_name; // Check to see if it is a system call - $system_call = (strncmp($methName, 'system', 5) === 0); + $system_call = (strpos($methName, 'system') === 0); - if ($this->xss_clean == FALSE) + if ($this->xss_clean === FALSE) { $m->xss_clean = FALSE; } @@ -296,7 +325,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc //------------------------------------- $method_parts = explode('.', $this->methods[$methName]['function']); - $objectCall = (isset($method_parts[1]) && $method_parts[1] != ''); + $objectCall = (isset($method_parts[1]) && $method_parts[1] !== ''); if ($system_call === TRUE) { @@ -328,9 +357,9 @@ class CI_Xmlrpcs extends CI_Xmlrpc for ($n = 0, $mc = count($m->params); $n < $mc; $n++) { $p = $m->params[$n]; - $pt = ($p->kindOf() == 'scalar') ? $p->scalarval() : $p->kindOf(); + $pt = ($p->kindOf() === 'scalar') ? $p->scalarval() : $p->kindOf(); - if ($pt != $current_sig[$n+1]) + if ($pt !== $current_sig[$n+1]) { $pno = $n+1; $wanted = $current_sig[$n+1]; @@ -499,7 +528,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc $attempt = $this->_execute($m); - if ($attempt->faultCode() != 0) + if ($attempt->faultCode() !== 0) { return $attempt; } @@ -539,7 +568,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc */ public function do_multicall($call) { - if ($call->kindOf() != 'struct') + if ($call->kindOf() !== 'struct') { return $this->multicall_error('notstruct'); } @@ -549,13 +578,13 @@ class CI_Xmlrpcs extends CI_Xmlrpc } list($scalar_type,$scalar_value)=each($methName->me); - $scalar_type = $scalar_type == $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type; + $scalar_type = $scalar_type === $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type; - if ($methName->kindOf() != 'scalar' OR $scalar_type != 'string') + if ($methName->kindOf() !== 'scalar' OR $scalar_type !== 'string') { return $this->multicall_error('notstring'); } - elseif ($scalar_value == 'system.multicall') + elseif ($scalar_value === 'system.multicall') { return $this->multicall_error('recursion'); } @@ -563,7 +592,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc { return $this->multicall_error('noparams'); } - elseif ($params->kindOf() != 'array') + elseif ($params->kindOf() !== 'array') { return $this->multicall_error('notarray'); } @@ -578,7 +607,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc $result = $this->_execute($msg); - if ($result->faultCode() != 0) + if ($result->faultCode() !== 0) { return $this->multicall_error($result); } diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php index 80438546b..9ecd0de9f 100644 --- a/system/libraries/Zip.php +++ b/system/libraries/Zip.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Zip Compression Class @@ -40,15 +41,55 @@ * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/libraries/zip.html */ -class CI_Zip { +class CI_Zip { + /** + * Zip data in string form + * + * @var string + */ public $zipdata = ''; + + /** + * Zip data for a directory in string form + * + * @var string + */ public $directory = ''; + + /** + * Number of files/folder in zip file + * + * @var int + */ public $entries = 0; + + /** + * Number of files in zip + * + * @var int + */ public $file_num = 0; + + /** + * relative offset of local header + * + * @var int + */ public $offset = 0; + + /** + * Reference to time at init + * + * @var int + */ public $now; + /** + * Initialize zip compression class + * + * @return void + */ public function __construct() { $this->now = time(); diff --git a/system/libraries/javascript/Jquery.php b/system/libraries/javascript/Jquery.php index f30d7c639..2bf47957f 100644 --- a/system/libraries/javascript/Jquery.php +++ b/system/libraries/javascript/Jquery.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,8 +24,7 @@ * @since Version 1.0 * @filesource */ - -// ------------------------------------------------------------------------ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Jquery Class @@ -36,17 +35,65 @@ * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/libraries/javascript.html */ - class CI_Jquery extends CI_Javascript { + /** + * JavaScript directory location + * + * @var string + */ protected $_javascript_folder = 'js'; + + /** + * JQuery code for load + * + * @var array + */ public $jquery_code_for_load = array(); + + /** + * JQuery code for compile + * + * @var array + */ public $jquery_code_for_compile = array(); + + /** + * JQuery corner active flag + * + * @var bool + */ public $jquery_corner_active = FALSE; + + /** + * JQuery table sorter active flag + * + * @var bool + */ public $jquery_table_sorter_active = FALSE; + + /** + * JQuery table sorder pager active + * + * @var bool + */ public $jquery_table_sorter_pager_active = FALSE; + + /** + * JQuery AJAX image + * + * @var string + */ public $jquery_ajax_img = ''; + // -------------------------------------------------------------------- + + /** + * Constructor + * + * @param array $params + * @return void + */ public function __construct($params) { $this->CI =& get_instance(); @@ -57,7 +104,7 @@ class CI_Jquery extends CI_Javascript { $this->script(); } - log_message('debug', "Jquery Class Initialized"); + log_message('debug', 'Jquery Class Initialized'); } // -------------------------------------------------------------------- @@ -103,19 +150,16 @@ class CI_Jquery extends CI_Javascript { * * @param string The element to attach the event to * @param string The code to execute - * @param boolean whether or not to return false + * @param bool whether or not to return false * @return string */ protected function _click($element = 'this', $js = '', $ret_false = TRUE) { - if ( ! is_array($js)) - { - $js = array($js); - } + is_array($js) OR $js = array($js); if ($ret_false) { - $js[] = "return false;"; + $js[] = 'return false;'; } return $this->_add_event($element, $js, 'click'); @@ -183,7 +227,7 @@ class CI_Jquery extends CI_Javascript { */ protected function _hover($element = 'this', $over, $out) { - $event = "\n\t$(" . $this->_prep_element($element) . ").hover(\n\t\tfunction()\n\t\t{\n\t\t\t{$over}\n\t\t}, \n\t\tfunction()\n\t\t{\n\t\t\t{$out}\n\t\t});\n"; + $event = "\n\t$(".$this->_prep_element($element).").hover(\n\t\tfunction()\n\t\t{\n\t\t\t{$over}\n\t\t}, \n\t\tfunction()\n\t\t{\n\t\t\t{$out}\n\t\t});\n"; $this->jquery_code_for_compile[] = $event; @@ -309,11 +353,10 @@ class CI_Jquery extends CI_Javascript { * * Outputs script directly * - * @param string The element to attach the event to - * @param string The code to execute - * @return string + * @param array $array_js = array() + * @return void */ - protected function _output($array_js = '') + protected function _output($array_js = array()) { if ( ! is_array($array_js)) { @@ -322,7 +365,7 @@ class CI_Jquery extends CI_Javascript { foreach ($array_js as $js) { - $this->jquery_code_for_compile[] = "\t$js\n"; + $this->jquery_code_for_compile[] = "\t".$js."\n"; } } @@ -383,13 +426,14 @@ class CI_Jquery extends CI_Javascript { * * Outputs a jQuery addClass event * - * @param string - element + * @param string $element + * @param string $class * @return string */ - protected function _addClass($element = 'this', $class='') + protected function _addClass($element = 'this', $class = '') { $element = $this->_prep_element($element); - return "$({$element}).addClass(\"$class\");"; + return '$('.$element.').addClass("'.$class.'");'; } // -------------------------------------------------------------------- @@ -399,9 +443,10 @@ class CI_Jquery extends CI_Javascript { * * Outputs a jQuery animate event * - * @param string - element - * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds - * @param string - Javascript callback function + * @param string $element + * @param array $params + * @param string $speed 'slow', 'normal', 'fast', or time in milliseconds + * @param string $extra * @return string */ protected function _animate($element = 'this', $params = array(), $speed = '', $extra = '') @@ -411,24 +456,24 @@ class CI_Jquery extends CI_Javascript { $animations = "\t\t\t"; - foreach ($params as $param=>$value) + foreach ($params as $param => $value) { - $animations .= $param.': \''.$value.'\', '; + $animations .= $param.": '".$value."', "; } $animations = substr($animations, 0, -2); // remove the last ", " - if ($speed != '') + if ($speed !== '') { $speed = ', '.$speed; } - if ($extra != '') + if ($extra !== '') { $extra = ', '.$extra; } - return "$({$element}).animate({\n$animations\n\t\t}".$speed.$extra.");"; + return "$({$element}).animate({\n$animations\n\t\t}".$speed.$extra.');'; } // -------------------------------------------------------------------- @@ -448,7 +493,7 @@ class CI_Jquery extends CI_Javascript { $element = $this->_prep_element($element); $speed = $this->_validate_speed($speed); - if ($callback != '') + if ($callback !== '') { $callback = ", function(){\n{$callback}\n}"; } @@ -473,12 +518,12 @@ class CI_Jquery extends CI_Javascript { $element = $this->_prep_element($element); $speed = $this->_validate_speed($speed); - if ($callback != '') + if ($callback !== '') { $callback = ", function(){\n{$callback}\n}"; } - return "$({$element}).fadeOut({$speed}{$callback});"; + return '$('.$element.').fadeOut('.$speed.$callback.');'; } // -------------------------------------------------------------------- @@ -498,7 +543,7 @@ class CI_Jquery extends CI_Javascript { $element = $this->_prep_element($element); $speed = $this->_validate_speed($speed); - if ($callback != '') + if ($callback !== '') { $callback = ", function(){\n{$callback}\n}"; } @@ -513,13 +558,14 @@ class CI_Jquery extends CI_Javascript { * * Outputs a jQuery remove class event * - * @param string - element + * @param string $element + * @param string $class * @return string */ - protected function _removeClass($element = 'this', $class='') + protected function _removeClass($element = 'this', $class = '') { $element = $this->_prep_element($element); - return "$({$element}).removeClass(\"$class\");"; + return '$('.$element.').removeClass("'.$class.'");'; } // -------------------------------------------------------------------- @@ -539,12 +585,12 @@ class CI_Jquery extends CI_Javascript { $element = $this->_prep_element($element); $speed = $this->_validate_speed($speed); - if ($callback != '') + if ($callback !== '') { $callback = ", function(){\n{$callback}\n}"; } - return "$({$element}).slideUp({$speed}{$callback});"; + return '$('.$element.').slideUp('.$speed.$callback.');'; } // -------------------------------------------------------------------- @@ -564,12 +610,12 @@ class CI_Jquery extends CI_Javascript { $element = $this->_prep_element($element); $speed = $this->_validate_speed($speed); - if ($callback != '') + if ($callback !== '') { $callback = ", function(){\n{$callback}\n}"; } - return "$({$element}).slideDown({$speed}{$callback});"; + return '$('.$element.').slideDown('.$speed.$callback.');'; } // -------------------------------------------------------------------- @@ -589,12 +635,12 @@ class CI_Jquery extends CI_Javascript { $element = $this->_prep_element($element); $speed = $this->_validate_speed($speed); - if ($callback != '') + if ($callback !== '') { $callback = ", function(){\n{$callback}\n}"; } - return "$({$element}).slideToggle({$speed}{$callback});"; + return '$('.$element.').slideToggle('.$speed.$callback.');'; } // -------------------------------------------------------------------- @@ -610,7 +656,7 @@ class CI_Jquery extends CI_Javascript { protected function _toggle($element = 'this') { $element = $this->_prep_element($element); - return "$({$element}).toggle();"; + return '$('.$element.').toggle();'; } // -------------------------------------------------------------------- @@ -620,13 +666,14 @@ class CI_Jquery extends CI_Javascript { * * Outputs a jQuery toggle class event * - * @param string - element + * @param string $element + * @param string $class * @return string */ - protected function _toggleClass($element = 'this', $class='') + protected function _toggleClass($element = 'this', $class = '') { $element = $this->_prep_element($element); - return "$({$element}).toggleClass(\"$class\");"; + return '$('.$element.').toggleClass("'.$class.'");'; } // -------------------------------------------------------------------- @@ -646,12 +693,12 @@ class CI_Jquery extends CI_Javascript { $element = $this->_prep_element($element); $speed = $this->_validate_speed($speed); - if ($callback != '') + if ($callback !== '') { $callback = ", function(){\n{$callback}\n}"; } - return "$({$element}).show({$speed}{$callback});"; + return '$('.$element.').show('.$speed.$callback.');'; } // -------------------------------------------------------------------- @@ -674,30 +721,29 @@ class CI_Jquery extends CI_Javascript { $controller = (strpos('://', $controller) === FALSE) ? $controller : $this->CI->config->site_url($controller); // ajaxStart and ajaxStop are better choices here... but this is a stop gap - if ($this->CI->config->item('javascript_ajax_img') == '') + if ($this->CI->config->item('javascript_ajax_img') === '') { - $loading_notifier = "Loading..."; + $loading_notifier = 'Loading...'; } else { - $loading_notifier = '<img src=\''.$this->CI->config->slash_item('base_url').$this->CI->config->item('javascript_ajax_img').'\' alt=\'Loading\' />'; + $loading_notifier = '<img src="'.$this->CI->config->slash_item('base_url').$this->CI->config->item('javascript_ajax_img').'" alt="Loading" />'; } - $updater = "$($container).empty();\n" // anything that was in... get it out - . "\t\t$($container).prepend(\"$loading_notifier\");\n"; // to replace with an image + $updater = '$('.$container.").empty();\n" // anything that was in... get it out + ."\t\t$(".$container.').prepend("'.$loading_notifier."\");\n"; // to replace with an image $request_options = ''; - if ($options != '') + if ($options !== '') { $request_options .= ', {' - . (is_array($options) ? "'".implode("', '", $options)."'" : "'".str_replace(":", "':'", $options)."'") - . '}'; + .(is_array($options) ? "'".implode("', '", $options)."'" : "'".str_replace(':', "':'", $options)."'") + .'}'; } return $updater."\t\t$($container).load('$controller'$request_options);"; } - // -------------------------------------------------------------------- // Pre-written handy stuff // -------------------------------------------------------------------- @@ -705,18 +751,19 @@ class CI_Jquery extends CI_Javascript { /** * Zebra tables * - * @param string table name - * @param string plugin location + * @param string $class + * @param string $odd + * @param string $hover * @return string */ protected function _zebraTables($class = '', $odd = 'odd', $hover = '') { - $class = ($class != '') ? '.'.$class : ''; - $zebra = "\t\$(\"table{$class} tbody tr:nth-child(even)\").addClass(\"{$odd}\");"; + $class = ($class !== '') ? '.'.$class : ''; + $zebra = "\t\$(\"table{$class} tbody tr:nth-child(even)\").addClass(\"{$odd}\");"; $this->jquery_code_for_compile[] = $zebra; - if ($hover != '') + if ($hover !== '') { $hover = $this->hover("table{$class} tbody tr", "$(this).addClass('hover');", "$(this).removeClass('hover');"); } @@ -731,9 +778,9 @@ class CI_Jquery extends CI_Javascript { /** * Corner Plugin * - * http://www.malsup.com/jquery/corner/ - * - * @param string target + * @link http://www.malsup.com/jquery/corner/ + * @param string $element + * @param string $corner_style * @return string */ public function corner($element = '', $corner_style = '') @@ -741,21 +788,23 @@ class CI_Jquery extends CI_Javascript { // may want to make this configurable down the road $corner_location = '/plugins/jquery.corner.js'; - if ($corner_style != '') + if ($corner_style !== '') { $corner_style = '"'.$corner_style.'"'; } - return "$(" . $this->_prep_element($element) . ").corner(".$corner_style.");"; + return '$('.$this->_prep_element($element).').corner('.$corner_style.');'; } // -------------------------------------------------------------------- /** - * modal window + * Modal window * * Load a thickbox modal window * + * @param string $src + * @param bool $relative * @return void */ public function modal($src, $relative = FALSE) @@ -770,6 +819,8 @@ class CI_Jquery extends CI_Javascript { * * Load an Effect library * + * @param string $src + * @param bool $relative * @return void */ public function effect($src, $relative = FALSE) @@ -784,6 +835,8 @@ class CI_Jquery extends CI_Javascript { * * Load a plugin library * + * @param string $src + * @param bool $relative * @return void */ public function plugin($src, $relative = FALSE) @@ -798,12 +851,15 @@ class CI_Jquery extends CI_Javascript { * * Load a user interface library * + * @param string $src + * @param bool $relative * @return void */ public function ui($src, $relative = FALSE) { $this->jquery_code_for_load[] = $this->external($src, $relative); } + // -------------------------------------------------------------------- /** @@ -811,26 +867,27 @@ class CI_Jquery extends CI_Javascript { * * Creates a jQuery sortable * - * @return void + * @param string $element + * @param array $options + * @return string */ public function sortable($element, $options = array()) { - if (count($options) > 0) { $sort_options = array(); foreach ($options as $k=>$v) { - $sort_options[] = "\n\t\t".$k.': '.$v.""; + $sort_options[] = "\n\t\t".$k.': '.$v; } - $sort_options = implode(",", $sort_options); + $sort_options = implode(',', $sort_options); } else { $sort_options = ''; } - return "$(" . $this->_prep_element($element) . ").sortable({".$sort_options."\n\t});"; + return '$('.$this->_prep_element($element).').sortable({'.$sort_options."\n\t});"; } // -------------------------------------------------------------------- @@ -844,7 +901,7 @@ class CI_Jquery extends CI_Javascript { */ public function tablesorter($table = '', $options = '') { - $this->jquery_code_for_compile[] = "\t$(" . $this->_prep_element($table) . ").tablesorter($options);\n"; + $this->jquery_code_for_compile[] = "\t$(".$this->_prep_element($table).').tablesorter('.$options.");\n"; } // -------------------------------------------------------------------- @@ -869,7 +926,7 @@ class CI_Jquery extends CI_Javascript { } - $event = "\n\t$(" . $this->_prep_element($element) . ").{$event}(function(){\n\t\t{$js}\n\t});\n"; + $event = "\n\t$(".$this->_prep_element($element).').'.$event."(function(){\n\t\t{$js}\n\t});\n"; $this->jquery_code_for_compile[] = $event; return $event; } @@ -882,7 +939,9 @@ class CI_Jquery extends CI_Javascript { * As events are specified, they are stored in an array * This funciton compiles them all for output on a page * - * @return string + * @param string $view_var + * @param bool $script_tags + * @return void */ protected function _compile($view_var = 'script_foot', $script_tags = TRUE) { @@ -898,13 +957,12 @@ class CI_Jquery extends CI_Javascript { // Inline references $script = '$(document).ready(function() {'."\n" - . implode('', $this->jquery_code_for_compile) - . '});'; + .implode('', $this->jquery_code_for_compile) + .'});'; $output = ($script_tags === FALSE) ? $script : $this->inline($script); $this->CI->load->vars(array($view_var => $output)); - } // -------------------------------------------------------------------- @@ -928,14 +986,12 @@ class CI_Jquery extends CI_Javascript { * * A wrapper for writing document.ready() * - * @return string + * @param array $js + * @return void */ protected function _document_ready($js) { - if ( ! is_array($js)) - { - $js = array($js); - } + is_array($js) OR $js = array($js); foreach ($js as $script) { @@ -950,7 +1006,8 @@ class CI_Jquery extends CI_Javascript { * * Outputs the script tag that loads the jquery.js file into an HTML document * - * @param string + * @param string $library_src + * @param bool $relative * @return string */ public function script($library_src = '', $relative = FALSE) @@ -974,7 +1031,7 @@ class CI_Jquery extends CI_Javascript { */ protected function _prep_element($element) { - if ($element != 'this') + if ($element !== 'this') { $element = '"'.$element.'"'; } @@ -998,7 +1055,7 @@ class CI_Jquery extends CI_Javascript { { return '"'.$speed.'"'; } - elseif (preg_match("/[^0-9]/", $speed)) + elseif (preg_match('/[^0-9]/', $speed)) { return ''; } @@ -1009,4 +1066,4 @@ class CI_Jquery extends CI_Javascript { } /* End of file Jquery.php */ -/* Location: ./system/libraries/Jquery.php */ +/* Location: ./system/libraries/Jquery.php */
\ No newline at end of file diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 9f89d1be8..8ce80b3fd 100644 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -7,14 +7,38 @@ error_reporting(E_ALL | E_STRICT); $dir = realpath(dirname(__FILE__)); // Path constants -define('PROJECT_BASE', realpath($dir.'/../').'/'); -define('BASEPATH', PROJECT_BASE.'system/'); -define('APPPATH', PROJECT_BASE.'application/'); -define('VIEWPATH', PROJECT_BASE.''); +defined('PROJECT_BASE') OR define('PROJECT_BASE', realpath($dir.'/../').'/'); +defined('SYSTEM_PATH') OR define('SYSTEM_PATH', PROJECT_BASE.'system/'); + +// Get vfsStream either via PEAR or composer +foreach (explode(PATH_SEPARATOR, get_include_path()) as $path) +{ + if (file_exists($path.DIRECTORY_SEPARATOR.'vfsStream/vfsStream.php')) + { + require_once 'vfsStream/vfsStream.php'; + break; + } +} + +if ( ! class_exists('vfsStream') && file_exists(PROJECT_BASE.'vendor/autoload.php')) +{ + include_once PROJECT_BASE.'vendor/autoload.php'; + class_alias('org\bovigo\vfs\vfsStream', 'vfsStream'); + class_alias('org\bovigo\vfs\vfsStreamDirectory', 'vfsStreamDirectory'); + class_alias('org\bovigo\vfs\vfsStreamWrapper', 'vfsStreamWrapper'); +} + +// Define CI path constants to VFS (filesystem setup in CI_TestCase::setUp) +defined('BASEPATH') OR define('BASEPATH', vfsStream::url('system/')); +defined('APPPATH') OR define('APPPATH', vfsStream::url('application/')); +defined('VIEWPATH') OR define('VIEWPATH', APPPATH.'views/'); + +// Set localhost "remote" IP +isset($_SERVER['REMOTE_ADDR']) OR $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // Prep our test environment -require_once 'vfsStream/vfsStream.php'; include_once $dir.'/mocks/core/common.php'; +include_once SYSTEM_PATH.'core/Common.php'; include_once $dir.'/mocks/autoloader.php'; spl_autoload_register('autoload'); diff --git a/tests/README.md b/tests/README.md index 6d83c34d8..a5f89a2b1 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,12 +1,6 @@ # CodeIgniter Unit Tests # -Status : [![Build Status](https://secure.travis-ci.org/EllisLab/CodeIgniter.png?branch=feature/unit-tests)](http://travis-ci.org/EllisLab/CodeIgniter) - -*Do not merge to default until these issues have been addressed* - -- Clean up naming conventions -- Figure out config stuff -- Figure out database testing +Status : [![Build Status](https://secure.travis-ci.org/EllisLab/CodeIgniter.png?branch=develop)](http://travis-ci.org/EllisLab/CodeIgniter) ### Introduction: @@ -27,8 +21,8 @@ PHP Unit >= 3.5.6 vfsStream - pear channel-discover pear.php-tools.net - pear install pat/vfsStream-alpha + pear channel-discover pear.bovigo.org + pear install bovigo/vfsStream-beta #### Installation of PEAR and PHPUnit on Ubuntu @@ -43,11 +37,11 @@ vfsStream pear channel-discover pear.phpunit.de pear channel-discover pear.symfony-project.com pear channel-discover components.ez.no - pear channel-discover pear.php-tools.net + pear channel-discover pear.bovigo.org # Finally install PHPUnit and vfsStream (including dependencies) pear install --alldeps phpunit/PHPUnit - pear install --alldeps pat/vfsStream-alpha + pear install --alldeps bovigo/vfsStream-beta # Finally, run 'phpunit' from within the ./tests directory # and you should be on your way! @@ -70,6 +64,30 @@ with a base for application and package tests. That gives us: 3. Application Test - bootstrapping for application/tests [not started] 4. Package Test - bootstrapping for <package>/tests [not started] +### Test Environment: + +The test/Bootstrap.php file establishes global constants such as BASEPATH, +APPPATH, and VIEWPATH, initializing them to point to VFS locations. The +test case class employs vfsStream to make a clean virtual filesystem with +the necessary paths for every individual test. + +Within each test case, VFS directory objects are available to use as arguments +to the VFS convenience functions (see below): + +- ci_vfs_root: VFS filesystem root +- ci_app_root: Application directory +- ci_base_root: System directory +- ci_view_root: Views directory + +Classes being instantiated for testing are read from the actual filesystem +by the unit test autoloader, as are mockups created in tests/mocks. If you +need access to the real system directory, the SYSTEM_PATH constant always +points to it. + +Any other resources which need to be read from the path constants must be +created or cloned within your test. Functions for doing so are outlined +below. + ### CI_TestCase Documentation Test cases should extend CI_TestCase. This internally extends @@ -84,8 +102,14 @@ Current API is *not stable*. Names and implementations will change. $this->ci_set_config($key, $val) -Set the global config variables. If key is an array, it will -replace the entire config array. They are _not_ merged. +Set the global config variables in a mock Config object. If key is an array, +it will replace the entire config array. They are _not_ merged. If called +without any parameters, it will create the mock object but not set any values. +The mock Config object also provides rudimentary item() and load() stubs for +delivering configured values to classes being tested and handling config load +calls, respectively. The load() stub does _not_ actually load any files, it +only records the filename provided. Check the config->loaded array to verify +calls made. $this->ci_instance($obj) @@ -109,11 +133,48 @@ $GLOBALS key. For example: $cfg = new $cfg; // instantiates config and overwrites the CFG global $this->ci_set_core_class($name, $obj) - + An alternative way to set one of the core globals. + $this->ci_vfs_mkdir($name, $root) + +Creates a new directory in the test VFS. Pass a directory object to be the +parent directory or none to create a root-level directory. Returns the new +directory object. + + $this->ci_vfs_create($file, $content, $root, $path) + +Creates a new VFS file. '.php' is automatically appended to the filename if +it has no extension. Pass a directory object as the root, and an optional path +to recurse and/or create for containing the file. Path may be a string (such +as 'models/subdir') or an array (e.g. - array('models', 'subdir') ). Existing +directories in the VFS root will be recursed until a new directory is +identified - all others in the path will be created, so you can mix-and-match +old and new directories. If $file is an array (key = name, value = content), +multiple files will be created in the same path. + + $this->ci_vfs_clone($path) + +Clones an existing file from the real filesystem to exist in the same path of +the VFS. Path must be relative to the project root (i.e. - starting with +'system' or 'application'). + + $this->ci_vfs_path($path, $base) + +Creates a VFS file path string suitable for use with PHP file operations. Path +may be absolute from the VFS root, or relative to a base path. It is often +useful to use APPPATH or BASEPATH as the base. + + $this->helper($name) + +Loads a helper from the real filesystem. + + $this->lang($name) + +Loads a language file from the real filesystem and returns the $lang array. + $this->ci_get_config() __internal__ - + Returns the global config array. Internal as you shouldn't need to call this (you're setting it, after all). Used internally to make CI's get_config() work. @@ -161,4 +222,4 @@ I don't have a clue how this will work. Needs to be able to handle packages that are used multiple times within the application (i.e. EE/Pyro modules) -as well as packages that are used by multiple applications (library distributions) +as well as packages that are used by multiple applications (library distributions)
\ No newline at end of file diff --git a/tests/codeigniter/Setup_test.php b/tests/codeigniter/Setup_test.php index 550245f2f..5317c56c7 100644 --- a/tests/codeigniter/Setup_test.php +++ b/tests/codeigniter/Setup_test.php @@ -1,13 +1,13 @@ <?php class Setup_test extends PHPUnit_Framework_TestCase { - - function test_nonsense() + + public function test_bootstrap_constants() { - $this->markTestIncomplete('not implemented'); - // ensure that our bootstrapped test environment - // is a good representation of an isolated CI install - //die('here'); + $this->assertTrue(defined('PROJECT_BASE')); + $this->assertTrue(defined('BASEPATH')); + $this->assertTrue(defined('APPPATH')); + $this->assertTrue(defined('VIEWPATH')); } - + }
\ No newline at end of file diff --git a/tests/codeigniter/core/Benchmark_test.php b/tests/codeigniter/core/Benchmark_test.php new file mode 100644 index 000000000..a239ba51d --- /dev/null +++ b/tests/codeigniter/core/Benchmark_test.php @@ -0,0 +1,43 @@ +<?php + +class Benchmark_test extends CI_TestCase { + + public function set_up() + { + $this->benchmark = new Mock_Core_Benchmark(); + } + + // -------------------------------------------------------------------- + + public function test_mark() + { + $this->assertEmpty($this->benchmark->marker); + + $this->benchmark->mark('code_start'); + + $this->assertEquals(1, count($this->benchmark->marker)); + $this->assertArrayHasKey('code_start', $this->benchmark->marker); + } + + // -------------------------------------------------------------------- + + public function test_elapsed_time() + { + $this->assertEquals('{elapsed_time}', $this->benchmark->elapsed_time()); + $this->assertEmpty($this->benchmark->elapsed_time('undefined_point')); + + $this->benchmark->mark('code_start'); + sleep(1); + $this->benchmark->mark('code_end'); + + $this->assertEquals('1.0', $this->benchmark->elapsed_time('code_start', 'code_end', 1)); + } + + // -------------------------------------------------------------------- + + public function test_memory_usage() + { + $this->assertEquals('{memory_usage}', $this->benchmark->memory_usage()); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/core/Common_test.php b/tests/codeigniter/core/Common_test.php index dded2e824..999b49cb3 100644 --- a/tests/codeigniter/core/Common_test.php +++ b/tests/codeigniter/core/Common_test.php @@ -1,13 +1,52 @@ <?php class Common_test extends CI_TestCase { - - // ------------------------------------------------------------------------ - + public function test_is_php() { $this->assertEquals(TRUE, is_php('1.2.0')); $this->assertEquals(FALSE, is_php('9999.9.9')); } - + + // ------------------------------------------------------------------------ + + public function test_stringify_attributes() + { + $this->assertEquals(' class="foo" id="bar"', _stringify_attributes(array('class' => 'foo', 'id' => 'bar'))); + + $atts = new stdClass; + $atts->class = 'foo'; + $atts->id = 'bar'; + $this->assertEquals(' class="foo" id="bar"', _stringify_attributes($atts)); + + $atts = new stdClass; + $this->assertEquals('', _stringify_attributes($atts)); + + $this->assertEquals(' class="foo" id="bar"', _stringify_attributes('class="foo" id="bar"')); + + $this->assertEquals('', _stringify_attributes(array())); + } + + // ------------------------------------------------------------------------ + + public function test_stringify_js_attributes() + { + $this->assertEquals('width=800,height=600', _stringify_attributes(array('width' => '800', 'height' => '600'), TRUE)); + + $atts = new stdClass; + $atts->width = 800; + $atts->height = 600; + $this->assertEquals('width=800,height=600', _stringify_attributes($atts, TRUE)); + } + + // ------------------------------------------------------------------------ + + public function test_html_escape() + { + $this->assertEquals( + html_escape('Here is a string containing "quoted" text.'), + 'Here is a string containing "quoted" text.' + ); + } + }
\ No newline at end of file diff --git a/tests/codeigniter/core/Config_test.php b/tests/codeigniter/core/Config_test.php index 30f0cc61d..be426d070 100644 --- a/tests/codeigniter/core/Config_test.php +++ b/tests/codeigniter/core/Config_test.php @@ -5,89 +5,229 @@ class Config_test extends CI_TestCase { public function set_up() { $cls =& $this->ci_core_class('cfg'); - + // set predictable config values - $this->ci_set_config(array( + $this->cfg = array( 'index_page' => 'index.php', - 'base_url' => 'http://example.com/', + 'base_url' => 'http://example.com/', 'subclass_prefix' => 'MY_' - )); + ); + $this->ci_set_config($this->cfg); - $this->config = new $cls; + $this->config = new $cls; } - + // -------------------------------------------------------------------- public function test_item() { - $this->assertEquals('http://example.com/', $this->config->item('base_url')); + $this->assertEquals($this->cfg['base_url'], $this->config->item('base_url')); // Bad Config value $this->assertFalse($this->config->item('no_good_item')); - + // Index $this->assertFalse($this->config->item('no_good_item', 'bad_index')); $this->assertFalse($this->config->item('no_good_item', 'default')); } - + // -------------------------------------------------------------------- - + public function test_set_item() { $this->assertFalse($this->config->item('not_yet_set')); - + $this->config->set_item('not_yet_set', 'is set'); - $this->assertEquals('is set', $this->config->item('not_yet_set')); } // -------------------------------------------------------------------- - + public function test_slash_item() { // Bad Config value $this->assertFalse($this->config->slash_item('no_good_item')); - - $this->assertEquals('http://example.com/', $this->config->slash_item('base_url')); - $this->assertEquals('MY_/', $this->config->slash_item('subclass_prefix')); + $this->assertEquals($this->cfg['base_url'], $this->config->slash_item('base_url')); + $this->assertEquals($this->cfg['subclass_prefix'].'/', $this->config->slash_item('subclass_prefix')); + } + + // -------------------------------------------------------------------- + + public function test_base_url() + { + // Test regular base URL + $base_url = $this->cfg['base_url']; + $this->assertEquals($base_url, $this->config->base_url()); + + // Test with URI + $uri = 'test'; + $this->assertEquals($base_url.$uri, $this->config->base_url($uri)); + + // Clear base_url + $this->ci_set_config('base_url', ''); + + // Rerun constructor + $cls =& $this->ci_core_class('cfg'); + $this->config = new $cls; + + // Test default base + $this->assertEquals('http://localhost/', $this->config->base_url()); + + // Capture server vars + $old_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : NULL; + $old_script = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : NULL; + $old_https = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : NULL; + + // Setup server vars for detection + $host = 'test.com'; + $path = '/path/'; + $script = 'base_test.php'; + $_SERVER['HTTP_HOST'] = $host; + $_SERVER['SCRIPT_NAME'] = $path.$script; + + // Rerun constructor + $this->config = new $cls; + + // Test plain detected + $this->assertEquals('http://'.$host.$path, $this->config->base_url()); + + // Rerun constructor + $_SERVER['HTTPS'] = 'on'; + $this->config = new $cls; + + // Test secure detected + $this->assertEquals('https://'.$host.$path, $this->config->base_url()); + + // Restore server vars + if ($old_host === NULL) unset($_SERVER['HTTP_HOST']); + else $_SERVER['HTTP_HOST'] = $old_host; + if ($old_script === NULL) unset($_SERVER['SCRIPT_NAME']); + else $_SERVER['SCRIPT_NAME'] = $old_script; + if ($old_https === NULL) unset($_SERVER['HTTPS']); + else $_SERVER['HTTPS'] = $old_https; } // -------------------------------------------------------------------- public function test_site_url() { - $this->assertEquals('http://example.com/index.php', $this->config->site_url()); - - $base_url = $this->config->item('base_url'); - + $base_url = $this->cfg['base_url']; + $index_page = $this->cfg['index_page']; + $this->assertEquals($base_url.$index_page, $this->config->site_url()); + + $old_base = $this->config->item('base_url'); $this->config->set_item('base_url', ''); - + $q_string = $this->config->item('enable_query_strings'); - $this->config->set_item('enable_query_strings', FALSE); - $this->assertEquals('index.php/test', $this->config->site_url('test')); - $this->assertEquals('index.php/test/1', $this->config->site_url(array('test', '1'))); - + $uri = 'test'; + $uri2 = '1'; + $this->assertEquals($index_page.'/'.$uri, $this->config->site_url($uri)); + $this->assertEquals($index_page.'/'.$uri.'/'.$uri2, $this->config->site_url(array($uri, $uri2))); + + $suffix = 'ing'; + $this->config->set_item('url_suffix', $suffix); + + $arg = 'pass'; + $this->assertEquals($index_page.'/'.$uri.$suffix, $this->config->site_url($uri)); + $this->assertEquals($index_page.'/'.$uri.$suffix.'?'.$arg, $this->config->site_url($uri.'?'.$arg)); + + $this->config->set_item('url_suffix', FALSE); $this->config->set_item('enable_query_strings', TRUE); - $this->assertEquals('index.php?test', $this->config->site_url('test')); - $this->assertEquals('index.php?0=test&1=1', $this->config->site_url(array('test', '1'))); - - $this->config->set_item('base_url', $base_url); + $this->assertEquals($index_page.'?'.$uri, $this->config->site_url($uri)); + $this->assertEquals($index_page.'?0='.$uri.'&1='.$uri2, $this->config->site_url(array($uri, $uri2))); + + $this->config->set_item('base_url', $old_base); + + $this->assertEquals($base_url.$index_page.'?'.$uri, $this->config->site_url($uri)); - $this->assertEquals('http://example.com/index.php?test', $this->config->site_url('test')); - // back to home base - $this->config->set_item('enable_query_strings', $q_string); + $this->config->set_item('enable_query_strings', $q_string); } // -------------------------------------------------------------------- - + public function test_system_url() { - $this->assertEquals('http://example.com/system/', $this->config->system_url()); + $this->assertEquals($this->cfg['base_url'].'system/', $this->config->system_url()); + } + + // -------------------------------------------------------------------- + + public function test_load() + { + // Test regular load + $file = 'test.php'; + $key = 'testconfig'; + $val = 'my_value'; + $cfg = array($key => $val); + $this->ci_vfs_create($file, '<?php $config = '.var_export($cfg, TRUE).';', $this->ci_app_root, 'config'); + $this->assertTrue($this->config->load($file)); + $this->assertEquals($val, $this->config->item($key)); + + // Test reload - value should not change + $val2 = 'new_value'; + $cfg = array($key => $val2); + $this->ci_vfs_create($file, '<?php $config = '.var_export($cfg, TRUE).';', $this->ci_app_root, 'config'); + $this->assertTrue($this->config->load($file)); + $this->assertEquals($val, $this->config->item($key)); + + // Test section load + $file = 'secttest'; + $cfg = array( + 'one' => 'prime', + 'two' => 2, + 'three' => true + ); + $this->ci_vfs_create($file.'.php', '<?php $config = '.var_export($cfg, TRUE).';', $this->ci_app_root, 'config'); + $this->assertTrue($this->config->load($file, TRUE)); + $this->assertEquals($cfg, $this->config->item($file)); + + // Test section merge + $cfg2 = array( + 'three' => 'tres', + 'number' => 42, + 'letter' => 'Z' + ); + $pkg_dir = 'package'; + $this->ci_vfs_create($file.'.php', '<?php $config = '.var_export($cfg2, TRUE).';', $this->ci_app_root, + array($pkg_dir, 'config')); + array_push($this->config->_config_paths, $this->ci_vfs_path($pkg_dir.'/', APPPATH)); + $this->assertTrue($this->config->load($file, TRUE)); + $this->assertEquals(array_merge($cfg, $cfg2), $this->config->item($file)); + array_pop($this->config->_config_paths); + + // Test graceful fail of invalid file + $file = 'badfile'; + $this->ci_vfs_create($file, '', $this->ci_app_root, 'config'); + $this->assertFalse($this->config->load($file, FALSE, TRUE)); + + // Test regular fail of invalid file + $this->setExpectedException( + 'RuntimeException', + 'CI Error: Your '.$this->ci_vfs_path('config/'.$file.'.php', APPPATH). + ' file does not appear to contain a valid configuration array.' + ); + $this->assertNull($this->config->load($file)); + } + + // -------------------------------------------------------------------- + + public function test_load_nonexistent() + { + // Test graceful fail of nonexistent file + $this->assertFalse($this->config->load('not_config_file', FALSE, TRUE)); + + // Test regular fail + $file = 'absentia'; + $this->setExpectedException( + 'RuntimeException', + 'CI Error: The configuration file '.$file.'.php does not exist.' + ); + $this->assertNull($this->config->load($file)); } }
\ No newline at end of file diff --git a/tests/codeigniter/core/Input_test.php b/tests/codeigniter/core/Input_test.php new file mode 100644 index 000000000..fe8738832 --- /dev/null +++ b/tests/codeigniter/core/Input_test.php @@ -0,0 +1,161 @@ +<?php + +class Input_test extends CI_TestCase { + + public function set_up() + { + // Set server variable to GET as default, since this will leave unset in STDIN env + $_SERVER['REQUEST_METHOD'] = 'GET'; + + // Set config for Input class + $this->ci_set_config('allow_get_array', TRUE); + $this->ci_set_config('global_xss_filtering', FALSE); + $this->ci_set_config('csrf_protection', FALSE); + + $security = new Mock_Core_Security(); + $utf8 = new Mock_Core_Utf8(); + + $this->input = new Mock_Core_Input($security, $utf8); + } + + // -------------------------------------------------------------------- + + public function test_get_not_exists() + { + $this->assertEmpty($this->input->get()); + $this->assertEmpty($this->input->get('foo')); + + $this->assertTrue( ! $this->input->get()); + $this->assertTrue( ! $this->input->get('foo')); + + // Test we're getting empty results + $this->assertTrue($this->input->get() === NULL); + $this->assertTrue($this->input->get('foo') === NULL); + + // Test new 3.0 behaviour for non existant results (used to be FALSE) + $this->assertTrue($this->input->get() === NULL); + $this->assertTrue($this->input->get('foo') === NULL); + } + + // -------------------------------------------------------------------- + + public function test_get_exist() + { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_GET['foo'] = 'bar'; + + $this->assertArrayHasKey('foo', $this->input->get()); + $this->assertEquals('bar', $this->input->get('foo')); + } + + // -------------------------------------------------------------------- + + public function test_get_exist_with_xss_clean() + { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_GET['harm'] = "Hello, i try to <script>alert('Hack');</script> your site"; + + $this->assertArrayHasKey('harm', $this->input->get()); + $this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $this->input->get('harm')); + $this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", $this->input->get('harm', TRUE)); + } + + // -------------------------------------------------------------------- + + public function test_post_not_exists() + { + $this->assertEmpty($this->input->post()); + $this->assertEmpty($this->input->post('foo')); + + $this->assertTrue( ! $this->input->post()); + $this->assertTrue( ! $this->input->post('foo')); + + $this->assertTrue($this->input->post() === NULL); + $this->assertTrue($this->input->post('foo') === NULL); + + $this->assertTrue($this->input->post() === NULL); + $this->assertTrue($this->input->post('foo') === NULL); + } + + // -------------------------------------------------------------------- + + public function test_post_exist() + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['foo'] = 'bar'; + + $this->assertArrayHasKey('foo', $this->input->post()); + $this->assertEquals('bar', $this->input->post('foo')); + } + + // -------------------------------------------------------------------- + + public function test_post_exist_with_xss_clean() + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['harm'] = "Hello, i try to <script>alert('Hack');</script> your site"; + + $this->assertArrayHasKey('harm', $this->input->post()); + $this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $this->input->post('harm')); + $this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", $this->input->post('harm', TRUE)); + } + + // -------------------------------------------------------------------- + + public function test_get_post() + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['foo'] = 'bar'; + + $this->assertEquals('bar', $this->input->get_post('foo')); + } + + // -------------------------------------------------------------------- + + public function test_cookie() + { + $_COOKIE['foo'] = 'bar'; + + $this->assertEquals('bar', $this->input->cookie('foo')); + } + + // -------------------------------------------------------------------- + + public function test_server() + { + $this->assertEquals('GET', $this->input->server('REQUEST_METHOD')); + } + + // -------------------------------------------------------------------- + + public function test_fetch_from_array() + { + $data = array( + 'foo' => 'bar', + 'harm' => 'Hello, i try to <script>alert(\'Hack\');</script> your site', + ); + + $foo = $this->input->fetch_from_array($data, 'foo'); + $harm = $this->input->fetch_from_array($data, 'harm'); + $harmless = $this->input->fetch_from_array($data, 'harm', TRUE); + + $this->assertEquals('bar', $foo); + $this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $harm); + $this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", $harmless); + } + + // -------------------------------------------------------------------- + + public function test_valid_ip() + { + $ip_v4 = '192.18.0.1'; + $this->assertTrue($this->input->valid_ip($ip_v4)); + + $ip_v6 = array('2001:0db8:0000:85a3:0000:0000:ac1f:8001', '2001:db8:0:85a3:0:0:ac1f:8001', '2001:db8:0:85a3::ac1f:8001'); + foreach ($ip_v6 as $ip) + { + $this->assertTrue($this->input->valid_ip($ip)); + } + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/core/Lang_test.php b/tests/codeigniter/core/Lang_test.php index a414f0ace..3364362e0 100644 --- a/tests/codeigniter/core/Lang_test.php +++ b/tests/codeigniter/core/Lang_test.php @@ -1,9 +1,9 @@ <?php class Lang_test extends CI_TestCase { - + protected $lang; - + public function set_up() { $loader_cls = $this->ci_core_class('load'); @@ -12,20 +12,23 @@ class Lang_test extends CI_TestCase { $cls = $this->ci_core_class('lang'); $this->lang = new $cls; } - + // -------------------------------------------------------------------- - + public function test_load() { + $this->ci_vfs_clone('system/language/english/profiler_lang.php'); $this->assertTrue($this->lang->load('profiler', 'english')); + $this->assertEquals('URI STRING', $this->lang->line('profiler_uri_string')); } - + // -------------------------------------------------------------------- - public function test_line() + public function test_load_with_unspecified_language() { - $this->assertTrue($this->lang->load('profiler', 'english')); + $this->ci_vfs_clone('system/language/english/profiler_lang.php'); + $this->assertTrue($this->lang->load('profiler')); $this->assertEquals('URI STRING', $this->lang->line('profiler_uri_string')); } - + }
\ No newline at end of file diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php index 43008651e..ecc5ca933 100644 --- a/tests/codeigniter/core/Loader_test.php +++ b/tests/codeigniter/core/Loader_test.php @@ -1,146 +1,286 @@ <?php class Loader_test extends CI_TestCase { - + private $ci_obj; - + public function set_up() { // Instantiate a new loader - $this->load = new Mock_Core_Loader(); - - // mock up a ci instance - $this->ci_obj = new StdClass; - - // Fix get_instance() - $this->ci_instance($this->ci_obj); + $loader = $this->ci_core_class('loader'); + $this->load = new $loader(); + + // Get CI instance + $this->ci_obj = $this->ci_instance(); + + // Set subclass prefix + $this->prefix = 'MY_'; + $this->ci_set_config('subclass_prefix', $this->prefix); } // -------------------------------------------------------------------- - + public function test_library() { - $this->_setup_config_mock(); - + // Create library in VFS + $lib = 'unit_test_lib'; + $class = 'CI_'.ucfirst($lib); + $this->ci_vfs_create($lib, '<?php class '.$class.' { }', $this->ci_base_root, 'libraries'); + + // Test is_loaded fail + $this->assertFalse($this->load->is_loaded($lib)); + // Test loading as an array. - $this->assertNull($this->load->library(array('table'))); - $this->assertTrue(class_exists('CI_Table'), 'Table class exists'); - $this->assertAttributeInstanceOf('CI_Table', 'table', $this->ci_obj); - + $this->assertNull($this->load->library(array($lib))); + $this->assertTrue(class_exists($class), $class.' does not exist'); + $this->assertAttributeInstanceOf($class, $lib, $this->ci_obj); + // Test no lib given - $this->assertEquals(FALSE, $this->load->library()); - + $this->assertNull($this->load->library()); + // Test a string given to params - $this->assertEquals(NULL, $this->load->library('table', ' ')); + $this->assertNull($this->load->library($lib, ' ')); + + // Create library w/o class + $lib = 'bad_test_lib'; + $this->ci_vfs_create($lib, '', $this->ci_base_root, 'libraries'); + + // Test non-existent class + $this->setExpectedException( + 'RuntimeException', + 'CI Error: Non-existent class: '.$lib + ); + $this->assertNull($this->load->library($lib)); } // -------------------------------------------------------------------- - public function test_load_library_in_application_dir() + public function test_library_extension() { - $this->_setup_config_mock(); - - $content = '<?php class Super_test_library {} '; - - $model = vfsStream::newFile('Super_test_library.php')->withContent($content) - ->at($this->load->libs_dir); - - $this->assertNull($this->load->library('super_test_library')); - - // Was the model class instantiated. - $this->assertTrue(class_exists('Super_test_library')); + // Create library and extension in VFS + $name = 'ext_test_lib'; + $lib = ucfirst($name); + $class = 'CI_'.$lib; + $ext = $this->prefix.$lib; + $this->ci_vfs_create($lib, '<?php class '.$class.' { }', $this->ci_base_root, 'libraries'); + $this->ci_vfs_create($ext, '<?php class '.$ext.' extends '.$class.' { }', $this->ci_app_root, 'libraries'); + + // Test loading with extension + $this->assertNull($this->load->library($lib)); + $this->assertTrue(class_exists($class), $class.' does not exist'); + $this->assertTrue(class_exists($ext), $ext.' does not exist'); + $this->assertAttributeInstanceOf($class, $name, $this->ci_obj); + $this->assertAttributeInstanceOf($ext, $name, $this->ci_obj); + + // Test reloading with object name + $obj = 'exttest'; + $this->assertNull($this->load->library($lib, NULL, $obj)); + $this->assertAttributeInstanceOf($class, $obj, $this->ci_obj); + $this->assertAttributeInstanceOf($ext, $obj, $this->ci_obj); + + // Test reloading + unset($this->ci_obj->$name); + $this->assertNull($this->load->library($lib)); + $this->assertObjectNotHasAttribute($name, $this->ci_obj); + + // Create baseless library + $name = 'ext_baseless_lib'; + $lib = ucfirst($name); + $class = $this->prefix.$lib; + $this->ci_vfs_create($class, '<?php class '.$class.' { }', $this->ci_app_root, 'libraries'); + + // Test missing base class + $this->setExpectedException( + 'RuntimeException', + 'CI Error: Unable to load the requested class: '.$lib + ); + $this->assertNull($this->load->library($lib)); } - + // -------------------------------------------------------------------- - - private function _setup_config_mock() + + public function test_library_config() { - // Mock up a config object until we - // figure out how to test the library configs - $config = $this->getMock('CI_Config', NULL, array(), '', FALSE); - $config->expects($this->any()) - ->method('load') - ->will($this->returnValue(TRUE)); - - // Add the mock to our stdClass - $this->ci_instance_var('config', $config); + // Create library in VFS + $lib = 'unit_test_config_lib'; + $class = 'CI_'.ucfirst($lib); + $content = '<?php class '.$class.' { public function __construct($params) { $this->config = $params; } }'; + $this->ci_vfs_create($lib, $content, $this->ci_base_root, 'libraries'); + + // Create config file + $cfg = array( + 'foo' => 'bar', + 'bar' => 'baz', + 'baz' => false + ); + $this->ci_vfs_create($lib, '<?php $config = '.var_export($cfg, TRUE).';', $this->ci_app_root, 'config'); + + // Test object name and config + $obj = 'testy'; + $this->assertNull($this->load->library($lib, NULL, $obj)); + $this->assertTrue(class_exists($class), $class.' does not exist'); + $this->assertAttributeInstanceOf($class, $obj, $this->ci_obj); + $this->assertEquals($cfg, $this->ci_obj->$obj->config); + + // Test is_loaded + $this->assertEquals($obj, $this->load->is_loaded($lib)); } // -------------------------------------------------------------------- - public function test_non_existent_model() + public function test_load_library_in_application_dir() { - $this->setExpectedException( - 'RuntimeException', - 'CI Error: Unable to locate the model you have specified: ci_test_nonexistent_model.php' - ); - - $this->load->model('ci_test_nonexistent_model.php'); + // Create library in VFS + $lib = 'super_test_library'; + $class = ucfirst($lib); + $this->ci_vfs_create($lib, '<?php class '.$class.' { }', $this->ci_app_root, 'libraries'); + + // Load library + $this->assertNull($this->load->library($lib)); + + // Was the model class instantiated. + $this->assertTrue(class_exists($class), $class.' does not exist'); + $this->assertAttributeInstanceOf($class, $lib, $this->ci_obj); + } + + // -------------------------------------------------------------------- + + public function test_driver() + { + // Create driver in VFS + $driver = 'unit_test_driver'; + $dir = ucfirst($driver); + $class = 'CI_'.$dir; + $content = '<?php class '.$class.' { } '; + $this->ci_vfs_create($driver, $content, $this->ci_base_root, 'libraries/'.$dir); + + // Test loading as an array. + $this->assertNull($this->load->driver(array($driver))); + $this->assertTrue(class_exists($class), $class.' does not exist'); + $this->assertAttributeInstanceOf($class, $driver, $this->ci_obj); + + // Test loading as a library with a name + $obj = 'testdrive'; + $this->assertNull($this->load->library($driver, NULL, $obj)); + $this->assertAttributeInstanceOf($class, $obj, $this->ci_obj); + + // Test no driver given + $this->assertFalse($this->load->driver()); + + // Test a string given to params + $this->assertNull($this->load->driver($driver, ' ')); } // -------------------------------------------------------------------- - - /** - * @coverts CI_Loader::model - */ + public function test_models() { $this->ci_set_core_class('model', 'CI_Model'); - - $content = '<?php class Unit_test_model extends CI_Model {} '; - - $model = vfsStream::newFile('unit_test_model.php')->withContent($content) - ->at($this->load->models_dir); - - $this->assertNull($this->load->model('unit_test_model')); - + + // Create model in VFS + $model = 'unit_test_model'; + $class = ucfirst($model); + $content = '<?php class '.$class.' extends CI_Model {} '; + $this->ci_vfs_create($model, $content, $this->ci_app_root, 'models'); + + // Load model + $this->assertNull($this->load->model($model)); + // Was the model class instantiated. - $this->assertTrue(class_exists('Unit_test_model')); - + $this->assertTrue(class_exists($class)); + // Test no model given - $this->assertNull($this->load->model('')); + $this->assertNull($this->load->model('')); + } + + // -------------------------------------------------------------------- + + public function test_model_subdir() + { + // Make sure base class is loaded - we'll test _ci_include later + $this->ci_core_class('model'); + + // Create modelin VFS + $model = 'test_sub_model'; + $base = 'CI_Model'; + $class = ucfirst($model); + $subdir = 'cars'; + $this->ci_vfs_create($model, '<?php class '.$class.' extends '.$base.' { }', $this->ci_app_root, + array('models', $subdir)); + + // Load model + $name = 'testors'; + $this->assertNull($this->load->model($subdir.'/'.$model, $name)); + + // Was the model class instantiated? + $this->assertTrue(class_exists($class)); + $this->assertObjectHasAttribute($name, $this->ci_obj); + $this->assertAttributeInstanceOf($base, $name, $this->ci_obj); + $this->assertAttributeInstanceOf($class, $name, $this->ci_obj); + + // Test name conflict + $obj = 'conflict'; + $this->ci_obj->$obj = new StdClass(); + $this->setExpectedException( + 'RuntimeException', + 'CI Error: The model name you are loading is the name of a resource that is already being used: '.$obj + ); + $this->load->model('not_real', $obj); + } + + // -------------------------------------------------------------------- + + public function test_non_existent_model() + { + $this->setExpectedException( + 'RuntimeException', + 'CI Error: Unable to locate the model you have specified: ci_test_nonexistent_model.php' + ); + + $this->load->model('ci_test_nonexistent_model.php'); } // -------------------------------------------------------------------- - + // public function testDatabase() // { - // $this->assertEquals(NULL, $this->load->database()); - // $this->assertEquals(NULL, $this->load->dbutil()); + // $this->assertNull($this->load->database()); + // $this->assertNull($this->load->dbutil()); // } // -------------------------------------------------------------------- - - /** - * @coverts CI_Loader::view - */ + public function test_load_view() { - $this->ci_set_core_class('output', 'CI_Output'); - - $content = 'This is my test page. <?php echo $hello; ?>'; - $view = vfsStream::newFile('unit_test_view.php')->withContent($content) - ->at($this->load->views_dir); - - // Use the optional return parameter in this test, so the view is not - // run through the output class. - $this->assertEquals('This is my test page. World!', - $this->load->view('unit_test_view', array('hello' => "World!"), TRUE)); - + // Create view in VFS + $view = 'unit_test_view'; + $var = 'hello'; + $value = 'World!'; + $content = 'This is my test page. '; + $this->ci_vfs_create($view, $content.'<?php echo $'.$var.';', $this->ci_app_root, 'views'); + + // Test returning view + $out = $this->load->view($view, array($var => $value), TRUE); + $this->assertEquals($content.$value, $out); + + // Mock output class + $output = $this->getMock('CI_Output', array('append_output')); + $output->expects($this->once())->method('append_output')->with($content.$value); + $this->ci_instance_var('output', $output); + + // Test view output + $this->assertNull($this->load->view($view, array($var => $value))); } // -------------------------------------------------------------------- - - /** - * @coverts CI_Loader::view - */ + public function test_non_existent_view() { $this->setExpectedException( 'RuntimeException', 'CI Error: Unable to load the requested file: ci_test_nonexistent_view.php' - ); - + ); + $this->load->view('ci_test_nonexistent_view', array('foo' => 'bar')); } @@ -148,88 +288,233 @@ class Loader_test extends CI_TestCase { public function test_file() { + // Create view in VFS + $dir = 'views'; + $file = 'ci_test_mock_file'; $content = 'Here is a test file, which we will load now.'; - $file = vfsStream::newFile('ci_test_mock_file.php')->withContent($content) - ->at($this->load->views_dir); - + $this->ci_vfs_create($file, $content, $this->ci_app_root, $dir); + // Just like load->view(), take the output class out of the mix here. - $load = $this->load->file(vfsStream::url('application').'/views/ci_test_mock_file.php', - TRUE); - - $this->assertEquals($content, $load); - + $out = $this->load->file(APPPATH.$dir.'/'.$file.'.php', TRUE); + $this->assertEquals($content, $out); + + // Test non-existent file $this->setExpectedException( 'RuntimeException', 'CI Error: Unable to load the requested file: ci_test_file_not_exists' - ); - + ); + $this->load->file('ci_test_file_not_exists', TRUE); - } // -------------------------------------------------------------------- - + public function test_vars() { - $vars = array( - 'foo' => 'bar' - ); - - $this->assertNull($this->load->vars($vars)); - $this->assertNull($this->load->vars('foo', 'bar')); + $key1 = 'foo'; + $val1 = 'bar'; + $key2 = 'boo'; + $val2 = 'hoo'; + $this->assertNull($this->load->vars(array($key1 => $val1))); + $this->assertNull($this->load->vars($key2, $val2)); + $this->assertEquals($val1, $this->load->get_var($key1)); + $this->assertEquals(array($key1 => $val1, $key2 => $val2), $this->load->get_vars()); } // -------------------------------------------------------------------- - + public function test_helper() { - $this->assertEquals(NULL, $this->load->helper('array')); - + // Create helper in VFS + $helper = 'test'; + $func = '_my_helper_test_func'; + $content = '<?php function '.$func.'() { return true; } '; + $this->ci_vfs_create($helper.'_helper', $content, $this->ci_base_root, 'helpers'); + + // Create helper extension + $exfunc = '_my_extension_func'; + $content = '<?php function '.$exfunc.'() { return true; } '; + $this->ci_vfs_create($this->prefix.$helper.'_helper', $content, $this->ci_app_root, 'helpers'); + + // Load helper + $this->assertNull($this->load->helper($helper)); + $this->assertTrue(function_exists($func), $func.' does not exist'); + $this->assertTrue(function_exists($exfunc), $exfunc.' does not exist'); + + // Create baseless extension + $ext = 'bad_ext'; + $this->ci_vfs_create($this->prefix.$ext.'_helper', '', $this->ci_app_root, 'helpers'); + + // Test bad extension + $this->setExpectedException( + 'RuntimeException', + 'CI Error: Unable to load the requested file: helpers/'.$ext.'_helper.php' + ); + $this->load->helper($ext); + } + + // -------------------------------------------------------------------- + + public function test_non_existent_helper() + { $this->setExpectedException( 'RuntimeException', 'CI Error: Unable to load the requested file: helpers/bad_helper.php' - ); - + ); $this->load->helper('bad'); } - + // -------------------------------------------------------------------- public function test_loading_multiple_helpers() { - $this->assertEquals(NULL, $this->load->helpers(array('file', 'array', 'string'))); + // Create helpers in VFS + $helpers = array(); + $funcs = array(); + $files = array(); + for ($i = 1; $i <= 3; ++$i) { + $helper = 'test'.$i; + $helpers[] = $helper; + $func = '_my_helper_test_func'.$i; + $funcs[] = $func; + $files[$helper.'_helper'] = '<?php function '.$func.'() { return true; } '; + } + $this->ci_vfs_create($files, NULL, $this->ci_base_root, 'helpers'); + + // Load helpers + $this->assertNull($this->load->helpers($helpers)); + + // Verify helper existence + foreach ($funcs as $func) { + $this->assertTrue(function_exists($func), $func.' does not exist'); + } } - - // -------------------------------------------------------------------- - - // public function testLanguage() - // { - // $this->assertEquals(NULL, $this->load->language('test')); - // } // -------------------------------------------------------------------- - public function test_load_config() + public function test_language() { - $this->_setup_config_mock(); - - $this->assertNull($this->load->config('config', FALSE)); + // Mock lang class and test load call + $file = 'test'; + $lang = $this->getMock('CI_Lang', array('load')); + $lang->expects($this->once())->method('load')->with($file); + $this->ci_instance_var('lang', $lang); + $this->assertNull($this->load->language($file)); } - + // -------------------------------------------------------------------- - public function test_load_bad_config() + public function test_packages() { - $this->_setup_config_mock(); - + // Create model in VFS package path + $dir = 'third-party'; + $lib = 'unit_test_package'; + $class = 'CI_'.ucfirst($lib); + $this->ci_vfs_create($lib, '<?php class '.$class.' { }', $this->ci_app_root, array($dir, 'libraries')); + + // Get paths + $paths = $this->load->get_package_paths(TRUE); + + // Add path and verify + $path = APPPATH.$dir.'/'; + $this->assertNull($this->load->add_package_path($path)); + $this->assertContains($path, $this->load->get_package_paths(TRUE)); + + // Test successful load + $this->assertNull($this->load->library($lib)); + $this->assertTrue(class_exists($class), $class.' does not exist'); + + // Add another path + $path2 = APPPATH.'another/'; + $this->assertNull($this->load->add_package_path($path2)); + $this->assertContains($path2, $this->load->get_package_paths(TRUE)); + + // Remove last path + $this->assertNull($this->load->remove_package_path()); + $this->assertNotContains($path2, $this->load->get_package_paths(TRUE)); + + // Remove path and verify restored paths + $this->assertNull($this->load->remove_package_path($path)); + $this->assertEquals($paths, $this->load->get_package_paths(TRUE)); + + // Test failed load without path $this->setExpectedException( 'RuntimeException', - 'CI Error: The configuration file foobar.php does not exist.' - ); - - $this->load->config('foobar', FALSE); + 'CI Error: Unable to load the requested class: '.$lib + ); + $this->load->library($lib); + } + + // -------------------------------------------------------------------- + + public function test_load_config() + { + $cfg = 'someconfig'; + $this->assertTrue($this->load->config($cfg, FALSE)); + $this->assertContains($cfg, $this->ci_obj->config->loaded); } // -------------------------------------------------------------------- - -} + + public function test_initialize() + { + // Create helper in VFS + $helper = 'autohelp'; + $hlp_func = '_autohelp_test_func'; + $content = '<?php function '.$hlp_func.'() { return true; }'; + $this->ci_vfs_create($helper.'_helper', $content, $this->ci_app_root, 'helpers'); + + // Create library in VFS + $lib = 'autolib'; + $lib_class = 'CI_'.ucfirst($lib); + $this->ci_vfs_create($lib, '<?php class '.$lib_class.' { }', $this->ci_base_root, 'libraries'); + + // Create driver in VFS + $drv = 'autodrv'; + $subdir = ucfirst($drv); + $drv_class = 'CI_'.$subdir; + $this->ci_vfs_create($drv, '<?php class '.$drv_class.' { }', $this->ci_base_root, array('libraries', $subdir)); + + // Create model in VFS package path + $dir = 'testdir'; + $path = APPPATH.$dir.'/'; + $model = 'automod'; + $mod_class = ucfirst($model); + $this->ci_vfs_create($model, '<?php class '.$mod_class.' { }', $this->ci_app_root, array($dir, 'models')); + + // Create autoloader config + $cfg = array( + 'packages' => array($path), + 'helper' => array($helper), + 'libraries' => array($lib), + 'drivers' => array($drv), + 'model' => array($model), + 'config' => array('config1', 'config2') + ); + $this->ci_vfs_create('autoload', '<?php $autoload = '.var_export($cfg, TRUE).';', $this->ci_app_root, 'config'); + + $this->load->initialize(); + + // Verify path + $this->assertContains($path, $this->load->get_package_paths()); + + // Verify helper + $this->assertTrue(function_exists($hlp_func), $hlp_func.' does not exist'); + + // Verify library + $this->assertTrue(class_exists($lib_class), $lib_class.' does not exist'); + $this->assertAttributeInstanceOf($lib_class, $lib, $this->ci_obj); + + // Verify driver + $this->assertTrue(class_exists($drv_class), $drv_class.' does not exist'); + $this->assertAttributeInstanceOf($drv_class, $drv, $this->ci_obj); + + // Verify model + $this->assertTrue(class_exists($mod_class), $mod_class.' does not exist'); + $this->assertAttributeInstanceOf($mod_class, $model, $this->ci_obj); + + // Verify config calls + $this->assertEquals($cfg['config'], $this->ci_obj->config->loaded); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/core/Security_test.php b/tests/codeigniter/core/Security_test.php new file mode 100644 index 000000000..3f6e3b07a --- /dev/null +++ b/tests/codeigniter/core/Security_test.php @@ -0,0 +1,106 @@ +<?php + +class Security_test extends CI_TestCase { + + public function set_up() + { + // Set cookie for security test + $_COOKIE['ci_csrf_cookie'] = md5(uniqid(rand(), TRUE)); + + // Set config for Security class + $this->ci_set_config('csrf_protection', TRUE); + $this->ci_set_config('csrf_token_name', 'ci_csrf_token'); + $this->ci_set_config('csrf_cookie_name', 'ci_csrf_cookie'); + + $this->security = new Mock_Core_Security(); + } + + // -------------------------------------------------------------------- + + public function test_csrf_verify() + { + $_SERVER['REQUEST_METHOD'] = 'GET'; + + $this->assertInstanceOf('CI_Security', $this->security->csrf_verify()); + } + + // -------------------------------------------------------------------- + + public function test_csrf_verify_invalid() + { + // Without issuing $_POST[csrf_token_name], this request will triggering CSRF error + $_SERVER['REQUEST_METHOD'] = 'POST'; + + $this->setExpectedException('RuntimeException', 'CI Error: The action you have requested is not allowed'); + + $this->security->csrf_verify(); + } + + // -------------------------------------------------------------------- + + public function test_csrf_verify_valid() + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST[$this->security->csrf_token_name] = $this->security->csrf_hash; + + $this->assertInstanceOf('CI_Security', $this->security->csrf_verify()); + } + + // -------------------------------------------------------------------- + + public function test_get_csrf_hash() + { + $this->assertEquals($this->security->csrf_hash, $this->security->get_csrf_hash()); + } + + // -------------------------------------------------------------------- + + public function test_get_csrf_token_name() + { + $this->assertEquals('ci_csrf_token', $this->security->get_csrf_token_name()); + } + + // -------------------------------------------------------------------- + + public function test_xss_clean() + { + $harm_string = "Hello, i try to <script>alert('Hack');</script> your site"; + + $harmless_string = $this->security->xss_clean($harm_string); + + $this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", $harmless_string); + } + + // -------------------------------------------------------------------- + + public function test_xss_hash() + { + $this->assertEmpty($this->security->xss_hash); + + // Perform hash + $this->security->xss_hash(); + + $this->assertTrue(preg_match('#^[0-9a-f]{32}$#iS', $this->security->xss_hash) === 1); + } + + // -------------------------------------------------------------------- + + public function test_entity_decode() + { + $encoded = '<div>Hello <b>Booya</b></div>'; + $decoded = $this->security->entity_decode($encoded); + + $this->assertEquals('<div>Hello <b>Booya</b></div>', $decoded); + } + + // -------------------------------------------------------------------- + + public function test_sanitize_filename() + { + $filename = './<!--foo-->'; + $safe_filename = $this->security->sanitize_filename($filename); + + $this->assertEquals('foo', $safe_filename); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/core/URI_test.php b/tests/codeigniter/core/URI_test.php index e340ddf73..e2deabe51 100644 --- a/tests/codeigniter/core/URI_test.php +++ b/tests/codeigniter/core/URI_test.php @@ -1,7 +1,7 @@ <?php class URI_test extends CI_TestCase { - + public function set_up() { $this->uri = new Mock_Core_URI(); @@ -9,23 +9,21 @@ class URI_test extends CI_TestCase { // -------------------------------------------------------------------- + /* As of the following commit, _set_uri_string() is a protected method: + + https://github.com/EllisLab/CodeIgniter/commit/d461934184d95b0cfb2feec93f27b621ef72a5c2 + public function test_set_uri_string() { // Slashes get killed $this->uri->_set_uri_string('/'); - - $a = ''; - $b =& $this->uri->uri_string; - - $this->assertEquals($a, $b); - + $this->assertEquals('', $this->uri->uri_string); + $this->uri->_set_uri_string('nice/uri'); - - $a = 'nice/uri'; - - $this->assertEquals($a, $b); + $this->assertEquals('nice/uri', $this->uri->uri_string); } - + */ + // -------------------------------------------------------------------- public function test_fetch_uri_string() @@ -34,75 +32,61 @@ class URI_test extends CI_TestCase { // uri_protocol: AUTO $this->uri->config->set_item('uri_protocol', 'AUTO'); - + // Test a variety of request uris $requests = array( '/index.php/controller/method' => 'controller/method', '/index.php?/controller/method' => 'controller/method', '/index.php?/controller/method/?var=foo' => 'controller/method' ); - - foreach($requests as $request => $expected) + + foreach ($requests as $request => $expected) { $_SERVER['SCRIPT_NAME'] = '/index.php'; $_SERVER['REQUEST_URI'] = $request; - + $this->uri->_fetch_uri_string(); - $this->assertEquals($expected, $this->uri->uri_string ); + $this->assertEquals($expected, $this->uri->uri_string); } - + // Test a subfolder $_SERVER['SCRIPT_NAME'] = '/subfolder/index.php'; $_SERVER['REQUEST_URI'] = '/subfolder/index.php/controller/method'; - + $this->uri->_fetch_uri_string(); - - $a = 'controller/method'; - $b = $this->uri->uri_string; - - $this->assertEquals($a, $b); - + $this->assertEquals('controller/method', $this->uri->uri_string); + // death to request uri unset($_SERVER['REQUEST_URI']); - + // life to path info $_SERVER['PATH_INFO'] = '/controller/method/'; - + $this->uri->_fetch_uri_string(); - - $a = '/controller/method/'; - $b =& $this->uri->uri_string; + $this->assertEquals('controller/method', $this->uri->uri_string); - $this->assertEquals($a, $b); - // death to path info // At this point your server must be seriously drunk unset($_SERVER['PATH_INFO']); - + $_SERVER['QUERY_STRING'] = '/controller/method/'; - + $this->uri->_fetch_uri_string(); + $this->assertEquals('controller/method', $this->uri->uri_string); - $a = '/controller/method/'; - $b = $this->uri->uri_string; - - $this->assertEquals($a, $b); - // At this point your server is a labotomy victim - unset($_SERVER['QUERY_STRING']); - + $_GET['/controller/method/'] = ''; - + $this->uri->_fetch_uri_string(); - $this->assertEquals($a, $b); + $this->assertEquals('controller/method', $this->uri->uri_string); // Test coverage implies that these will work // uri_protocol: REQUEST_URI // uri_protocol: CLI - } - + // -------------------------------------------------------------------- public function test_explode_segments() @@ -113,18 +97,15 @@ class URI_test extends CI_TestCase { '/test2/uri2' => array('test2', 'uri2'), '//test3/test3///' => array('test3', 'test3') ); - - foreach($uris as $uri => $a) + + foreach ($uris as $uri => $a) { $this->uri->segments = array(); $this->uri->uri_string = $uri; $this->uri->_explode_segments(); - - $b = $this->uri->segments; - - $this->assertEquals($a, $b); + + $this->assertEquals($a, $this->uri->segments); } - } // -------------------------------------------------------------------- @@ -133,7 +114,7 @@ class URI_test extends CI_TestCase { { $this->uri->config->set_item('enable_query_strings', FALSE); $this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-'); - + $str_in = 'abc01239~%.:_-'; $str = $this->uri->_filter_uri($str_in); @@ -145,52 +126,52 @@ class URI_test extends CI_TestCase { public function test_filter_uri_escaping() { // ensure escaping even if dodgey characters are permitted - + $this->uri->config->set_item('enable_query_strings', FALSE); $this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-()$'); $str = $this->uri->_filter_uri('$destroy_app(foo)'); - + $this->assertEquals($str, '$destroy_app(foo)'); } // -------------------------------------------------------------------- - public function test_filter_uri_throws_error() - { + public function test_filter_uri_throws_error() + { $this->setExpectedException('RuntimeException'); - + $this->uri->config->set_item('enable_query_strings', FALSE); $this->uri->config->set_item('permitted_uri_chars', 'a-z 0-9~%.:_\-'); $this->uri->_filter_uri('$this()'); - } + } // -------------------------------------------------------------------- public function test_remove_url_suffix() { $this->uri->config->set_item('url_suffix', '.html'); - + $this->uri->uri_string = 'controller/method/index.html'; $this->uri->_remove_url_suffix(); - + $this->assertEquals($this->uri->uri_string, 'controller/method/index'); - + $this->uri->uri_string = 'controller/method/index.htmlify.html'; $this->uri->_remove_url_suffix(); - + $this->assertEquals($this->uri->uri_string, 'controller/method/index.htmlify'); } // -------------------------------------------------------------------- - + public function test_segment() { $this->uri->segments = array(1 => 'controller'); $this->assertEquals($this->uri->segment(1), 'controller'); $this->assertEquals($this->uri->segment(2, 'default'), 'default'); } - + // -------------------------------------------------------------------- public function test_rsegment() @@ -205,32 +186,33 @@ class URI_test extends CI_TestCase { public function test_uri_to_assoc() { $this->uri->segments = array('a', '1', 'b', '2', 'c', '3'); - - $a = array('a' => '1', 'b' => '2', 'c' => '3'); - $b = $this->uri->uri_to_assoc(1); - $this->assertEquals($a, $b); - - $a = array('b' => '2', 'c' => '3'); - $b = $this->uri->uri_to_assoc(3); - $this->assertEquals($a, $b); - - + + $this->assertEquals( + array('a' => '1', 'b' => '2', 'c' => '3'), + $this->uri->uri_to_assoc(1) + ); + + $this->assertEquals( + array('b' => '2', 'c' => '3'), + $this->uri->uri_to_assoc(3) + ); + $this->uri->keyval = array(); // reset cache - $this->uri->segments = array('a', '1', 'b', '2', 'c'); - - $a = array('a' => '1', 'b' => '2', 'c' => FALSE); - $b = $this->uri->uri_to_assoc(1); - $this->assertEquals($a, $b); - + + $this->assertEquals( + array('a' => '1', 'b' => '2', 'c' => FALSE), + $this->uri->uri_to_assoc(1) + ); + $this->uri->keyval = array(); // reset cache - $this->uri->segments = array('a', '1'); - + // test default - $a = array('a' => '1', 'b' => FALSE); - $b = $this->uri->uri_to_assoc(1, array('a', 'b')); - $this->assertEquals($a, $b); + $this->assertEquals( + array('a' => '1', 'b' => FALSE), + $this->uri->uri_to_assoc(1, array('a', 'b')) + ); } // -------------------------------------------------------------------- @@ -238,33 +220,33 @@ class URI_test extends CI_TestCase { public function test_ruri_to_assoc() { $this->uri->rsegments = array('x', '1', 'y', '2', 'z', '3'); - - $a = array('x' => '1', 'y' => '2', 'z' => '3'); - $b = $this->uri->ruri_to_assoc(1); - $this->assertEquals($a, $b); - - $a = array('y' => '2', 'z' => '3'); - $b = $this->uri->ruri_to_assoc(3); - $this->assertEquals($a, $b); - - + + $this->assertEquals( + array('x' => '1', 'y' => '2', 'z' => '3'), + $this->uri->ruri_to_assoc(1) + ); + + $this->assertEquals( + array('y' => '2', 'z' => '3'), + $this->uri->ruri_to_assoc(3) + ); + $this->uri->keyval = array(); // reset cache - $this->uri->rsegments = array('x', '1', 'y', '2', 'z'); - - $a = array('x' => '1', 'y' => '2', 'z' => FALSE); - $b = $this->uri->ruri_to_assoc(1); - $this->assertEquals($a, $b); - + + $this->assertEquals( + array('x' => '1', 'y' => '2', 'z' => FALSE), + $this->uri->ruri_to_assoc(1) + ); + $this->uri->keyval = array(); // reset cache - $this->uri->rsegments = array('x', '1'); - - // test default - $a = array('x' => '1', 'y' => FALSE); - $b = $this->uri->ruri_to_assoc(1, array('x', 'y')); - $this->assertEquals($a, $b); + // test default + $this->assertEquals( + array('x' => '1', 'y' => FALSE), + $this->uri->ruri_to_assoc(1, array('x', 'y')) + ); } // -------------------------------------------------------------------- @@ -272,11 +254,7 @@ class URI_test extends CI_TestCase { public function test_assoc_to_uri() { $this->uri->config->set_item('uri_string_slashes', 'none'); - - $arr = array('a' => 1, 'b' => 2); - $a = 'a/1/b/2'; - $b = $this->uri->assoc_to_uri($arr); - $this->assertEquals($a, $b); + $this->assertEquals('a/1/b/2', $this->uri->assoc_to_uri(array('a' => '1', 'b' => '2'))); } // -------------------------------------------------------------------- @@ -286,28 +264,18 @@ class URI_test extends CI_TestCase { $this->uri->segments[1] = 'segment'; $this->uri->rsegments[1] = 'segment'; - $a = '/segment/'; - $b = $this->uri->slash_segment(1, 'both'); - $this->assertEquals($a, $b); - $b = $this->uri->slash_rsegment(1, 'both'); - $this->assertEquals($a, $b); - + $this->assertEquals('/segment/', $this->uri->slash_segment(1, 'both')); + $this->assertEquals('/segment/', $this->uri->slash_rsegment(1, 'both')); + $a = '/segment'; - $b = $this->uri->slash_segment(1, 'leading'); - $this->assertEquals($a, $b); - $b = $this->uri->slash_rsegment(1, 'leading'); - $this->assertEquals($a, $b); - - $a = 'segment/'; - $b = $this->uri->slash_segment(1, 'trailing'); - $this->assertEquals($a, $b); - $b = $this->uri->slash_rsegment(1, 'trailing'); - $this->assertEquals($a, $b); - } + $this->assertEquals('/segment', $this->uri->slash_segment(1, 'leading')); + $this->assertEquals('/segment', $this->uri->slash_rsegment(1, 'leading')); + $this->assertEquals('segment/', $this->uri->slash_segment(1, 'trailing')); + $this->assertEquals('segment/', $this->uri->slash_rsegment(1, 'trailing')); + } } -// END URI_test Class /* End of file URI_test.php */ -/* Location: ./tests/core/URI_test.php */ +/* Location: ./tests/core/URI_test.php */
\ No newline at end of file diff --git a/tests/codeigniter/database/DB_driver_test.php b/tests/codeigniter/database/DB_driver_test.php new file mode 100644 index 000000000..1f48ca984 --- /dev/null +++ b/tests/codeigniter/database/DB_driver_test.php @@ -0,0 +1,34 @@ +<?php + +class DB_driver_test extends CI_TestCase { + + public function test_initialize() + { + $config = Mock_Database_DB::config(DB_DRIVER); + sscanf(DB_DRIVER, '%[^/]/', $driver_name); + $driver = $this->$driver_name($config[DB_DRIVER]); + + $this->assertTrue($driver->initialize()); + } + + protected function pdo($config) + { + return new Mock_Database_Drivers_PDO($config); + } + + protected function mysql($config) + { + return new Mock_Database_Drivers_Mysql($config); + } + + protected function sqlite($config) + { + return new Mock_Database_Drivers_Sqlite($config); + } + + protected function pgsql($config) + { + return new Mock_Database_Drivers_Postgre($config); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/DB_test.php b/tests/codeigniter/database/DB_test.php index 9b93e223d..d5c0dea08 100644 --- a/tests/codeigniter/database/DB_test.php +++ b/tests/codeigniter/database/DB_test.php @@ -2,8 +2,6 @@ class DB_test extends CI_TestCase { - // ------------------------------------------------------------------------ - public function test_db_invalid() { $connection = new Mock_Database_DB(array( @@ -45,5 +43,5 @@ class DB_test extends CI_TestCase { $this->assertTrue($db instanceof CI_DB); $this->assertTrue($db instanceof CI_DB_Driver); } - + }
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/.gitkeep b/tests/codeigniter/database/query_builder/.gitkeep deleted file mode 100644 index e69de29bb..000000000 --- a/tests/codeigniter/database/query_builder/.gitkeep +++ /dev/null diff --git a/tests/codeigniter/database/query_builder/count_test.php b/tests/codeigniter/database/query_builder/count_test.php new file mode 100644 index 000000000..90ac5283e --- /dev/null +++ b/tests/codeigniter/database/query_builder/count_test.php @@ -0,0 +1,38 @@ +<?php + +class Count_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_count_all() + { + $this->assertEquals(4, $this->db->count_all('job')); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_count_all_results() + { + $this->assertEquals(2, $this->db->like('name', 'ian')->count_all_results('job')); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/delete_test.php b/tests/codeigniter/database/query_builder/delete_test.php new file mode 100644 index 000000000..ab9d97f56 --- /dev/null +++ b/tests/codeigniter/database/query_builder/delete_test.php @@ -0,0 +1,64 @@ +<?php + +class Delete_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_delete() + { + // Check initial record + $job1 = $this->db->where('id', 1)->get('job')->row(); + + $this->assertEquals('Developer', $job1->name); + + // Do the delete + $this->db->delete('job', array('id' => 1)); + + // Check the record + $job1 = $this->db->where('id', 1)->get('job'); + + $this->assertEmpty($job1->result_array()); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_delete_several_tables() + { + // Check initial record + $user4 = $this->db->where('id', 4)->get('user')->row(); + $job4 = $this->db->where('id', 4)->get('job')->row(); + + $this->assertEquals('Musician', $job4->name); + $this->assertEquals('Chris Martin', $user4->name); + + // Do the delete + $this->db->delete(array('job', 'user'), array('id' => 4)); + + // Check the record + $job4 = $this->db->where('id', 4)->get('job'); + $user4 = $this->db->where('id', 4)->get('user'); + + $this->assertEmpty($job4->result_array()); + $this->assertEmpty($user4->result_array()); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/distinct_test.php b/tests/codeigniter/database/query_builder/distinct_test.php new file mode 100644 index 000000000..cc98009ce --- /dev/null +++ b/tests/codeigniter/database/query_builder/distinct_test.php @@ -0,0 +1,33 @@ +<?php + +class Distinct_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_distinct() + { + $users = $this->db->select('country') + ->distinct() + ->get('user') + ->result_array(); + + $this->assertEquals(3, count($users)); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/empty_test.php b/tests/codeigniter/database/query_builder/empty_test.php new file mode 100644 index 000000000..d1f56285f --- /dev/null +++ b/tests/codeigniter/database/query_builder/empty_test.php @@ -0,0 +1,39 @@ +<?php + +class Empty_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_empty_table() + { + // Check initial record + $jobs = $this->db->get('job')->result_array(); + + $this->assertEquals(4, count($jobs)); + + // Do the empty + $this->db->empty_table('job'); + + // Check the record + $jobs = $this->db->get('job'); + + $this->assertEmpty($jobs->result_array()); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/escape_test.php b/tests/codeigniter/database/query_builder/escape_test.php new file mode 100644 index 000000000..27e678f22 --- /dev/null +++ b/tests/codeigniter/database/query_builder/escape_test.php @@ -0,0 +1,68 @@ +<?php + +class Escape_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_escape_like_percent_sign() + { + // Escape the like string + $string = $this->db->escape_like_str('\%foo'); + + if (strpos(DB_DRIVER, 'mysql') !== FALSE) + { + $sql = "SELECT `value` FROM `misc` WHERE `key` LIKE '$string%' ESCAPE '!';"; + } + else + { + $sql = 'SELECT "value" FROM "misc" WHERE "key" LIKE \''.$string.'%\' ESCAPE \'!\';'; + } + + $res = $this->db->query($sql)->result_array(); + + // Check the result + $this->assertEquals(1, count($res)); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_escape_like_backslash_sign() + { + // Escape the like string + $string = $this->db->escape_like_str('\\'); + + if (strpos(DB_DRIVER, 'mysql') !== FALSE) + { + $sql = "SELECT `value` FROM `misc` WHERE `key` LIKE '$string%' ESCAPE '!';"; + } + else + { + $sql = 'SELECT "value" FROM "misc" WHERE "key" LIKE \''.$string.'%\' ESCAPE \'!\';'; + } + + $res = $this->db->query($sql)->result_array(); + + // Check the result + $this->assertEquals(2, count($res)); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/from_test.php b/tests/codeigniter/database/query_builder/from_test.php new file mode 100644 index 000000000..7aaae348d --- /dev/null +++ b/tests/codeigniter/database/query_builder/from_test.php @@ -0,0 +1,49 @@ +<?php + +class From_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_from_simple() + { + $jobs = $this->db->from('job') + ->get() + ->result_array(); + + $this->assertEquals(4, count($jobs)); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_from_with_where() + { + $job1 = $this->db->from('job') + ->where('id', 1) + ->get() + ->row(); + + $this->assertEquals('1', $job1->id); + $this->assertEquals('Developer', $job1->name); + $this->assertEquals('Awesome job, but sometimes makes you bored', $job1->description); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/get_test.php b/tests/codeigniter/database/query_builder/get_test.php new file mode 100644 index 000000000..156027537 --- /dev/null +++ b/tests/codeigniter/database/query_builder/get_test.php @@ -0,0 +1,53 @@ +<?php + +class Get_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_get_simple() + { + $jobs = $this->db->get('job')->result_array(); + + // Dummy jobs contain 4 rows + $this->assertCount(4, $jobs); + + // Check rows item + $this->assertEquals('Developer', $jobs[0]['name']); + $this->assertEquals('Politician', $jobs[1]['name']); + $this->assertEquals('Accountant', $jobs[2]['name']); + $this->assertEquals('Musician', $jobs[3]['name']); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_get_where() + { + $job1 = $this->db->get_where('job', array('id' => 1))->result_array(); + + // Dummy jobs contain 1 rows + $this->assertCount(1, $job1); + + // Check rows item + $this->assertEquals('Developer', $job1[0]['name']); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/group_test.php b/tests/codeigniter/database/query_builder/group_test.php new file mode 100644 index 000000000..5249f7c87 --- /dev/null +++ b/tests/codeigniter/database/query_builder/group_test.php @@ -0,0 +1,51 @@ +<?php + +class Group_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_group_by() + { + $jobs = $this->db->select('name') + ->from('job') + ->group_by('name') + ->get() + ->result_array(); + + $this->assertEquals(4, count($jobs)); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_having_by() + { + $jobs = $this->db->select('name') + ->from('job') + ->group_by('name') + ->having('SUM(id) > 2') + ->get() + ->result_array(); + + $this->assertEquals(2, count($jobs)); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/insert_test.php b/tests/codeigniter/database/query_builder/insert_test.php new file mode 100644 index 000000000..30c055680 --- /dev/null +++ b/tests/codeigniter/database/query_builder/insert_test.php @@ -0,0 +1,66 @@ +<?php + +class Insert_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + * @see ./mocks/schema/skeleton.php + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + + // Truncate the current datas + $this->db->truncate('job'); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_insert() + { + $job_data = array('id' => 1, 'name' => 'Grocery Sales', 'description' => 'Discount!'); + + // Do normal insert + $this->assertTrue($this->db->insert('job', $job_data)); + + $job1 = $this->db->get('job')->row(); + + // Check the result + $this->assertEquals('Grocery Sales', $job1->name); + + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_insert_batch() + { + $job_datas = array( + array('id' => 2, 'name' => 'Commedian', 'description' => 'Theres something in your teeth'), + array('id' => 3, 'name' => 'Cab Driver', 'description' => 'Iam yellow'), + ); + + // Do insert batch except for sqlite driver + if (strpos(DB_DRIVER, 'sqlite') === FALSE) + { + $this->assertEquals(2, $this->db->insert_batch('job', $job_datas)); + + $job_2 = $this->db->where('id', 2)->get('job')->row(); + $job_3 = $this->db->where('id', 3)->get('job')->row(); + + // Check the result + $this->assertEquals('Commedian', $job_2->name); + $this->assertEquals('Cab Driver', $job_3->name); + } + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/join_test.php b/tests/codeigniter/database/query_builder/join_test.php new file mode 100644 index 000000000..25bd4accb --- /dev/null +++ b/tests/codeigniter/database/query_builder/join_test.php @@ -0,0 +1,58 @@ +<?php + +class Join_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_join_simple() + { + $job_user = $this->db->select('job.id as job_id, job.name as job_name, user.id as user_id, user.name as user_name') + ->from('job') + ->join('user', 'user.id = job.id') + ->get() + ->result_array(); + + // Check the result + $this->assertEquals('1', $job_user[0]['job_id']); + $this->assertEquals('1', $job_user[0]['user_id']); + $this->assertEquals('Derek Jones', $job_user[0]['user_name']); + $this->assertEquals('Developer', $job_user[0]['job_name']); + } + + // ------------------------------------------------------------------------ + + public function test_join_escape_multiple_conditions() + { + // We just need a valid query produced, not one that makes sense + $fields = array($this->db->protect_identifiers('table1.field1'), $this->db->protect_identifiers('table2.field2')); + + $expected = 'SELECT '.implode(', ', $fields) + ."\nFROM ".$this->db->escape_identifiers('table1') + ."\nLEFT JOIN ".$this->db->escape_identifiers('table2').' ON '.implode(' = ', $fields) + .' AND '.$fields[0]." = 'foo' AND ".$fields[1].' = 0'; + + $result = $this->db->select('table1.field1, table2.field2') + ->from('table1') + ->join('table2', "table1.field1 = table2.field2 AND table1.field1 = 'foo' AND table2.field2 = 0", 'LEFT') + ->get_compiled_select(); + + $this->assertEquals($expected, $result); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/like_test.php b/tests/codeigniter/database/query_builder/like_test.php new file mode 100644 index 000000000..2736fbe0b --- /dev/null +++ b/tests/codeigniter/database/query_builder/like_test.php @@ -0,0 +1,106 @@ +<?php + +class Like_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_like() + { + $job1 = $this->db->like('name', 'veloper') + ->get('job') + ->row(); + + // Check the result + $this->assertEquals('1', $job1->id); + $this->assertEquals('Developer', $job1->name); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_or_like() + { + $jobs = $this->db->like('name', 'ian') + ->or_like('name', 'veloper') + ->get('job') + ->result_array(); + + // Check the result + $this->assertEquals(3, count($jobs)); + $this->assertEquals('Developer', $jobs[0]['name']); + $this->assertEquals('Politician', $jobs[1]['name']); + $this->assertEquals('Musician', $jobs[2]['name']); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_not_like() + { + $jobs = $this->db->not_like('name', 'veloper') + ->get('job') + ->result_array(); + + // Check the result + $this->assertEquals(3, count($jobs)); + $this->assertEquals('Politician', $jobs[0]['name']); + $this->assertEquals('Accountant', $jobs[1]['name']); + $this->assertEquals('Musician', $jobs[2]['name']); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_or_not_like() + { + $jobs = $this->db->like('name', 'an') + ->or_not_like('name', 'veloper') + ->get('job') + ->result_array(); + + // Check the result + $this->assertEquals(3, count($jobs)); + $this->assertEquals('Politician', $jobs[0]['name']); + $this->assertEquals('Accountant', $jobs[1]['name']); + $this->assertEquals('Musician', $jobs[2]['name']); + } + + // ------------------------------------------------------------------------ + + /** + * GitHub issue #273 + * + * @see ./mocks/schema/skeleton.php + */ + public function test_like_spaces_and_tabs() + { + $spaces = $this->db->like('value', ' ')->get('misc')->result_array(); + $tabs = $this->db->like('value', "\t")->get('misc')->result_array(); + + $this->assertEquals(1, count($spaces)); + $this->assertEquals(1, count($tabs)); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/limit_test.php b/tests/codeigniter/database/query_builder/limit_test.php new file mode 100644 index 000000000..a0954c7ab --- /dev/null +++ b/tests/codeigniter/database/query_builder/limit_test.php @@ -0,0 +1,48 @@ +<?php + +class Limit_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_limit() + { + $jobs = $this->db->limit(2) + ->get('job') + ->result_array(); + + $this->assertEquals(2, count($jobs)); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_limit_and_offset() + { + $jobs = $this->db->limit(2, 2) + ->get('job') + ->result_array(); + + $this->assertEquals(2, count($jobs)); + $this->assertEquals('Accountant', $jobs[0]['name']); + $this->assertEquals('Musician', $jobs[1]['name']); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/order_test.php b/tests/codeigniter/database/query_builder/order_test.php new file mode 100644 index 000000000..46f452bae --- /dev/null +++ b/tests/codeigniter/database/query_builder/order_test.php @@ -0,0 +1,55 @@ +<?php + +class Order_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_order_ascending() + { + $jobs = $this->db->order_by('name', 'asc') + ->get('job') + ->result_array(); + + // Check the result + $this->assertEquals(4, count($jobs)); + $this->assertEquals('Accountant', $jobs[0]['name']); + $this->assertEquals('Developer', $jobs[1]['name']); + $this->assertEquals('Musician', $jobs[2]['name']); + $this->assertEquals('Politician', $jobs[3]['name']); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_order_descending() + { + $jobs = $this->db->order_by('name', 'desc') + ->get('job') + ->result_array(); + + $this->assertEquals(4, count($jobs)); + $this->assertEquals('Politician', $jobs[0]['name']); + $this->assertEquals('Musician', $jobs[1]['name']); + $this->assertEquals('Developer', $jobs[2]['name']); + $this->assertEquals('Accountant', $jobs[3]['name']); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/select_test.php b/tests/codeigniter/database/query_builder/select_test.php new file mode 100644 index 000000000..877b5d8c0 --- /dev/null +++ b/tests/codeigniter/database/query_builder/select_test.php @@ -0,0 +1,95 @@ +<?php + +class Select_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_select_only_one_collumn() + { + $jobs_name = $this->db->select('name') + ->get('job') + ->result_array(); + + // Check rows item + $this->assertArrayHasKey('name',$jobs_name[0]); + $this->assertFalse(array_key_exists('id', $jobs_name[0])); + $this->assertFalse(array_key_exists('description', $jobs_name[0])); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_select_min() + { + $job_min = $this->db->select_min('id') + ->get('job') + ->row(); + + // Minimum id was 1 + $this->assertEquals('1', $job_min->id); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_select_max() + { + $job_max = $this->db->select_max('id') + ->get('job') + ->row(); + + // Maximum id was 4 + $this->assertEquals('4', $job_max->id); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_select_avg() + { + $job_avg = $this->db->select_avg('id') + ->get('job') + ->row(); + + // Average should be 2.5 + $this->assertEquals('2.5', $job_avg->id); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_select_sum() + { + $job_sum = $this->db->select_sum('id') + ->get('job') + ->row(); + + // Sum of ids should be 10 + $this->assertEquals('10', $job_sum->id); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/truncate_test.php b/tests/codeigniter/database/query_builder/truncate_test.php new file mode 100644 index 000000000..09923c7f1 --- /dev/null +++ b/tests/codeigniter/database/query_builder/truncate_test.php @@ -0,0 +1,56 @@ +<?php + +class Truncate_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_truncate() + { + // Check initial record + $jobs = $this->db->get('job')->result_array(); + $this->assertEquals(4, count($jobs)); + + // Do the empty + $this->db->truncate('job'); + + // Check the record + $jobs = $this->db->get('job'); + $this->assertEmpty($jobs->result_array()); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_truncate_with_from() + { + // Check initial record + $users = $this->db->get('user')->result_array(); + $this->assertEquals(4, count($users)); + + // Do the empty + $this->db->from('user')->truncate(); + + // Check the record + $users = $this->db->get('user'); + $this->assertEmpty($users->result_array()); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/update_test.php b/tests/codeigniter/database/query_builder/update_test.php new file mode 100644 index 000000000..27a647c45 --- /dev/null +++ b/tests/codeigniter/database/query_builder/update_test.php @@ -0,0 +1,57 @@ +<?php + +class Update_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_update() + { + // Check initial record + $job1 = $this->db->where('id', 1)->get('job')->row(); + $this->assertEquals('Developer', $job1->name); + + // Do the update + $this->db->where('id', 1)->update('job', array('name' => 'Programmer')); + + // Check updated record + $job1 = $this->db->where('id', 1)->get('job')->row(); + $this->assertEquals('Programmer', $job1->name); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_update_with_set() + { + // Check initial record + $job1 = $this->db->where('id', 4)->get('job')->row(); + $this->assertEquals('Musician', $job1->name); + + // Do the update + $this->db->set('name', 'Vocalist'); + $this->db->update('job', NULL, 'id = 4'); + + // Check updated record + $job1 = $this->db->where('id', 4)->get('job')->row(); + $this->assertEquals('Vocalist', $job1->name); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/database/query_builder/where_test.php b/tests/codeigniter/database/query_builder/where_test.php new file mode 100644 index 000000000..20b7a567c --- /dev/null +++ b/tests/codeigniter/database/query_builder/where_test.php @@ -0,0 +1,126 @@ +<?php + +class Where_test extends CI_TestCase { + + /** + * @var object Database/Query Builder holder + */ + protected $db; + + public function set_up() + { + $this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER); + + Mock_Database_Schema_Skeleton::create_tables(); + Mock_Database_Schema_Skeleton::create_data(); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_where_simple_key_value() + { + $job1 = $this->db->where('id', 1)->get('job')->row(); + + $this->assertEquals('1', $job1->id); + $this->assertEquals('Developer', $job1->name); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_where_custom_key_value() + { + $jobs = $this->db->where('id !=', 1)->get('job')->result_array(); + $this->assertEquals(3, count($jobs)); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_where_associative_array() + { + $where = array('id >' => 2, 'name !=' => 'Accountant'); + $jobs = $this->db->where($where)->get('job')->result_array(); + + $this->assertEquals(1, count($jobs)); + + // Should be Musician + $job = current($jobs); + $this->assertEquals('Musician', $job['name']); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_where_custom_string() + { + $where = "id > 2 AND name != 'Accountant'"; + $jobs = $this->db->where($where)->get('job')->result_array(); + + $this->assertEquals(1, count($jobs)); + + // Should be Musician + $job = current($jobs); + $this->assertEquals('Musician', $job['name']); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_where_or() + { + $jobs = $this->db->where('name !=', 'Accountant') + ->or_where('id >', 3) + ->get('job') + ->result_array(); + + $this->assertEquals(3, count($jobs)); + $this->assertEquals('Developer', $jobs[0]['name']); + $this->assertEquals('Politician', $jobs[1]['name']); + $this->assertEquals('Musician', $jobs[2]['name']); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_where_in() + { + $jobs = $this->db->where_in('name', array('Politician', 'Accountant')) + ->get('job') + ->result_array(); + + $this->assertEquals(2, count($jobs)); + $this->assertEquals('Politician', $jobs[0]['name']); + $this->assertEquals('Accountant', $jobs[1]['name']); + } + + // ------------------------------------------------------------------------ + + /** + * @see ./mocks/schema/skeleton.php + */ + public function test_where_not_in() + { + $jobs = $this->db->where_not_in('name', array('Politician', 'Accountant')) + ->get('job') + ->result_array(); + + $this->assertEquals(2, count($jobs)); + $this->assertEquals('Developer', $jobs[0]['name']); + $this->assertEquals('Musician', $jobs[1]['name']); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/helpers/array_helper_test.php b/tests/codeigniter/helpers/array_helper_test.php index 9cd15960f..ba46e86f9 100644 --- a/tests/codeigniter/helpers/array_helper_test.php +++ b/tests/codeigniter/helpers/array_helper_test.php @@ -1,7 +1,7 @@ <?php class Array_helper_test extends CI_TestCase { - + public function set_up() { $this->helper('array'); @@ -13,31 +13,31 @@ class Array_helper_test extends CI_TestCase { 'herb' => 'cook' ); } - + // ------------------------------------------------------------------------ - + public function test_element_with_existing_item() - { + { $this->assertEquals(FALSE, element('testing', $this->my_array)); - + $this->assertEquals('not set', element('testing', $this->my_array, 'not set')); - + $this->assertEquals('bar', element('foo', $this->my_array)); } - - // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ public function test_random_element() { // Send a string, not an array to random_element $this->assertEquals('my string', random_element('my string')); - + // Test sending an array $this->assertEquals(TRUE, in_array(random_element($this->my_array), $this->my_array)); } - // ------------------------------------------------------------------------ - + // ------------------------------------------------------------------------ + public function test_elements() { $this->assertEquals(TRUE, is_array(elements('test', $this->my_array))); diff --git a/tests/codeigniter/helpers/captcha_helper_test.php b/tests/codeigniter/helpers/captcha_helper_test.php new file mode 100644 index 000000000..fc86305e3 --- /dev/null +++ b/tests/codeigniter/helpers/captcha_helper_test.php @@ -0,0 +1,10 @@ +<?php + +class Captcha_helper_test extends CI_TestCase { + + public function test_create_captcha() + { + $this->markTestSkipped('Cant easily test'); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/helpers/cookie_helper_test.php b/tests/codeigniter/helpers/cookie_helper_test.php new file mode 100644 index 000000000..fba68f20f --- /dev/null +++ b/tests/codeigniter/helpers/cookie_helper_test.php @@ -0,0 +1,59 @@ +<?php + +class Cookie_helper_test extends CI_TestCase { + + public function set_up() + { + $this->helper('cookie'); + } + + // ------------------------------------------------------------------------ + + function test_set_cookie() + { + /*$input_cls = $this->ci_core_class('input'); + $this->ci_instance_var('input', new $input_cls); + + $this->assertTrue(set_cookie( + 'my_cookie', + 'foobar' + ));*/ + + $this->markTestSkipped('Need to find a way to overcome a headers already set exception'); + } + + // ------------------------------------------------------------------------ + + function test_get_cookie() + { + $_COOKIE['foo'] = 'bar'; + + $security = new Mock_Core_Security(); + $utf8 = new Mock_Core_Utf8(); + $input_cls = $this->ci_core_class('input'); + $this->ci_instance_var('input', new Mock_Core_Input($security, $utf8)); + + $this->assertEquals('bar', get_cookie('foo', FALSE)); + $this->assertEquals('bar', get_cookie('foo', TRUE)); + + $_COOKIE['bar'] = "Hello, i try to <script>alert('Hack');</script> your site"; + + $this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", get_cookie('bar', TRUE)); + $this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", get_cookie('bar', FALSE)); + } + + // ------------------------------------------------------------------------ + + function test_delete_cookie() + { + /*$input_cls = $this->ci_core_class('input'); + $this->ci_instance_var('input', new $input_cls); + + $this->assertTrue(delete_cookie( + 'my_cookie' + ));*/ + + $this->markTestSkipped('Need to find a way to overcome a headers already set exception'); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/helpers/date_helper_test.php b/tests/codeigniter/helpers/date_helper_test.php index 17d1ef21e..1458acd3e 100644 --- a/tests/codeigniter/helpers/date_helper_test.php +++ b/tests/codeigniter/helpers/date_helper_test.php @@ -5,159 +5,171 @@ class Date_helper_test extends CI_TestCase { public function set_up() { $this->helper('date'); + + $this->time = time(); } // ------------------------------------------------------------------------ public function test_now_local() { + /* + // This stub job, is simply to cater $config['time_reference'] $config = $this->getMock('CI_Config'); $config->expects($this->any()) ->method('item') ->will($this->returnValue('local')); - + // Add the stub to our test instance $this->ci_instance_var('config', $config); - $expected = time(); - $test = now(); - $this->assertEquals($expected, $test); + */ + + $this->ci_set_config('time_reference', 'local'); + + $this->assertEquals(time(), now()); } // ------------------------------------------------------------------------ - public function test_now_gmt() + public function test_now_utc() { + /* + // This stub job, is simply to cater $config['time_reference'] $config = $this->getMock('CI_Config'); $config->expects($this->any()) ->method('item') - ->will($this->returnValue('gmt')); - + ->will($this->returnValue('UTC')); + // Add the stub to our stdClass $this->ci_instance_var('config', $config); - $t = time(); - $expected = mktime(gmdate("H", $t), gmdate("i", $t), gmdate("s", $t), gmdate("m", $t), gmdate("d", $t), gmdate("Y", $t)); - $test = now(); - $this->assertEquals($expected, $test); + */ + + $this->assertEquals( + mktime(gmdate('G'), gmdate('i'), gmdate('s'), gmdate('n'), gmdate('j'), gmdate('Y')), + now('UTC') + ); } // ------------------------------------------------------------------------ public function test_mdate() { - $time = time(); - $expected = date("Y-m-d - h:i a", $time); - $test = mdate("%Y-%m-%d - %h:%i %a", $time); - $this->assertEquals($expected, $test); + $this->assertEquals( + date('Y-m-d - h:i a', $this->time), + mdate('%Y-%m-%d - %h:%i %a', $this->time) + ); } // ------------------------------------------------------------------------ public function test_standard_date_rfc822() { - $time = time(); - $format = 'DATE_RFC822'; - $expected = date("D, d M y H:i:s O", $time); - $this->assertEquals($expected, standard_date($format, $time)); + $this->assertEquals( + date(DATE_RFC822, $this->time), + standard_date('DATE_RFC822', $this->time) + ); } // ------------------------------------------------------------------------ public function test_standard_date_atom() { - $time = time(); - $format = 'DATE_ATOM'; - $expected = date("Y-m-d\TH:i:sO", $time); - $this->assertEquals($expected, standard_date($format, $time)); + $this->assertEquals( + date(DATE_ATOM, $this->time), + standard_date('DATE_ATOM', $this->time) + ); } // ------------------------------------------------------------------------ public function test_standard_date_cookie() { - $time = time(); - $format = 'DATE_COOKIE'; - $expected = date("l, d-M-y H:i:s \U\T\C", $time); - $this->assertEquals($expected, standard_date($format, $time)); + $this->assertEquals( + date(DATE_COOKIE, $this->time), + standard_date('DATE_COOKIE', $this->time) + ); } // ------------------------------------------------------------------------ public function test_standard_date_iso8601() { - $time = time(); - $format = 'DATE_ISO8601'; - $expected = date("Y-m-d\TH:i:sO", $time); - $this->assertEquals($expected, standard_date($format, $time)); + $this->assertEquals( + date(DATE_ISO8601, $this->time), + standard_date('DATE_ISO8601', $this->time) + ); } // ------------------------------------------------------------------------ public function test_standard_date_rfc850() { - $time = time(); - $format = 'DATE_RFC850'; - $expected = date("l, d-M-y H:i:s \U\T\C", $time); - $this->assertEquals($expected, standard_date($format, $time)); + $this->assertEquals( + date(DATE_RFC850, $this->time), + standard_date('DATE_RFC850', $this->time) + ); } // ------------------------------------------------------------------------ public function test_standard_date_rfc1036() { - $time = time(); - $format = 'DATE_RFC1036'; - $expected = date("D, d M y H:i:s O", $time); - $this->assertEquals($expected, standard_date($format, $time)); + $this->assertEquals( + date(DATE_RFC1036, $this->time), + standard_date('DATE_RFC1036', $this->time) + ); } // ------------------------------------------------------------------------ public function test_standard_date_rfc1123() { - $time = time(); - $format = 'DATE_RFC1123'; - $expected = date("D, d M Y H:i:s O", $time); - $this->assertEquals($expected, standard_date($format, $time)); + $this->assertEquals( + date(DATE_RFC1123, $this->time), + standard_date('DATE_RFC1123', $this->time) + ); } // ------------------------------------------------------------------------ public function test_standard_date_rfc2822() { - $time = time(); - $format = 'DATE_RFC2822'; - $expected = date("D, d M Y H:i:s O", $time); - $this->assertEquals($expected, standard_date($format, $time)); + $this->assertEquals( + date(DATE_RFC2822, $this->time), + standard_date('DATE_RFC2822', $this->time) + ); } // ------------------------------------------------------------------------ public function test_standard_date_rss() { - $time = time(); - $format = 'DATE_RSS'; - $expected = date("D, d M Y H:i:s O", $time); - $this->assertEquals($expected, standard_date($format, $time)); + $this->assertEquals( + date(DATE_RSS, $this->time), + standard_date('DATE_RSS', $this->time) + ); } // ------------------------------------------------------------------------ public function test_standard_date_w3c() { - $time = time(); - $format = 'DATE_W3C'; - $expected = date("Y-m-d\TH:i:sO", $time); - $this->assertEquals($expected, standard_date($format, $time)); + $this->assertEquals( + date(DATE_W3C, $this->time), + standard_date('DATE_W3C', $this->time) + ); } // ------------------------------------------------------------------------ public function test_timespan() { + $this->ci_vfs_clone('system/language/english/date_lang.php'); + $loader_cls = $this->ci_core_class('load'); $this->ci_instance_var('load', new $loader_cls); @@ -183,39 +195,36 @@ class Date_helper_test extends CI_TestCase { public function test_local_to_gmt() { - $t = time(); - $expected = mktime(gmdate("H", $t), gmdate("i", $t), gmdate("s", $t), gmdate("m", $t), gmdate("d", $t), gmdate("Y", $t)); - $this->assertEquals($expected, local_to_gmt($t)); + $this->assertEquals( + mktime( + gmdate('G', $this->time), gmdate('i', $this->time), gmdate('s', $this->time), + gmdate('n', $this->time), gmdate('j', $this->time), gmdate('Y', $this->time) + ), + local_to_gmt($this->time) + ); } // ------------------------------------------------------------------------ public function test_gmt_to_local() { - $timestamp = '1140153693'; - $timezone = 'UM8'; - $daylight_saving = TRUE; - - $this->assertEquals(1140128493, gmt_to_local($timestamp, $timezone, $daylight_saving)); + $this->assertEquals(1140128493, gmt_to_local('1140153693', 'UM8', TRUE)); } // ------------------------------------------------------------------------ public function test_mysql_to_unix() { - $time = time(); - $this->assertEquals($time, - mysql_to_unix(date("Y-m-d H:i:s", $time))); + $this->assertEquals($this->time, mysql_to_unix(date('Y-m-d H:i:s', $this->time))); } // ------------------------------------------------------------------------ public function test_unix_to_human() { - $time = time(); - $this->assertEquals(date("Y-m-d h:i A", $time), unix_to_human($time)); - $this->assertEquals(date("Y-m-d h:i:s A", $time), unix_to_human($time, TRUE, 'us')); - $this->assertEquals(date("Y-m-d H:i:s", $time), unix_to_human($time, TRUE, 'eu')); + $this->assertEquals(date('Y-m-d h:i A', $this->time), unix_to_human($this->time)); + $this->assertEquals(date('Y-m-d h:i:s A', $this->time), unix_to_human($this->time, TRUE, 'us')); + $this->assertEquals(date('Y-m-d H:i:s', $this->time), unix_to_human($this->time, TRUE, 'eu')); } // ------------------------------------------------------------------------ @@ -223,8 +232,7 @@ class Date_helper_test extends CI_TestCase { public function test_human_to_unix() { $date = '2000-12-31 10:00:00 PM'; - $expected = strtotime($date); - $this->assertEquals($expected, human_to_unix($date)); + $this->assertEquals(strtotime($date), human_to_unix($date)); $this->assertFalse(human_to_unix()); } @@ -283,6 +291,30 @@ class Date_helper_test extends CI_TestCase { $this->assertArrayHasKey('UP3', timezones()); $this->assertEquals(0, timezones('non_existant')); } + + // ------------------------------------------------------------------------ + + public function test_date_range() + { + $dates = array( + '29-01-2012', '30-01-2012', '31-01-2012', + '01-02-2012', '02-02-2012', '03-02-2012', + '04-02-2012', '05-02-2012', '06-02-2012', + '07-02-2012', '08-02-2012', '09-02-2012', + '10-02-2012', '11-02-2012', '12-02-2012', + '13-02-2012', '14-02-2012', '15-02-2012', + '16-02-2012', '17-02-2012', '18-02-2012', + '19-02-2012', '20-02-2012', '21-02-2012', + '22-02-2012', '23-02-2012', '24-02-2012', + '25-02-2012', '26-02-2012', '27-02-2012', + '28-02-2012', '29-02-2012', '01-03-2012' + ); + + $this->assertEquals($dates, date_range(mktime(12, 0, 0, 1, 29, 2012), mktime(12, 0, 0, 3, 1, 2012), TRUE, 'd-m-Y')); + array_pop($dates); + $this->assertEquals($dates, date_range(mktime(12, 0, 0, 1, 29, 2012), 31, FALSE, 'd-m-Y')); + } + } /* End of file date_helper_test.php */
\ No newline at end of file diff --git a/tests/codeigniter/helpers/directory_helper_test.php b/tests/codeigniter/helpers/directory_helper_test.php index 3937d2913..41370e6e7 100644 --- a/tests/codeigniter/helpers/directory_helper_test.php +++ b/tests/codeigniter/helpers/directory_helper_test.php @@ -1,41 +1,52 @@ <?php class Directory_helper_test extends CI_TestCase { - + public function set_up() { $this->helper('directory'); vfsStreamWrapper::register(); vfsStreamWrapper::setRoot(new vfsStreamDirectory('testDir')); - + $this->_test_dir = vfsStreamWrapper::getRoot(); - } - + } + public function test_directory_map() { - $structure = array('libraries' => array('benchmark.html' => '', 'database' => - array('active_record.html' => '', 'binds.html' => ''), 'email.html' => '', '.hiddenfile.txt' => '')); - + $structure = array( + 'libraries' => array( + 'benchmark.html' => '', + 'database' => array('active_record.html' => '', 'binds.html' => ''), + 'email.html' => '', + '0' => '', + '.hiddenfile.txt' => '' + ) + ); + vfsStream::create($structure, $this->_test_dir); // test default recursive behavior - $expected = array('libraries' => array('benchmark.html', 'database' => - array('active_record.html', 'binds.html'), 'email.html')); - - $this->assertEquals($expected, directory_map(vfsStream::url('testDir'))); + $expected = array( + 'libraries/' => array( + 'benchmark.html', + 'database/' => array('active_record.html', 'binds.html'), + 'email.html', + '0' + ) + ); - // test recursion depth behavior - $expected = array('libraries'); - - $this->assertEquals($expected, directory_map(vfsStream::url('testDir'), 1)); + $this->assertEquals($expected, directory_map(vfsStream::url('testDir'))); // test detection of hidden files - $expected = array('libraries' => array('benchmark.html', 'database' => - array('active_record.html', 'binds.html'), 'email.html', '.hiddenfile.txt')); - + $expected['libraries/'][] = '.hiddenfile.txt'; + $this->assertEquals($expected, directory_map(vfsStream::url('testDir'), FALSE, TRUE)); - } + + // test recursion depth behavior + $this->assertEquals(array('libraries/'), directory_map(vfsStream::url('testDir'), 1)); + } + } /* End of file directory_helper_test.php */
\ No newline at end of file diff --git a/tests/codeigniter/helpers/download_helper_test.php b/tests/codeigniter/helpers/download_helper_test.php new file mode 100644 index 000000000..d2b42e46b --- /dev/null +++ b/tests/codeigniter/helpers/download_helper_test.php @@ -0,0 +1,10 @@ +<?php + +class Download_helper_test extends CI_TestCase { + + public function test_force_download() + { + $this->markTestSkipped('Cant easily test'); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/helpers/email_helper_test.php b/tests/codeigniter/helpers/email_helper_test.php index a01f3d5af..fea452f5f 100644 --- a/tests/codeigniter/helpers/email_helper_test.php +++ b/tests/codeigniter/helpers/email_helper_test.php @@ -14,5 +14,5 @@ class Email_helper_test extends CI_TestCase { $this->assertEquals(TRUE, valid_email('test@test.com')); $this->assertEquals(TRUE, valid_email('my.test@test.com')); } - + }
\ No newline at end of file diff --git a/tests/codeigniter/helpers/file_helper_test.php b/tests/codeigniter/helpers/file_helper_test.php index 4b9c29485..9b03da9d7 100644 --- a/tests/codeigniter/helpers/file_helper_test.php +++ b/tests/codeigniter/helpers/file_helper_test.php @@ -5,24 +5,23 @@ class File_helper_Test extends CI_TestCase { public function set_up() { $this->helper('file'); - + vfsStreamWrapper::register(); vfsStreamWrapper::setRoot(new vfsStreamDirectory('testDir')); - + $this->_test_dir = vfsStreamWrapper::getRoot(); } - + // -------------------------------------------------------------------- - + public function test_read_file() { $this->assertFalse(read_file('does_not_exist')); - + $content = 'Jack and Jill went up the mountain to fight a billy goat.'; - - $file = vfsStream::newFile('my_file.txt')->withContent($content) - ->at($this->_test_dir); - + + $file = vfsStream::newFile('my_file.txt')->withContent($content)->at($this->_test_dir); + $this->assertEquals($content, read_file(vfsStream::url('my_file.txt'))); } @@ -31,126 +30,124 @@ class File_helper_Test extends CI_TestCase { public function test_octal_permissions() { $content = 'Jack and Jill went up the mountain to fight a billy goat.'; - + $file = vfsStream::newFile('my_file.txt', 0777)->withContent($content) - ->lastModified(time() - 86400) - ->at($this->_test_dir); - - $this->assertEquals('777', octal_permissions($file->getPermissions())); + ->lastModified(time() - 86400) + ->at($this->_test_dir); + + $this->assertEquals('777', octal_permissions($file->getPermissions())); } - // -------------------------------------------------------------------- - + // -------------------------------------------------------------------- + /** * More tests should happen here, since I'm not hitting the whole function. */ public function test_symbolic_permissions() { $content = 'Jack and Jill went up the mountain to fight a billy goat.'; - + $file = vfsStream::newFile('my_file.txt', 0777)->withContent($content) - ->lastModified(time() - 86400) - ->at($this->_test_dir); - - $this->assertEquals('urwxrwxrwx', symbolic_permissions($file->getPermissions())); + ->lastModified(time() - 86400) + ->at($this->_test_dir); + + $this->assertEquals('urwxrwxrwx', symbolic_permissions($file->getPermissions())); } - // -------------------------------------------------------------------- - + // -------------------------------------------------------------------- + public function test_get_mime_by_extension() { $content = 'Jack and Jill went up the mountain to fight a billy goat.'; - + $file = vfsStream::newFile('my_file.txt', 0777)->withContent($content) - ->lastModified(time() - 86400) - ->at($this->_test_dir); - - $this->assertEquals('text/plain', - get_mime_by_extension(vfsStream::url('my_file.txt'))); - - // Test a mime with an array, such as png + ->lastModified(time() - 86400) + ->at($this->_test_dir); + + $this->assertEquals('text/plain', get_mime_by_extension(vfsStream::url('my_file.txt'))); + + // Test a mime with an array, such as png $file = vfsStream::newFile('foo.png')->at($this->_test_dir); - - $this->assertEquals('image/png', get_mime_by_extension(vfsStream::url('foo.png'))); - + + $this->assertEquals('image/png', get_mime_by_extension(vfsStream::url('foo.png'))); + // Test a file not in the mimes array $file = vfsStream::newFile('foo.blarfengar')->at($this->_test_dir); - + $this->assertFalse(get_mime_by_extension(vfsStream::url('foo.blarfengar'))); } - // -------------------------------------------------------------------- + // -------------------------------------------------------------------- public function test_get_file_info() { // Test Bad File $this->assertFalse(get_file_info('i_am_bad_boo')); - + // Test the rest - + // First pass in an array $vals = array( 'name', 'server_path', 'size', 'date', - 'readable', 'writable', 'executable', 'fileperms' + 'readable', 'writable', 'executable', 'fileperms' ); - + $this->_test_get_file_info($vals); // Test passing in vals as a string. - $vals = 'name, server_path, size, date, readable, writable, executable, fileperms'; - $this->_test_get_file_info($vals); + $this->_test_get_file_info(implode(', ', $vals)); } - + private function _test_get_file_info($vals) { $content = 'Jack and Jill went up the mountain to fight a billy goat.'; $last_modified = time() - 86400; - + $file = vfsStream::newFile('my_file.txt', 0777)->withContent($content) - ->lastModified($last_modified) - ->at($this->_test_dir); - + ->lastModified($last_modified) + ->at($this->_test_dir); + $ret_values = array( - 'name' => 'my_file.txt', - 'server_path' => 'vfs://my_file.txt', - 'size' => 57, - 'date' => $last_modified, + 'name' => 'my_file.txt', + 'server_path' => 'vfs://my_file.txt', + 'size' => 57, + 'date' => $last_modified, 'readable' => TRUE, - 'writable' => TRUE, - 'executable' => TRUE, + 'writable' => TRUE, + 'executable' => TRUE, 'fileperms' => 33279 ); - + $info = get_file_info(vfsStream::url('my_file.txt'), $vals); - + foreach ($info as $k => $v) { $this->assertEquals($ret_values[$k], $v); } } - - // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- // Skipping for now, as it's not implemented in vfsStreamWrapper // flock(): vfsStreamWrapper::stream_lock is not implemented! - + // public function test_write_file() // { - // if ( ! defined('FOPEN_WRITE_CREATE_DESTRUCTIVE')) - // { - // define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb'); - // } - // - // $content = 'Jack and Jill went up the mountain to fight a billy goat.'; - // - // $file = vfsStream::newFile('write.txt', 0777)->withContent('') - // ->lastModified(time() - 86400) - // ->at($this->_test_dir); - // - // $this->assertTrue(write_file(vfsStream::url('write.txt'), $content)); - // + // if ( ! defined('FOPEN_WRITE_CREATE_DESTRUCTIVE')) + // { + // define('FOPEN_WRITE_CREATE_DESTRUCTIVE', 'wb'); + // } + // + // $content = 'Jack and Jill went up the mountain to fight a billy goat.'; + // + // $file = vfsStream::newFile('write.txt', 0777)->withContent('') + // ->lastModified(time() - 86400) + // ->at($this->_test_dir); + // + // $this->assertTrue(write_file(vfsStream::url('write.txt'), $content)); + // // } - // -------------------------------------------------------------------- - + // -------------------------------------------------------------------- + }
\ No newline at end of file diff --git a/tests/codeigniter/helpers/form_helper_test.php b/tests/codeigniter/helpers/form_helper_test.php index 80bace9d1..89165271e 100644 --- a/tests/codeigniter/helpers/form_helper_test.php +++ b/tests/codeigniter/helpers/form_helper_test.php @@ -1,28 +1,34 @@ <?php -require BASEPATH . 'core/Common.php'; -require BASEPATH . 'helpers/form_helper.php'; - -class Form_helper_test extends CI_TestCase +class Form_helper_test extends CI_TestCase { + public function set_up() + { + $this->helper('form'); + } + + // ------------------------------------------------------------------------ + public function test_form_hidden() - { + { $expected = <<<EOH <input type="hidden" name="username" value="johndoe" /> EOH; - + $this->assertEquals($expected, form_hidden('username', 'johndoe')); } - + + // ------------------------------------------------------------------------ + public function test_form_input() { $expected = <<<EOH <input type="text" name="username" value="johndoe" id="username" maxlength="100" size="50" style="width:50%" /> EOH; - + $data = array( 'name' => 'username', 'id' => 'username', @@ -34,37 +40,45 @@ EOH; $this->assertEquals($expected, form_input($data)); } - + + // ------------------------------------------------------------------------ + public function test_form_password() - { + { $expected = <<<EOH <input type="password" name="password" value="" /> EOH; - + $this->assertEquals($expected, form_password('password')); } - + + // ------------------------------------------------------------------------ + public function test_form_upload() - { + { $expected = <<<EOH <input type="file" name="attachment" value="" /> EOH; - + $this->assertEquals($expected, form_upload('attachment')); } - + + // ------------------------------------------------------------------------ + public function test_form_textarea() - { + { $expected = <<<EOH <textarea name="notes" cols="40" rows="10" >Notes</textarea> EOH; - + $this->assertEquals($expected, form_textarea('notes', 'Notes')); } - + + // ------------------------------------------------------------------------ + public function test_form_dropdown() { $expected = <<<EOH @@ -76,16 +90,16 @@ EOH; </select> EOH; - + $options = array( - 'small' => 'Small Shirt', - 'med' => 'Medium Shirt', - 'large' => 'Large Shirt', - 'xlarge' => 'Extra Large Shirt', + 'small' => 'Small Shirt', + 'med' => 'Medium Shirt', + 'large' => 'Large Shirt', + 'xlarge' => 'Extra Large Shirt', ); - + $this->assertEquals($expected, form_dropdown('shirts', $options, 'large')); - + $expected = <<<EOH <select name="shirts" multiple="multiple"> <option value="small" selected="selected">Small Shirt</option> @@ -95,22 +109,22 @@ EOH; </select> EOH; - + $shirts_on_sale = array('small', 'large'); - + $this->assertEquals($expected, form_dropdown('shirts', $options, $shirts_on_sale)); - + $options = array( 'Swedish Cars' => array( - 'volvo' => 'Volvo', - 'saab' => 'Saab' + 'volvo' => 'Volvo', + 'saab' => 'Saab' ), 'German Cars' => array( - 'mercedes' => 'Mercedes', - 'audi' => 'Audi' + 'mercedes' => 'Mercedes', + 'audi' => 'Audi' ) ); - + $expected = <<<EOH <select name="cars" multiple="multiple"> <optgroup label="Swedish Cars"> @@ -124,13 +138,12 @@ EOH; </select> EOH; - - $cars_on_sale = array('volvo', 'audi'); - - $this->assertEquals($expected, form_dropdown('cars', $options, $cars_on_sale)); - + + $this->assertEquals($expected, form_dropdown('cars', $options, array('volvo', 'audi'))); } - + + // ------------------------------------------------------------------------ + public function test_form_multiselect() { $expected = <<<EOH @@ -142,17 +155,19 @@ EOH; </select> EOH; - + $options = array( - 'small' => 'Small Shirt', - 'med' => 'Medium Shirt', - 'large' => 'Large Shirt', - 'xlarge' => 'Extra Large Shirt', - ); - + 'small' => 'Small Shirt', + 'med' => 'Medium Shirt', + 'large' => 'Large Shirt', + 'xlarge' => 'Extra Large Shirt', + ); + $this->assertEquals($expected, form_multiselect('shirts[]', $options, array('med', 'large'))); } - + + // ------------------------------------------------------------------------ + public function test_form_fieldset() { $expected = <<<EOH @@ -160,19 +175,23 @@ EOH; <legend>Address Information</legend> EOH; - + $this->assertEquals($expected, form_fieldset('Address Information')); } + // ------------------------------------------------------------------------ + public function test_form_fieldset_close() { $expected = <<<EOH </fieldset></div></div> EOH; - + $this->assertEquals($expected, form_fieldset_close('</div></div>')); } - + + // ------------------------------------------------------------------------ + public function test_form_checkbox() { $expected = <<<EOH @@ -182,7 +201,9 @@ EOH; $this->assertEquals($expected, form_checkbox('newsletter', 'accept', TRUE)); } - + + // ------------------------------------------------------------------------ + public function test_form_radio() { $expected = <<<EOH @@ -192,7 +213,9 @@ EOH; $this->assertEquals($expected, form_radio('newsletter', 'accept', TRUE)); } - + + // ------------------------------------------------------------------------ + public function test_form_submit() { $expected = <<<EOH @@ -202,7 +225,9 @@ EOH; $this->assertEquals($expected, form_submit('mysubmit', 'Submit Post!')); } - + + // ------------------------------------------------------------------------ + public function test_form_label() { $expected = <<<EOH @@ -211,7 +236,9 @@ EOH; $this->assertEquals($expected, form_label('What is your Name', 'username')); } - + + // ------------------------------------------------------------------------ + public function test_form_reset() { $expected = <<<EOH @@ -221,7 +248,9 @@ EOH; $this->assertEquals($expected, form_reset('myreset', 'Reset')); } - + + // ------------------------------------------------------------------------ + public function test_form_button() { $expected = <<<EOH @@ -229,9 +258,11 @@ EOH; EOH; - $this->assertEquals($expected, form_button('name','content')); + $this->assertEquals($expected, form_button('name', 'content')); } - + + // ------------------------------------------------------------------------ + public function test_form_close() { $expected = <<<EOH @@ -240,13 +271,22 @@ EOH; $this->assertEquals($expected, form_close('</div></div>')); } - + + // ------------------------------------------------------------------------ + public function test_form_prep() { - $expected = "Here is a string containing "quoted" text."; - - $this->assertEquals($expected, form_prep('Here is a string containing "quoted" text.')); + $this->assertEquals( + 'Here is a string containing "quoted" text.', + form_prep('Here is a string containing "quoted" text.') + ); + + $this->assertEquals( + 'Here is a string containing a <tag>.', + form_prep('Here is a string containing a <tag>.', TRUE) + ); } + } /* End of file form_helper_test.php */
\ No newline at end of file diff --git a/tests/codeigniter/helpers/html_helper_test.php b/tests/codeigniter/helpers/html_helper_test.php index 28974b0f8..4dd717ff7 100644 --- a/tests/codeigniter/helpers/html_helper_test.php +++ b/tests/codeigniter/helpers/html_helper_test.php @@ -6,24 +6,40 @@ class Html_helper_test extends CI_TestCase { { $this->helper('html'); } - + // ------------------------------------------------------------------------ - + public function test_br() { $this->assertEquals('<br /><br />', br(2)); } - + // ------------------------------------------------------------------------ - + public function test_heading() { $this->assertEquals('<h1>foobar</h1>', heading('foobar')); $this->assertEquals('<h2 class="bar">foobar</h2>', heading('foobar', 2, 'class="bar"')); } + public function test_heading_array_attributes() + { + // Test array of attributes + $this->assertEquals('<h2 class="bar" id="foo">foobar</h2>', heading('foobar', 2, array('class' => 'bar', 'id' => 'foo'))); + } + + public function test_heading_object_attributes() + { + // Test array of attributes + $this->assertEquals('<h2 class="bar" id="foo">foobar</h2>', heading('foobar', 2, array('class' => 'bar', 'id' => 'foo'))); + $test = new stdClass; + $test->class = "bar"; + $test->id = "foo"; + $this->assertEquals('<h2 class="bar" id="foo">foobar</h2>', heading('foobar', 2, $test)); + } + // ------------------------------------------------------------------------ - + public function test_Ul() { $expect = <<<EOH @@ -35,11 +51,9 @@ class Html_helper_test extends CI_TestCase { EOH; $expect = ltrim($expect); - $list = array('foo', 'bar'); - - $this->assertEquals($expect, ul($list)); + $this->assertEquals(ltrim($expect), ul($list)); $expect = <<<EOH <ul class="test"> @@ -51,13 +65,11 @@ EOH; $expect = ltrim($expect); - $list = array('foo', 'bar'); - $this->assertEquals($expect, ul($list, 'class="test"')); $this->assertEquals($expect, ul($list, array('class' => 'test'))); } - + // ------------------------------------------------------------------------ public function test_NBS() @@ -66,15 +78,14 @@ EOH; } // ------------------------------------------------------------------------ - + public function test_meta() { $this->assertEquals("<meta name=\"test\" content=\"foo\" />\n", meta('test', 'foo')); - + $expect = "<meta name=\"foo\" content=\"\" />\n"; - + $this->assertEquals($expect, meta(array('name' => 'foo'))); - + } - }
\ No newline at end of file diff --git a/tests/codeigniter/helpers/inflector_helper_test.php b/tests/codeigniter/helpers/inflector_helper_test.php index 9e9478711..f3b0ebbe8 100644 --- a/tests/codeigniter/helpers/inflector_helper_test.php +++ b/tests/codeigniter/helpers/inflector_helper_test.php @@ -1,12 +1,12 @@ <?php class Inflector_helper_test extends CI_TestCase { - + public function set_up() { $this->helper('inflector'); } - + public function test_singular() { $strs = array( @@ -16,15 +16,15 @@ class Inflector_helper_test extends CI_TestCase { 'smells' => 'smell', 'equipment' => 'equipment' ); - + foreach ($strs as $str => $expect) { $this->assertEquals($expect, singular($str)); } } - + // -------------------------------------------------------------------- - + public function test_plural() { $strs = array( @@ -35,15 +35,15 @@ class Inflector_helper_test extends CI_TestCase { 'witch' => 'witches', 'equipment' => 'equipment' ); - + foreach ($strs as $str => $expect) { $this->assertEquals($expect, plural($str)); - } - } + } + } // -------------------------------------------------------------------- - + public function test_camelize() { $strs = array( @@ -52,15 +52,15 @@ class Inflector_helper_test extends CI_TestCase { 'i-am-playing-a-trick' => 'i-am-playing-a-trick', 'what_do_you_think-yo?' => 'whatDoYouThink-yo?', ); - + foreach ($strs as $str => $expect) { $this->assertEquals($expect, camelize($str)); } - } + } // -------------------------------------------------------------------- - + public function test_underscore() { $strs = array( @@ -69,7 +69,7 @@ class Inflector_helper_test extends CI_TestCase { 'i-am-playing-a-trick' => 'i-am-playing-a-trick', 'what_do_you_think-yo?' => 'what_do_you_think-yo?', ); - + foreach ($strs as $str => $expect) { $this->assertEquals($expect, underscore($str)); @@ -77,7 +77,7 @@ class Inflector_helper_test extends CI_TestCase { } // -------------------------------------------------------------------- - + public function test_humanize() { $strs = array( @@ -86,10 +86,11 @@ class Inflector_helper_test extends CI_TestCase { 'i-am-playing-a-trick' => 'I-am-playing-a-trick', 'what_do_you_think-yo?' => 'What Do You Think-yo?', ); - + foreach ($strs as $str => $expect) { $this->assertEquals($expect, humanize($str)); } } + }
\ No newline at end of file diff --git a/tests/codeigniter/helpers/language_helper_test.php b/tests/codeigniter/helpers/language_helper_test.php new file mode 100644 index 000000000..06932b9fd --- /dev/null +++ b/tests/codeigniter/helpers/language_helper_test.php @@ -0,0 +1,14 @@ +<?php + +class Language_helper_test extends CI_TestCase { + + public function test_lang() + { + $this->helper('language'); + $this->ci_instance_var('lang', new Mock_Core_Lang()); + + $this->assertFalse(lang(1)); + $this->assertEquals('<label for="foo"></label>', lang(1, 'foo')); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/helpers/number_helper_test.php b/tests/codeigniter/helpers/number_helper_test.php index 4bb9a918a..817db2c7e 100644 --- a/tests/codeigniter/helpers/number_helper_test.php +++ b/tests/codeigniter/helpers/number_helper_test.php @@ -1,77 +1,63 @@ <?php class Number_helper_test extends CI_TestCase { - + public function set_up() { $this->helper('number'); - + // Grab the core lang class $lang_cls = $this->ci_core_class('lang'); - + // Mock away load, too much going on in there, // we'll just check for the expected parameter - $lang = $this->getMock($lang_cls, array('load')); $lang->expects($this->once()) ->method('load') ->with($this->equalTo('number')); - + // Assign the proper language array - - $lang->language = $this->_get_lang('number'); - + $lang->language = $this->lang('number'); + // We don't have a controller, so just create // a cheap class to act as our super object. // Make sure it has a lang attribute. - - $obj = new StdClass; - $obj->lang = $lang; - $this->ci_instance($obj); - } - - // Quick helper to actually grab the language - // file. Consider moving this to ci_testcase? - public function _get_lang($name) - { - require BASEPATH.'language/english/'.$name.'_lang.php'; - return $lang; + $this->ci_instance_var('lang', $lang); } - + public function test_byte_format() { $this->assertEquals('456 Bytes', byte_format(456)); } - + public function test_kb_format() { $this->assertEquals('4.5 KB', byte_format(4567)); } - + public function test_kb_format_medium() { $this->assertEquals('44.6 KB', byte_format(45678)); } - + public function test_kb_format_large() { $this->assertEquals('446.1 KB', byte_format(456789)); } - + public function test_mb_format() { $this->assertEquals('3.3 MB', byte_format(3456789)); } - + public function test_gb_format() { $this->assertEquals('1.8 GB', byte_format(1932735283.2)); } - + public function test_tb_format() { $this->assertEquals('112,283.3 TB', byte_format(123456789123456789)); } -} -// EOF
\ No newline at end of file +}
\ No newline at end of file diff --git a/tests/codeigniter/helpers/path_helper_test.php b/tests/codeigniter/helpers/path_helper_test.php index 632f57501..0faf6f383 100644 --- a/tests/codeigniter/helpers/path_helper_test.php +++ b/tests/codeigniter/helpers/path_helper_test.php @@ -8,9 +8,8 @@ class Path_helper_test extends CI_TestCase { } public function test_set_realpath() - { - $expected = getcwd() . DIRECTORY_SEPARATOR; - $this->assertEquals($expected, set_realpath(getcwd())); + { + $this->assertEquals(getcwd().DIRECTORY_SEPARATOR, set_realpath(getcwd())); } public function test_set_realpath_nonexistent_directory() diff --git a/tests/codeigniter/helpers/security_helper_test.php b/tests/codeigniter/helpers/security_helper_test.php new file mode 100644 index 000000000..effd3ec02 --- /dev/null +++ b/tests/codeigniter/helpers/security_helper_test.php @@ -0,0 +1,64 @@ +<?php + +class Security_helper_tests extends CI_TestCase { + + function setUp() + { + $this->helper('security'); + $obj = new stdClass; + $obj->security = new Mock_Core_Security(); + $this->ci_instance($obj); + } + + function test_xss_clean() + { + $this->assertEquals('foo', xss_clean('foo')); + + $this->assertEquals("Hello, i try to [removed]alert('Hack');[removed] your site", xss_clean("Hello, i try to <script>alert('Hack');</script> your site")); + } + + function test_sanitize_filename() + { + $this->assertEquals('hello.doc', sanitize_filename('hello.doc')); + + $filename = './<!--foo-->'; + $this->assertEquals('foo', sanitize_filename($filename)); + } + + function test_do_hash() + { + $md5 = md5('foo'); + $sha1 = sha1('foo'); + + $algos = hash_algos(); + $algo_results = array(); + foreach ($algos as $k => $v) + { + $algo_results[$v] = hash($v, 'foo'); + } + + $this->assertEquals($sha1, do_hash('foo')); + $this->assertEquals($sha1, do_hash('foo', 'sha1')); + $this->assertEquals($md5, do_hash('foo', 'md5')); + $this->assertEquals($md5, do_hash('foo', 'foobar')); + + // Test each algorithm available to PHP + foreach ($algo_results as $algo => $result) + { + $this->assertEquals($result, do_hash('foo', $algo)); + } + } + + function test_strip_image_tags() + { + $this->assertEquals('http://example.com/spacer.gif', strip_image_tags('http://example.com/spacer.gif')); + + $this->assertEquals('http://example.com/spacer.gif', strip_image_tags('<img src="http://example.com/spacer.gif" alt="Who needs CSS when you have a spacer.gif?" />')); + } + + function test_encode_php_tags() + { + $this->assertEquals('<? echo $foo; ?>', encode_php_tags('<? echo $foo; ?>')); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/helpers/string_helper_test.php b/tests/codeigniter/helpers/string_helper_test.php index 29c3d6594..75701ec13 100644 --- a/tests/codeigniter/helpers/string_helper_test.php +++ b/tests/codeigniter/helpers/string_helper_test.php @@ -10,18 +10,18 @@ class String_helper_test extends CI_TestCase { public function test_strip_slashes() { $expected = array( - "Is your name O'reilly?", + "Is your name O'reilly?", "No, my name is O'connor." ); - + $str = array( "Is your name O\'reilly?", "No, my name is O\'connor." ); - + $this->assertEquals($expected, strip_slashes($str)); } - + public function test_trim_slashes() { $strs = array( @@ -144,4 +144,5 @@ class String_helper_test extends CI_TestCase { $this->assertEquals('file-1', increment_string('file', '-', '1')); $this->assertEquals(124, increment_string('123', '')); } + }
\ No newline at end of file diff --git a/tests/codeigniter/helpers/text_helper_test.php b/tests/codeigniter/helpers/text_helper_test.php index 584066b0c..d75d26208 100644 --- a/tests/codeigniter/helpers/text_helper_test.php +++ b/tests/codeigniter/helpers/text_helper_test.php @@ -3,16 +3,16 @@ class Text_helper_test extends CI_TestCase { private $_long_string; - + public function set_up() { $this->helper('text'); - + $this->_long_string = 'Once upon a time, a framework had no tests. It sad. So some nice people began to write tests. The more time that went on, the happier it became. Everyone was happy.'; } - + // ------------------------------------------------------------------------ - + public function test_word_limiter() { $this->assertEquals('Once upon a time,…', word_limiter($this->_long_string, 4)); @@ -20,8 +20,8 @@ class Text_helper_test extends CI_TestCase { $this->assertEquals('', word_limiter('', 4)); } - // ------------------------------------------------------------------------ - + // ------------------------------------------------------------------------ + public function test_character_limiter() { $this->assertEquals('Once upon a time, a…', character_limiter($this->_long_string, 20)); @@ -30,22 +30,22 @@ class Text_helper_test extends CI_TestCase { $this->assertEquals('Short', character_limiter('Short', 5)); } - // ------------------------------------------------------------------------ - + // ------------------------------------------------------------------------ + public function test_ascii_to_entities() { $strs = array( '“‘ “test”' => '“‘ “test”', '†¥¨ˆøåß∂ƒ©˙∆˚¬' => '†¥¨ˆøåß∂ƒ©˙∆˚¬' ); - + foreach ($strs as $str => $expect) { $this->assertEquals($expect, ascii_to_entities($str)); } } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------ public function test_entities_to_ascii() { @@ -53,27 +53,28 @@ class Text_helper_test extends CI_TestCase { '“‘ “test”' => '“‘ “test”', '†¥¨ˆøåß∂ƒ©˙∆˚¬' => '†¥¨ˆøåß∂ƒ©˙∆˚¬' ); - + foreach ($strs as $str => $expect) { $this->assertEquals($expect, entities_to_ascii($str)); - } + } } - - // ------------------------------------------------------------------------ - - function test_convert_accented_characters() + + // ------------------------------------------------------------------------ + + public function test_convert_accented_characters() { + $this->ci_vfs_clone('application/config/foreign_chars.php'); $this->assertEquals('AAAeEEEIIOOEUUUeY', convert_accented_characters('ÀÂÄÈÊËÎÏÔŒÙÛÜŸ')); $this->assertEquals('a e i o u n ue', convert_accented_characters('á é í ó ú ñ ü')); } - // ------------------------------------------------------------------------ - + // ------------------------------------------------------------------------ + public function test_censored_words() { $censored = array('boob', 'nerd', 'ass', 'fart'); - + $strs = array( 'Ted bobbled the ball' => 'Ted bobbled the ball', 'Jake is a nerdo' => 'Jake is a nerdo', @@ -81,28 +82,26 @@ class Text_helper_test extends CI_TestCase { 'Did Mary Fart?' => 'Did Mary $*#?', 'Jake is really a boob' => 'Jake is really a $*#' ); - - + foreach ($strs as $str => $expect) { $this->assertEquals($expect, word_censor($str, $censored, '$*#')); } - + // test censored words being sent as a string $this->assertEquals('test', word_censor('test', 'test')); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------ public function test_highlight_code() { - $code = '<?php var_dump($this); ?>'; $expect = "<code><span style=\"color: #000000\">\n<span style=\"color: #0000BB\"><?php var_dump</span><span style=\"color: #007700\">(</span><span style=\"color: #0000BB\">\$this</span><span style=\"color: #007700\">); </span><span style=\"color: #0000BB\">?> </span>\n</span>\n</code>"; - $this->assertEquals($expect, highlight_code($code)); + $this->assertEquals($expect, highlight_code('<?php var_dump($this); ?>')); } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------ public function test_highlight_phrase() { @@ -113,16 +112,16 @@ class Text_helper_test extends CI_TestCase { 'Or tell me what this is' => 'Or tell me what <strong>this is</strong>', '' => '' ); - + foreach ($strs as $str => $expect) { $this->assertEquals($expect, highlight_phrase($str, 'this is')); } } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------ - public function test_ellipsizing() + public function test_ellipsize() { $strs = array( '0' => array( @@ -144,16 +143,30 @@ class Text_helper_test extends CI_TestCase { 'short' => 'short' ), ); - + foreach ($strs as $pos => $s) { foreach ($s as $str => $expect) { - $this->assertEquals($expect, ellipsize($str, 10, $pos)); + $this->assertEquals($expect, ellipsize($str, 10, $pos)); } } } - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------ + + public function test_word_wrap() + { + $string = 'Here is a simple string of text that will help us demonstrate this function.'; + $this->assertEquals(substr_count(word_wrap($string, 25), "\n"), 4); + } + + // ------------------------------------------------------------------------ + + public function test_default_word_wrap_charlim() + { + $string = "Here is a longer string of text that will help us demonstrate the default charlim of this function."; + $this->assertEquals(strpos(word_wrap($string), "\n"), 73); + } }
\ No newline at end of file diff --git a/tests/codeigniter/helpers/url_helper_test.php b/tests/codeigniter/helpers/url_helper_test.php index c561809ce..5fc364238 100644 --- a/tests/codeigniter/helpers/url_helper_test.php +++ b/tests/codeigniter/helpers/url_helper_test.php @@ -51,6 +51,8 @@ class Url_helper_test extends CI_TestCase { 'www.codeigniter.com test' => '<a href="http://www.codeigniter.com">http://www.codeigniter.com</a> test', 'This is my noreply@codeigniter.com test' => 'This is my noreply@codeigniter.com test', '<br />www.google.com' => '<br /><a href="http://www.google.com">http://www.google.com</a>', + 'Download CodeIgniter at www.codeigniter.com. Period test.' => 'Download CodeIgniter at <a href="http://www.codeigniter.com">http://www.codeigniter.com</a>. Period test.', + 'Download CodeIgniter at www.codeigniter.com, comma test' => 'Download CodeIgniter at <a href="http://www.codeigniter.com">http://www.codeigniter.com</a>, comma test' ); foreach ($strings as $in => $out) @@ -72,4 +74,5 @@ class Url_helper_test extends CI_TestCase { $this->assertEquals($out, auto_link($in, 'url')); } } + }
\ No newline at end of file diff --git a/tests/codeigniter/helpers/xml_helper_test.php b/tests/codeigniter/helpers/xml_helper_test.php index a83fef91e..e8cf411da 100644 --- a/tests/codeigniter/helpers/xml_helper_test.php +++ b/tests/codeigniter/helpers/xml_helper_test.php @@ -6,10 +6,10 @@ class Xml_helper_test extends CI_TestCase { { $this->helper('xml'); } - + public function test_xml_convert() { $this->assertEquals('<tag>my & test - </tag>', xml_convert('<tag>my & test - </tag>')); } - + }
\ No newline at end of file diff --git a/tests/codeigniter/libraries/Calendar_test.php b/tests/codeigniter/libraries/Calendar_test.php new file mode 100644 index 000000000..95668d70d --- /dev/null +++ b/tests/codeigniter/libraries/Calendar_test.php @@ -0,0 +1,204 @@ +<?php + +class Calendar_test extends CI_TestCase { + + function __construct() + { + $obj = new stdClass; + $obj->calendar = new Mock_Libraries_Calendar(); + + $this->calendar = $obj->calendar; + } + + function test_initialize() + { + $this->calendar->initialize(array( + 'month_type' => 'short', + 'start_day' => 'monday' + )); + $this->assertEquals('short', $this->calendar->month_type); + $this->assertEquals('monday', $this->calendar->start_day); + } + + /** + * @covers Mock_Libraries_Calendar::parse_template + */ + function test_generate() + { + $no_events = '<table border="0" cellpadding="4" cellspacing="0"> + +<tr> +<th colspan="7">September 2011</th> + +</tr> + +<tr> +<td>Su</td><td>Mo</td><td>Tu</td><td>We</td><td>Th</td><td>Fr</td><td>Sa</td> +</tr> + +<tr> +<td> </td><td> </td><td> </td><td> </td><td>1</td><td>2</td><td>3</td> +</tr> + +<tr> +<td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td> +</tr> + +<tr> +<td>11</td><td>12</td><td>13</td><td>14</td><td>15</td><td>16</td><td>17</td> +</tr> + +<tr> +<td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td><td>24</td> +</tr> + +<tr> +<td>25</td><td>26</td><td>27</td><td>28</td><td>29</td><td>30</td><td> </td> +</tr> + +</table>'; + + $this->assertEquals($no_events, $this->calendar->generate(2011, 9)); + + $data = array( + 3 => 'http://example.com/news/article/2006/03/', + 7 => 'http://example.com/news/article/2006/07/', + 13 => 'http://example.com/news/article/2006/13/', + 26 => 'http://example.com/news/article/2006/26/' + ); + + $events = '<table border="0" cellpadding="4" cellspacing="0"> + +<tr> +<th colspan="7">September 2011</th> + +</tr> + +<tr> +<td>Su</td><td>Mo</td><td>Tu</td><td>We</td><td>Th</td><td>Fr</td><td>Sa</td> +</tr> + +<tr> +<td> </td><td> </td><td> </td><td> </td><td>1</td><td>2</td><td><a href="http://example.com/news/article/2006/03/">3</a></td> +</tr> + +<tr> +<td>4</td><td>5</td><td>6</td><td><a href="http://example.com/news/article/2006/07/">7</a></td><td>8</td><td>9</td><td>10</td> +</tr> + +<tr> +<td>11</td><td>12</td><td><a href="http://example.com/news/article/2006/13/">13</a></td><td>14</td><td>15</td><td>16</td><td>17</td> +</tr> + +<tr> +<td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td><td>24</td> +</tr> + +<tr> +<td>25</td><td><a href="http://example.com/news/article/2006/26/">26</a></td><td>27</td><td>28</td><td>29</td><td>30</td><td> </td> +</tr> + +</table>'; + + $this->assertEquals($events, $this->calendar->generate(2011, 9, $data)); + } + + function test_get_month_name() + { + $this->calendar->month_type = NULL; + $this->assertEquals('January', $this->calendar->get_month_name('01')); + + $this->calendar->month_type = 'short'; + $this->assertEquals('Jan', $this->calendar->get_month_name('01')); + } + + function test_get_day_names() + { + $this->assertEquals(array( + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday' + ), $this->calendar->get_day_names('long')); + + $this->assertEquals(array( + 'Sun', + 'Mon', + 'Tue', + 'Wed', + 'Thu', + 'Fri', + 'Sat' + ), $this->calendar->get_day_names('short')); + + $this->calendar->day_type = NULL; + + $this->assertEquals(array( + 'Su', + 'Mo', + 'Tu', + 'We', + 'Th', + 'Fr', + 'Sa' + ), $this->calendar->get_day_names()); + } + + function test_adjust_date() + { + $this->assertEquals(array('month' => 8, 'year' => 2012), $this->calendar->adjust_date(8, 2012)); + $this->assertEquals(array('month' => 1, 'year' => 2013), $this->calendar->adjust_date(13, 2012)); + } + + function test_get_total_days() + { + $this->assertEquals(0, $this->calendar->get_total_days(13, 2012)); + + $this->assertEquals(31, $this->calendar->get_total_days(1, 2012)); + $this->assertEquals(28, $this->calendar->get_total_days(2, 2011)); + $this->assertEquals(29, $this->calendar->get_total_days(2, 2012)); + $this->assertEquals(31, $this->calendar->get_total_days(3, 2012)); + $this->assertEquals(30, $this->calendar->get_total_days(4, 2012)); + $this->assertEquals(31, $this->calendar->get_total_days(5, 2012)); + $this->assertEquals(30, $this->calendar->get_total_days(6, 2012)); + $this->assertEquals(31, $this->calendar->get_total_days(7, 2012)); + $this->assertEquals(31, $this->calendar->get_total_days(8, 2012)); + $this->assertEquals(30, $this->calendar->get_total_days(9, 2012)); + $this->assertEquals(31, $this->calendar->get_total_days(10, 2012)); + $this->assertEquals(30, $this->calendar->get_total_days(11, 2012)); + $this->assertEquals(31, $this->calendar->get_total_days(12, 2012)); + } + + function test_default_template() + { + $array = array( + 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">', + 'heading_row_start' => '<tr>', + 'heading_previous_cell' => '<th><a href="{previous_url}"><<</a></th>', + 'heading_title_cell' => '<th colspan="{colspan}">{heading}</th>', + 'heading_next_cell' => '<th><a href="{next_url}">>></a></th>', + 'heading_row_end' => '</tr>', + 'week_row_start' => '<tr>', + 'week_day_cell' => '<td>{week_day}</td>', + 'week_row_end' => '</tr>', + 'cal_row_start' => '<tr>', + 'cal_cell_start' => '<td>', + 'cal_cell_start_today' => '<td>', + 'cal_cell_content' => '<a href="{content}">{day}</a>', + 'cal_cell_content_today' => '<a href="{content}"><strong>{day}</strong></a>', + 'cal_cell_no_content' => '{day}', + 'cal_cell_no_content_today' => '<strong>{day}</strong>', + 'cal_cell_blank' => ' ', + 'cal_cell_end' => '</td>', + 'cal_cell_end_today' => '</td>', + 'cal_row_end' => '</tr>', + 'table_close' => '</table>' + ); + + $this->assertEquals($array, $this->calendar->default_template()); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/libraries/Encrypt_test.php b/tests/codeigniter/libraries/Encrypt_test.php new file mode 100644 index 000000000..21ac85f03 --- /dev/null +++ b/tests/codeigniter/libraries/Encrypt_test.php @@ -0,0 +1,94 @@ +<?php + +class Encrypt_test extends CI_TestCase { + + public function set_up() + { + $this->encrypt = new Mock_Libraries_Encrypt(); + $this->ci_instance_var('encrypt', $this->encrypt); + + $this->ci_set_config('encryption_key', "Encryptin'glike@boss!"); + $this->msg = 'My secret message'; + $this->mcrypt = extension_loaded('mcrypt'); + } + + // -------------------------------------------------------------------- + + public function test_encode() + { + $this->assertNotEquals($this->msg, $this->encrypt->encode($this->msg)); + } + + // -------------------------------------------------------------------- + + public function test_decode() + { + $encoded_msg = $this->encrypt->encode($this->msg); + $this->assertEquals($this->msg, $this->encrypt->decode($encoded_msg)); + } + + // -------------------------------------------------------------------- + + public function test_optional_key() + { + $key = 'Ohai!ù0129°03182%HD1892P0'; + $encoded_msg = $this->encrypt->encode($this->msg, $key); + $this->assertEquals($this->msg, $this->encrypt->decode($encoded_msg, $key)); + } + + // -------------------------------------------------------------------- + + public function test_default_cipher() + { + if ( ! $this->mcrypt) + { + $this->markTestSkipped('MCrypt not available'); + return; + } + + $this->assertEquals('rijndael-256', $this->encrypt->get_cipher()); + } + + // -------------------------------------------------------------------- + + + public function test_set_cipher() + { + if ( ! $this->mcrypt) + { + $this->markTestSkipped('MCrypt not available'); + return; + } + + $this->encrypt->set_cipher(MCRYPT_BLOWFISH); + $this->assertEquals('blowfish', $this->encrypt->get_cipher()); + } + + // -------------------------------------------------------------------- + + public function test_default_mode() + { + if ( ! $this->mcrypt) + { + $this->markTestSkipped('MCrypt not available'); + return; + } + + $this->assertEquals('cbc', $this->encrypt->get_mode()); + } + + // -------------------------------------------------------------------- + + public function test_set_mode() + { + if ( ! $this->mcrypt) + { + $this->markTestSkipped('MCrypt not available'); + return; + } + + $this->encrypt->set_mode(MCRYPT_MODE_CFB); + $this->assertEquals('cfb', $this->encrypt->get_mode()); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/libraries/Parser_test.php b/tests/codeigniter/libraries/Parser_test.php index c3d88fa85..394c22692 100644 --- a/tests/codeigniter/libraries/Parser_test.php +++ b/tests/codeigniter/libraries/Parser_test.php @@ -1,73 +1,70 @@ <?php class Parser_test extends CI_TestCase { - + public function set_up() { - $obj = new StdClass; - $obj->parser = new Mock_Libraries_Parser(); - - $this->ci_instance($obj); - - $this->parser = $obj->parser; + $this->parser = new Mock_Libraries_Parser(); + $this->ci_instance_var('parser', $this->parser); } + // -------------------------------------------------------------------- - + public function test_set_delimiters() { // Make sure default delimiters are there $this->assertEquals('{', $this->parser->l_delim); $this->assertEquals('}', $this->parser->r_delim); - + // Change them to square brackets $this->parser->set_delimiters('[', ']'); - + // Make sure they changed $this->assertEquals('[', $this->parser->l_delim); $this->assertEquals(']', $this->parser->r_delim); - + // Reset them $this->parser->set_delimiters(); - + // Make sure default delimiters are there $this->assertEquals('{', $this->parser->l_delim); $this->assertEquals('}', $this->parser->r_delim); } - + // -------------------------------------------------------------------- - + public function test_parse_simple_string() { $data = array( 'title' => 'Page Title', 'body' => 'Lorem ipsum dolor sit amet.' ); - + $template = "{title}\n{body}"; - + $result = implode("\n", $data); - + $this->assertEquals($result, $this->parser->parse_string($template, $data, TRUE)); } - + // -------------------------------------------------------------------- - + public function test_parse() { $this->_parse_no_template(); $this->_parse_var_pair(); $this->_mismatched_var_pair(); } - + // -------------------------------------------------------------------- - + private function _parse_no_template() { $this->assertFalse($this->parser->parse_string('', '', TRUE)); } - + // -------------------------------------------------------------------- - + private function _parse_var_pair() { $data = array( @@ -78,16 +75,14 @@ class Parser_test extends CI_TestCase { 'flying' => 'no'), ) ); - + $template = "{title}\n{powers}{invisibility}\n{flying}{/powers}"; - - $result = "Super Heroes\nyes\nno"; - - $this->assertEquals($result, $this->parser->parse_string($template, $data, TRUE)); + + $this->assertEquals("Super Heroes\nyes\nno", $this->parser->parse_string($template, $data, TRUE)); } - + // -------------------------------------------------------------------- - + private function _mismatched_var_pair() { $data = array( @@ -98,13 +93,11 @@ class Parser_test extends CI_TestCase { 'flying' => 'no'), ) ); - + $template = "{title}\n{powers}{invisibility}\n{flying}"; - $result = "Super Heroes\n{powers}{invisibility}\n{flying}"; - - $this->assertEquals($result, $this->parser->parse_string($template, $data, TRUE)); + + $this->assertEquals($result, $this->parser->parse_string($template, $data, TRUE)); } - // -------------------------------------------------------------------- }
\ No newline at end of file diff --git a/tests/codeigniter/libraries/Session_test.php b/tests/codeigniter/libraries/Session_test.php new file mode 100644 index 000000000..14469f7fa --- /dev/null +++ b/tests/codeigniter/libraries/Session_test.php @@ -0,0 +1,402 @@ +<?php + +/** + * Session driver library unit test + */ +class Session_test extends CI_TestCase { + protected $settings = array( + 'use_cookies' => 0, + 'use_only_cookies' => 0, + 'cache_limiter' => false + ); + protected $setting_vals = array(); + protected $cookie_vals; + protected $session; + + /** + * Set up test framework + */ + public function set_up() + { + // Override settings + foreach ($this->settings as $name => $value) { + $this->setting_vals[$name] = ini_get('session.'.$name); + ini_set('session.'.$name, $value); + } + + // Start with clean environment + $this->cookie_vals = $_COOKIE; + $_COOKIE = array(); + + // Establish necessary support classes + $cfg = $this->ci_core_class('cfg'); + $ldr = $this->ci_core_class('load'); + $ci = $this->ci_instance(); + $ci->config = new $cfg(); + $ci->load = new $ldr(); + $ci->input = new Mock_Core_Input(NULL, NULL); + + // Make sure string helper is available + $this->ci_vfs_clone('system/helpers/string_helper.php'); + + // Attach session instance locally + $config = array( + 'sess_encrypt_cookie' => FALSE, + 'sess_use_database' => FALSE, + 'sess_table_name' => '', + 'sess_expiration' => 7200, + 'sess_expire_on_close' => FALSE, + 'sess_match_ip' => FALSE, + 'sess_match_useragent' => TRUE, + 'sess_cookie_name' => 'ci_session', + 'cookie_path' => '', + 'cookie_domain' => '', + 'cookie_secure' => FALSE, + 'cookie_httponly' => FALSE, + 'sess_time_to_update' => 300, + 'time_reference' => 'local', + 'cookie_prefix' => '', + 'encryption_key' => 'foobar', + 'sess_valid_drivers' => array( + 'Mock_Libraries_Session_native', + 'Mock_Libraries_Session_cookie' + ) + ); + $this->session = new Mock_Libraries_Session($config); + } + + /** + * Tear down test framework + */ + public function tear_down() + { + // Restore environment + if (session_id()) session_destroy(); + $_SESSION = array(); + $_COOKIE = $this->cookie_vals; + + // Restore settings + foreach ($this->settings as $name => $value) { + ini_set('session.'.$name, $this->setting_vals[$name]); + } + } + + /** + * Test set_userdata() function + * + * @covers CI_Session::set_userdata + * @covers CI_Session::userdata + */ + public function test_set_userdata() + { + // Set userdata values for each driver + $key1 = 'test1'; + $ckey2 = 'test2'; + $nkey2 = 'test3'; + $cmsg1 = 'Some test data'; + $cmsg2 = 42; + $nmsg1 = 'Other test data'; + $nmsg2 = true; + $this->session->cookie->set_userdata($key1, $cmsg1); + $this->session->set_userdata($ckey2, $cmsg2); + $this->session->native->set_userdata($key1, $nmsg1); + $this->session->set_userdata($nkey2, $nmsg2); + + // Verify independent messages + $this->assertEquals($cmsg1, $this->session->cookie->userdata($key1)); + $this->assertEquals($nmsg1, $this->session->native->userdata($key1)); + + // Verify pre-selected driver sets + $this->assertEquals($cmsg2, $this->session->cookie->userdata($ckey2)); + $this->assertEquals($nmsg2, $this->session->native->userdata($nkey2)); + + // Verify no crossover + $this->assertNull($this->session->cookie->userdata($nkey2)); + $this->assertNull($this->session->native->userdata($ckey2)); + } + + /** + * Test the has_userdata() function + * + * @covers CI_Session::has_userdata + */ + public function test_has_userdata() + { + // Set a userdata value for each driver + $key = 'hastest'; + $cmsg = 'My test data'; + $this->session->cookie->set_userdata($key, $cmsg); + $nmsg = 'Your test data'; + $this->session->native->set_userdata($key, $nmsg); + + // Verify values exist + $this->assertTrue($this->session->cookie->has_userdata($key)); + $this->assertTrue($this->session->native->has_userdata($key)); + + // Verify non-existent values + $nokey = 'hasnot'; + $this->assertFalse($this->session->cookie->has_userdata($nokey)); + $this->assertFalse($this->session->native->has_userdata($nokey)); + } + + /** + * Test the all_userdata() function + * + * @covers CI_Session::all_userdata + */ + public function test_all_userdata() + { + // Set a specific series of data for each driver + $cdata = array( + 'one' => 'first', + 'two' => 'second', + 'three' => 'third', + 'foo' => 'bar', + 'bar' => 'baz' + ); + $ndata = array( + 'one' => 'gold', + 'two' => 'silver', + 'three' => 'bronze', + 'foo' => 'baz', + 'bar' => 'foo' + ); + $this->session->cookie->set_userdata($cdata); + $this->session->native->set_userdata($ndata); + + // Make sure all values are present + $call = $this->session->cookie->all_userdata(); + foreach ($cdata as $key => $value) { + $this->assertEquals($value, $call[$key]); + } + $nall = $this->session->native->all_userdata(); + foreach ($ndata as $key => $value) { + $this->assertEquals($value, $nall[$key]); + } + } + + /** + * Test the unset_userdata() function + * + * @covers CI_Session::unset_userdata + */ + public function test_unset_userdata() + { + // Set a userdata message for each driver + $key = 'untest'; + $cmsg = 'Other test data'; + $this->session->cookie->set_userdata($key, $cmsg); + $nmsg = 'Sundry test data'; + $this->session->native->set_userdata($key, $nmsg); + + // Verify independent messages + $this->assertEquals($this->session->cookie->userdata($key), $cmsg); + $this->assertEquals($this->session->native->userdata($key), $nmsg); + + // Unset them and verify absence + $this->session->cookie->unset_userdata($key); + $this->session->native->unset_userdata($key); + $this->assertNull($this->session->cookie->userdata($key)); + $this->assertNull($this->session->native->userdata($key)); + } + + /** + * Test the flashdata() functions + * + * @covers CI_Session::set_flashdata + * @covers CI_Session::flashdata + */ + public function test_flashdata() + { + // Set flashdata message for each driver + $key = 'fltest'; + $cmsg = 'Some flash data'; + $this->session->cookie->set_flashdata($key, $cmsg); + $nmsg = 'Other flash data'; + $this->session->native->set_flashdata($key, $nmsg); + + // Simulate page reload + $this->session->cookie->reload(); + $this->session->native->reload(); + + // Verify independent messages + $this->assertEquals($cmsg, $this->session->cookie->flashdata($key)); + $this->assertEquals($nmsg, $this->session->native->flashdata($key)); + + // Simulate next page reload + $this->session->cookie->reload(); + $this->session->native->reload(); + + // Verify absence of messages + $this->assertNull($this->session->cookie->flashdata($key)); + $this->assertNull($this->session->native->flashdata($key)); + } + + /** + * Test the keep_flashdata() function + * + * @covers CI_Session::keep_flashdata + */ + public function test_keep_flashdata() + { + // Set flashdata message for each driver + $key = 'kfltest'; + $cmsg = 'My flash data'; + $this->session->cookie->set_flashdata($key, $cmsg); + $nmsg = 'Your flash data'; + $this->session->native->set_flashdata($key, $nmsg); + + // Simulate page reload and verify independent messages + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertEquals($cmsg, $this->session->cookie->flashdata($key)); + $this->assertEquals($nmsg, $this->session->native->flashdata($key)); + + // Keep messages + $this->session->cookie->keep_flashdata($key); + $this->session->native->keep_flashdata($key); + + // Simulate next page reload and verify message persistence + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertEquals($cmsg, $this->session->cookie->flashdata($key)); + $this->assertEquals($nmsg, $this->session->native->flashdata($key)); + + // Simulate next page reload and verify absence of messages + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertNull($this->session->cookie->flashdata($key)); + $this->assertNull($this->session->native->flashdata($key)); + } + + /** + * Test the all_flashdata() function + * + * @covers CI_Session::all_flashdata + */ + public function test_all_flashdata() + { + // Set a specific series of data for each driver + $cdata = array( + 'one' => 'first', + 'two' => 'second', + 'three' => 'third', + 'foo' => 'bar', + 'bar' => 'baz' + ); + $ndata = array( + 'one' => 'gold', + 'two' => 'silver', + 'three' => 'bronze', + 'foo' => 'baz', + 'bar' => 'foo' + ); + $this->session->cookie->set_flashdata($cdata); + $this->session->native->set_flashdata($ndata); + + // Simulate page reload and make sure all values are present + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertEquals($cdata, $this->session->cookie->all_flashdata()); + $this->assertEquals($ndata, $this->session->native->all_flashdata()); + } + + /** + * Test the tempdata() functions + * + * @covers CI_Session::set_tempdata + * @covers CI_Session::tempdata + */ + public function test_set_tempdata() + { + // Set tempdata message for each driver - 1 second timeout + $key = 'tmptest'; + $cmsg = 'Some temp data'; + $this->session->cookie->set_tempdata($key, $cmsg, 1); + $nmsg = 'Other temp data'; + $this->session->native->set_tempdata($key, $nmsg, 1); + + // Simulate page reload and verify independent messages + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertEquals($cmsg, $this->session->cookie->tempdata($key)); + $this->assertEquals($nmsg, $this->session->native->tempdata($key)); + + // Wait 2 seconds, simulate page reload and verify message absence + sleep(2); + $this->session->cookie->reload(); + $this->session->native->reload(); + $this->assertNull($this->session->cookie->tempdata($key)); + $this->assertNull($this->session->native->tempdata($key)); + } + + /** + * Test the unset_tempdata() function + * + * @covers CI_Session::unset_tempdata + */ + public function test_unset_tempdata() + { + // Set tempdata message for each driver - 1 second timeout + $key = 'utmptest'; + $cmsg = 'My temp data'; + $this->session->cookie->set_tempdata($key, $cmsg, 1); + $nmsg = 'Your temp data'; + $this->session->native->set_tempdata($key, $nmsg, 1); + + // Verify independent messages + $this->assertEquals($cmsg, $this->session->cookie->tempdata($key)); + $this->assertEquals($nmsg, $this->session->native->tempdata($key)); + + // Unset data and verify message absence + $this->session->cookie->unset_tempdata($key); + $this->session->native->unset_tempdata($key); + $this->assertNull($this->session->cookie->tempdata($key)); + $this->assertNull($this->session->native->tempdata($key)); + } + + /** + * Test the sess_regenerate() function + * + * @covers CI_Session::sess_regenerate + */ + public function test_sess_regenerate() + { + // Get current session id, regenerate, and compare + // Cookie driver + $oldid = $this->session->cookie->userdata('session_id'); + $this->session->cookie->sess_regenerate(); + $newid = $this->session->cookie->userdata('session_id'); + $this->assertNotEquals($oldid, $newid); + + // Native driver - bug #55267 (https://bugs.php.net/bug.php?id=55267) prevents testing this + // $oldid = session_id(); + // $this->session->native->sess_regenerate(); + // $oldid = session_id(); + // $this->assertNotEquals($oldid, $newid); + } + + /** + * Test the sess_destroy() function + * + * @covers CI_Session::sess_destroy + */ + public function test_sess_destroy() + { + // Set a userdata message, destroy session, and verify absence + $key = 'dsttest'; + $msg = 'More test data'; + + // Cookie driver + $this->session->cookie->set_userdata($key, $msg); + $this->assertEquals($msg, $this->session->cookie->userdata($key)); + $this->session->cookie->sess_destroy(); + $this->assertNull($this->session->cookie->userdata($key)); + + // Native driver + $this->session->native->set_userdata($key, $msg); + $this->assertEquals($msg, $this->session->native->userdata($key)); + $this->session->native->sess_destroy(); + $this->assertNull($this->session->native->userdata($key)); + } +}
\ No newline at end of file diff --git a/tests/codeigniter/libraries/Table_test.php b/tests/codeigniter/libraries/Table_test.php index 13f338c6b..ce04b6a6d 100644 --- a/tests/codeigniter/libraries/Table_test.php +++ b/tests/codeigniter/libraries/Table_test.php @@ -4,43 +4,35 @@ class Table_test extends CI_TestCase { public function set_up() { - $obj = new StdClass; - $obj->table = new Mock_Libraries_Table(); - - $this->ci_instance($obj); - - $this->table = $obj->table; + $this->table = new Mock_Libraries_Table(); + $this->ci_instance_var('table', $this->table); } - // Setter Methods // -------------------------------------------------------------------- - + public function test_set_template() { $this->assertFalse($this->table->set_template('not an array')); - - $template = array( - 'a' => 'b' - ); - + + $template = array('a' => 'b'); + $this->table->set_template($template); $this->assertEquals($template, $this->table->template); } - + public function test_set_empty() { $this->table->set_empty('nada'); $this->assertEquals('nada', $this->table->empty_cells); } - + public function test_set_caption() { $this->table->set_caption('awesome cap'); $this->assertEquals('awesome cap', $this->table->caption); } - - + /* * @depends testPrepArgs */ @@ -49,9 +41,9 @@ class Table_test extends CI_TestCase { // uses _prep_args internally, so we'll just do a quick // check to verify that func_get_args and prep_args are // being called. - + $this->table->set_heading('name', 'color', 'size'); - + $this->assertEquals( array( array('data' => 'name'), @@ -61,8 +53,7 @@ class Table_test extends CI_TestCase { $this->table->heading ); } - - + /* * @depends testPrepArgs */ @@ -71,13 +62,13 @@ class Table_test extends CI_TestCase { // uses _prep_args internally, so we'll just do a quick // check to verify that func_get_args and prep_args are // being called. - + $this->table->add_row('my', 'pony', 'sings'); $this->table->add_row('your', 'pony', 'stinks'); $this->table->add_row('my pony', '>', 'your pony'); - + $this->assertEquals(count($this->table->rows), 3); - + $this->assertEquals( array( array('data' => 'your'), @@ -87,11 +78,10 @@ class Table_test extends CI_TestCase { $this->table->rows[1] ); } - - + // Uility Methods // -------------------------------------------------------------------- - + public function test_prep_args() { $expected = array( @@ -99,7 +89,7 @@ class Table_test extends CI_TestCase { array('data' => 'color'), array('data' => 'size') ); - + $this->assertEquals( $expected, $this->table->prep_args(array('name', 'color', 'size')) @@ -114,7 +104,7 @@ class Table_test extends CI_TestCase { $this->table->prep_args(array('name', 'color', 'size', array('data' => 'weight', 'class' => 'awesome'))) ); } - + public function test_default_template_keys() { $keys = array( @@ -126,132 +116,124 @@ class Table_test extends CI_TestCase { 'row_alt_start', 'row_alt_end', 'cell_alt_start', 'cell_alt_end', 'table_close' ); - + foreach ($keys as $key) { $this->assertArrayHasKey($key, $this->table->default_template()); } } - + public function test_compile_template() { $this->assertFalse($this->table->set_template('invalid_junk')); - + // non default key $this->table->set_template(array('nonsense' => 'foo')); $this->table->compile_template(); - + $this->assertArrayHasKey('nonsense', $this->table->template); $this->assertEquals('foo', $this->table->template['nonsense']); - + // override default $this->table->set_template(array('table_close' => '</table junk>')); $this->table->compile_template(); - + $this->assertArrayHasKey('table_close', $this->table->template); $this->assertEquals('</table junk>', $this->table->template['table_close']); } - + public function test_make_columns() { // Test bogus parameters $this->assertFalse($this->table->make_columns('invalid_junk')); $this->assertFalse($this->table->make_columns(array())); $this->assertFalse($this->table->make_columns(array('one', 'two'), '2.5')); - - + // Now on to the actual column creation - + $five_values = array( 'Laura', 'Red', '15', 'Katie', 'Blue' ); - + // No column count - no changes to the array $this->assertEquals( $five_values, $this->table->make_columns($five_values) ); - + // Column count of 3 leaves us with one $this->assertEquals( array( array('Laura', 'Red', '15'), - array('Katie', 'Blue', ' ') + array('Katie', 'Blue', ' ') ), $this->table->make_columns($five_values, 3) ); } - + public function test_clear() { $this->table->set_heading('Name', 'Color', 'Size'); - + // Make columns changes auto_heading $rows = $this->table->make_columns(array( 'Laura', 'Red', '15', 'Katie', 'Blue' ), 3); - + foreach ($rows as $row) { $this->table->add_row($row); } - + $this->assertFalse($this->table->auto_heading); $this->assertEquals(count($this->table->heading), 3); $this->assertEquals(count($this->table->rows), 2); - + $this->table->clear(); - + $this->assertTrue($this->table->auto_heading); $this->assertEmpty($this->table->heading); $this->assertEmpty($this->table->rows); } - - + public function test_set_from_array() { $this->assertFalse($this->table->set_from_array('bogus')); $this->assertFalse($this->table->set_from_array(NULL)); - + $data = array( array('name', 'color', 'number'), array('Laura', 'Red', '22'), - array('Katie', 'Blue') + array('Katie', 'Blue') ); - + $this->table->set_from_array($data, FALSE); $this->assertEmpty($this->table->heading); - + $this->table->clear(); - - $expected_heading = array( + + $this->table->set_from_array($data); + $this->assertEquals(count($this->table->rows), 2); + + $expected = array( array('data' => 'name'), array('data' => 'color'), array('data' => 'number') ); - - $expected_second = array( + + $this->assertEquals($expected, $this->table->heading); + + $expected = array( array('data' => 'Katie'), array('data' => 'Blue'), ); - - $this->table->set_from_array($data); - $this->assertEquals(count($this->table->rows), 2); - - $this->assertEquals( - $expected_heading, - $this->table->heading - ); - - $this->assertEquals( - $expected_second, - $this->table->rows[1] - ); + + $this->assertEquals($expected, $this->table->rows[1]); } - - function test_set_from_object() + + public function test_set_from_object() { // Make a stub of query instance $query = new CI_TestCase(); @@ -268,29 +250,44 @@ class Table_test extends CI_TestCase { return 2; }; - $expected_heading = array( + $this->table->set_from_object($query); + + $expected = array( array('data' => 'name'), array('data' => 'email') ); - $expected_second = array( + $this->assertEquals($expected, $this->table->heading); + + $expected = array( 'name' => array('data' => 'Foo Bar'), 'email' => array('data' => 'foo@bar.com'), ); - $this->table->set_from_object($query); + $this->assertEquals($expected, $this->table->rows[1]); + } - $this->assertEquals( - $expected_heading, - $this->table->heading - ); - - $this->assertEquals( - $expected_second, - $this->table->rows[1] + public function test_generate() + { + // Prepare the data + $data = array( + array('Name', 'Color', 'Size'), + array('Fred', 'Blue', 'Small'), + array('Mary', 'Red', 'Large'), + array('John', 'Green', 'Medium') ); + + $table = $this->table->generate($data); + + // Test the table header + $this->assertTrue(strpos($table, '<th>Name</th>') !== FALSE); + $this->assertTrue(strpos($table, '<th>Color</th>') !== FALSE); + $this->assertTrue(strpos($table, '<th>Size</th>') !== FALSE); + + // Test the first entry + $this->assertTrue(strpos($table, '<td>Fred</td>') !== FALSE); + $this->assertTrue(strpos($table, '<td>Blue</td>') !== FALSE); + $this->assertTrue(strpos($table, '<td>Small</td>') !== FALSE); } - - // Test main generate method - // -------------------------------------------------------------------- + }
\ No newline at end of file diff --git a/tests/codeigniter/libraries/Typography_test.php b/tests/codeigniter/libraries/Typography_test.php index 250aefb24..5dba06243 100644 --- a/tests/codeigniter/libraries/Typography_test.php +++ b/tests/codeigniter/libraries/Typography_test.php @@ -4,12 +4,8 @@ class Typography_test extends CI_TestCase { public function set_up() { - $obj = new StdClass; - $obj->type = new Mock_Libraries_Typography(); - - $this->ci_instance($obj); - - $this->type = $obj->type; + $this->type = new Mock_Libraries_Typography(); + $this->ci_instance('type', $this->type); } // -------------------------------------------------------------------- @@ -33,18 +29,18 @@ class Typography_test extends CI_TestCase { 'foo..' => 'foo..', 'foo...bar.' => 'foo…bar.', 'test. new' => 'test. new', - ); - + ); + foreach ($strs as $str => $expected) { - $this->assertEquals($expected, $this->type->format_characters($str)); + $this->assertEquals($expected, $this->type->format_characters($str)); } } // -------------------------------------------------------------------- public function test_nl2br_except_pre() - { + { $str = <<<EOH Hello, I'm a happy string with some new lines. @@ -85,12 +81,11 @@ That's my story and I'm sticking to it.<br /> The End. EOH; - $this->assertEquals($expected, - $this->type->nl2br_except_pre($str)); + $this->assertEquals($expected, $this->type->nl2br_except_pre($str)); } // -------------------------------------------------------------------- - + public function test_auto_typography() { $this->_blank_string(); @@ -103,7 +98,7 @@ EOH; } // -------------------------------------------------------------------- - + private function _blank_string() { // Test blank string @@ -131,7 +126,7 @@ EOH; { $str = "This has way too many linebreaks.\n\n\n\nSee?"; $expect = "<p>This has way too many linebreaks.</p>\n\n<p>See?</p>"; - + $this->assertEquals($expect, $this->type->auto_typography($str, TRUE)); } @@ -141,7 +136,7 @@ EOH; { $str = '<!-- I can haz comments? --> But no!'; $expect = '<p><!-- I can haz comments? --> But no!</p>'; - + $this->assertEquals($expect, $this->type->auto_typography($str)); } @@ -151,7 +146,7 @@ EOH; { $str = '<p>My Sentence</p><pre>var_dump($this);</pre>'; $expect = '<p>My Sentence</p><pre>var_dump($this);</pre>'; - + $this->assertEquals($expect, $this->type->auto_typography($str)); } @@ -161,7 +156,7 @@ EOH; { $str = 'My Sentence<pre>var_dump($this);</pre>'; $expect = '<p>My Sentence</p><pre>var_dump($this);</pre>'; - + $this->assertEquals($expect, $this->type->auto_typography($str)); } @@ -170,19 +165,18 @@ EOH; public function _protect_braced_quotes() { $this->type->protect_braced_quotes = TRUE; - + $str = 'Test {parse="foobar"}'; $expect = '<p>Test {parse="foobar"}</p>'; - + $this->assertEquals($expect, $this->type->auto_typography($str)); $this->type->protect_braced_quotes = FALSE; - + $str = 'Test {parse="foobar"}'; $expect = '<p>Test {parse=“foobar”}</p>'; - - $this->assertEquals($expect, $this->type->auto_typography($str)); - + $this->assertEquals($expect, $this->type->auto_typography($str)); } + }
\ No newline at end of file diff --git a/tests/codeigniter/libraries/Upload_test.php b/tests/codeigniter/libraries/Upload_test.php new file mode 100644 index 000000000..546cebc59 --- /dev/null +++ b/tests/codeigniter/libraries/Upload_test.php @@ -0,0 +1,273 @@ +<?php + +class Upload_test extends CI_TestCase { + + function set_up() + { + $ci = $this->ci_instance(); + $ci->upload = new Mock_Libraries_Upload(); + $ci->security = new Mock_Core_Security(); + $ci->lang = new Mock_Core_Lang(); + $this->upload = $ci->upload; + } + + function test_do_upload() + { + $this->markTestSkipped('We can\'t really test this at the moment because of the call to `is_uploaded_file` in do_upload which isn\'t supported by vfsStream'); + } + + function test_data() + { + $data = array( + 'file_name' => 'hello.txt', + 'file_type' => 'text/plain', + 'file_path' => '/tmp/', + 'full_path' => '/tmp/hello.txt', + 'raw_name' => 'hello', + 'orig_name' => 'hello.txt', + 'client_name' => '', + 'file_ext' => '.txt', + 'file_size' => 100, + 'is_image' => FALSE, + 'image_width' => '', + 'image_height' => '', + 'image_type' => '', + 'image_size_str' => '' + ); + + $this->upload->set_upload_path('/tmp/'); + + foreach ($data as $k => $v) + { + $this->upload->{$k} = $v; + } + + $this->assertEquals('hello.txt', $this->upload->data('file_name')); + $this->assertEquals($data, $this->upload->data()); + } + + function test_set_upload_path() + { + $this->upload->set_upload_path('/tmp/'); + $this->assertEquals('/tmp/', $this->upload->upload_path); + + $this->upload->set_upload_path('/tmp'); + $this->assertEquals('/tmp/', $this->upload->upload_path); + } + + function test_set_filename() + { + $dir = 'uploads'; + $isnew = 'helloworld.txt'; + $exists = 'hello-world.txt'; + $this->ci_vfs_create($exists, 'Hello world.', $this->ci_app_root, $dir); + $path = $this->ci_vfs_path($dir.'/', APPPATH); + $this->upload->file_ext = '.txt'; + + $this->assertEquals($isnew, $this->upload->set_filename($path, $isnew)); + $this->assertEquals('hello-world1.txt', $this->upload->set_filename($path, $exists)); + } + + function test_set_max_filesize() + { + $this->upload->set_max_filesize(100); + $this->assertEquals(100, $this->upload->max_size); + } + + function test_set_max_filename() + { + $this->upload->set_max_filename(100); + $this->assertEquals(100, $this->upload->max_filename); + } + + function test_set_max_width() + { + $this->upload->set_max_width(100); + $this->assertEquals(100, $this->upload->max_width); + } + + function test_set_max_height() + { + $this->upload->set_max_height(100); + $this->assertEquals(100, $this->upload->max_height); + } + + function test_set_allowed_types() + { + $this->upload->set_allowed_types('*'); + $this->assertEquals('*', $this->upload->allowed_types); + + $this->upload->set_allowed_types('foo|bar'); + $this->assertEquals(array('foo', 'bar'), $this->upload->allowed_types); + } + + function test_set_image_properties() + { + $this->upload->file_type = 'image/gif'; + $this->upload->file_temp = realpath(PROJECT_BASE.'tests/mocks/uploads/ci_logo.gif'); + + $props = array( + 'image_width' => 170, + 'image_height' => 73, + 'image_type' => 'gif', + 'image_size_str' => 'width="170" height="73"' + ); + + $this->upload->set_image_properties($this->upload->file_temp); + + $this->assertEquals($props['image_width'], $this->upload->image_width); + $this->assertEquals($props['image_height'], $this->upload->image_height); + $this->assertEquals($props['image_type'], $this->upload->image_type); + $this->assertEquals($props['image_size_str'], $this->upload->image_size_str); + } + + function test_set_xss_clean() + { + $this->upload->set_xss_clean(TRUE); + $this->assertTrue($this->upload->xss_clean); + + $this->upload->set_xss_clean(FALSE); + $this->assertFalse($this->upload->xss_clean); + } + + function test_is_image() + { + $this->upload->file_type = 'image/x-png'; + $this->assertTrue($this->upload->is_image()); + + $this->upload->file_type = 'text/plain'; + $this->assertFalse($this->upload->is_image()); + } + + function test_is_allowed_filetype() + { + $this->upload->allowed_types = array('html', 'gif'); + + $this->upload->file_ext = '.txt'; + $this->upload->file_type = 'text/plain'; + $this->assertFalse($this->upload->is_allowed_filetype(FALSE)); + $this->assertFalse($this->upload->is_allowed_filetype(TRUE)); + + $this->upload->file_ext = '.html'; + $this->upload->file_type = 'text/html'; + $this->assertTrue($this->upload->is_allowed_filetype(FALSE)); + $this->assertTrue($this->upload->is_allowed_filetype(TRUE)); + + $this->upload->file_temp = realpath(PROJECT_BASE.'tests/mocks/uploads/ci_logo.gif'); + $this->upload->file_ext = '.gif'; + $this->upload->file_type = 'image/gif'; + $this->assertTrue($this->upload->is_allowed_filetype()); + } + + function test_is_allowed_filesize() + { + $this->upload->max_size = 100; + $this->upload->file_size = 99; + + $this->assertTrue($this->upload->is_allowed_filesize()); + + $this->upload->file_size = 101; + $this->assertFalse($this->upload->is_allowed_filesize()); + } + + function test_is_allowed_dimensions() + { + $this->upload->file_type = 'text/plain'; + $this->assertTrue($this->upload->is_allowed_dimensions()); + + $this->upload->file_type = 'image/gif'; + $this->upload->file_temp = realpath(PROJECT_BASE.'tests/mocks/uploads/ci_logo.gif'); + + $this->upload->max_width = 10; + $this->assertFalse($this->upload->is_allowed_dimensions()); + + $this->upload->max_width = 170; + $this->upload->max_height = 10; + $this->assertFalse($this->upload->is_allowed_dimensions()); + + $this->upload->max_height = 73; + $this->assertTrue($this->upload->is_allowed_dimensions()); + } + + function test_validate_upload_path() + { + $this->upload->upload_path = ''; + $this->assertFalse($this->upload->validate_upload_path()); + + $dir = 'uploads'; + $this->ci_vfs_mkdir($dir); + $this->upload->upload_path = $this->ci_vfs_path($dir); + $this->assertTrue($this->upload->validate_upload_path()); + } + + function test_get_extension() + { + $this->assertEquals('.txt', $this->upload->get_extension('hello.txt')); + $this->assertEquals('.htaccess', $this->upload->get_extension('.htaccess')); + $this->assertEquals('', $this->upload->get_extension('hello')); + } + + function test_clean_file_name() + { + $this->assertEquals('hello.txt', $this->upload->clean_file_name('hello.txt')); + $this->assertEquals('hello.txt', $this->upload->clean_file_name('%253chell>o.txt')); + } + + function test_limit_filename_length() + { + $this->assertEquals('hello.txt', $this->upload->limit_filename_length('hello.txt', 10)); + $this->assertEquals('hello.txt', $this->upload->limit_filename_length('hello-world.txt', 9)); + } + + function test_do_xss_clean() + { + $dir = 'uploads'; + $file1 = 'file1.txt'; + $file2 = 'file2.txt'; + $file3 = 'file3.txt'; + $this->ci_vfs_create($file1, 'The billy goat was waiting for them.', $this->ci_vfs_root, $dir); + $this->ci_vfs_create($file2, '', $this->ci_vfs_root, $dir); + $this->ci_vfs_create($file3, '<script type="text/javascript">alert("Boo! said the billy goat")</script>', $this->ci_vfs_root, $dir); + + $this->upload->file_temp = $this->ci_vfs_path($file1, $dir); + $this->assertTrue($this->upload->do_xss_clean()); + + $this->upload->file_temp = $this->ci_vfs_path($file2, $dir); + $this->assertFalse($this->upload->do_xss_clean()); + + $this->upload->file_temp = $this->ci_vfs_path($file3, $dir); + $this->assertFalse($this->upload->do_xss_clean()); + + $this->upload->file_temp = realpath(PROJECT_BASE.'tests/mocks/uploads/ci_logo.gif'); + $this->assertTrue($this->upload->do_xss_clean()); + } + + function test_set_error() + { + $errors = array( + 'An error!' + ); + + $another = 'Another error!'; + + $this->upload->set_error($errors); + $this->assertEquals($errors, $this->upload->error_msg); + + $errors[] = $another; + $this->upload->set_error($another); + $this->assertEquals($errors, $this->upload->error_msg); + } + + function test_display_errors() + { + $this->upload->error_msg[] = 'Error test'; + $this->assertEquals('<p>Error test</p>', $this->upload->display_errors()); + } + + function test_mimes_types() + { + $this->assertEquals('text/plain', $this->upload->mimes_types('txt')); + $this->assertFalse($this->upload->mimes_types('foobar')); + } + +}
\ No newline at end of file diff --git a/tests/codeigniter/libraries/Useragent_test.php b/tests/codeigniter/libraries/Useragent_test.php index 7dad7ac54..e3726554e 100644 --- a/tests/codeigniter/libraries/Useragent_test.php +++ b/tests/codeigniter/libraries/Useragent_test.php @@ -1,7 +1,7 @@ <?php class UserAgent_test extends CI_TestCase { - + protected $_user_agent = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27'; protected $_mobile_ua = 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7'; @@ -10,12 +10,11 @@ class UserAgent_test extends CI_TestCase { // set a baseline user agent $_SERVER['HTTP_USER_AGENT'] = $this->_user_agent; - $obj = new StdClass; - $obj->agent = new Mock_Libraries_UserAgent(); + $this->ci_vfs_clone('application/config/user_agents.php'); - $this->ci_instance($obj); + $this->agent = new Mock_Libraries_UserAgent(); - $this->agent = $obj->agent; + $this->ci_instance_var('agent', $this->agent); } // -------------------------------------------------------------------- @@ -82,6 +81,4 @@ class UserAgent_test extends CI_TestCase { $this->assertFalse($this->agent->accept_charset()); } - // -------------------------------------------------------------------- - }
\ No newline at end of file diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php index dd5929206..3d216da1f 100644 --- a/tests/mocks/autoloader.php +++ b/tests/mocks/autoloader.php @@ -6,73 +6,104 @@ // // Prototype : // -// include_once('Mock_Core_Loader') // Will load ./mocks/core/loader.php // $mock_table = new Mock_Libraries_Table(); // Will load ./mocks/libraries/table.php -// $mock_database_driver = new Mock_Database_Driver(); // Will load ./mocks/database/driver.php +// $mock_database_driver = new Mock_Database_Driver(); // Will load ./mocks/database/driver.php // and so on... -function autoload($class) +function autoload($class) { $dir = realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR; $ci_core = array( 'Benchmark', 'Config', 'Controller', 'Exceptions', 'Hooks', 'Input', - 'Lang', 'Loader', 'Model', + 'Lang', 'Loader', 'Log', 'Model', 'Output', 'Router', 'Security', 'URI', 'Utf8', ); $ci_libraries = array( - 'Calendar', 'Cart', 'Driver', + 'Calendar', 'Cart', 'Driver_Library', 'Email', 'Encrypt', 'Form_validation', 'Ftp', 'Image_lib', 'Javascript', - 'Log', 'Migration', 'Pagination', - 'Parser', 'Profiler', 'Session', - 'Table', 'Trackback', 'Typography', - 'Unit_test', 'Upload', 'User_agent', - 'Xmlrpc', 'Zip', + 'Migration', 'Pagination', 'Parser', + 'Profiler', 'Table', 'Trackback', + 'Typography', 'Unit_test', 'Upload', + 'User_agent', 'Xmlrpc', 'Zip' + ); + + $ci_drivers = array( + 'Session', ); if (strpos($class, 'Mock_') === 0) { - $class = str_replace(array('Mock_', '_'), array('', DIRECTORY_SEPARATOR), $class); - $class = strtolower($class); + $class = strtolower(str_replace(array('Mock_', '_'), array('', DIRECTORY_SEPARATOR), $class)); } elseif (strpos($class, 'CI_') === 0) { - $fragments = explode('_', $class, 2); - $subclass = next($fragments); + $subclass = substr($class, 3); if (in_array($subclass, $ci_core)) { - $dir = BASEPATH.'core'.DIRECTORY_SEPARATOR; + $dir = SYSTEM_PATH.'core'.DIRECTORY_SEPARATOR; $class = $subclass; } elseif (in_array($subclass, $ci_libraries)) { - $dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR; + $dir = SYSTEM_PATH.'libraries'.DIRECTORY_SEPARATOR; + $class = ($subclass === 'Driver_Library') ? 'Driver' : $subclass; + } + elseif (in_array($subclass, $ci_drivers)) + { + $dir = SYSTEM_PATH.'libraries'.DIRECTORY_SEPARATOR.$subclass.DIRECTORY_SEPARATOR; $class = $subclass; } + elseif (in_array(($parent = strtok($subclass, '_')), $ci_drivers)) { + $dir = SYSTEM_PATH.'libraries'.DIRECTORY_SEPARATOR.$parent.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR; + $class = $subclass; + } + elseif (preg_match('/^CI_DB_(.+)_(.+)_(driver|forge|result|utility)$/', $class, $m) && count($m) === 4) + { + $driver_path = SYSTEM_PATH.'database'.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR; + $dir = $driver_path.$m[1].DIRECTORY_SEPARATOR.'subdrivers'.DIRECTORY_SEPARATOR; + $file = $dir.$m[1].'_'.$m[2].'_'.$m[3].'.php'; + } + elseif (preg_match('/^CI_DB_(.+)_(driver|forge|result|utility)$/', $class, $m) && count($m) === 3) + { + $driver_path = SYSTEM_PATH.'database'.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR; + $dir = $driver_path.$m[1].DIRECTORY_SEPARATOR; + $file = $dir.$m[1].'_'.$m[2].'.php'; + } + elseif (strpos($class, 'CI_DB') === 0) + { + $dir = SYSTEM_PATH.'database'.DIRECTORY_SEPARATOR; + $file = $dir.str_replace(array('CI_DB','active_record'), array('DB', 'active_rec'), $subclass).'.php'; + } else { $class = strtolower($class); } } - $file = $dir.$class.'.php'; + $file = isset($file) ? $file : $dir.$class.'.php'; if ( ! file_exists($file)) { $trace = debug_backtrace(); - // If the autoload call came from `class_exists` or `file_exists`, - // we skipped and return FALSE - if ($trace[2]['function'] == 'class_exists' OR $trace[2]['function'] == 'file_exists') + if ($trace[2]['function'] === 'class_exists' OR $trace[2]['function'] === 'file_exists') + { + // If the autoload call came from `class_exists` or `file_exists`, + // we skipped and return FALSE + return FALSE; + } + elseif (($autoloader = spl_autoload_functions()) && end($autoloader) !== __FUNCTION__) { + // If there was other custom autoloader, passed away return FALSE; } - throw new InvalidArgumentException("Unable to load $class."); + throw new InvalidArgumentException("Unable to load {$class}."); } include_once($file); diff --git a/tests/mocks/ci_testcase.php b/tests/mocks/ci_testcase.php index f327e6b07..f16492945 100644 --- a/tests/mocks/ci_testcase.php +++ b/tests/mocks/ci_testcase.php @@ -1,11 +1,13 @@ <?php class CI_TestCase extends PHPUnit_Framework_TestCase { - - protected $ci_config; + + public $ci_vfs_root; + public $ci_app_root; + public $ci_base_root; protected $ci_instance; protected static $ci_test_instance; - + private $global_map = array( 'benchmark' => 'bm', 'config' => 'cfg', @@ -19,29 +21,34 @@ class CI_TestCase extends PHPUnit_Framework_TestCase { 'loader' => 'load', 'model' => 'model' ); - + // -------------------------------------------------------------------- - + public function __construct() { parent::__construct(); - - $this->ci_config = array(); + $this->ci_instance = new StdClass(); } - + // -------------------------------------------------------------------- - + public function setUp() { + // Setup VFS with base directories + $this->ci_vfs_root = vfsStream::setup(); + $this->ci_app_root = vfsStream::newDirectory('application')->at($this->ci_vfs_root); + $this->ci_base_root = vfsStream::newDirectory('system')->at($this->ci_vfs_root); + $this->ci_view_root = vfsStream::newDirectory('views')->at($this->ci_app_root); + if (method_exists($this, 'set_up')) { $this->set_up(); } } - + // -------------------------------------------------------------------- - - public function tearDown() + + public function tearDown() { if (method_exists($this, 'tear_down')) { @@ -50,57 +57,69 @@ class CI_TestCase extends PHPUnit_Framework_TestCase { } // -------------------------------------------------------------------- - + public static function instance() { return self::$ci_test_instance; } - + // -------------------------------------------------------------------- - - function ci_set_config($key, $val = '') + + public function ci_set_config($key = '', $val = '') { + // Add test config + if ( ! isset($this->ci_instance->config)) + { + $this->ci_instance->config = new CI_TestConfig(); + } + + // Empty key means just do setup above + if ($key === '') + { + return; + } + if (is_array($key)) { - $this->ci_config = $key; + $this->ci_instance->config->config = $key; } else { - $this->ci_config[$key] = $val; + $this->ci_instance->config->config[$key] = $val; } } // -------------------------------------------------------------------- - - function ci_get_config() + + public function ci_get_config() { - return $this->ci_config; + return isset($this->ci_instance->config) ? $this->ci_instance->config->config : array(); } - + // -------------------------------------------------------------------- - - function ci_instance($obj = FALSE) + + public function ci_instance($obj = FALSE) { if ( ! is_object($obj)) { return $this->ci_instance; } - + $this->ci_instance = $obj; } - + // -------------------------------------------------------------------- - - function ci_instance_var($name, $obj = FALSE) + + public function ci_instance_var($name, $obj = FALSE) { if ( ! is_object($obj)) { return $this->ci_instance->$name; } - + $this->ci_instance->$name =& $obj; } - + // -------------------------------------------------------------------- /** @@ -112,10 +131,10 @@ class CI_TestCase extends PHPUnit_Framework_TestCase { * test can modify the variable it assigns to and * still maintain the global. */ - function &ci_core_class($name) + public function &ci_core_class($name) { $name = strtolower($name); - + if (isset($this->global_map[$name])) { $class_name = ucfirst($name); @@ -130,29 +149,188 @@ class CI_TestCase extends PHPUnit_Framework_TestCase { { throw new Exception('Not a valid core class.'); } - + if ( ! class_exists('CI_'.$class_name)) { - require_once BASEPATH.'core/'.$class_name.'.php'; + require_once SYSTEM_PATH.'core/'.$class_name.'.php'; } - + $GLOBALS[strtoupper($global_name)] = 'CI_'.$class_name; return $GLOBALS[strtoupper($global_name)]; } - + // -------------------------------------------------------------------- - + // convenience function for global mocks - function ci_set_core_class($name, $obj) + public function ci_set_core_class($name, $obj) { $orig =& $this->ci_core_class($name); $orig = $obj; } - + + /** + * Create VFS directory + * + * @param string Directory name + * @param object Optional root to create in + * @return object New directory object + */ + public function ci_vfs_mkdir($name, $root = NULL) + { + // Check for root + if ( ! $root) + { + $root = $this->ci_vfs_root; + } + + // Return new directory object + return vfsStream::newDirectory($name)->at($root); + } + + // -------------------------------------------------------------------- + + /** + * Create VFS content + * + * @param string File name + * @param string File content + * @param object VFS directory object + * @param mixed Optional subdirectory path or array of subs + * @return void + */ + public function ci_vfs_create($file, $content = '', $root = NULL, $path = NULL) + { + // Check for array + if (is_array($file)) + { + foreach ($file as $name => $content) + { + $this->ci_vfs_create($name, $content, $root, $path); + } + return; + } + + // Assert .php extension if none given + if (pathinfo($file, PATHINFO_EXTENSION) == '') + { + $file .= '.php'; + } + + // Build content + $tree = array($file => $content); + + // Check for path + $subs = array(); + if ($path) + { + // Explode if not array + $subs = is_array($path) ? $path : explode('/', trim($path, '/')); + } + + // Check for root + if ( ! $root) + { + // Use base VFS root + $root = $this->ci_vfs_root; + } + + // Handle subdirectories + while (($dir = array_shift($subs))) + { + // See if subdir exists under current root + $dir_root = $root->getChild($dir); + if ($dir_root) + { + // Yes - recurse into subdir + $root = $dir_root; + } + else + { + // No - put subdirectory back and quit + array_unshift($subs, $dir); + break; + } + } + + // Create any remaining subdirectories + if ($subs) + { + foreach (array_reverse($subs) as $dir) + { + // Wrap content in subdirectory for creation + $tree = array($dir => $tree); + } + } + + // Create tree + vfsStream::create($tree, $root); + } + + // -------------------------------------------------------------------- + + /** + * Clone a real file into VFS + * + * @param string Path from base directory + * @return bool TRUE on success, otherwise FALSE + */ + public function ci_vfs_clone($path) + { + // Check for array + if (is_array($path)) + { + foreach ($path as $file) + { + $this->ci_vfs_clone($file); + } + return; + } + + // Get real file contents + $content = file_get_contents(PROJECT_BASE.$path); + if ($content === FALSE) + { + // Couldn't find file to clone + return FALSE; + } + + $this->ci_vfs_create(basename($path), $content, NULL, dirname($path)); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Helper to get a VFS URL path + * + * @param string Path + * @param string Optional base path + * @return string Path URL + */ + public function ci_vfs_path($path, $base = '') + { + // Check for base path + if ($base) + { + // Prepend to path + $path = rtrim($base, '/').'/'.ltrim($path, '/'); + + // Is it already in URL form? + if (strpos($path, '://') !== FALSE) + { + // Done - return path + return $path; + } + } + + // Trim leading slash and return URL + return vfsStream::url(ltrim($path, '/')); + } + // -------------------------------------------------------------------- // Internals // -------------------------------------------------------------------- - + /** * Overwrite runBare * @@ -169,28 +347,35 @@ class CI_TestCase extends PHPUnit_Framework_TestCase { } // -------------------------------------------------------------------- - - function helper($name) + + public function helper($name) { - require_once(BASEPATH.'helpers/'.$name.'_helper.php'); + require_once(SYSTEM_PATH.'helpers/'.$name.'_helper.php'); } // -------------------------------------------------------------------- - + + public function lang($name) + { + require(SYSTEM_PATH.'language/english/'.$name.'_lang.php'); + return $lang; + } + + // -------------------------------------------------------------------- + /** * This overload is useful to create a stub, that need to have a specific method. */ - function __call($method, $args) + public function __call($method, $args) { - if ($this->{$method} instanceof Closure) + if ($this->{$method} instanceof Closure) { return call_user_func_array($this->{$method},$args); - } - else + } + else { return parent::__call($method, $args); } } -} -// EOF
\ No newline at end of file +}
\ No newline at end of file diff --git a/tests/mocks/ci_testconfig.php b/tests/mocks/ci_testconfig.php new file mode 100644 index 000000000..0c52bb984 --- /dev/null +++ b/tests/mocks/ci_testconfig.php @@ -0,0 +1,20 @@ +<?php + +class CI_TestConfig { + + public $config = array(); + public $_config_paths = array(APPPATH); + public $loaded = array(); + + public function item($key) + { + return isset($this->config[$key]) ? $this->config[$key] : FALSE; + } + + public function load($file, $arg2 = FALSE, $arg3 = FALSE) + { + $this->loaded[] = $file; + return TRUE; + } + +} diff --git a/tests/mocks/core/benchmark.php b/tests/mocks/core/benchmark.php new file mode 100644 index 000000000..d92be21db --- /dev/null +++ b/tests/mocks/core/benchmark.php @@ -0,0 +1,3 @@ +<?php + +class Mock_Core_Benchmark extends CI_Benchmark {}
\ No newline at end of file diff --git a/tests/mocks/core/common.php b/tests/mocks/core/common.php index fc94d7fff..9289b2716 100644 --- a/tests/mocks/core/common.php +++ b/tests/mocks/core/common.php @@ -2,53 +2,89 @@ // Set up the global CI functions in their most minimal core representation -function &get_instance() +if ( ! function_exists('get_instance')) { - $test = CI_TestCase::instance(); - $instance = $test->ci_instance(); - return $instance; + function &get_instance() + { + $test = CI_TestCase::instance(); + $test = $test->ci_instance(); + return $test; + } } // -------------------------------------------------------------------- -function &get_config() { - $test = CI_TestCase::instance(); - $config = $test->ci_get_config(); - - return $config; +if ( ! function_exists('get_config')) +{ + function &get_config() + { + $test = CI_TestCase::instance(); + $config = $test->ci_get_config(); + return $config; + } } -function config_item($item) +if ( ! function_exists('config_item')) { - $config =& get_config(); - - if ( ! isset($config[$item])) + function config_item($item) { - return FALSE; + $config =& get_config(); + + if ( ! isset($config[$item])) + { + return FALSE; + } + + return $config[$item]; } - - return $config[$item]; } -// -------------------------------------------------------------------- - -function load_class($class, $directory = 'libraries', $prefix = 'CI_') +if ( ! function_exists('get_mimes')) { - if ($directory != 'core' OR $prefix != 'CI_') + /** + * Returns the MIME types array from config/mimes.php + * + * @return array + */ + function &get_mimes() { - throw new Exception('Not Implemented: Non-core load_class()'); + static $_mimes = array(); + + if (empty($_mimes)) + { + $path = realpath(PROJECT_BASE.'application/config/mimes.php'); + if (is_file($path)) + { + $_mimes = include($path); + } + } + + return $_mimes; } - - $test = CI_TestCase::instance(); - - $obj =& $test->ci_core_class($class); - - if (is_string($obj)) +} + +// -------------------------------------------------------------------- + +if ( ! function_exists('load_class')) +{ + function load_class($class, $directory = 'libraries', $prefix = 'CI_') { - throw new Exception('Bad Isolation: Use ci_set_core_class to set '.$class.''); + if ($directory !== 'core' OR $prefix !== 'CI_') + { + throw new Exception('Not Implemented: Non-core load_class()'); + } + + $test = CI_TestCase::instance(); + + $obj =& $test->ci_core_class($class); + + if (is_string($obj)) + { + throw new Exception('Bad Isolation: Use ci_set_core_class to set '.$class); + } + + return $obj; } - - return $obj; } // This is sort of meh. Should probably be mocked up with @@ -57,76 +93,102 @@ function load_class($class, $directory = 'libraries', $prefix = 'CI_') // bootstrap testsuite. // -------------------------------------------------------------------- -function remove_invisible_characters($str, $url_encoded = TRUE) +if ( ! function_exists('remove_invisible_characters')) { - $non_displayables = array(); - - // every control character except newline (dec 10) - // carriage return (dec 13), and horizontal tab (dec 09) - - if ($url_encoded) + function remove_invisible_characters($str, $url_encoded = TRUE) { - $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 + $non_displayables = array(); - do - { - $str = preg_replace($non_displayables, '', $str, -1, $count); - } - while ($count); + // 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 + } - return $str; + $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; + } } // Clean up error messages // -------------------------------------------------------------------- -function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered') +if ( ! function_exists('show_error')) { - throw new RuntimeException('CI Error: '.$message); + function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered') + { + throw new RuntimeException('CI Error: '.$message); + } } -function show_404($page = '', $log_error = TRUE) +if ( ! function_exists('show_404')) { - throw new RuntimeException('CI Error: 404'); + function show_404($page = '', $log_error = TRUE) + { + throw new RuntimeException('CI Error: 404'); + } } -function _exception_handler($severity, $message, $filepath, $line) +if ( ! function_exists('_exception_handler')) { - throw new RuntimeException('CI Exception: '.$message.' | '.$filepath.' | '.$line); + function _exception_handler($severity, $message, $filepath, $line) + { + throw new RuntimeException('CI Exception: '.$message.' | '.$filepath.' | '.$line); + } } // We assume a few things about our environment ... // -------------------------------------------------------------------- -function is_php($version = '5.0.0') +if ( ! function_exists('is_php')) { - return ! (version_compare(PHP_VERSION, $version) < 0); + function is_php($version = '5.0.0') + { + return ! (version_compare(PHP_VERSION, $version) < 0); + } } -function is_really_writable($file) +if ( ! function_exists('is_really_writable')) { - return is_writable($file); + function is_really_writable($file) + { + return is_writable($file); + } } -function is_loaded() +if ( ! function_exists('is_loaded')) { - throw new Exception('Bad Isolation: mock up environment'); + function &is_loaded() + { + $loaded = array(); + return $loaded; + } } -function log_message($level = 'error', $message, $php_error = FALSE) +if ( ! function_exists('log_message')) { - return TRUE; + function log_message($level = 'error', $message, $php_error = FALSE) + { + return TRUE; + } } -function set_status_header($code = 200, $text = '') +if ( ! function_exists('set_status_header')) { - return TRUE; -} - -// EOF
\ No newline at end of file + function set_status_header($code = 200, $text = '') + { + return TRUE; + } +}
\ No newline at end of file diff --git a/tests/mocks/core/input.php b/tests/mocks/core/input.php new file mode 100644 index 000000000..0d1873849 --- /dev/null +++ b/tests/mocks/core/input.php @@ -0,0 +1,41 @@ +<?php + +class Mock_Core_Input extends CI_Input { + + /** + * Since we use GLOBAL to fetch Security and Utf8 classes, + * we need to use inversion of control to mock up + * the same process within CI_Input class constructor. + * + * @covers CI_Input::__construct() + */ + public function __construct($security, $utf8) + { + $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); + + // Assign Security and Utf8 classes + $this->security = $security; + $this->uni = $utf8; + + // Sanitize global arrays + $this->_sanitize_globals(); + } + + public function fetch_from_array($array, $index = '', $xss_clean = FALSE) + { + return parent::_fetch_from_array($array, $index, $xss_clean); + } + + /** + * Lie about being a CLI request + * + * We take advantage of this in libraries/Session_test + */ + public function is_cli_request() + { + return FALSE; + } + +}
\ No newline at end of file diff --git a/tests/mocks/core/lang.php b/tests/mocks/core/lang.php new file mode 100644 index 000000000..27ea3faba --- /dev/null +++ b/tests/mocks/core/lang.php @@ -0,0 +1,15 @@ +<?php + +class Mock_Core_Lang extends CI_Lang { + + public function line($line = '') + { + return FALSE; + } + + public function load($langfile, $idiom = '', $return = FALSE, $add_suffix = TRUE, $alt_path = '') + { + return; + } + +}
\ No newline at end of file diff --git a/tests/mocks/core/loader.php b/tests/mocks/core/loader.php deleted file mode 100644 index d4b29bb3d..000000000 --- a/tests/mocks/core/loader.php +++ /dev/null @@ -1,30 +0,0 @@ -<?php - -class Mock_Core_Loader extends CI_Loader { - - /** - * Since we use paths to load up models, views, etc, we need the ability to - * mock up the file system so when core tests are run, we aren't mucking - * in the application directory. this will give finer grained control over - * these tests. So yeah, while this looks odd, I need to overwrite protected - * class vars in the loader. So here we go... - * - * @covers CI_Loader::__construct() - */ - public function __construct() - { - vfsStreamWrapper::register(); - vfsStreamWrapper::setRoot(new vfsStreamDirectory('application')); - - $this->models_dir = vfsStream::newDirectory('models')->at(vfsStreamWrapper::getRoot()); - $this->libs_dir = vfsStream::newDirectory('libraries')->at(vfsStreamWrapper::getRoot()); - $this->helpers_dir = vfsStream::newDirectory('helpers')->at(vfsStreamWrapper::getRoot()); - $this->views_dir = vfsStream::newDirectory('views')->at(vfsStreamWrapper::getRoot()); - - $this->_ci_ob_level = ob_get_level(); - $this->_ci_library_paths = array(vfsStream::url('application').'/', BASEPATH); - $this->_ci_helper_paths = array(vfsStream::url('application').'/', BASEPATH); - $this->_ci_model_paths = array(vfsStream::url('application').'/'); - $this->_ci_view_paths = array(vfsStream::url('application').'/views/' => TRUE); - } -}
\ No newline at end of file diff --git a/tests/mocks/core/security.php b/tests/mocks/core/security.php new file mode 100644 index 000000000..e19a8b20b --- /dev/null +++ b/tests/mocks/core/security.php @@ -0,0 +1,30 @@ +<?php + +class Mock_Core_Security extends CI_Security { + + public function csrf_set_cookie() + { + // We cannot set cookie in CLI mode, so for csrf test, who rely on $_COOKIE, + // we superseded set_cookie with directly set the cookie variable, + // @see : ./tests/codeigniter/core/Security_test.php, line 8 + return $this; + } + + // Overide inaccesible protected properties + public function __get($property) + { + return isset($this->{'_'.$property}) ? $this->{'_'.$property} : NULL; + } + + // Overide inaccesible protected method + public function __call($method, $params) + { + if (is_callable(array($this, '_'.$method))) + { + return call_user_func_array(array($this, '_'.$method), $params); + } + + throw new BadMethodCallException('Method '.$method.' was not found'); + } + +}
\ No newline at end of file diff --git a/tests/mocks/core/uri.php b/tests/mocks/core/uri.php index b6946091e..94f75df64 100644 --- a/tests/mocks/core/uri.php +++ b/tests/mocks/core/uri.php @@ -1,12 +1,12 @@ <?php class Mock_Core_URI extends CI_URI { - + public function __construct() { $test = CI_TestCase::instance(); $cls =& $test->ci_core_class('cfg'); - + // set predictable config values $test->ci_set_config(array( 'index_page' => 'index.php', @@ -14,12 +14,13 @@ class Mock_Core_URI extends CI_URI { 'subclass_prefix' => 'MY_' )); - $this->config = new $cls; + $this->config = new $cls; } - + protected function _is_cli_request() { return FALSE; } + }
\ No newline at end of file diff --git a/tests/mocks/core/utf8.php b/tests/mocks/core/utf8.php new file mode 100644 index 000000000..068e74ac1 --- /dev/null +++ b/tests/mocks/core/utf8.php @@ -0,0 +1,26 @@ +<?php + +class Mock_Core_Utf8 extends CI_Utf8 { + + /** + * We need to define several constants as + * the same process within CI_Utf8 class constructor. + * + * @covers CI_Utf8::__construct() + */ + public function __construct() + { + defined('UTF8_ENABLED') OR define('UTF8_ENABLED', TRUE); + + if (extension_loaded('mbstring')) + { + defined('MB_ENABLED') OR define('MB_ENABLED', TRUE); + mb_internal_encoding('UTF-8'); + } + else + { + defined('MB_ENABLED') OR define('MB_ENABLED', FALSE); + } + } + +}
\ No newline at end of file diff --git a/tests/mocks/database/ci_test.sqlite b/tests/mocks/database/ci_test.sqlite Binary files differindex 37ce4f870..44dcef9ec 100755 --- a/tests/mocks/database/ci_test.sqlite +++ b/tests/mocks/database/ci_test.sqlite diff --git a/tests/mocks/database/config/mysql.php b/tests/mocks/database/config/mysql.php index ace0a31b1..a590b9f53 100644 --- a/tests/mocks/database/config/mysql.php +++ b/tests/mocks/database/config/mysql.php @@ -1,7 +1,7 @@ <?php return array( - + // Typical Database configuration 'mysql' => array( 'dsn' => '', @@ -9,7 +9,7 @@ return array( 'username' => 'travis', 'password' => '', 'database' => 'ci_test', - 'dbdriver' => 'mysql', + 'dbdriver' => 'mysql' ), // Database configuration with failover @@ -28,7 +28,7 @@ return array( 'password' => '', 'database' => 'ci_test', 'dbdriver' => 'mysql', - ), - ), - ), + ) + ) + ) );
\ No newline at end of file diff --git a/tests/mocks/database/config/pdo/mysql.php b/tests/mocks/database/config/pdo/mysql.php new file mode 100644 index 000000000..96608f787 --- /dev/null +++ b/tests/mocks/database/config/pdo/mysql.php @@ -0,0 +1,37 @@ +<?php + +return array( + + // Typical Database configuration + 'pdo/mysql' => array( + 'dsn' => 'mysql:host=localhost;dbname=ci_test', + 'hostname' => 'localhost', + 'username' => 'travis', + 'password' => '', + 'database' => 'ci_test', + 'dbdriver' => 'pdo', + 'subdriver' => 'mysql' + ), + + // Database configuration with failover + 'pdo/mysql_failover' => array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'not_travis', + 'password' => 'wrong password', + 'database' => 'not_ci_test', + 'dbdriver' => 'pdo', + 'subdriver' => 'mysql', + 'failover' => array( + array( + 'dsn' => 'mysql:host=localhost;dbname=ci_test', + 'hostname' => 'localhost', + 'username' => 'travis', + 'password' => '', + 'database' => 'ci_test', + 'dbdriver' => 'pdo', + 'subdriver' => 'mysql' + ) + ) + ) +);
\ No newline at end of file diff --git a/tests/mocks/database/config/pdo/pgsql.php b/tests/mocks/database/config/pdo/pgsql.php new file mode 100644 index 000000000..e55e3ea77 --- /dev/null +++ b/tests/mocks/database/config/pdo/pgsql.php @@ -0,0 +1,37 @@ +<?php + +return array( + + // Typical Database configuration + 'pdo/pgsql' => array( + 'dsn' => 'pgsql:host=localhost;port=5432;dbname=ci_test;', + 'hostname' => 'localhost', + 'username' => 'postgres', + 'password' => '', + 'database' => 'ci_test', + 'dbdriver' => 'pdo', + 'subdriver' => 'pgsql' + ), + + // Database configuration with failover + 'pdo/pgsql_failover' => array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'not_travis', + 'password' => 'wrong password', + 'database' => 'not_ci_test', + 'dbdriver' => 'pdo', + 'subdriver' => 'pgsql', + 'failover' => array( + array( + 'dsn' => 'pgsql:host=localhost;port=5432;dbname=ci_test;', + 'hostname' => 'localhost', + 'username' => 'postgres', + 'password' => '', + 'database' => 'ci_test', + 'dbdriver' => 'pdo', + 'subdriver' => 'pgsql' + ) + ) + ) +);
\ No newline at end of file diff --git a/tests/mocks/database/config/pdo/sqlite.php b/tests/mocks/database/config/pdo/sqlite.php new file mode 100644 index 000000000..1bf56b3ac --- /dev/null +++ b/tests/mocks/database/config/pdo/sqlite.php @@ -0,0 +1,37 @@ +<?php + +return array( + + // Typical Database configuration + 'pdo/sqlite' => array( + 'dsn' => 'sqlite:/'.realpath(__DIR__.'/../..').'/ci_test.sqlite', + 'hostname' => 'localhost', + 'username' => 'sqlite', + 'password' => 'sqlite', + 'database' => 'sqlite', + 'dbdriver' => 'pdo', + 'subdriver' => 'sqlite' + ), + + // Database configuration with failover + 'pdo/sqlite_failover' => array( + 'dsn' => 'sqlite:not_exists.sqlite', + 'hostname' => 'localhost', + 'username' => 'sqlite', + 'password' => 'sqlite', + 'database' => 'sqlite', + 'dbdriver' => 'pdo', + 'subdriver' => 'sqlite', + 'failover' => array( + array( + 'dsn' => 'sqlite:/'.realpath(__DIR__.'/../..').'/ci_test.sqlite', + 'hostname' => 'localhost', + 'username' => 'sqlite', + 'password' => 'sqlite', + 'database' => 'sqlite', + 'dbdriver' => 'pdo', + 'subdriver' => 'sqlite' + ) + ) + ) +);
\ No newline at end of file diff --git a/tests/mocks/database/config/pgsql.php b/tests/mocks/database/config/pgsql.php index c06af8ce0..1444b0066 100644 --- a/tests/mocks/database/config/pgsql.php +++ b/tests/mocks/database/config/pgsql.php @@ -1,7 +1,7 @@ <?php return array( - + // Typical Database configuration 'pgsql' => array( 'dsn' => '', @@ -9,7 +9,7 @@ return array( 'username' => 'postgres', 'password' => '', 'database' => 'ci_test', - 'dbdriver' => 'postgre', + 'dbdriver' => 'postgre' ), // Database configuration with failover @@ -28,7 +28,7 @@ return array( 'password' => '', 'database' => 'ci_test', 'dbdriver' => 'postgre', - ), - ), - ), + ) + ) + ) );
\ No newline at end of file diff --git a/tests/mocks/database/config/sqlite.php b/tests/mocks/database/config/sqlite.php index 8665e208d..d37ee4871 100644 --- a/tests/mocks/database/config/sqlite.php +++ b/tests/mocks/database/config/sqlite.php @@ -1,5 +1,4 @@ <?php -$dbdriver = is_php('5.4') ? 'sqlite3' : 'sqlite'; return array( @@ -10,7 +9,7 @@ return array( 'username' => 'sqlite', 'password' => 'sqlite', 'database' => realpath(__DIR__.'/..').'/ci_test.sqlite', - 'dbdriver' => $dbdriver, + 'dbdriver' => 'sqlite3' ), // Database configuration with failover @@ -20,16 +19,16 @@ return array( 'username' => 'sqlite', 'password' => 'sqlite', 'database' => '../not_exists.sqlite', - 'dbdriver' => $dbdriver, + 'dbdriver' => 'sqlite3', 'failover' => array( array( 'dsn' => '', 'hostname' => 'localhost', 'username' => 'sqlite', 'password' => 'sqlite', - 'database' => realpath(__DIR__.'/..').'/ci_testf.sqlite', - 'dbdriver' => $dbdriver, - ), - ), - ), + 'database' => realpath(__DIR__.'/..').'/ci_test.sqlite', + 'dbdriver' => 'sqlite3' + ) + ) + ) );
\ No newline at end of file diff --git a/tests/mocks/database/db.php b/tests/mocks/database/db.php index 43a0d391f..7e0030e15 100644 --- a/tests/mocks/database/db.php +++ b/tests/mocks/database/db.php @@ -6,7 +6,17 @@ class Mock_Database_DB { * @var array DB configuration */ private $config = array(); - + + /** + * @var string DB driver name + */ + private static $dbdriver = ''; + + /** + * @var string DB sub-driver name + */ + private static $subdriver = ''; + /** * Prepare database configuration skeleton * @@ -21,7 +31,7 @@ class Mock_Database_DB { /** * Build DSN connection string for DB driver instantiate process * - * @param string Group name + * @param string Group name * @return string DSN Connection string */ public function set_dsn($group = 'default') @@ -31,6 +41,12 @@ class Mock_Database_DB { throw new InvalidArgumentException('Group '.$group.' not exists'); } + self::$dbdriver = $this->config[$group]['dbdriver']; + if (isset($this->config[$group]['subdriver'])) + { + self::$subdriver = $this->config[$group]['subdriver']; + } + $params = array( 'dbprefix' => '', 'pconnect' => FALSE, @@ -45,19 +61,18 @@ class Mock_Database_DB { ); $config = array_merge($this->config[$group], $params); + $dsnstring = empty($config['dsn']) ? FALSE : $config['dsn']; + $subdriver = empty($config['subdriver']) ? FALSE: $config['subdriver']; + $failover = empty($config['failover']) ? FALSE : $config['failover']; - if ( ! empty($config['dsn'])) - { - $dsn = $config['dsn']; - } - else - { - $dsn = $config['dbdriver'].'://'.$config['username'].':'.$config['password'] - .'@'.$config['hostname'].'/'.$config['database']; - - } + $dsn = $config['dbdriver'].'://'.$config['username'].':'.$config['password'] + .'@'.$config['hostname'].'/'.$config['database']; + // Build the parameter $other_params = array_slice($config, 6); + if ($dsnstring) $other_params['dsn'] = $dsnstring; + if ($subdriver) $other_params['subdriver'] = $subdriver; + if ($failover) $other_params['failover'] = $failover; return $dsn.'?'.http_build_query($other_params); } @@ -66,28 +81,52 @@ class Mock_Database_DB { * Return a database config array * * @see ./config - * @param string Driver based configuration - * @return array + * @param string Driver based configuration + * @return array */ public static function config($driver) { $dir = realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR; - return include($dir.'config'.DIRECTORY_SEPARATOR.$driver.'.php'); } /** * Main DB method wrapper * - * @param string Group or DSN string - * @param bool - * @return object + * @param string Group or DSN string + * @param bool + * @return object */ public static function DB($group, $query_builder = FALSE) { - include_once(BASEPATH.'database/DB.php'); + // Create dummy driver and builder files to "load" - the mocks have + // already triggered autoloading of the real files + $case = CI_TestCase::instance(); + $driver = self::$dbdriver; + $subdriver = self::$subdriver; + $case->ci_vfs_create(array( + 'DB_driver.php' => '', + 'DB_forge.php' => '', + 'DB_query_builder.php' => '' + ), '', $case->ci_base_root, 'database'); + if (file_exists(SYSTEM_PATH.'database/drivers/'.$driver.'/'.$driver.'_driver.php')) + { + $case->ci_vfs_create(array( + $driver.'_driver.php' => '', + $driver.'_forge.php' => '' + ), '', $case->ci_base_root, 'database/drivers/'.$driver); + } + if ($subdriver) + { + $case->ci_vfs_create(array( + $driver.'_'.$subdriver.'_driver.php' => '', + $driver.'_'.$subdriver.'_forge.php' => '' + ), '', $case->ci_base_root, 'database/drivers/'.$driver.'/subdrivers'); + } - try + include_once(SYSTEM_PATH.'database/DB.php'); + + try { $db = DB($group, $query_builder); } @@ -98,4 +137,5 @@ class Mock_Database_DB { return $db; } + }
\ No newline at end of file diff --git a/tests/mocks/database/db/driver.php b/tests/mocks/database/db/driver.php new file mode 100644 index 000000000..2cf54b97b --- /dev/null +++ b/tests/mocks/database/db/driver.php @@ -0,0 +1,40 @@ +<?php + +class Mock_Database_DB_Driver extends CI_DB_driver { + + /** + * @var object The actual Driver + */ + protected $ci_db_driver; + + /** + * Instantiate the database driver + * + * @param string DB Driver class name + * @param array DB configuration to set + * @return void + */ + public function __construct($driver_class, $config = array()) + { + if (is_string($driver_class)) + { + $this->ci_db_driver = new $driver_class($config); + } + } + + /** + * Overloading method, emulate the actual driver method (multiple inheritance workaround) + */ + public function __call($method, $arguments) + { + if ( ! is_callable(array($this->ci_db_driver, $method))) + { + throw new BadMethodCallException($method. ' not exists or not implemented'); + } + + return call_user_func_array(array($this->ci_db_driver, $method), $arguments); + } + +} + +class CI_DB extends Mock_Database_DB_QueryBuilder {}
\ No newline at end of file diff --git a/tests/mocks/database/db/querybuilder.php b/tests/mocks/database/db/querybuilder.php new file mode 100644 index 000000000..3f2252622 --- /dev/null +++ b/tests/mocks/database/db/querybuilder.php @@ -0,0 +1,3 @@ +<?php + +class Mock_Database_DB_QueryBuilder extends CI_DB_query_builder {}
\ No newline at end of file diff --git a/tests/mocks/database/drivers/mysql.php b/tests/mocks/database/drivers/mysql.php new file mode 100644 index 000000000..e0c1fb06c --- /dev/null +++ b/tests/mocks/database/drivers/mysql.php @@ -0,0 +1,17 @@ +<?php + +class Mock_Database_Drivers_Mysql extends Mock_Database_DB_Driver { + + /** + * Instantiate the database driver + * + * @param string DB Driver class name + * @param array DB configuration to set + * @return void + */ + public function __construct($config = array()) + { + parent::__construct('CI_DB_mysql_driver', $config); + } + +}
\ No newline at end of file diff --git a/tests/mocks/database/drivers/pdo.php b/tests/mocks/database/drivers/pdo.php new file mode 100644 index 000000000..17768eed7 --- /dev/null +++ b/tests/mocks/database/drivers/pdo.php @@ -0,0 +1,16 @@ +<?php + +class Mock_Database_Drivers_PDO extends Mock_Database_DB_Driver { + + /** + * Instantiate the database driver + * + * @param string DB Driver class name + * @param array DB configuration to set + * @return void + */ + public function __construct($config = array()) + { + parent::__construct('CI_DB_pdo_driver', $config); + } +}
\ No newline at end of file diff --git a/tests/mocks/database/drivers/postgre.php b/tests/mocks/database/drivers/postgre.php new file mode 100644 index 000000000..5a45115fa --- /dev/null +++ b/tests/mocks/database/drivers/postgre.php @@ -0,0 +1,17 @@ +<?php + +class Mock_Database_Drivers_Postgre extends Mock_Database_DB_Driver { + + /** + * Instantiate the database driver + * + * @param string DB Driver class name + * @param array DB configuration to set + * @return void + */ + public function __construct($config = array()) + { + parent::__construct('CI_DB_postgre_driver', $config); + } + +}
\ No newline at end of file diff --git a/tests/mocks/database/drivers/sqlite.php b/tests/mocks/database/drivers/sqlite.php new file mode 100644 index 000000000..512467520 --- /dev/null +++ b/tests/mocks/database/drivers/sqlite.php @@ -0,0 +1,17 @@ +<?php + +class Mock_Database_Drivers_Sqlite extends Mock_Database_DB_Driver { + + /** + * Instantiate the database driver + * + * @param string DB Driver class name + * @param array DB configuration to set + * @return void + */ + public function __construct($config = array()) + { + parent::__construct('CI_DB_sqlite3_driver', $config); + } + +}
\ No newline at end of file diff --git a/tests/mocks/database/schema/.gitkeep b/tests/mocks/database/schema/.gitkeep deleted file mode 100644 index e69de29bb..000000000 --- a/tests/mocks/database/schema/.gitkeep +++ /dev/null diff --git a/tests/mocks/database/schema/skeleton.php b/tests/mocks/database/schema/skeleton.php new file mode 100644 index 000000000..e5c536090 --- /dev/null +++ b/tests/mocks/database/schema/skeleton.php @@ -0,0 +1,148 @@ +<?php + +class Mock_Database_Schema_Skeleton { + + /** + * @var object Database Holder + */ + public static $db; + + /** + * @var object Forge Holder + */ + public static $forge; + + /** + * @var object Driver Holder + */ + public static $driver; + + /** + * Initialize both database and forge components + */ + public static function init($driver) + { + if (empty(static::$db) && empty(static::$forge)) + { + $config = Mock_Database_DB::config($driver); + $connection = new Mock_Database_DB($config); + $db = Mock_Database_DB::DB($connection->set_dsn($driver), TRUE); + + CI_TestCase::instance()->ci_instance_var('db', $db); + + $loader = new CI_Loader(); + $loader->dbforge(); + $forge = CI_TestCase::instance()->ci_instance_var('dbforge'); + + static::$db = $db; + static::$forge = $forge; + static::$driver = $driver; + } + + return static::$db; + } + + /** + * Create the dummy tables + * + * @return void + */ + public static function create_tables() + { + // User Table + static::$forge->add_field(array( + 'id' => array( + 'type' => 'INTEGER', + 'constraint' => 3 + ), + 'name' => array( + 'type' => 'VARCHAR', + 'constraint' => 40 + ), + 'email' => array( + 'type' => 'VARCHAR', + 'constraint' => 100 + ), + 'country' => array( + 'type' => 'VARCHAR', + 'constraint' => 40 + ) + )); + static::$forge->add_key('id', TRUE); + static::$forge->create_table('user', TRUE); + + // Job Table + static::$forge->add_field(array( + 'id' => array( + 'type' => 'INTEGER', + 'constraint' => 3 + ), + 'name' => array( + 'type' => 'VARCHAR', + 'constraint' => 40 + ), + 'description' => array( + 'type' => 'TEXT' + ) + )); + static::$forge->add_key('id', TRUE); + static::$forge->create_table('job', TRUE); + + // Misc Table + static::$forge->add_field(array( + 'id' => array( + 'type' => 'INTEGER', + 'constraint' => 3 + ), + 'key' => array( + 'type' => 'VARCHAR', + 'constraint' => 40 + ), + 'value' => array( + 'type' => 'TEXT' + ) + )); + static::$forge->add_key('id', TRUE); + static::$forge->create_table('misc', TRUE); + } + + /** + * Create the dummy datas + * + * @return void + */ + public static function create_data() + { + // Job Data + $data = array( + 'user' => array( + array('id' => 1, 'name' => 'Derek Jones', 'email' => 'derek@world.com', 'country' => 'US'), + array('id' => 2, 'name' => 'Ahmadinejad', 'email' => 'ahmadinejad@world.com', 'country' => 'Iran'), + array('id' => 3, 'name' => 'Richard A Causey', 'email' => 'richard@world.com', 'country' => 'US'), + array('id' => 4, 'name' => 'Chris Martin', 'email' => 'chris@world.com', 'country' => 'UK') + ), + 'job' => array( + array('id' => 1, 'name' => 'Developer', 'description' => 'Awesome job, but sometimes makes you bored'), + array('id' => 2, 'name' => 'Politician', 'description' => 'This is not really a job'), + array('id' => 3, 'name' => 'Accountant', 'description' => 'Boring job, but you will get free snack at lunch'), + array('id' => 4, 'name' => 'Musician', 'description' => 'Only Coldplay can actually called Musician') + ), + 'misc' => array( + array('id' => 1, 'key' => '\\xxxfoo456', 'value' => 'Entry with \\xxx'), + array('id' => 2, 'key' => '\\%foo456', 'value' => 'Entry with \\%'), + array('id' => 3, 'key' => 'spaces and tabs', 'value' => ' One two three tab') + ) + ); + + foreach ($data as $table => $dummy_data) + { + static::$db->truncate($table); + + foreach ($dummy_data as $single_dummy_data) + { + static::$db->insert($table, $single_dummy_data); + } + } + } + +}
\ No newline at end of file diff --git a/tests/mocks/libraries/calendar.php b/tests/mocks/libraries/calendar.php new file mode 100644 index 000000000..8fee5365e --- /dev/null +++ b/tests/mocks/libraries/calendar.php @@ -0,0 +1,25 @@ +<?php + +class Mock_Libraries_Calendar extends CI_Calendar { + + public function __construct($config = array()) + { + $this->CI = new stdClass; + $this->CI->lang = new Mock_Core_Lang(); + + if ( ! in_array('calendar_lang.php', $this->CI->lang->is_loaded, TRUE)) + { + $this->CI->lang->load('calendar'); + } + + $this->local_time = time(); + + if (count($config) > 0) + { + $this->initialize($config); + } + + log_message('debug', 'Calendar Class Initialized'); + } + +}
\ No newline at end of file diff --git a/tests/mocks/libraries/encrypt.php b/tests/mocks/libraries/encrypt.php new file mode 100644 index 000000000..f1859398f --- /dev/null +++ b/tests/mocks/libraries/encrypt.php @@ -0,0 +1,16 @@ +<?php + +class Mock_Libraries_Encrypt extends CI_Encrypt { + + // Overide inaccesible protected method + public function __call($method, $params) + { + if (is_callable(array($this, '_'.$method))) + { + return call_user_func_array(array($this, '_'.$method), $params); + } + + throw new BadMethodCallException('Method '.$method.' was not found'); + } + +}
\ No newline at end of file diff --git a/tests/mocks/libraries/session.php b/tests/mocks/libraries/session.php new file mode 100644 index 000000000..c6e194f58 --- /dev/null +++ b/tests/mocks/libraries/session.php @@ -0,0 +1,43 @@ +<?php + +/** + * Mock library to add testing features to Session driver library + */ +class Mock_Libraries_Session extends CI_Session { + + /** + * Simulate new page load + */ + public function reload() + { + $this->_flashdata_sweep(); + $this->_flashdata_mark(); + $this->_tempdata_sweep(); + } +} + +/** + * Mock cookie driver to overload cookie setting + */ +class Mock_Libraries_Session_cookie extends CI_Session_cookie { + + /** + * Overload _setcookie to manage $_COOKIE values, since actual cookies can't be set in unit testing + */ + protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = FALSE, $httponly = FALSE) + { + if (empty($value) OR $expire <= time()) + { + unset($_COOKIE[$name]); + } + else + { + $_COOKIE[$name] = $value; + } + } +} + +/** + * Mock native driver (just for consistency in loading) + */ +class Mock_Libraries_Session_native extends CI_Session_native { }
\ No newline at end of file diff --git a/tests/mocks/libraries/table.php b/tests/mocks/libraries/table.php index 1a6ff8d35..87c278bce 100644 --- a/tests/mocks/libraries/table.php +++ b/tests/mocks/libraries/table.php @@ -1,8 +1,8 @@ <?php class Mock_Libraries_Table extends CI_Table { - - // Overide inaccesible private or protected method + + // Overide inaccesible protected method public function __call($method, $params) { if (is_callable(array($this, '_'.$method))) @@ -12,4 +12,5 @@ class Mock_Libraries_Table extends CI_Table { throw new BadMethodCallException('Method '.$method.' was not found'); } + }
\ No newline at end of file diff --git a/tests/mocks/libraries/upload.php b/tests/mocks/libraries/upload.php new file mode 100644 index 000000000..988723e45 --- /dev/null +++ b/tests/mocks/libraries/upload.php @@ -0,0 +1,3 @@ +<?php + +class Mock_Libraries_Upload extends CI_Upload {}
\ No newline at end of file diff --git a/tests/mocks/uploads/ci_logo.gif b/tests/mocks/uploads/ci_logo.gif Binary files differnew file mode 100644 index 000000000..073ec14b4 --- /dev/null +++ b/tests/mocks/uploads/ci_logo.gif diff --git a/tests/phpunit.xml b/tests/phpunit.xml new file mode 100644 index 000000000..96c3af9bb --- /dev/null +++ b/tests/phpunit.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<phpunit + bootstrap="./Bootstrap.php" + colors="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + stopOnError="false" + stopOnFailure="false" + stopOnIncomplete="false" + stopOnSkipped="false"> + <testsuites> + <testsuite name="CodeIgniter Core Test Suite"> + <directory suffix="test.php">./codeigniter/core</directory> + <directory suffix="test.php">./codeigniter/helpers</directory> + <directory suffix="test.php">./codeigniter/libraries</directory> + </testsuite> + </testsuites> + <filter> + <blacklist> + <directory suffix=".php">PEAR_INSTALL_DIR</directory> + <directory suffix=".php">PHP_LIBDIR</directory> + <directory suffix=".php">../vendor</directory> + </blacklist> + </filter> +</phpunit>
\ No newline at end of file diff --git a/tests/travis/mysql.phpunit.xml b/tests/travis/mysql.phpunit.xml index 44d6d6ed9..06d4a011b 100644 --- a/tests/travis/mysql.phpunit.xml +++ b/tests/travis/mysql.phpunit.xml @@ -14,24 +14,12 @@ </php> <testsuites> <testsuite name="CodeIgniter Core Test Suite"> - <file>../codeigniter/Setup_test.php</file> - <directory suffix="test.php">../codeigniter/core</directory> - <directory suffix="test.php">../codeigniter/helpers</directory> - <directory suffix="test.php">../codeigniter/libraries</directory> - <directory suffix="test.php">../codeigniter/database</directory> + <directory suffix="test.php">../codeigniter</directory> </testsuite> </testsuites> - <filters> - <blacklist> - <directory suffix=".php">PEAR_INSTALL_DIR</directory> - <directory suffix=".php">PHP_LIBDIR</directory> - <directory suffix=".php">PROJECT_BASE.'tests'</directory> - <directory suffix=".php">'../../system/core/CodeIgniter.php'</directory> - </blacklist> - <whitelist> - <!-- - <directory suffix=".php">'../system/core'</directory> - --> - </whitelist> - </filters> + <filter> + <whitelist addUncoveredFilesFromWhitelist="false"> + <directory suffix=".php">../../system</directory> + </whitelist> + </filter> </phpunit>
\ No newline at end of file diff --git a/tests/travis/pdo/mysql.phpunit.xml b/tests/travis/pdo/mysql.phpunit.xml new file mode 100644 index 000000000..7121edc45 --- /dev/null +++ b/tests/travis/pdo/mysql.phpunit.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<phpunit + bootstrap="../../Bootstrap.php" + colors="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + stopOnError="false" + stopOnFailure="false" + stopOnIncomplete="false" + stopOnSkipped="false"> + <php> + <const name="DB_DRIVER" value="pdo/mysql"/> + </php> + <testsuites> + <testsuite name="CodeIgniter Core Test Suite"> + <directory suffix="test.php">../../codeigniter</directory> + </testsuite> + </testsuites> + <filter> + <whitelist addUncoveredFilesFromWhitelist="false"> + <directory suffix=".php">../../../system</directory> + </whitelist> + </filter> +</phpunit>
\ No newline at end of file diff --git a/tests/travis/pdo/pgsql.phpunit.xml b/tests/travis/pdo/pgsql.phpunit.xml new file mode 100644 index 000000000..df3ff986e --- /dev/null +++ b/tests/travis/pdo/pgsql.phpunit.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<phpunit + bootstrap="../../Bootstrap.php" + colors="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + stopOnError="false" + stopOnFailure="false" + stopOnIncomplete="false" + stopOnSkipped="false"> + <php> + <const name="DB_DRIVER" value="pdo/pgsql"/> + </php> + <testsuites> + <testsuite name="CodeIgniter Core Test Suite"> + <directory suffix="test.php">../../codeigniter</directory> + </testsuite> + </testsuites> + <filter> + <whitelist addUncoveredFilesFromWhitelist="false"> + <directory suffix=".php">../../../system</directory> + </whitelist> + </filter> +</phpunit>
\ No newline at end of file diff --git a/tests/travis/pdo/sqlite.phpunit.xml b/tests/travis/pdo/sqlite.phpunit.xml new file mode 100644 index 000000000..7d867f6d1 --- /dev/null +++ b/tests/travis/pdo/sqlite.phpunit.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<phpunit + bootstrap="../../Bootstrap.php" + colors="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + stopOnError="false" + stopOnFailure="false" + stopOnIncomplete="false" + stopOnSkipped="false"> + <php> + <const name="DB_DRIVER" value="pdo/sqlite"/> + </php> + <testsuites> + <testsuite name="CodeIgniter Core Test Suite"> + <directory suffix="test.php">../../codeigniter</directory> + </testsuite> + </testsuites> + <filter> + <whitelist addUncoveredFilesFromWhitelist="false"> + <directory suffix=".php">../../../system</directory> + </whitelist> + </filter> +</phpunit>
\ No newline at end of file diff --git a/tests/travis/pgsql.phpunit.xml b/tests/travis/pgsql.phpunit.xml index 9f52b40ae..bfddbf6b5 100644 --- a/tests/travis/pgsql.phpunit.xml +++ b/tests/travis/pgsql.phpunit.xml @@ -14,24 +14,12 @@ </php> <testsuites> <testsuite name="CodeIgniter Core Test Suite"> - <file>../codeigniter/Setup_test.php</file> - <directory suffix="test.php">../codeigniter/core</directory> - <directory suffix="test.php">../codeigniter/helpers</directory> - <directory suffix="test.php">../codeigniter/libraries</directory> - <directory suffix="test.php">../codeigniter/database</directory> + <directory suffix="test.php">../codeigniter</directory> </testsuite> </testsuites> - <filters> - <blacklist> - <directory suffix=".php">PEAR_INSTALL_DIR</directory> - <directory suffix=".php">PHP_LIBDIR</directory> - <directory suffix=".php">PROJECT_BASE.'tests'</directory> - <directory suffix=".php">'../../system/core/CodeIgniter.php'</directory> - </blacklist> - <whitelist> - <!-- - <directory suffix=".php">'../system/core'</directory> - --> - </whitelist> - </filters> + <filter> + <whitelist addUncoveredFilesFromWhitelist="false"> + <directory suffix=".php">../../system</directory> + </whitelist> + </filter> </phpunit>
\ No newline at end of file diff --git a/tests/travis/sqlite.phpunit.xml b/tests/travis/sqlite.phpunit.xml index 74ebb482b..75c946aee 100644 --- a/tests/travis/sqlite.phpunit.xml +++ b/tests/travis/sqlite.phpunit.xml @@ -14,24 +14,12 @@ </php> <testsuites> <testsuite name="CodeIgniter Core Test Suite"> - <file>../codeigniter/Setup_test.php</file> - <directory suffix="test.php">../codeigniter/core</directory> - <directory suffix="test.php">../codeigniter/helpers</directory> - <directory suffix="test.php">../codeigniter/libraries</directory> - <directory suffix="test.php">../codeigniter/database</directory> + <directory suffix="test.php">../codeigniter</directory> </testsuite> </testsuites> - <filters> - <blacklist> - <directory suffix=".php">PEAR_INSTALL_DIR</directory> - <directory suffix=".php">PHP_LIBDIR</directory> - <directory suffix=".php">PROJECT_BASE.'tests'</directory> - <directory suffix=".php">'../../system/core/CodeIgniter.php'</directory> - </blacklist> - <whitelist> - <!-- - <directory suffix=".php">'../system/core'</directory> - --> - </whitelist> - </filters> + <filter> + <whitelist addUncoveredFilesFromWhitelist="false"> + <directory suffix=".php">../../system</directory> + </whitelist> + </filter> </phpunit>
\ No newline at end of file diff --git a/user_guide_src/source/DCO.rst b/user_guide_src/source/DCO.rst new file mode 100644 index 000000000..c8f9b49c6 --- /dev/null +++ b/user_guide_src/source/DCO.rst @@ -0,0 +1,27 @@ +##################################### +Developer's Certificate of Origin 1.1 +##################################### + +By making a contribution to this project, I certify that: + +(1) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(2) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(3) The contribution was provided directly to me by some other + person who certified (1), (2) or (3) and I have not modified + it. + +(4) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/user_guide_src/source/_themes/eldocs/layout.html b/user_guide_src/source/_themes/eldocs/layout.html index 4b1a0221c..51d61b849 100644 --- a/user_guide_src/source/_themes/eldocs/layout.html +++ b/user_guide_src/source/_themes/eldocs/layout.html @@ -9,6 +9,9 @@ {%- if project == 'ExpressionEngine' %}{% set project_abbreviation = 'ee' %}{% set project_domain = 'expressionengine.com' %}{% endif -%} {%- if project == 'CodeIgniter' %}{% set project_abbreviation = 'ci' %}{% set project_domain = 'codeigniter.com' %}{% endif -%} {%- if project == 'MojoMotor' %}{% set project_abbreviation = 'mm' %}{% set project_domain = 'mojomotor.com' %}{% endif -%} +{%- set exclude_comments = ['index', 'license', 'changelog', + 'development/index', 'development/extension_hooks/index', + 'development/guidelines/template'] %} <html> <head> @@ -85,36 +88,29 @@ <div id="brand" class="{{ project_abbreviation }}"> <a href="http://{{ project_domain }}/"><img src="{{ pathto('_static/asset/img/' + project_abbreviation + '-logo.gif', 1) }}" alt="{{ project }}"></a> <p>{{ release }} User Guide</p> - {%- if show_source and has_source and sourcename %} - <p><a href="{{ pathto('_sources/' + sourcename, true)|e }}" - rel="nofollow">{{ _('Show Source') }}</a></p> - {%- endif %} </div><!-- /#brand --> <div id="header"> - <form method="get" action="http://www.google.com/search"> - <fieldset> - <input type="text" name="q" id="q" value=""> - <input type="hidden" name="as_sitesearch" id="as_sitesearch" value="{{ project_domain }}/user_guide/" /> - <input class="grades" type="submit" value="search"> - </fieldset> - </form> + {%- include "searchbox.html" %} <ul> {%- block rootrellink %} - <li><a href="{{ pathto(master_doc) }}">Home</a> {{ reldelim1 }}</li> - <li><a id="toc-link" href="{{ pathto(master_doc) }}">Table of Contents</a> {{ reldelim1 }}</li> + <li><a href="{{ pathto(master_doc) }}">User Guide Home</a>{%- if pagename != 'index' %} {{ reldelim1 }}{%- endif %}</li> {%- endblock %} {%- for parent in parents %} <li><a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a> {{ reldelim1 }}</li> {%- endfor %} + {%- if pagename != 'index' %} <li><strong>{{ title }}</strong></li> + {%- endif %} </ul> </div><!-- /#header --> - <div class="section" id="content"> + <div class="section body" id="content"> + {%- block body %} {{ body }} + {%- endblock %} </div> {%- endblock %} @@ -124,49 +120,9 @@ {%- block footer %} <div id="footer"> - <p class="top"> - {% if prev %} - <span class="prev">Previous Topic: <a href="{{ prev.link }}">{{ prev.title }}</a></span> - {% endif %} - {% if next %} - <span class="next">Next Topic: <a href="{{ next.link }}">{{ next.title }}</a></span> - {% endif %} - <a href="#header" title="Return to top">Return to top</a> - </p> - <p><a href="{{ project_url }}">{{ project }}</a> – Copyright © {{ copyright }}</a> – Last updated: {{ last_updated }}</p> + <p class="top"><a href="#header" title="Return to top">Return to top</a></p> + <p><a href="http://{{ project_domain }}/">{{ project }}</a> – Copyright © {{ copyright }}</a></p> </div><!-- /#footer --> {%- endblock %} - - <script src="{{ pathto('_static/asset/js/jquery-ui-min.js', 1) }}" type="text/javascript" charset="utf-8" async></script> - <script type="text/javascript" charset="utf-8"> - $('#toc-link').click(function(){ - $('#table-contents').animate({ left: '0' },1000); - return false; - }); - $('html').click(function(){ - if ($('#table-contents').css("left") == '0px'){ - $('#table-contents').animate({ left: '-520' },1000); - } - }); - $('#table-contents').click(function(event){ - event.stopPropagation(); - }); -/* $('*:not(#table-contents,#toc-link)').click(function(){ - if ($('#table-contents').css("left") == '0px'){ - $('#table-contents').animate({ left: '-520' },1000); - } - }); -/* $("#toc-link").click(function () { - $('#table-contents').show("slide", { direction: "left" }, 100); - event.stopPropagation(); - return false; - }); - $('*:not(#table-contents,#toc-link)').click(function () { - if ($('#table-contents').is(":visible")) { - $('#table-contents').hide("slide", { direction: "left" }, 100); - event.stopPropagation(); - } - }); */ - </script> </body> </html>
\ No newline at end of file diff --git a/user_guide_src/source/_themes/eldocs/searchbox.html b/user_guide_src/source/_themes/eldocs/searchbox.html new file mode 100644 index 000000000..039590bd9 --- /dev/null +++ b/user_guide_src/source/_themes/eldocs/searchbox.html @@ -0,0 +1,21 @@ +<!-- + -------------------------------- + Original Google search box block + -------------------------------- + +<form method="get" action="http://www.google.com/search"> + <fieldset> + <input type="text" name="q" id="q" value=""> + <input type="hidden" name="as_sitesearch" id="as_sitesearch" value="{{ project_domain }}/user_guide/" /> + <input class="grades" type="submit" value="search"> + </fieldset> +</form> +--> + + +<form class="search" action="{{ pathto('search') }}" method="get"> + <input type="text" name="q" id="q" value="" /> + <input type="submit" value="search" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> +</form> diff --git a/user_guide_src/source/_themes/eldocs/static/asset/css/common.css b/user_guide_src/source/_themes/eldocs/static/asset/css/common.css index 66768bac6..0a63871c5 100644 --- a/user_guide_src/source/_themes/eldocs/static/asset/css/common.css +++ b/user_guide_src/source/_themes/eldocs/static/asset/css/common.css @@ -49,7 +49,9 @@ h1, h2, h3, h4, h5, h6, pre{ color: #094776; } h1{ font-size: 28px; } -h2{ font-size: 24px; } +h2{ font-size: 24px; font-weight: normal; } + +h1, h2, h3, h4, h5, h6{ margin-bottom: 20px; } h2, h3{ border-bottom: 2px solid #EEEEEE; padding: 0 0 3px; } @@ -73,6 +75,10 @@ p, dl, ul, ol{ margin: 20px 0; } li > ol{ margin: 0; margin-left: 40px; } dl > dd{ margin-left: 20px; } + + li > p { margin: 0; } + +#expressionengine-user-guide li em { font-style: normal; } p, li, dd, dt, pre{ line-height: 1.5; } @@ -141,39 +147,35 @@ img{ display: block; max-width: 100%; } fieldset{ border: 0; } .top{ float: right; } -.next{ padding: 0 20px 0 10px; } -.prev{ padding-right: 10px; } -.highlight-ci, +.highlight{ overflow-x: auto; } + +.admonition, .highlight-ee, +.highlight-ci, .highlight-rst, .highlight-bash, .highlight-perl, +.highlight-php, .cp-path, -.important, -.note{ - background-color: #F5FBFF; +.codeblock{ + background-color: #F9FEFF; border: 1px solid #C8DEF0; - margin: 20px 0 20px 20px; + -moz-box-shadow: 4px 4px 0 rgba(0,0,0,0.03); + -webkit-box-shadow: 4px 4px 0 rgba(0,0,0,0.03); + box-shadow: 4px 4px 0 rgba(0,0,0,0.03); + margin: 20px 0; padding: 10px 10px 8px; } - .highlight-ci, - .highlight-ee, - .highlight-rst, - .highlight-bash, - .highlight-perl{ - -moz-box-shadow: 4px 4px 0 rgba(0,0,0,0.03); - -webkit-box-shadow: 4px 4px 0 rgba(0,0,0,0.03); - box-shadow: 4px 4px 0 rgba(0,0,0,0.03); - } +.highlight-ci{ background-color: #FEFEFE; border-color: #E5E5E5; } - .cp-path{ background-color: #FFFDED; border-color: #D1CDB0; } - .important, .note{ background-color: #F2FFE8; border-color: #B9D3A6; } - .highlight-rst{ background-color: #F9FEFE; border-color: #AACFCF; } + .admonition p{ margin: 0; } + + .codeblock{ margin: 10px 0; } - .important p, - .note p{ margin: 0; } + .cp-path{ background-color: #FAFFF6; border-color: #D1CDB0; } + .important, .note{ background-color: #FFFFF2; border-color: #C8C8A5; } .admonition-title{ float: left; @@ -183,6 +185,8 @@ fieldset{ border: 0; } } .admonition-title:after{ content: ': '; } + +.highlighted{ background-color: #FFF09B; } #table-contents{ bottom: 0; @@ -295,6 +299,43 @@ fieldset{ border: 0; } #footer p{ margin: 0; } +#comments, +#feedLink{ background: #FCFCFC; padding: 1px 40px 20px; } + + #comments{ border-top: 1px solid #CCCCCC; } + #comments h3{ margin: 20px 0; } + +.comments td.avatar{ min-width: 100px; } + +.comments td.column1, +.comments td.post{ background-color: #FFFFFF; padding: 10px; } + +.comments td.staffeven{ border-left: 10px solid #C8DEF0; } + +#comment_form p, +.comments p{ margin: 0; } + + .comments p{ margin-bottom: 10px; } + +#comment_form textarea{ + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + margin-bottom: 10px; + resize: none; + width: 100%; +} + +#comment_form input[type="submit"]{ margin-top: 10px; } + + #comment_form textarea:focus{ background-color: #FFFFF2; border: 1px solid #666666; outline: 0; } + + #commentFormInstructions{ font-size: 12px; margin: 20px 0; } + + #feedLink a{ font-size: 16px; } + + #feedLink a img{ float: left; margin-right: 5px; } + @media (max-width:800px){ #footer .top, #header form{ float: none; margin-bottom: 10px; } @@ -310,4 +351,4 @@ fieldset{ border: 0; } @media screen and (-webkit-min-device-pixel-ratio:0){ #header input[type="submit"]{ padding-bottom: 7px; } -}
\ No newline at end of file +} diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst index 5f6d5912c..3567ae7c6 100644 --- a/user_guide_src/source/changelog.rst +++ b/user_guide_src/source/changelog.rst @@ -9,8 +9,7 @@ Release Date: Not Released - License - - CodeIgniter has been relicensed with the Open Software License (3.0), - eliminating its old proprietary licensing. + - CodeIgniter has been relicensed with the Open Software License (3.0), eliminating its old proprietary licensing. - All system files are licensed with OSL 3.0. - Config, error, and sample files shipped in the application folder are @@ -20,151 +19,312 @@ Release Date: Not Released - General Changes - PHP 5.1.6 is no longer supported. CodeIgniter now requires PHP 5.2.4. + - ``$_SERVER['CI_ENV']`` can now be set to control the ``ENVIRONMENT`` constant. - Added an optional backtrace to php-error template. - Added Android to the list of user agents. - - Added Windows 7 to the list of user platforms. + - Added Windows 7, Windows 8, Android, Blackberry, iOS and PlayStation 3 to the list of user platforms. + - Added Fennec (Firefox for mobile) to the list of mobile user agents. - Ability to log certain error types, not all under a threshold. - Added support for pem, p10, p12, p7a, p7c, p7m, p7r, p7s, crt, crl, der, kdb, rsa, cer, sst, csr Certs to mimes.php. - - Added support for pgp and gpg to mimes.php. + - Added support for pgp, gpg, zsh and cdr files to mimes.php. - Added support for 3gp, 3g2, mp4, wmv, f4v, vlc Video files to mimes.php. - - Added support for m4a, aac, m4u, xspf, au, ac3, flac, ogg Audio files to mimes.php. + - Added support for m4a, aac, m4u, xspf, au, ac3, flac, ogg, wma Audio files to mimes.php. - Added support for kmz and kml (Google Earth) files to mimes.php. + - Added support for ics Calendar files to mimes.php. + - Added support for rar, jar and 7zip archives to mimes.php. + - Updated support for xml ('application/xml') and xsl ('application/xml', 'text/xsl') files in mimes.php. - Updated support for doc files in mimes.php. - - Added application/xml for xml and application/xml, text/xsl for xsl in mimes.php. + - Updated support for docx files in mimes.php. + - Updated support for php files in mimes.php. + - Updated support for zip files in mimes.php. + - Updated support for csv files in mimes.php. + - Added some more doctypes. + - Added Romanian, Greek, Vietnamese and Cyrilic characters in *application/config/foreign_characters.php*. - Changed logger to only chmod when file is first created. - Removed previously deprecated SHA1 Library. - - Removed previously deprecated use of ``$autoload['core']`` in application/config/autoload.php. + - Removed previously deprecated use of ``$autoload['core']`` in *application/config/autoload.php*. Only entries in ``$autoload['libraries']`` are auto-loaded now. - - Added some more doctypes. + - Removed previously deprecated EXT constant. - Updated all classes to be written in PHP 5 style, with visibility declarations and no ``var`` usage for properties. + - Moved error templates to *application/views/errors/*. + - Moved the Log class to *application/core/* + - Global config files are loaded first, then environment ones. Environment config keys overwrite base ones, allowing to only set the keys we want changed per environment. + - Changed detection of ``$view_folder`` so that if it's not found in the current path, it will now also be searched for under the application folder. + - Path constants BASEPATH, APPPATH and VIEWPATH are now (internally) defined as absolute paths. + - Updated email validation methods to use ``filter_var()`` instead of PCRE. + - Changed environment defaults to report all errors in *development* and only fatal ones in *testing*, *production* but only display them in *development*. + - Updated *ip_address* database field lengths from 16 to 45 for supporting IPv6 address on :doc:`Trackback Library <libraries/trackback>` and :doc:`Captcha Helper <helpers/captcha_helper>`. + - Removed *cheatsheets* and *quick_reference* PDFs from the documentation. + - Added availability checks where usage of dangerous functions like ``eval()`` and ``exec()`` is required. - Helpers - - url_title() will now trim extra dashes from beginning and end. + - :doc:`Date Helper <helpers/date_helper>` changes include: + - ``now()`` now works with all timezone strings supported by PHP. + - Added an optional third parameter to ``timespan()`` that constrains the number of time units displayed. + - Added an optional parameter to ``timezone_menu()`` that allows more attributes to be added to the generated select tag. + - Deprecated ``standard_date()``, which now just uses the native ``date()`` with `DateTime constants <http://www.php.net/manual/en/class.datetime.php#datetime.constants.types>`_. + - Added function ``date_range()`` that generates a list of dates between a specified period. + - ``create_captcha()`` accepts additional colors parameter, allowing for color customization. + - :doc:`URL Helper <helpers/url_helper>` changes include: + - Deprecated *separator* options **dash** and **underscore** for function :php:func:`url_title()` (they are only aliases for '-' and '_' respectively). + - :php:func:`url_title()` will now trim extra dashes from beginning and end. + - :php:func:`anchor_popup()` will now fill the *href* attribute with the URL and its JS code will return FALSE instead. + - Added JS window name support to the :php:func:`anchor_popup()` function. + - Added support (auto-detection) for HTTP/1.1 response code 303 in :php:func:`redirect()`. + - Changed :php:func:`redirect()` to only choose the **refresh** method only on IIS servers, instead of all servers on Windows (when **auto** is used). - Added XHTML Basic 1.1 doctype to :doc:`HTML Helper <helpers/html_helper>`. - - Changed humanize to include a second param for the separator. - - Refactored ``plural()`` and ``singular()`` to avoid double pluralization and support more words. + - :doc:`Inflector Helper <helpers/inflector_helper>` changes include: + - Changed :php:func:`humanize()` to allow passing an input separator as its second parameter. + - Refactored :php:func:`plural()` and :php:func:`singular()` to avoid double pluralization and support more words. - Added an optional third parameter to ``force_download()`` that enables/disables sending the actual file MIME type in the Content-Type header (disabled by default). - - Added an optional third parameter to ``timespan()`` that constrains the number of time units displayed. - - Added a work-around in force_download() for a bug Android <= 2.1, where the filename extension needs to be in uppercase. - - form_dropdown() will now also take an array for unity with other form helpers. - - set_realpath() can now also handle file paths as opposed to just directories. - - do_hash() now uses PHP's native hash() function, supporting more algorithms. - - Added an optional paramater to ``delete_files()`` to enable it to skip deleting files such as .htaccess and index.html. + - Added a work-around in ``force_download()`` for a bug Android <= 2.1, where the filename extension needs to be in uppercase. + - :doc:`Form Helper <helpers/form_helper>` changes include: + - :php:func:`form_dropdown()` will now also take an array for unity with other form helpers. + - :php:func:`form_prep()`'s second argument now only accepts a boolean value, which determines whether the value is escaped for a <textarea> or a regular <input> element. + - :doc:`Security Helper <helpers/security_helper>` changes include: + - :php:func:`do_hash()` now uses PHP's native ``hash()`` function (supporting more algorithms) and is deprecated. + - :php:func:`strip_image_tags()` is now an alias for the same method in the :doc:`Security Library <libraries/security>`. + - Removed previously deprecated helper function ``js_insert_smiley()`` from :doc:`Smiley Helper <helpers/smiley_helper>`. + - :doc:`File Helper <helpers/file_helper>` changes include: + - :php:func:`set_realpath()` can now also handle file paths as opposed to just directories. + - Added an optional paramater to :php:func:`delete_files()` to enable it to skip deleting files such as *.htaccess* and *index.html*. + - Deprecated function ``read_file()`` - it's just an alias for PHP's native ``file_get_contents()``. + - :doc:`String Helper <helpers/string_helper>` changes include: + - Deprecated function ``repeater()`` - it's just an alias for PHP's native ``str_repeat()``. + - Deprecated function ``trim_slashes()`` - it's just an alias for PHP's native ``trim()`` (with a slash as its second argument). + - Deprecated randomization type options **unique** and **encrypt** for funcion :php:func:`random_string()` (they are only aliases for **md5** and **sha1** respectively). + - :doc:`Directory Helper <helpers/directory_helper>` ``directory_map()`` will now append DIRECTORY_SEPARATOR to directory names in the returned array. + - Deprecated the :doc:`Email Helper <helpers/email_helper>` as its ``valid_email()``, ``send_email()`` functions are now only aliases for PHP native functions ``filter_var()`` and ``mail()`` respectively. - Database - - Added new :doc:`Active Record <database/active_record>` methods that return - the SQL string of queries without executing them: get_compiled_select(), - get_compiled_insert(), get_compiled_update(), get_compiled_delete(). - - Adding $escape parameter to the order_by function, this enables ordering by custom fields. - - Improved support for the MySQLi driver, including: - - OOP style of the PHP extension is now used, instead of the procedural aliases. - - Server version checking is now done via ``mysqli::$server_info`` instead of running an SQL query. - - Added persistent connections support for PHP >= 5.3. - - Added 'dsn' configuration setting for drivers that support DSN strings (PDO, PostgreSQL, Oracle, ODBC, CUBRID). - - Improved PDO database support. - - Added Interbase/Firebird database support via the "interbase" driver - - Added an optional database name parameter to db_select(). - - Replaced the _error_message() and _error_number() methods with error(), that returns an array containing the last database error code and message. - - Improved version() implementation so that drivers that have a native function to get the version number don't have to be defined in the core DB_driver class. - - Improved support of the PostgreSQL driver, including: - - pg_version() is now used to get the database version number, when possible. - - Added db_set_charset() support. - - Added _optimize_table() support for the :doc:`Database Utility Class <database/utilities>` (rebuilds table indexes). - - Added a constructor to the DB_result class and moved all driver-specific properties and logic out of the base DB_driver class to allow better abstraction. - - Removed limit() and order_by() support for UPDATE and DELETE queries in PostgreSQL driver. Postgres does not support those features. - - Removed protect_identifiers() and renamed internal method _protect_identifiers() to it instead - it was just an alias. + - Added **dsn** configuration setting for drivers that support DSN strings (PDO, PostgreSQL, Oracle, ODBC, CUBRID). + - Added **schema** configuration setting (defaults to *public*) for drivers that might need it (currently used by PostgreSQL and ODBC). + - Added subdrivers support (currently only used by PDO). + - Added an optional database name parameter to ``db_select()``. + - Added a constructor to the ``DB_result`` class and moved all driver-specific properties and logic out of the base ``DB_driver`` class to allow better abstraction. + - Removed ``protect_identifiers()`` and renamed internal method ``_protect_identifiers()`` to it instead - it was just an alias. + - Renamed internal method ``_escape_identifiers()`` to ``escape_identifiers()``. + - Updated ``escape_identifiers()`` to accept an array of fields as well as strings. - MySQL and MySQLi drivers now require at least MySQL version 5.1. - - db_set_charset() now only requires one parameter (collation was only needed due to legacy support for MySQL versions prior to 5.1). - - Added DSN string support for CUBRID. - - Added persistent connections support for CUBRID. - - Added random ordering support for MSSQL, SQLSRV. + - ``db_set_charset()`` now only requires one parameter (collation was only needed due to legacy support for MySQL versions prior to 5.1). + - Replaced the ``_error_message()`` and ``_error_number()`` methods with ``error()``, which returns an array containing the last database error code and message. + - Improved ``version()`` implementation so that drivers that have a native function to get the version number don't have to be defined in the core ``DB_driver`` class. + - Added ``unbuffered_row()`` method for getting a row without prefetching whole result (consume less memory). + - Added capability for packages to hold *database.php* config files. + - Added MySQL client compression support. + - Added encrypted connections support (for *mysql*, *sqlsrv* and PDO with *sqlsrv*). + - Removed :doc:`Loader Class <libraries/loader>` from Database error tracing to better find the likely culprit. - Added support for SQLite3 database driver. + - Added Interbase/Firebird database support via the *ibase* driver. + - Added ODBC support for ``create_database()``, ``drop_database()`` and ``drop_table()`` in :doc:`Database Forge <database/forge>`. + - :doc:`Query Builder <database/query_builder>` changes include: + - Renamed the Active Record class to Query Builder to remove confusion with the Active Record design pattern. + - Added the ability to insert objects with ``insert_batch()``. + - Added new methods that return the SQL string of queries without executing them: ``get_compiled_select()``, ``get_compiled_insert()``, ``get_compiled_update()``, ``get_compiled_delete()``. + - Added an optional parameter that allows to disable escaping (useful for custom fields) for methods ``join()``, ``order_by()``, ``where_in()``, ``or_where_in()``, ``where_not_in()``, ``or_where_not_in()``, ``insert()``, ``insert_batch()``. + - Added support for ``join()`` with multiple conditions. + - Added support for *USING* in ``join()``. + - Added seed values support for random ordering with ``order_by(seed, 'RANDOM')``. + - Changed ``limit()`` to ignore NULL values instead of always casting to integer. + - Changed ``offset()`` to ignore empty values instead of always casting to integer. + - Methods ``insert_batch()`` and ``update_batch()`` now return an integer representing the number of rows affected by them. + - Improved support for the MySQLi driver, including: + - OOP style of the PHP extension is now used, instead of the procedural aliases. + - Server version checking is now done via ``mysqli::$server_info`` instead of running an SQL query. + - Added persistent connections support for PHP >= 5.3. + - Added support for ``backup()`` in :doc:`Database Utilities <database/utilities>`. + - Improved support of the PDO driver, including: + - Added support for ``create_database()``, ``drop_database()`` and ``drop_table()`` in :doc:`Database Forge <database/forge>`. + - Added support for ``list_fields()`` in :doc:`Database Results <database/results>`. + - Subdrivers are now isolated from each other instead of being in one large class. + - Improved support of the PostgreSQL driver, including: + - ``pg_version()`` is now used to get the database version number, when possible. + - Added ``db_set_charset()`` support. + - Added support for ``optimize_table()`` in :doc:`Database Utilities <database/utilities>` (rebuilds table indexes). + - Added boolean data type support in ``escape()``. + - Added ``update_batch()`` support. + - Removed ``limit()`` and ``order_by()`` support for *UPDATE* and *DELETE* queries as PostgreSQL does not support those features. + - Added a work-around for dead persistent connections to be re-created after a database restart. + - Improved support of the CUBRID driver, including: + - Added DSN string support. + - Added persistent connections support. + - Improved ``list_databases()`` in :doc:`Database Utility <database/utilities>` (until now only the currently used database was returned). + - Improved support of the MSSQL and SQLSRV drivers, including: + - Added random ordering support. + - Added support for ``optimize_table()`` in :doc:`Database Utility <database/utilities>`. + - Added escaping with *QUOTE_IDENTIFIER* setting detection. + - Added port handling support for UNIX-based systems (MSSQL driver). + - Added *OFFSET* support for SQL Server 2005 and above. - Improved support of the Oracle (OCI8) driver, including: - - Added DSN string support (Easy Connect and TNS). - - Added support for dropping tables to :doc:`Database Forge <database/forge>`. - - Added support for listing database schemas to :doc:`Database Utilities <database/utilities>`. - - Generally improved for speed and cleaned up all of its components. - - *Row* result methods now really only fetch only the needed number of rows, instead of depending entirely on result(). - - num_rows() is now only called explicitly by the developer and no longer re-executes statements. - - Added replace() support for SQLite. - - Renamed internal method _escape_identifiers() to escape_identifiers(). - - Added SQLite support for drop_table() in :doc:`Database Forge <database/forge>`. - - Added ODBC support for create_database(), drop_database() and drop_table() in :doc:`Database Forge <database/forge>`. - - Added PDO support for create_database(), drop_database and drop_table() in :doc:`Database Forge <database/forge>`. - - Added MSSQL, SQLSRV support for optimize_table() in :doc:`Database Utility <database/utilities>`. - - Improved CUBRID support for list_databases() in :doc:`Database Utility <database/utilities>` (until now only the currently used database was returned). + - Added DSN string support (Easy Connect and TNS). + - Added support for ``drop_table()`` in :doc:`Database Forge <database/forge>`. + - Added support for ``list_databases()`` in :doc:`Database Utilities <database/utilities>`. + - Generally improved for speed and cleaned up all of its components. + - ``num_rows()`` is now only called explicitly by the developer and no longer re-executes statements. + - Improved support of the SQLite driver, including: + - Added support for ``replace()`` in :doc:`Query Builder <database/query_builder>`. + - Added support for ``drop_table()`` in :doc:`Database Forge <database/forge>`. + - :doc:`Database Forge <database/forge>` changes include: + - Added an optional second parameter to ``drop_table()`` that allows adding the **IF EXISTS** condition, which is no longer the default. + - Added support for passing a custom database object to the loader. + - Deprecated ``add_column()``'s third method. *AFTER* clause should now be added to the field definition array instead. + - Added support for usage of the *FIRST* clause in ``add_column()`` for MySQL and CUBRID. + - Overall improved support for all of the drivers. + - :doc:`Database Utility <database/utilities>` chages include: + - Added support for passing a custom database object to the loader. + - Modified the class to no longer extend :doc:`Database Forge <database/forge>`, which has been a deprecated behavior for awhile. + - Overall improved support for all of the drivers. - Libraries - - Added max_filename_increment config setting for Upload library. - - CI_Loader::_ci_autoloader() is now a protected method. - - Added custom filename to Email::attach() as $this->email->attach($filename, $disposition, $newname). - - Added possibility to send attachment as buffer string in Email::attach() as $this->email->attach($buffer, $disposition, $newname, $mime). - - Cart library changes include: - - It now auto-increments quantity's instead of just resetting it, this is the default behaviour of large e-commerce sites. - - Product Name strictness can be disabled via the Cart Library by switching "$product_name_safe" - - Added function remove() to remove a cart item, updating with quantity of 0 seemed like a hack but has remained to retain compatability + - :doc:`Session Library <libraries/sessions>` changes include: + - Library changed to :doc:`Driver <general/drivers>` with classic Cookie driver as default. + - Added Native PHP Session driver to work with ``$_SESSION``. + - Custom drivers can be added anywhere in package paths and be loaded with the library. + - Drivers interchangeable on the fly. + - New **tempdata** feature allows setting user data items with an expiration time. + - Added default ``$config['sess_driver']`` and ``$config['sess_valid_drivers']`` items to *config.php* file. + - Cookie driver now respects php.ini's *session.gc_probability* and *session.gc_divisor* settings. + - Cookie driver now uses HMAC authentication instead of the simple md5 checksum. + - The Cookie driver now also checks authentication on encrypted session data. + - Changed the Cookie driver to select only one row when using database sessions. + - Cookie driver now only writes to database at end of request when using database. + - Cookie driver now uses PHP functions for faster array manipulation when using database. + - Added ``all_flashdata()`` method to session class. Returns an associative array of only flashdata. + - Added ``has_userdata()`` method to verify existence of userdata item. + - Added ``tempdata()``, ``set_tempdata()``, and ``unset_tempdata()`` methods for manipulating tempdata. + - :doc:`File Uploading Library <libraries/file_uploading>` changes include: + - Added *max_filename_increment* config setting. + - Added an "index" parameter to the ``data()`` method. + - :doc:`Cart library <libraries/cart>` changes include: + - ``insert()`` now auto-increments quantity for an item when inserted twice instead of resetting it, this is the default behaviour of large e-commerce sites. + - *Product Name* strictness can be disabled by switching the ``$product_name_safe`` property to FALSE. + - Added method ``remove()`` to remove a cart item, updating with quantity of 0 seemed like a hack but has remained to retain compatibility. + - Added method ``get_item()`` to enable retrieving data for a single cart item. - :doc:`Image Manipulation library <libraries/image_lib>` changes include: - - The initialize() method now only sets existing class properties. - - Added support for 3-length hex color values for wm_font_color and wm_shadow_color properties, as well as validation for them. - - Class properties wm_font_color, wm_shadow_color and wm_use_drop_shadow are now protected, to avoid breaking the text_watermark() method - if they are set manually after initialization. - - If property maintain_ratio is set to TRUE, image_reproportion() now doesn't need both width and height to be specified. - - Minor speed optimizations and method & property visibility declarations in the Calendar Library. - - Removed SHA1 function in the :doc:`Encryption Library <libraries/encryption>`. - - Added $config['csrf_regeneration'] to the CSRF protection in the :doc:`Security library <libraries/security>`, which makes token regeneration optional. + - The ``initialize()`` method now only sets existing class properties. + - Added support for 3-length hex color values for *wm_font_color* and *wm_shadow_color* properties, as well as validation for them. + - Class properties *wm_font_color*, *wm_shadow_color* and *wm_use_drop_shadow* are now protected, to avoid breaking the ``text_watermark()`` method if they are set manually after initialization. + - If property *maintain_ratio* is set to TRUE, ``image_reproportion()`` now doesn't need both width and height to be specified. + - Property *maintain_ratio* is now taken into account when resizing images using ImageMagick library. + - Added support for maintaining transparency for PNG images in method ``text_watermark()``. - :doc:`Form Validation library <libraries/form_validation>` changes include: - - Added method error_array() to return all error messages as an array. - - Added method set_data() to set an alternative data array to be validated instead of the default $_POST. - - Added method reset_validation(), which resets internal validation variables in case of multiple validation routines. - - Added support for setting error delimiters in the config file via $config['error_prefix'] and $config['error_suffix']. - - _execute() now considers input data to be invalid if a specified rule is not found. - - Removed method is_numeric() as it exists as a native PHP function and _execute() will find and use that (the 'is_numeric' rule itself is deprecated since 1.6.1). + - Added method ``error_array()`` to return all error messages as an array. + - Added method ``set_data()`` to set an alternative data array to be validated instead of the default ``$_POST``. + - Added method ``reset_validation()`` which resets internal validation variables in case of multiple validation routines. + - Added support for setting error delimiters in the config file via ``$config['error_prefix']`` and ``$config['error_suffix']``. + - ``_execute()`` now considers input data to be invalid if a specified rule is not found. + - Removed method ``is_numeric()`` as it exists as a native PHP function and ``_execute()`` will find and use that (the *is_numeric* rule itself is deprecated since 1.6.1). - Native PHP functions used as rules can now accept an additional parameter, other than the data itself. - - Changed the :doc:`Session Library <libraries/sessions>` to select only one row when using database sessions. - - Added all_flashdata() method to session class. Returns an associative array of only flashdata. - - Allowed for setting table class defaults in a config file. - - Added a Wincache driver to the :doc:`Caching Library <libraries/caching>`. - - Added dsn (delivery status notification) option to the :doc:`Email Library <libraries/email>`. + - Updated ``set_rules()`` to accept an array of rules as well as a string. + - Fields that have empty rules set no longer run through validation (and therefore are not considered erroneous). + - Added rule *differs* to check if the value of a field differs from the value of another field. + - Added support for setting :doc:`Table <libraries/table>` class defaults in a config file. + - :doc:`Caching Library <libraries/caching>` changes include: + - Added Wincache driver. + - Added Redis driver. + - Added a *key_prefix* option for cache IDs. + - :doc:`Email library <libraries/email>` changes include: + - Added custom filename to ``Email::attach()`` as ``$this->email->attach($filename, $disposition, $newname)``. + - Added possibility to send attachment as buffer string in ``Email::attach()`` as ``$this->email->attach($buffer, $disposition, $newname, $mime)``. + - Added dsn (delivery status notification) option. + - Renamed method _set_header() to set_header() and made it public to enable adding custom headers in the :doc:`Email Library <libraries/email>`. + - Successfully sent emails will automatically clear the parameters. + - Added a *return_path* parameter to the ``from()`` method. + - Removed the second parameter (character limit) from internal method ``_prep_quoted_printable()`` as it is never used. + - Internal method ``_prep_quoted_printable()`` will now utilize the native ``quoted_printable_encode()``, ``imap_8bit()`` functions (if available) when CRLF is set to "\r\n". + - Default charset now relies on the global ``$config['charset']`` setting. + - Removed unused protected method ``_get_ip()`` (:doc:`Input Library <libraries/input>`'s ``ip_address()`` should be used anyway). + - Internal method ``_prep_q_encoding()`` now utilizes PHP's *mbstring* and *iconv* extensions (when available) and no longer has a second (``$from``) argument. + - :doc:`Pagination Library <libraries/pagination>` changes include: + - Added support for the anchor "rel" attribute. + - Added support for setting custom attributes. + - Deprecated usage of the "anchor_class" setting (use the new "attributes" setting instead). + - Added $config['reuse_query_string'] to allow automatic repopulation of query string arguments, combined with normal URI segments. + - Removed the default `` `` from a number of the configuration variables. + - Added the ability to use a proxy with the :doc:`XML-RPC Library <libraries/xmlrpc>`. + - :doc:`Encryption Library <libraries/encryption>` changes include: + - Added support for hashing algorithms other than SHA1 and MD5. + - Removed previously deprecated ``sha1()`` method. + - Changed :doc:`Language Library <libraries/language>` method ``load()`` to filter the language name with ``ctype_digit()``. + - :doc:`Profiler Library <general/profiling>` now also displays database object names. + - :doc:`Migration Library <libraries/migration>` changes include: + - Added support for timestamp-based migrations (enabled by default). + - Added ``$config['migration_type']`` to allow switching between *sequential* and *timestamp* migrations. - Core - - Changed private functions in CI_URI to protected so MY_URI can override them. - - Removed CI_CORE boolean constant from CodeIgniter.php (no longer Reactor and Core versions). - - Added method get_vars() to CI_Loader to retrieve all variables loaded with $this->load->vars(). - - is_loaded() function from system/core/Commons.php now returns a reference. - - $config['rewrite_short_tags'] now has no effect when using PHP 5.4 as *<?=* will always be available. - - Added method() to CI_Input to retrieve $_SERVER['REQUEST_METHOD']. - - Modified valid_ip() to use PHP's filter_var() in the :doc:`Input Library <libraries/input>`. - - Added support for HTTP-Only cookies with new config option ``cookie_httponly`` (default FALSE). - - Renamed method _call_hook() to call_hook() in the :doc:`Hooks Library <general/hooks>`. - - Added get_content_type() method to the :doc:`Output Library <libraries/output>`. + - :doc:`URI Library <libraries/uri>` changes include: + - Changed private methods to protected so that MY_URI can override them. + - Renamed internal method ``_parse_cli_args()`` to ``_parse_argv()``. + - Renamed internal method ``_detect_uri()`` to ``_parse_request_uri()``. + - Changed ``_parse_request_uri()`` to accept absolute URIs for compatibility with HTTP/1.1 as per `RFC2616 <http://www.ietf.org/rfc/rfc2616.txt>`. + - Added protected method ``_parse_query_string()`` to URI paths in the the **QUERY_STRING** value, like ``_parse_request_uri()`` does. + - Changed ``_fetch_uri_string()`` to try the **PATH_INFO** variable first when auto-detecting. + - Removed ``CI_CORE`` boolean constant from *CodeIgniter.php* (no longer Reactor and Core versions). + - :doc:`Loader Library <libraries/loader>` changes include: + - Added method ``get_vars()`` to the Loader to retrieve all variables loaded with ``$this->load->vars()``. + - ``_ci_autoloader()`` is now a protected method. + - Added autoloading of drivers with ``$autoload['drivers']``. + - ``library()`` method will now load drivers as well, for backward compatibility of converted libraries (like :doc:`Session <libraries/sessions>`). + - ``$config['rewrite_short_tags']`` now has no effect when using PHP 5.4 as ``<?=`` will always be available. + - Changed method ``config()`` to return whatever ``CI_Config::load()`` returns instead of always being void. + - :doc:`Input Library <libraries/input>` changes include: + - Added ``method()`` to retrieve ``$_SERVER['REQUEST_METHOD']``. + - Added support for arrays and network addresses (e.g. 192.168.1.1/24) for use with the *proxy_ips* setting. + - Added method ``input_stream()`` to aid in using **php://input** stream data such as one passed via PUT, DELETE and PATCH requests. + - Changed method ``valid_ip()`` to use PHP's native ``filter_var()`` function. + - Changed internal method ``_sanitize_globals()`` to skip enforcing reversal of *register_globals* in PHP 5.4+, where this functionality no longer exists. + - Changed methods ``get()``, ``post()``, ``get_post()``, ``cookie()``, ``server()``, ``user_agent()`` to return NULL instead of FALSE when no value is found. + - :doc:`Common functions <general/common_functions>` changes include: + - Added function :php:func:`get_mimes()` to return the *application/config/mimes.php* array. + - Added support for HTTP code 303 ("See Other") in :php:func:`set_status_header()`. + - Removed redundant conditional to determine HTTP server protocol in :php:func:`set_status_header()`. + - Changed ``_exception_handler()`` to respect php.ini *display_errors* setting. + - Added function :php:func:`is_https()` to check if a secure connection is used. + - Added function :php:func:`function_usable()` to check if a function exists and is not disabled by `Suhosin <http://www.hardened-php.net/suhosin/>`. + - Added support for HTTP-Only cookies with new config option *cookie_httponly* (default FALSE). + - Renamed method ``_call_hook()`` to ``call_hook()`` in the :doc:`Hooks Library <general/hooks>`. + - :doc:`Output Library <libraries/output>` changes include: + - Added method ``get_content_type()``. + - Added a second argument to method ``set_content_type()`` that allows setting the document charset as well. + - ``$config['time_reference']`` now supports all timezone strings supported by PHP. + - :doc:`Config Library <libraries/config>` changes include: + - Changed ``site_url()`` method to accept an array as well. + - Removed internal method ``_assign_to_config()`` and moved it's implementation in *CodeIgniter.php* instead. + - :doc:`Security Library <libraries/security>` changes include: + - Added method ``strip_image_tags()``. + - Added ``$config['csrf_regeneration']``, which makes token regeneration optional. + - Added ``$config['csrf_exclude_uris']``, which allows you list URIs which will not have the CSRF validation methods run. + - :doc:`URI Routing <general/routing>` changes include: + - Added possibility to route requests using callbacks. + - Added possibility to use dashes in the controller and method URI segments (translated to underscores). Bug fixes for 3.0 ------------------ -- Unlink raised an error if cache file did not exist when you try to delete it. +- Fixed a bug where ``unlink()`` raised an error if cache file did not exist when you try to delete it. - Fixed a bug (#181) where a mis-spelling was in the form validation language file. -- Fixed a bug (#159, #163) that mishandled Active Record nested transactions because _trans_depth was not getting incremented. -- Fixed a bug (#737, #75) where pagination anchor class was not set properly when using initialize method. +- Fixed a bug (#159, #163) that mishandled Query Builder nested transactions because _trans_depth was not getting incremented. +- Fixed a bug (#737, #75) - :doc:`Pagination <libraries/pagination>` anchor class was not set properly when using initialize method. - Fixed a bug (#419) - auto_link() now recognizes URLs that come after a word boundary. - Fixed a bug (#724) - is_unique in form validation now checks that you are connected to a database. -- Fixed a bug (#647) - _get_mod_time() in Zip library no longer generates stat failed errors -- Fixed a bug (#608) - Fixes an issue with the Image_lib class not clearing properties completely -- Fixed bugs (#157 and #174) - the Image_lib clear() function now resets all variables to their default values. +- Fixed a bug (#647) - _get_mod_time() in Zip library no longer generates stat failed errors. +- Fixed a bug (#608) - Fixes an issue with the Image_lib class not clearing properties completely. +- Fixed a bug (#157, #174) - the Image_lib clear() function now resets all variables to their default values. - Fixed a bug where using $this->dbforge->create_table() with PostgreSQL database could lead to fetching whole table. - Fixed a bug (#795) - Fixed form method and accept-charset when passing an empty array. -- Fixed a bug (#797) - timespan was using incorrect seconds for year and month. +- Fixed a bug (#797) - timespan() was using incorrect seconds for year and month. - Fixed a bug in CI_Cart::contents() where if called without a TRUE (or equal) parameter, it would fail due to a typo. -- Fixed a bug (#696) - make oci_execute calls inside num_rows non-committing, since they are only there to reset which row is next in line for oci_fetch calls and thus don't need to be committed. -- Fixed a bug (#406) - sqlsrv DB driver not reuturning resource on <samp>db_pconnect()</samp>. +- Fixed a bug (#696) - make oci_execute() calls inside num_rows() non-committing, since they are only there to reset which row is next in line for oci_fetch calls and thus don't need to be committed. +- Fixed a bug (#406) - SQLSRV DB driver not returning resource on ``db_pconnect()``. - Fixed a bug in CI_Image_lib::gd_loaded() where it was possible for the script execution to end or a PHP E_WARNING message to be emitted. -- In Pagination library, when use_page_numbers=TRUE previous link and page 1 link do not have the same url +- Fixed a bug in the :doc:`Pagination library <libraries/pagination>` where when use_page_numbers=TRUE previous link and page 1 link did not have the same url. - Fixed a bug (#561) - Errors in :doc:`XML-RPC Library <libraries/xmlrpc>` were not properly escaped. - Fixed a bug (#904) - ``CI_Loader::initialize()`` caused a PHP Fatal error to be triggered if error level E_STRICT is used. -- Fixed a hosting edge case where an empty $_SERVER['HTTPS'] variable would evaluate to 'on' +- Fixed a hosting edge case where an empty $_SERVER['HTTPS'] variable would evaluate to 'on'. - Fixed a bug (#154) - ``CI_Session::sess_update()`` caused the session to be destroyed on pages where multiple AJAX requests were executed at once. - Fixed a possible bug in ``CI_Input::is_ajax_request()`` where some clients might not send the X-Requested-With HTTP header value exactly as 'XmlHttpRequest'. - Fixed a bug (#1039) - MySQL's _backup() method failed due to a table name not being escaped. @@ -175,30 +335,28 @@ Bug fixes for 3.0 - Fixed a bug (#129) - ODBC's num_rows() returned -1 in some cases, due to not all subdrivers supporting the odbc_num_rows() function. - Fixed a bug (#153) - E_NOTICE being generated by getimagesize() in the :doc:`File Uploading Library <libraries/file_uploading>`. - Fixed a bug (#611) - SQLSRV's error handling methods used to issue warnings when there's no actual error. -- Fixed a bug (#1036) - is_write_type() method in the :doc:`Database Library <database/index>` didn't return TRUE for RENAME and OPTIMIZE queries. +- Fixed a bug (#1036) - ``is_write_type()`` method in the :doc:`Database Library <database/index>` didn't return TRUE for RENAME queries. - Fixed a bug in PDO's _version() method where it used to return the client version as opposed to the server one. - Fixed a bug in PDO's insert_id() method where it could've failed if it's used with Postgre versions prior to 8.1. - Fixed a bug in CUBRID's affected_rows() method where a connection resource was passed to cubrid_affected_rows() instead of a result. - Fixed a bug (#638) - db_set_charset() ignored its arguments and always used the configured charset instead. - Fixed a bug (#413) - Oracle's error handling methods used to only return connection-related errors. -- Fixed a bug (#804) - Profiler library was trying to handle objects as strings in some cases, resulting in warnings being issued by htmlspecialchars(). - Fixed a bug (#1101) - MySQL/MySQLi result method field_data() was implemented as if it was handling a DESCRIBE result instead of the actual result set. - Fixed a bug in Oracle's :doc:`Database Forge Class <database/forge>` method _create_table() where it failed with AUTO_INCREMENT as it's not supported. - Fixed a bug (#1080) - When using the SMTP protocol, the :doc:`Email Library <libraries/email>` send() method was returning TRUE even if the connection/authentication against the server failed. -- Fixed a bug (#499) - a CSRF cookie was created even with CSRF protection being disabled. - Fixed a bug (#306) - ODBC's insert_id() method was calling non-existent function odbc_insert_id(), which resulted in a fatal error. - Fixed a bug in Oracle's DB_result class where the cursor id passed to it was always NULL. -- Fixed a bug (#64) - Regular expression in DB_active_rec.php failed to handle queries containing SQL bracket delimiters in the join condition. +- Fixed a bug (#64) - Regular expression in DB_query_builder.php failed to handle queries containing SQL bracket delimiters in the join condition. - Fixed a bug in the :doc:`Session Library <libraries/sessions>` where a PHP E_NOTICE error was triggered by _unserialize() due to results from databases such as MSSQL and Oracle being space-padded on the right. - Fixed a bug (#501) - set_rules() to check if the request method is not 'POST' before aborting, instead of depending on count($_POST) in the :doc:`Form Validation Library <libraries/form_validation>`. -- Fixed a bug (#940) - csrf_verify() used to set the CSRF cookie while processing a POST request with no actual POST data, which resulted in validating a request that should be considered invalid. -- Fixed a bug in PostgreSQL's escape_str() where it didn't properly escape LIKE wild characters. +- Fixed a bug (#136) - PostgreSQL, MySQL and MySQLi's escape_str() method didn't properly escape LIKE wild characters. - Fixed a bug in the library loader where some PHP versions wouldn't execute the class constructor. - Fixed a bug (#88) - An unexisting property was used for configuration of the Memcache cache driver. - Fixed a bug (#14) - create_database() method in the :doc:`Database Forge Library <database/forge>` didn't utilize the configured database character set. -- Fixed a bug (#1238) - delete_all() in the `Database Caching Library <database/caching>` used to delete .htaccess and index.html files, which is a potential security risk. +- Fixed a bug (#23, #1238) - delete_all() in the `Database Caching Library <database/caching>` used to delete .htaccess and index.html files, which is a potential security risk. - Fixed a bug in :doc:`Trackback Library <libraries/trackback>` method validate_url() where it didn't actually do anything, due to input not being passed by reference. - Fixed a bug (#11, #183, #863) - CI_Form_validation::_execute() silently continued to the next rule, if a rule method/function is not found. +- Fixed a bug (#122) Where routed uri string was being reported incorrectly in sub-directories. - Fixed a bug (#1242) - read_dir() in the :doc:`Zip Library <libraries/zip>` wasn't compatible with Windows. - Fixed a bug (#306) - ODBC driver didn't have an _insert_batch() method, which resulted in fatal error being triggered when insert_batch() is used with it. - Fixed a bug in MSSQL and SQLSrv's _truncate() where the TABLE keyword was missing. @@ -206,29 +364,145 @@ Bug fixes for 3.0 - Fixed a bug (#798) - update() used to ignore LIKE conditions that were set with like(). - Fixed a bug in Oracle's and MSSQL's delete() methods where an erroneous SQL statement was generated when used with limit(). - Fixed a bug in SQLSRV's delete() method where like() and limit() conditions were ignored. +- Fixed a bug (#1265) - Database connections were always closed, regardless of the 'pconnect' option value. +- Fixed a bug (#128) - :doc:`Language Library <libraries/language>` did not correctly keep track of loaded language files. +- Fixed a bug (#1242) - Added Windows path compatibility to function read_dir of ZIP library. +- Fixed a bug (#1349) - get_extension() in the :doc:`File Uploading Library <libraries/file_uploading>` returned the original filename when it didn't have an actual extension. +- Fixed a bug (#1273) - E_NOTICE being generated by :doc:`Query Builder <database/query_builder>`'s set_update_batch() method. +- Fixed a bug (#44, #110) - :doc:`Upload library <libraries/file_uploading>`'s clean_file_name() method didn't clear '!' and '#' characters. +- Fixed a bug (#121) - ``CI_DB_result::row()`` returned an array when there's no actual result to be returned. +- Fixed a bug (#319) - SQLSRV's affected_rows() method failed due to a scrollable cursor being created for write-type queries. +- Fixed a bug (#356) - PostgreSQL driver didn't have an _update_batch() method, which resulted in fatal error being triggered when update_batch() is used with it. +- Fixed a bug (#784, #862) - :doc:`Database Forge <database/forge>` method ``create_table()`` failed on SQLSRV/MSSQL when used with 'IF NOT EXISTS'. +- Fixed a bug (#1419) - libraries/Driver.php had a static variable that was causing an error. +- Fixed a bug (#1411) - the :doc:`Email library <libraries/email>` used its own short list of MIMEs instead the one from config/mimes.php. +- Fixed a bug where the magic_quotes_runtime setting wasn't turned off for PHP 5.3 (where it is indeed deprecated, but not non-existent). +- Fixed a bug (#666) - :doc:`Output library <libraries/output>`'s set_content_type() method didn't set the document charset. +- Fixed a bug (#784, #861) - :doc:`Database Forge <database/forge>` method ``create_table()`` used to accept constraints for MSSQL/SQLSRV integer-type columns. +- Fixed a bug (#706) - SQLSRV/MSSSQL didn't escape field names. +- Fixed a bug (#1452) - ``protect_identifiers()`` didn't properly detect identifiers with spaces in their names. +- Fixed a bug where ``protect_identifiers()`` ignored it's extra arguments when the value passed to it is an array. +- Fixed a bug where ``_has_operator()`` didn't detect BETWEEN. +- Fixed a bug in :doc:`Query Builder <database/query_builder>`'s ``join()`` method where it failed with identifiers containing dashes. +- Fixed a bug (#1264) - :doc:`Database Forge <database/forge>` and :doc:`Database Utilities <database/utilities>` didn't update/reset the databases and tables list cache when a table or a database is created, dropped or renamed. +- Fixed a bug (#7) - :doc:`Query Builder <database/query_builder>`'s ``join()`` method only escaped one set of conditions. +- Fixed a bug (#1321) - Core Exceptions class couldn't find the errors/ folder in some cases. +- Fixed a bug (#1202) - :doc:`Encryption Library <libraries/encryption>` encode_from_legacy() didn't set back the encrypt mode on failure. +- Fixed a bug (#145) - compile_binds() failed when the bind marker was present in a literal string within the query. +- Fixed a bug in protect_identifiers() where if passed along with the field names, operators got escaped as well. +- Fixed a bug (#10) - :doc:`URI Library <libraries/uri>` internal method _detect_uri() failed with paths containing a colon. +- Fixed a bug (#1387) - :doc:`Query Builder <database/query_builder>`'s from() method didn't escape table aliases. +- Fixed a bug (#520) - :doc:`Date Helper <helpers/date_helper>` function nice_date() failed when the optional second parameter is not passed. +- Fixed a bug (#167) - ``$config['permitted_uri_chars']`` didn't affect URL-encoded characters. +- Fixed a bug (#318) - :doc:`Profiling <general/profiling>` setting *query_toggle_count* was not settable as described in the manual. +- Fixed a bug (#938) - :doc:`Config Library <libraries/config>` method ``site_url()`` added a question mark to the URL string when query strings are enabled even if it already existed. +- Fixed a bug (#999) - :doc:`Config Library <libraries/config>` method ``site_url()`` always appended ``$config['url_suffix']`` to the end of the URL string, regardless of whether a query string exists in it. +- Fixed a bug where :doc:`URL Helper <helpers/url_helper>` function ``anchor_popup()`` ignored the attributes argument if it is not an array. +- Fixed a bug (#1328) - :doc:`Form Validation Library <libraries/form_validation>` didn't properly check the type of the form fields before processing them. +- Fixed a bug (#79) - :doc:`Form Validation Library <libraries/form_validation>` didn't properly validate array fields that use associative keys or have custom indexes. +- Fixed a bug (#427) - :doc:`Form Validation Library <libraries/form_validation>` method ``strip_image_tags()`` was an alias to a non-existent method. +- Fixed a bug (#1545) - :doc:`Query Builder <database/query_builder>` method ``limit()`` wasn't executed properly under Oracle. +- Fixed a bug (#1551) - :doc:`Date Helper <helpers/date_helper>` function ``standard_date()`` didn't properly format *W3C* and *ATOM* standard dates. +- Fixed a bug in :doc:`Query Builder <database/query_builder>` method join() where literal values were escaped as if they were fields. +- Fixed a bug (#135) - PHP Error logging was impossible without the errors being displayed. +- Fixed a bug (#1613) - :doc:`Form Helper <helpers/form_helper>` functions ``form_multiselect()``, ``form_dropdown()`` didn't properly handle empty array option groups. +- Fixed a bug (#1605) - :doc:`Pagination Library <libraries/pagination>` produced incorrect *previous* and *next* link values. +- Fixed a bug in SQLSRV's ``affected_rows()`` method where an erroneous function name was used. +- Fixed a bug (#1000) - Change syntax of ``$view_file`` to ``$_ci_view_file`` to prevent being overwritten by application. +- Fixed a bug (#1757) - :doc:`Directory Helper <helpers/directory_helper>` function ``directory_map()`` was skipping files and directories named *0*. +- Fixed a bug (#1789) - :doc:`Database Library <database/index>` method ``escape_str()`` escaped quote characters in LIKE conditions twice under MySQL. +- Fixed a bug (#395) - :doc:`Unit Testing Library <libraries/unit_testing>` method ``result()`` didn't properly check array result columns when called from ``report()``. +- Fixed a bug (#1692) - :doc:`Database Library <database/index>` method ``display_error()`` didn't properly trace the possible error source on Windows systems. +- Fixed a bug (#1745) - ``is_write_type()`` method in the :doc:`Database Library <database/index>` didn't return TRUE for LOAD queries. +- Fixed a bug (#1765) - :doc:`Database Library <database/index>` didn't properly detect connection errors for MySQLi. +- Fixed a bug (#1257) - :doc:`Query Builder <database/query_builder>` used to (unnecessarily) group FROM clause contents, which breaks certain queries and is invalid for some databases. +- Fixed a bug (#1709) - :doc:`Email <libraries/email>` headers were broken when using long email subjects and \r\n as CRLF. +- Fixed a bug where ``MB_ENABLED`` was only declared if ``UTF8_ENABLED`` was set to TRUE. +- Fixed a bug where the :doc:`Session Library <libraries/sessions>` accepted cookies with *last_activity* values being in the future. +- Fixed a bug (#1897) - :doc:`Email Library <libraries/email>` triggered PHP E_WARNING errors when *mail* protocol used and ``to()`` is never called. +- Fixed a bug (#1409) - :doc:`Email Library <libraries/email>` didn't properly handle multibyte characters when applying Q-encoding to headers. +- Fixed a bug where :doc:`Email Library <libraries/email>` didn't honor it's *wordwrap* setting while handling alternative messages. +- Fixed a bug (#1476, #1909) - :doc:`Pagination Library <libraries/pagination>` didn't take into account actual routing when determining the current page. +- Fixed a bug (#1766) - :doc:`Query Builder <database/query_builder>` didn't always take into account the *dbprefix* setting. +- Fixed a bug (#779) - :doc:`URI Class <libraries/uri>` didn't always trim slashes from the *uri_string* as shown in the documentation. +- Fixed a bug (#134) - :doc:`Database Caching <database/caching>` method ``delete_cache()`` didn't work in some cases due to *cachedir* not being initialized properly. +- Fixed a bug (#191) - :doc:`Loader Library <libraries/loader>` ignored attempts for (re)loading databases to ``get_instance()->db`` even when the old database connection is dead. +- Fixed a bug (#1255) - :doc:`User Agent Library <libraries/user_agent>` method ``is_referral()`` only checked if ``$_SERVER['HTTP_REFERER']`` exists. +- Fixed a bug (#1146) - :doc:`Download Helper <helpers/download_helper>` function ``force_download()`` incorrectly sent *Cache-Control* directives *pre-check* and *post-check* to Internet Explorer. +- Fixed a bug (#1811) - :doc:`URI Library <libraries/uri>` didn't properly cache segments for ``uri_to_assoc()`` and ``ruri_to_assoc()``. +- Fixed a bug (#1506) - :doc:`Form Helpers <helpers/form_helper>` set empty *name* attributes. +- Fixed a bug (#59) - :doc:`Query Builder <database/query_builder>` method ``count_all_results()`` ignored the DISTINCT clause. +- Fixed a bug (#1624) - :doc:`Form Validation Library <libraries/form_validation>` rule **matches** didn't property handle array field names. +- Fixed a bug (#1630) - :doc:`Form Helper <helpers/form_helper>` function ``set_value()`` didn't escape HTML entities. +- Fixed a bug (#142) - :doc:`Form Helper <helpers/form_helper>` function ``form_dropdown()`` didn't escape HTML entities in option values. +- Fixed a bug (#50) - :doc:`Session Library <libraries/sessions>` unnecessarily stripped slashed from serialized data, making it impossible to read objects in a namespace. +- Fixed a bug (#658) - :doc:`Routing <general/routing>` wildcard **:any** didn't work as advertised and matched multiple URI segments instead of all characters within a single segment. +- Fixed a bug (#1938) - :doc:`Email Library <libraries/email>` removed multiple spaces inside a pre-formatted plain text message. +- Fixed a bug (#388, #705) - :doc:`URI Library <libraries/uri>` didn't apply URL-decoding to URI segments that it got from **REQUEST_URI** and/or **QUERY_STRING**. +- Fixed a bug (#122) - :doc:`URI Library <libraries/uri>` method ``ruri_string()`` didn't include a directory if one is used. +- Fixed a bug - :doc:`Routing Library <general/routing>` didn't properly handle *default_controller* in a subdirectory when a method is also specified. +- Fixed a bug (#953) - :doc:`post_controller_constructor hook <general/hooks>` wasn't called with a *404_override*. +- Fixed a bug (#1220) - :doc:`Profiler Library <general/profiling>` didn't display information for database objects that are instantiated inside models. +- Fixed a bug (#1978) - :doc:`Directory Helper <helpers/directory_helper>` function :php:func:`directory_map()`'s return array didn't make a distinction between directories and file indexes when a directory with a numeric name is present. +- Fixed a bug (#777) - :doc:`Loader Library <libraries/loader>` didn't look for helper extensions in added package paths. + +Version 2.1.3 +============= + +Release Date: October 8, 2012 + +- Core + - :doc:`Common function <general/common_functions>` ``is_loaded()`` now returns a reference. + +Bug fixes for 2.1.3 +------------------- + +- Fixed a bug (#1543) - File-based :doc:`Caching <libraries/caching>` method ``get_metadata()`` used a non-existent array key to look for the TTL value. +- Fixed a bug (#1314) - :doc:`Session Library <libraries/sessions>` method ``sess_destroy()`` didn't destroy the userdata array. +- Fixed a bug (#804) - :doc:`Profiler library <general/profiling>` was trying to handle objects as strings in some cases, resulting in *E_WARNING* messages being issued by ``htmlspecialchars()``. +- Fixed a bug (#1699) - :doc:`Migration Library <libraries/migration>` ignored the ``$config['migration_path']`` setting. +- Fixed a bug (#227) - :doc:`Input Library <libraries/input>` allowed unconditional spoofing of HTTP clients' IP addresses through the *HTTP_CLIENT_IP* header. +- Fixed a bug (#907) - :doc:`Input Library <libraries/input>` ignored *HTTP_X_CLUSTER_CLIENT_IP* and *HTTP_X_CLIENT_IP* headers when checking for proxies. +- Fixed a bug (#940) - ``csrf_verify()`` used to set the CSRF cookie while processing a POST request with no actual POST data, which resulted in validating a request that should be considered invalid. +- Fixed a bug (#499) - :doc:`Security Library <libraries/security>` where a CSRF cookie was created even if ``$config['csrf_protection']`` is set tot FALSE. +- Fixed a bug (#1715) - :doc:`Input Library <libraries/input>` triggered ``csrf_verify()`` on CLI requests. + +Version 2.1.2 +============= + +Release Date: June 29, 2012 + +- General Changes + - Improved security in ``xss_clean()``. Version 2.1.1 ============= -Release Date: Not Released +Release Date: June 12, 2012 - General Changes - Fixed support for docx, xlsx files in mimes.php. - Libraries - Further improved MIME type detection in the :doc:`File Uploading Library <libraries/file_uploading>`. + - Added support for IPv6 to the :doc:`Input Library <libraries/input>`. + - Added support for the IP format parameter to the :doc:`Form Validation Library <libraries/form_validation>`. - Helpers - - url_title() performance and output improved. You can now use any string as the word delimiter, but 'dash' and 'underscore' are still supported. + - ``url_title()`` performance and output improved. You can now use any string as the word delimiter, but 'dash' and 'underscore' are still supported. Bug fixes for 2.1.1 ------------------- -- Fixed a bug (#697) - A wrong array key was used in the Upload library to check for mime-types. -- Fixed a bug - form_open() compared $action against site_url() instead of base_url(). -- Fixed a bug - CI_Upload::_file_mime_type() could've failed if mime_content_type() is used for the detection and returns FALSE. +- Fixed a bug (#697) - A wrong array key was used in the :doc:`File Uploading Library <libraries/file_uploading>` to check for mime-types. +- Fixed a bug - ``form_open()`` compared $action against ``site_url()`` instead of ``base_url()``. +- Fixed a bug - ``CI_Upload::_file_mime_type()`` could've failed if ``mime_content_type()`` is used for the detection and returns FALSE. - Fixed a bug (#538) - Windows paths were ignored when using the :doc:`Image Manipulation Library <libraries/image_lib>` to create a new file. -- Fixed a bug - When database caching was enabled, $this->db->query() checked the cache before binding variables which resulted in cached queries never being found +- Fixed a bug - When database caching was enabled, $this->db->query() checked the cache before binding variables which resulted in cached queries never being found. +- Fixed a bug - CSRF cookie value was allowed to be any (non-empty) string before being written to the output, making code injection a risk. +- Fixed a bug (#726) - PDO put a 'dbname' argument in it's connection string regardless of the database platform in use, which made it impossible to use SQLite. +- Fixed a bug - ``CI_DB_pdo_driver::num_rows()`` was not returning properly value with SELECT queries, cause it was relying on ``PDOStatement::rowCount()``. +- Fixed a bug (#1059) - ``CI_Image_lib::clear()`` was not correctly clearing all necessary object properties, namely width and height. Version 2.1.0 ============= @@ -264,7 +538,7 @@ Release Date: November 14, 2011 injection. - Added additional option 'none' for the optional third argument for $this->db->like() in the :doc:`Database - Driver <database/active_record>`. + Driver <database/query_builder>`. - Added $this->db->insert_batch() support to the OCI8 (Oracle) driver. - Added failover if the main connections in the config should fail @@ -362,7 +636,6 @@ Release Date: August 20, 2011 - Added insert_batch() function to the PostgreSQL database driver. Thanks to epallerols for the patch. - Added "application/x-csv" to mimes.php. - - Added CSRF protection URI whitelisting. - Fixed a bug where :doc:`Email library <libraries/email>` attachments with a "." in the name would using invalid MIME-types. @@ -1539,27 +1812,27 @@ Release Date: January 30, 2008 - Active Record - Added protect_identifiers() in :doc:`Active - Record <./database/active_record>`. + Record <./database/query_builder>`. - All AR queries are backticked if appropriate to the database. - Added where_in(), or_where_in(), where_not_in(), or_where_not_in(), not_like() and or_not_like() to :doc:`Active - Record <./database/active_record>`. + Record <./database/query_builder>`. - Added support for limit() into update() and delete() statements in - :doc:`Active Record <./database/active_record>`. + :doc:`Active Record <./database/query_builder>`. - Added empty_table() and truncate_table() to :doc:`Active - Record <./database/active_record>`. + Record <./database/query_builder>`. - Added the ability to pass an array of tables to the delete() - statement in :doc:`Active Record <./database/active_record>`. + statement in :doc:`Active Record <./database/query_builder>`. - Added count_all_results() function to :doc:`Active - Record <./database/active_record>`. + Record <./database/query_builder>`. - Added select_max(), select_min(), select_avg() and - select_sum() to :doc:`Active Record <./database/active_record>`. + select_sum() to :doc:`Active Record <./database/query_builder>`. - Added the ability to use aliases with joins in :doc:`Active - Record <./database/active_record>`. + Record <./database/query_builder>`. - Added a third parameter to Active Record's like() clause to control where the wildcard goes. - Added a third parameter to set() in :doc:`Active - Record <./database/active_record>` that withholds escaping + Record <./database/query_builder>` that withholds escaping data. - Changed the behaviour of variables submitted to the where() clause with no values to auto set "IS NULL" @@ -1667,7 +1940,7 @@ Release Date: January 30, 2008 the table of contents of the userguide. - Moved part of the userguide menu javascript to an external file. - Documented distinct() in :doc:`Active - Record <./database/active_record>`. + Record <./database/query_builder>`. - Documented the timezones() function in the :doc:`Date Helper <./helpers/date_helper>`. - Documented unset_userdata in the :doc:`Session @@ -2243,9 +2516,9 @@ Release Date: April 11, 2006 function <./general/views>`: $this->load->view('my_view', $object); - Added getwhere function to :doc:`Active Record - class <./database/active_record>`. + class <./database/query_builder>`. - Added count_all function to :doc:`Active Record - class <./database/active_record>`. + class <./database/query_builder>`. - Added language file for scaffolding and fixed a scaffolding bug that occurs when there are no rows in the specified table. - Added :doc:`$this->db->last_query() <./database/queries>`, which @@ -2270,7 +2543,7 @@ Release Date: April 3, 2006 - Added support for :doc:`Models <general/models>`. - Redesigned the database libraries to support additional RDBMs (Postgres, MySQLi, etc.). -- Redesigned the :doc:`Active Record class <./database/active_record>` +- Redesigned the :doc:`Active Record class <./database/query_builder>` to enable more varied types of queries with simpler syntax, and advanced features like JOINs. - Added a feature to the database class that lets you run :doc:`custom @@ -2303,7 +2576,7 @@ Release Date: April 3, 2006 whether PHP 4 or 5 is being run, since PHP 5 allows a more graceful way to manage objects that utilizes a bit less resources. - Deprecated: $this->db->use_table() has been deprecated. Please read - the :doc:`Active Record <./database/active_record>` page for + the :doc:`Active Record <./database/query_builder>` page for information. - Deprecated: $this->db->smart_escape_str() has been deprecated. Please use this instead: $this->db->escape() diff --git a/user_guide_src/source/conf.py b/user_guide_src/source/conf.py index e972a388b..f68405b36 100644 --- a/user_guide_src/source/conf.py +++ b/user_guide_src/source/conf.py @@ -167,6 +167,7 @@ html_last_updated_fmt = '%b %d, %Y' # Output file base name for HTML help builder. htmlhelp_basename = 'CodeIgniterdoc' +html_copy_source = False # -- Options for LaTeX output -------------------------------------------------- diff --git a/user_guide_src/source/contributing/index.rst b/user_guide_src/source/contributing/index.rst new file mode 100644 index 000000000..0771a4192 --- /dev/null +++ b/user_guide_src/source/contributing/index.rst @@ -0,0 +1,105 @@ +########################### +Contributing to CodeIgniter +########################### + +CodeIgniter is a community driven project and accepts contributions of code +and documentation from the community. These contributions are made in the form +of Issues or `Pull Requests <http://help.github.com/send-pull-requests/>`_ on +the `EllisLab CodeIgniter repository +<https://github.com/EllisLab/CodeIgniter>`_ on GitHub. + +Issues are a quick way to point out a bug. If you find a bug or documentation +error in CodeIgniter then please check a few things first: + +- There is not already an open Issue +- The issue has already been fixed (check the develop branch, or look for + closed Issues) +- Is it something really obvious that you fix it yourself? + +Reporting issues is helpful but an even better approach is to send a Pull +Request, which is done by "Forking" the main repository and committing to your +own copy. This will require you to use the version control system called Git. + +********** +Guidelines +********** + +Before we look into how, here are the guidelines. If your Pull Requests fail +to pass these guidelines it will be declined and you will need to re-submit +when you’ve made the changes. This might sound a bit tough, but it is required +for us to maintain quality of the code-base. + +PHP Style +========= + +All code must meet the `Style Guide +<http://codeigniter.com/user_guide/general/styleguide.html>`_, which is +essentially the `Allman indent style +<http://en.wikipedia.org/wiki/Indent_style#Allman_style>`_, underscores and +readable operators. This makes certain that all code is the same format as the +existing code and means it will be as readable as possible. + +Documentation +============= + +If you change anything that requires a change to documentation then you will +need to add it. New classes, methods, parameters, changing default values, etc +are all things that will require a change to documentation. The change-log +must also be updated for every change. Also PHPDoc blocks must be maintained. + +Compatibility +============= + +CodeIgniter is compatible with PHP 5.2.4 so all code supplied must stick to +this requirement. If PHP 5.3 or 5.4 functions or features are used then there +must be a fallback for PHP 5.2.4. + +Branching +========= + +CodeIgniter uses the `Git-Flow +<http://nvie.com/posts/a-successful-git-branching-model/>`_ branching model +which requires all pull requests to be sent to the "develop" branch. This is +where the next planned version will be developed. The "master" branch will +always contain the latest stable version and is kept clean so a "hotfix" (e.g: +an emergency security patch) can be applied to master to create a new version, +without worrying about other features holding it up. For this reason all +commits need to be made to "develop" and any sent to "master" will be closed +automatically. If you have multiple changes to submit, please place all +changes into their own branch on your fork. + +One thing at a time: A pull request should only contain one change. That does +not mean only one commit, but one change - however many commits it took. The +reason for this is that if you change X and Y but send a pull request for both +at the same time, we might really want X but disagree with Y, meaning we +cannot merge the request. Using the Git-Flow branching model you can create +new branches for both of these features and send two requests. + +Signing +======= +You must sign your work, certifying that you either wrote the work or +otherwise have the right to pass it on to an open source project. git makes +this trivial as you merely have to use `--signoff` on your commits to your +CodeIgniter fork. + +.. code-block:: bash + + git commit --signoff + +or simply + +.. code-block:: bash + + git commit -s + +This will sign your commits with the information setup in your git config, e.g. + + Signed-off-by: John Q Public <john.public@example.com> + +If you are using Tower there is a "Sign-Off" checkbox in the commit window. You +could even alias git commit to use the -s flag so you don’t have to think about +it. + +By signing your work in this manner, you certify to a "Developer's Certificate +or Origin". The current version of this certificate is in the :doc:`/DCO` file +in the root of this documentation.
\ No newline at end of file diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index 3f3bae336..34cefffbd 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -12,26 +12,46 @@ it the respective environment config folder. The config settings are stored in a multi-dimensional array with this prototype:: - $db['default']['hostname'] = "localhost"; - $db['default']['username'] = "root"; - $db['default']['password'] = ""; - $db['default']['database'] = "database_name"; - $db['default']['dbdriver'] = "mysql"; - $db['default']['dbprefix'] = ""; - $db['default']['pconnect'] = TRUE; - $db['default']['db_debug'] = FALSE; - $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; - -If you use PDO as your dbdriver, you can specify the full DSN string describe a connection to the database like this:: - + $db['default'] = array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'root', + 'password' => '', + 'database' => 'database_name', + 'dbdriver' => 'mysqli', + 'dbprefix' => '', + 'pconnect' => TRUE, + 'db_debug' => TRUE, + 'cache_on' => FALSE, + 'cachedir' => '', + 'char_set' => 'utf8', + 'dbcollat' => 'utf8_general_ci', + 'swap_pre' => '', + 'autoinit' => TRUE, + 'encrypt' => FALSE, + 'compress' => FALSE, + 'stricton' => FALSE, + 'failover' => array() + ); + +Some database drivers (such as PDO, PostgreSQL, Oracle, ODBC) might +require a full DSN string to be provided. If that is the case, you +should use the 'dsn' configuration setting, as if you're using the +driver's underlying native PHP extension, like this:: + + // PDO $db['default']['dsn'] = 'pgsql:host=localhost;port=5432;dbname=database_name'; + // Oracle + $db['default']['dsn'] = '//localhost/XE'; + +.. note:: If you do not specify a DSN string for a driver that requires it, CodeIgniter + will try to build it with the rest of the provided settings. + +.. note:: If you provide a DSN string and it is missing some valid settings (e.g. the + database character set), which are present in the rest of the configuration + fields, CodeIgniter will append them. + You can also specify failovers for the situation when the main connection cannot connect for some reason. These failovers can be specified by setting the failover for a connection like this:: @@ -41,7 +61,7 @@ These failovers can be specified by setting the failover for a connection like t 'username' => '', 'password' => '', 'database' => '', - 'dbdriver' => 'mysql', + 'dbdriver' => 'mysqli', 'dbprefix' => '', 'pconnect' => TRUE, 'db_debug' => TRUE, @@ -51,6 +71,8 @@ These failovers can be specified by setting the failover for a connection like t 'dbcollat' => 'utf8_general_ci', 'swap_pre' => '', 'autoinit' => TRUE, + 'encrypt' => FALSE, + 'compress' => FALSE, 'stricton' => FALSE ), array( @@ -58,7 +80,7 @@ These failovers can be specified by setting the failover for a connection like t 'username' => '', 'password' => '', 'database' => '', - 'dbdriver' => 'mysql', + 'dbdriver' => 'mysqli', 'dbprefix' => '', 'pconnect' => TRUE, 'db_debug' => TRUE, @@ -68,6 +90,8 @@ These failovers can be specified by setting the failover for a connection like t 'dbcollat' => 'utf8_general_ci', 'swap_pre' => '', 'autoinit' => TRUE, + 'encrypt' => FALSE, + 'compress' => FALSE, 'stricton' => FALSE ) ); @@ -81,46 +105,52 @@ production, test, etc.) under a single installation, you can set up a connection group for each, then switch between groups as needed. For example, to set up a "test" environment you would do this:: - $db['test']['hostname'] = "localhost"; - $db['test']['username'] = "root"; - $db['test']['password'] = ""; - $db['test']['database'] = "database_name"; - $db['test']['dbdriver'] = "mysql"; - $db['test']['dbprefix'] = ""; - $db['test']['pconnect'] = TRUE; - $db['test']['db_debug'] = FALSE; - $db['test']['cache_on'] = FALSE; - $db['test']['cachedir'] = ""; - $db['test']['char_set'] = "utf8"; - $db['test']['dbcollat'] = "utf8_general_ci"; - $db['test']['swap_pre'] = ""; - $db['test']['autoinit'] = TRUE; - $db['test']['stricton'] = FALSE; + $db['test'] = array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'root', + 'password' => '', + 'database' => 'database_name', + 'dbdriver' => 'mysqli', + 'dbprefix' => '', + 'pconnect' => TRUE, + 'db_debug' => TRUE, + 'cache_on' => FALSE, + 'cachedir' => '', + 'char_set' => 'utf8', + 'dbcollat' => 'utf8_general_ci', + 'swap_pre' => '', + 'autoinit' => TRUE, + 'compress' => FALSE, + 'encrypt' => FALSE, + 'stricton' => FALSE, + 'failover' => array() + ); Then, to globally tell the system to use that group you would set this variable located in the config file:: - $active_group = "test"; + $active_group = 'test'; -Note: The name "test" is arbitrary. It can be anything you want. By -default we've used the word "default" for the primary connection, but it -too can be renamed to something more relevant to your project. +.. note:: The name 'test' is arbitrary. It can be anything you want. By + default we've used the word "default" for the primary connection, + but it too can be renamed to something more relevant to your project. -Active Record +Query Builder ------------- -The :doc:`Active Record Class <active_record>` is globally enabled or -disabled by setting the $active_record variable in the database +The :doc:`Query Builder Class <query_builder>` is globally enabled or +disabled by setting the $query_builder variable in the database configuration file to TRUE/FALSE (boolean). If you are not using the -active record class, setting it to FALSE will utilize fewer resources +query builder class, setting it to FALSE will utilize fewer resources when the database classes are initialized. :: - $active_record = TRUE; + $query_builder = TRUE; -.. note:: that some CodeIgniter classes such as Sessions require Active - Records be enabled to access certain functionality. +.. note:: that some CodeIgniter classes such as Sessions require Query + Builder to be enabled to access certain functionality. Explanation of Values: ---------------------- @@ -128,13 +158,14 @@ Explanation of Values: ====================== ================================================================================================== Name Config Description ====================== ================================================================================================== -**hostname** The hostname of your database server. Often this is "localhost". +**dsn** The DSN connect string (an all-in-one configuration sequence). +**hostname** The hostname of your database server. Often this is 'localhost'. **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, postgre, odbc, etc. Must be specified in lower case. +**dbdriver** The database type. ie: mysqli, postgre, odbc, etc. Must be specified in lower case. **dbprefix** An optional table prefix which will added to the table name when running :doc: - `Active Record <active_record>` queries. This permits multiple CodeIgniter installations + `Query Builder <query_builder>` queries. This permits multiple CodeIgniter installations to share one database. **pconnect** TRUE/FALSE (boolean) - Whether to use a persistent connection. **db_debug** TRUE/FALSE (boolean) - Whether database errors should be displayed. @@ -144,30 +175,26 @@ Explanation of Values: **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. + .. note:: Only used in the 'mysql' and 'mysqli' drivers. **swap_pre** A default table prefix that should be swapped with dbprefix. This is useful for distributed applications where you might run manually written queries, and need the prefix to still be customizable by the end user. **autoinit** Whether or not to automatically connect to the database when the library loads. If set to false, the connection will take place prior to executing the first query. +**schema** The database schema, defaults to 'public'. Used by PostgreSQL and ODBC drivers. +**encrypt** Whether or not to use an encrypted connection. +**compress** Whether or not to use client compression (MySQL only). **stricton** TRUE/FALSE (boolean) - Whether to force "Strict Mode" connections, good for ensuring strict SQL while developing an application. **port** The database port number. To use this value you have to add a line to the database config array. :: - - $db['default']['port'] = 5432; + + $db['default']['port'] = 5432; ====================== ================================================================================================== .. note:: Depending on what database platform you are using (MySQL, PostgreSQL, etc.) not all values will be needed. For example, when using SQLite you will not need to supply a username or password, and the database name will be the path to your database file. The information above assumes - you are using MySQL. + you are using MySQL.
\ No newline at end of file diff --git a/user_guide_src/source/database/connecting.rst b/user_guide_src/source/database/connecting.rst index fb4524116..9b8117076 100644 --- a/user_guide_src/source/database/connecting.rst +++ b/user_guide_src/source/database/connecting.rst @@ -36,7 +36,7 @@ Available Parameters string. #. TRUE/FALSE (boolean). Whether to return the connection ID (see Connecting to Multiple Databases below). -#. TRUE/FALSE (boolean). Whether to enable the Active Record class. Set +#. TRUE/FALSE (boolean). Whether to enable the Query Builder class. Set to TRUE by default. Manually Connecting to a Database @@ -57,25 +57,28 @@ file. To connect manually to a desired database you can pass an array of values:: - $config['hostname'] = "localhost"; - $config['username'] = "myusername"; - $config['password'] = "mypassword"; - $config['database'] = "mydatabase"; - $config['dbdriver'] = "mysql"; - $config['dbprefix'] = ""; - $config['pconnect'] = FALSE; - $config['db_debug'] = TRUE; - $config['cache_on'] = FALSE; - $config['cachedir'] = ""; - $config['char_set'] = "utf8"; - $config['dbcollat'] = "utf8_general_ci"; + $config['hostname'] = 'localhost'; + $config['username'] = 'myusername'; + $config['password'] = 'mypassword'; + $config['database'] = 'mydatabase'; + $config['dbdriver'] = 'mysqli'; + $config['dbprefix'] = ''; + $config['pconnect'] = FALSE; + $config['db_debug'] = TRUE; + $config['cache_on'] = FALSE; + $config['cachedir'] = ''; + $config['char_set'] = 'utf8'; + $config['dbcollat'] = 'utf8_general_ci'; $this->load->database($config); For information on each of these values please see the :doc:`configuration page <configuration>`. -.. note:: For the PDO driver, $config['hostname'] should look like - this: 'mysql:host=localhost' +.. note:: For the PDO driver, you should use the $config['dsn'] setting + instead of 'hostname' and 'database': + + | + | $config['dsn'] = 'mysql:host=localhost;dbname=mydatabase'; Or you can submit your database values as a Data Source Name. DSNs must have this prototype:: @@ -149,5 +152,4 @@ connections, you can explicitly close the connection. :: - $this->db->close(); - + $this->db->close();
\ No newline at end of file diff --git a/user_guide_src/source/database/examples.rst b/user_guide_src/source/database/examples.rst index d1cd48837..8b3cc4701 100644 --- a/user_guide_src/source/database/examples.rst +++ b/user_guide_src/source/database/examples.rst @@ -104,10 +104,10 @@ Standard Insert $this->db->query($sql); echo $this->db->affected_rows(); -Active Record Query +Query Builder Query =================== -The :doc:`Active Record Pattern <active_record>` gives you a simplified +The :doc:`Query Builder Pattern <query_builder>` gives you a simplified means of retrieving data:: $query = $this->db->get('table_name'); @@ -118,10 +118,10 @@ means of retrieving data:: } The above get() function retrieves all the results from the supplied -table. The :doc:`Active Record <active_record>` class contains a full +table. The :doc:`Query Builder <query_builder>` class contains a full compliment of functions for working with data. -Active Record Insert +Query Builder Insert ==================== :: diff --git a/user_guide_src/source/database/forge.rst b/user_guide_src/source/database/forge.rst index bf17e2918..ca904ed00 100644 --- a/user_guide_src/source/database/forge.rst +++ b/user_guide_src/source/database/forge.rst @@ -2,7 +2,7 @@ Database Forge Class #################### -The Database Forge Class contains functions that help you manage your +The Database Forge Class contains methods that help you manage your database. .. contents:: Table of Contents @@ -18,13 +18,25 @@ Load the Forge Class as follows:: $this->load->dbforge() -Once initialized you will access the functions using the $this->dbforge +You can also pass another database object to the DB Forge loader, in case +the database you want to manage isn't the default one:: + + $this->myforge = $this->load->dbforge($this->other_db, TRUE); + +In the above example, we're passing a custom database object as the first +parameter and then tell it to return the dbforge object, instead of +assigning it directly to ``$this->dbforge``. + +.. note:: Both of the parameters can be used individually, just pass an empty + value as the first one if you wish to skip it. + +Once initialized you will access the methods using the ``$this->dbforge`` object:: - $this->dbforge->some_function() + $this->dbforge->some_method(); $this->dbforge->create_database('db_name') -============================================ +========================================== Permits you to create the database specified in the first parameter. Returns TRUE/FALSE based on success or failure:: @@ -108,13 +120,13 @@ Additionally, the following key/values can be used: After the fields have been defined, they can be added using -$this->dbforge->add_field($fields); followed by a call to the -create_table() function. +``$this->dbforge->add_field($fields);`` followed by a call to the +``create_table()`` method. $this->dbforge->add_field() ----------------------------- +--------------------------- -The add fields function will accept the above array. +The add fields method will accept the above array. Passing strings as fields ------------------------- @@ -193,13 +205,15 @@ into the definition Dropping a table ================ -Executes a DROP TABLE sql +Execute a DROP TABLE statement and optionally add an IF EXISTS clause. :: + // Produces: DROP TABLE table_name $this->dbforge->drop_table('table_name'); - // gives DROP TABLE IF EXISTS table_name + // Produces: DROP TABLE IF EXISTS table_name + $this->dbforge->drop_table('table_name'); Renaming a table ================ @@ -217,9 +231,9 @@ Modifying Tables **************** $this->dbforge->add_column() -============================= +============================ -The add_column() function is used to modify an existing table. It +The ``add_column()`` method is used to modify an existing table. It accepts the same field array as above, and can be used for an unlimited number of additional fields. @@ -229,18 +243,25 @@ number of additional fields. 'preferences' => array('type' => 'TEXT') ); $this->dbforge->add_column('table_name', $fields); - // gives ALTER TABLE table_name ADD preferences TEXT + // Executes: ALTER TABLE table_name ADD preferences TEXT -An optional third parameter can be used to specify which existing column -to add the new column after. +If you are using MySQL or CUBIRD, then you can take advantage of their +AFTER and FIRST clauses to position the new column. -:: +Examples:: - $this->dbforge->add_column('table_name', $fields, 'after_field'); + // Will place the new column after the `another_field` column: + $fields = array( + 'preferences' => array('type' => 'TEXT', 'after' => 'another_field') + ); + // Will place the new column at the start of the table definition: + $fields = array( + 'preferences' => array('type' => 'TEXT', 'first' => TRUE) + ); $this->dbforge->drop_column() -============================== +============================= Used to remove a column from a table. @@ -250,9 +271,9 @@ Used to remove a column from a table. $this->dbforge->modify_column() -================================ +=============================== -The usage of this function is identical to add_column(), except it +The usage of this method is identical to ``add_column()``, except it alters an existing column rather than adding a new one. In order to change the name you can add a "name" key into the field defining array. diff --git a/user_guide_src/source/database/index.rst b/user_guide_src/source/database/index.rst index ab12b7cb7..7ccb8fb00 100644 --- a/user_guide_src/source/database/index.rst +++ b/user_guide_src/source/database/index.rst @@ -3,7 +3,7 @@ The Database Class ################## CodeIgniter comes with a full-featured and very fast abstracted database -class that supports both traditional structures and Active Record +class that supports both traditional structures and Query Builder patterns. The database functions offer clear, simple syntax. .. toctree:: @@ -15,7 +15,7 @@ patterns. The database functions offer clear, simple syntax. Running Queries <queries> Generating Query Results <results> Query Helper Functions <helpers> - Active Record Class <active_record> + Query Builder Class <query_builder> Transactions <transactions> Table MetaData <table_data> Field MetaData <fields> diff --git a/user_guide_src/source/database/queries.rst b/user_guide_src/source/database/queries.rst index 15a73614a..11dd78392 100644 --- a/user_guide_src/source/database/queries.rst +++ b/user_guide_src/source/database/queries.rst @@ -21,11 +21,31 @@ this:: $this->db->simple_query(); =========================== -This is a simplified version of the $this->db->query() function. It ONLY -returns TRUE/FALSE on success or failure. It DOES NOT return a database -result set, nor does it set the query timer, or compile bind data, or -store your query for debugging. It simply lets you submit a query. Most -users will rarely use this function. +This is a simplified version of the $this->db->query() method. It DOES +NOT return a database result set, nor does it set the query timer, or +compile bind data, or store your query for debugging. It simply lets you +submit a query. Most users will rarely use this function. + +It returns whatever the database drivers' "execute" function returns. +That typically is TRUE/FALSE on success or failure for write type queries +such as INSERT, DELETE or UPDATE statements (which is what it really +should be used for) and a resource/object on success for queries with +fetchable results. + +:: + + if ($this->db->simple_query('YOUR QUERY')) + { + echo "Success!"; + } + else + { + echo "Query failed!"; + } + +.. note:: PostgreSQL's pg_exec() function always returns a resource on + success, even for write type queries. So take that in mind if + you're looking for a boolean value. *************************************** Working with Database prefixes manually @@ -50,7 +70,7 @@ Protecting identifiers ********************** In many databases it is advisable to protect table and field names - for -example with backticks in MySQL. **Active Record queries are +example with backticks in MySQL. **Query Builder queries are automatically protected**, however if you need to manually protect an identifier you can use:: diff --git a/user_guide_src/source/database/active_record.rst b/user_guide_src/source/database/query_builder.rst index e328c11e2..8fb906052 100644 --- a/user_guide_src/source/database/active_record.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -1,15 +1,15 @@ ################### -Active Record Class +Query Builder Class ################### -CodeIgniter uses a modified version of the Active Record Database -Pattern. This pattern allows information to be retrieved, inserted, and -updated in your database with minimal scripting. In some cases only one -or two lines of code are necessary to perform a database action. +CodeIgniter gives you access to a Query Builder class. This pattern +allows information to be retrieved, inserted, and updated in your +database with minimal scripting. In some cases only one or two lines +of code are necessary to perform a database action. CodeIgniter does not require that each database table be its own class file. It instead provides a more simplified interface. -Beyond simplicity, a major benefit to using the Active Record features +Beyond simplicity, a major benefit to using the Query Builder features is that it allows you to create database independent applications, since the query syntax is generated by each database adapter. It also allows for safer queries, since the values are escaped automatically by the @@ -67,8 +67,8 @@ Example:: // Produces string: SELECT * FROM mytable -The second parameter enables you to set whether or not the active record query -will be reset (by default it will be just like `$this->db->get()`):: +The second parameter enables you to set whether or not the query builder query +will be reset (by default it will be—just like `$this->db->get()`):: echo $this->db->limit(10,20)->get_compiled_select('mytable', FALSE); // Produces string: SELECT * FROM mytable LIMIT 20, 10 @@ -469,31 +469,47 @@ Identical to having(), only separates multiple clauses with "OR". $this->db->order_by() ===================== -Lets you set an ORDER BY clause. The first parameter contains the name -of the column you would like to order by. The second parameter lets you -set the direction of the result. Options are asc or desc, or random. +Lets you set an ORDER BY clause. + +The first parameter contains the name of the column you would like to order by. + +The second parameter lets you set the direction of the result. +Options are **ASC**, **DESC** AND **RANDOM**. :: - $this->db->order_by("title", "desc"); // Produces: ORDER BY title DESC + $this->db->order_by('title', 'DESC'); + // Produces: ORDER BY `title` DESC You can also pass your own string in the first parameter:: - $this->db->order_by('title desc, name asc'); // Produces: ORDER BY title DESC, name ASC + $this->db->order_by('title DESC, name ASC'); + // Produces: ORDER BY `title` DESC, `name` ASC Or multiple function calls can be made if you need multiple fields. :: - $this->db->order_by("title", "desc"); - $this->db->order_by("name", "asc"); // Produces: ORDER BY title DESC, name ASC + $this->db->order_by('title', 'DESC'); + $this->db->order_by('name', 'ASC'); + // Produces: ORDER BY `title` DESC, `name` ASC + +If you choose the **RANDOM** direction option, then the first parameters will +be ignored, unless you specify a numeric seed value. + +:: + + $this->db->order_by('title', 'RANDOM'); + // Produces: ORDER BY RAND() + $this->db->order_by(42, 'RANDOM'); + // Produces: ORDER BY RAND(42) .. note:: order_by() was formerly known as orderby(), which has been removed. -.. note:: random ordering is not currently supported in Oracle or MSSQL - drivers. These will default to 'ASC'. +.. note:: Random ordering is not currently supported in Oracle and + will default to ASC instead. $this->db->limit() ================== @@ -512,7 +528,7 @@ $this->db->count_all_results() ============================== Permits you to determine the number of rows in a particular Active -Record query. Queries will accept Active Record restrictors such as +Record query. Queries will accept Query Builder restrictors such as where(), or_where(), like(), or_like(), etc. Example:: echo $this->db->count_all_results('my_table'); // Produces an integer, like 25 @@ -603,9 +619,9 @@ Here is an example using an object:: /* class Myclass { - var $title = 'My Title'; - var $content = 'My Content'; - var $date = 'My Date'; + public $title = 'My Title'; + public $content = 'My Content'; + public $date = 'My Date'; } */ @@ -636,7 +652,7 @@ Example:: // Produces string: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date') -The second parameter enables you to set whether or not the active record query +The second parameter enables you to set whether or not the query builder query will be reset (by default it will be--just like `$this->db->insert()`_):: echo $this->db->set('title', 'My Title')->get_compiled_insert('mytable', FALSE); @@ -681,6 +697,35 @@ associative array of values. .. note:: All values are escaped automatically producing safer queries. +$this->db->replace() +==================== + +This method executes a REPLACE statement, which is basically the SQL +standard for (optional) DELETE + INSERT, using *PRIMARY* and *UNIQUE* +keys as the determining factor. +In our case, it will save you from the need to implement complex +logics with different combinations of ``select()``, ``update()``, +``delete()`` and ``insert()`` calls. + +Example:: + + $data = array( + 'title' => 'My title', + 'name' => 'My Name', + 'date' => 'My date' + ); + + $this->db->replace('table', $data); + + // Executes: REPLACE INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date') + +In the above example, if we assume that the *title* field is our primary +key, then if a row containing 'My title' as the *title* value, that row +will be deleted with our new row data replacing it. + +Usage of the ``set()`` method is also allowed and all fields are +automatically escaped, just like with ``insert()``. + $this->db->set() ================ @@ -730,9 +775,9 @@ Or an object:: /* class Myclass { - var $title = 'My Title'; - var $content = 'My Content'; - var $date = 'My Date'; + public $title = 'My Title'; + public $content = 'My Content'; + public $date = 'My Date'; } */ @@ -740,7 +785,6 @@ Or an object:: $this->db->set($object); $this->db->insert('mytable'); - ************* Updating Data ************* @@ -766,9 +810,9 @@ Or you can supply an object:: /* class Myclass { - var $title = 'My Title'; - var $content = 'My Content'; - var $date = 'My Date'; + public $title = 'My Title'; + public $content = 'My Content'; + public $date = 'My Date'; } */ @@ -792,6 +836,7 @@ Or as an array:: You may also use the $this->db->set() function described above when performing updates. + $this->db->update_batch() ========================= @@ -830,6 +875,10 @@ array of values, the third parameter is the where key. .. note:: All values are escaped automatically producing safer queries. +.. note:: ``affected_rows()`` won't give you proper results with this method, + due to the very nature of how it works. Instead, ``update_batch()`` + returns the number of rows affected. + $this->db->get_compiled_update() ================================ @@ -928,12 +977,12 @@ multiple functions. Consider this example:: .. _ar-caching: ********************* -Active Record Caching +Query Builder Caching ********************* -While not "true" caching, Active Record enables you to save (or "cache") +While not "true" caching, Query Builder enables you to save (or "cache") certain parts of your queries for reuse at a later point in your -script's execution. Normally, when an Active Record call is completed, +script's execution. Normally, when an Query Builder call is completed, all stored information is reset for the next call. With caching, you can prevent this reset, and reuse information easily. @@ -944,7 +993,7 @@ There are three Caching functions available: $this->db->start_cache() ======================== -This function must be called to begin caching. All Active Record queries +This function must be called to begin caching. All Query Builder queries of the correct type (see below for supported queries) are stored for later use. @@ -956,7 +1005,7 @@ This function can be called to stop caching. $this->db->flush_cache() ======================== -This function deletes all items from the Active Record cache. +This function deletes all items from the Query Builder cache. Here's a usage example:: @@ -983,12 +1032,12 @@ Here's a usage example:: $this->db->reset_query() ======================== -Resetting Active Record allows you to start fresh with your query without +Resetting Query Builder allows you to start fresh with your query without executing it first using a method like $this->db->get() or $this->db->insert(). Just like the methods that execute a query, this will *not* reset items you've -cached using `Active Record Caching`_. +cached using `Query Builder Caching`_. -This is useful in situations where you are using Active Record to generate SQL +This is useful in situations where you are using Query Builder to generate SQL (ex. ``$this->db->get_compiled_select()``) but then choose to, for instance, run the query:: diff --git a/user_guide_src/source/database/results.rst b/user_guide_src/source/database/results.rst index 865345762..d032f734e 100644 --- a/user_guide_src/source/database/results.rst +++ b/user_guide_src/source/database/results.rst @@ -136,6 +136,26 @@ parameter: | **$row = $query->next_row('array')** | **$row = $query->previous_row('array')** +.. note:: all the functions above will load the whole result into memory (prefetching) use unbuffered_row() for processing large result sets. + +unbuffered_row($type) +===================== + +This function returns a single result row without prefetching the whole result in memory as row() does. +If your query has more than one row, it returns the current row and moves the internal data pointer ahead. +The result is returned as $type could be 'object' (default) or 'array' that will return an associative array. + +:: + + $query = $this->db->query("YOUR QUERY"); + + while ($row = $query->unbuffered_row()) + { + echo $row->title; + echo $row->name; + echo $row->body; + } + *********************** Result Helper Functions *********************** diff --git a/user_guide_src/source/database/utilities.rst b/user_guide_src/source/database/utilities.rst index 4e83929b2..06ecb2da1 100644 --- a/user_guide_src/source/database/utilities.rst +++ b/user_guide_src/source/database/utilities.rst @@ -2,7 +2,7 @@ Database Utility Class ###################### -The Database Utility Class contains functions that help you manage your +The Database Utility Class contains methods that help you manage your database. .. contents:: Table of Contents @@ -22,12 +22,24 @@ Load the Utility Class as follows:: $this->load->dbutil() -Once initialized you will access the functions using the $this->dbutil +You can also pass another database object to the DB Utility loader, in case +the database you want to manage isn't the default one:: + + $this->myutil = $this->load->dbutil($this->other_db, TRUE); + +In the above example, we're passing a custom database object as the first +parameter and then tell it to return the dbutil object, instead of +assigning it directly to ``$this->dbutil``. + +.. note:: Both of the parameters can be used individually, just pass an empty + value as the first one if you wish to skip it. + +Once initialized you will access the methods using the ``$this->dbutil`` object:: - $this->dbutil->some_function() + $this->dbutil->some_method() -$this->dbutil->list_databases() +$this->dbutil->list_databases(); ================================ Returns an array of database names:: @@ -40,7 +52,7 @@ Returns an array of database names:: } $this->dbutil->database_exists(); -================================== +================================= Sometimes it's helpful to know whether a particular database exists. Returns a boolean TRUE/FALSE. Usage example:: @@ -50,13 +62,11 @@ Returns a boolean TRUE/FALSE. Usage example:: // some code... } -Note: Replace *database_name* with the name of the table you are -looking for. This function is case sensitive. +.. note:: Replace *database_name* with the name of the table you are + looking for. This method is case sensitive. $this->dbutil->optimize_table('table_name'); -============================================== - -.. note:: This features is only available for MySQL/MySQLi databases. +============================================ Permits you to optimize a table using the table name specified in the first parameter. Returns TRUE/FALSE based on success or failure:: @@ -66,12 +76,11 @@ first parameter. Returns TRUE/FALSE based on success or failure:: echo 'Success!'; } -.. note:: Not all database platforms support table optimization. +.. note:: Not all database platforms support table optimization. It is + mostly for use with MySQL. $this->dbutil->repair_table('table_name'); -============================================ - -.. note:: This features is only available for MySQL/MySQLi databases. +========================================== Permits you to repair a table using the table name specified in the first parameter. Returns TRUE/FALSE based on success or failure:: @@ -86,8 +95,6 @@ first parameter. Returns TRUE/FALSE based on success or failure:: $this->dbutil->optimize_database(); ==================================== -.. note:: This features is only available for MySQL/MySQLi databases. - Permits you to optimize the database your DB class is currently connected to. Returns an array containing the DB status messages or FALSE on failure. @@ -101,13 +108,14 @@ FALSE on failure. print_r($result); } -.. note:: Not all database platforms support table optimization. +.. note:: Not all database platforms support table optimization. It + it is mostly for use with MySQL. -$this->dbutil->csv_from_result($db_result) -============================================= +$this->dbutil->csv_from_result($db_result); +=========================================== Permits you to generate a CSV file from a query result. The first -parameter of the function must contain the result object from your +parameter of the method must contain the result object from your query. Example:: $this->load->dbutil(); @@ -127,12 +135,12 @@ is used as the enclosure. Example:: echo $this->dbutil->csv_from_result($query, $delimiter, $newline, $enclosure); -.. important:: This function will NOT write the CSV file for you. It +.. important:: This method will NOT write the CSV file for you. It simply creates the CSV layout. If you need to write the file use the :doc:`File Helper <../helpers/file_helper>`. -$this->dbutil->xml_from_result($db_result) -============================================= +$this->dbutil->xml_from_result($db_result); +=========================================== Permits you to generate an XML file from a query result. The first parameter expects a query result object, the second may contain an @@ -151,17 +159,17 @@ optional array of config parameters. Example:: echo $this->dbutil->xml_from_result($query, $config); -.. important:: This function will NOT write the XML file for you. It +.. important:: This method will NOT write the XML file for you. It simply creates the XML layout. If you need to write the file use the :doc:`File Helper <../helpers/file_helper>`. -$this->dbutil->backup() -======================= +$this->dbutil->backup(); +======================== Permits you to backup your full database or individual tables. The backup data can be compressed in either Zip or Gzip format. -.. note:: This features is only available for MySQL and Interbase/Firebird databases. +.. note:: This feature is only available for MySQL and Interbase/Firebird databases. .. note:: For Interbase/Firebird databases, the backup file name is the only parameter. @@ -196,16 +204,16 @@ Setting Backup Preferences -------------------------- Backup preferences are set by submitting an array of values to the first -parameter of the backup function. Example:: +parameter of the ``backup()`` method. Example:: $prefs = array( - 'tables' => array('table1', 'table2'), // Array of tables to backup. - 'ignore' => array(), // List of tables to omit from the backup - 'format' => 'txt', // gzip, zip, txt - 'filename' => 'mybackup.sql', // File name - NEEDED ONLY WITH ZIP FILES - 'add_drop' => TRUE, // Whether to add DROP TABLE statements to backup file - 'add_insert' => TRUE, // Whether to add INSERT data to backup file - 'newline' => "\n" // Newline character used in backup file + 'tables' => array('table1', 'table2'), // Array of tables to backup. + 'ignore' => array(), // List of tables to omit from the backup + 'format' => 'txt', // gzip, zip, txt + 'filename' => 'mybackup.sql', // File name - NEEDED ONLY WITH ZIP FILES + 'add_drop' => TRUE, // Whether to add DROP TABLE statements to backup file + 'add_insert' => TRUE, // Whether to add INSERT data to backup file + 'newline' => "\n" // Newline character used in backup file ); $this->dbutil->backup($prefs); diff --git a/user_guide_src/source/general/alternative_php.rst b/user_guide_src/source/general/alternative_php.rst index 4dc857a50..418d2e6eb 100644 --- a/user_guide_src/source/general/alternative_php.rst +++ b/user_guide_src/source/general/alternative_php.rst @@ -17,12 +17,12 @@ Automatic Short Tag Support work on your server it might be that "short tags" are disabled in your PHP ini file. CodeIgniter will optionally rewrite short tags on-the-fly, allowing you to use that syntax even if your server doesn't support it. - This feature can be enabled in your config/config.php file. + This feature can be enabled in your *config/config.php* file. Please note that if you do use this feature, if PHP errors are encountered in your **view files**, the error message and line number will not be accurately shown. Instead, all errors will be shown as -eval() errors. +``eval()`` errors. Alternative Echos ================= @@ -39,13 +39,13 @@ Alternative Control Structures ============================== Controls structures, like if, for, foreach, and while can be written in -a simplified format as well. Here is an example using foreach:: +a simplified format as well. Here is an example using ``foreach``:: <ul> <?php foreach ($todo as $item): ?> - <li><?=$item?></li> + <li><?=$item?></li> <?php endforeach; ?> @@ -60,17 +60,16 @@ Also notice that instead of using a semicolon after each structure Here is another example, using ``if``/``elseif``/``else``. Notice the colons:: - <?php if ($username == 'sally'): ?> + <?php if ($username === 'sally'): ?> - <h3>Hi Sally</h3> + <h3>Hi Sally</h3> - <?php elseif ($username == 'joe'): ?> + <?php elseif ($username === 'joe'): ?> - <h3>Hi Joe</h3> + <h3>Hi Joe</h3> <?php else: ?> - <h3>Hi unknown user</h3> - - <?php endif; ?> + <h3>Hi unknown user</h3> + <?php endif; ?>
\ No newline at end of file diff --git a/user_guide_src/source/general/ancillary_classes.rst b/user_guide_src/source/general/ancillary_classes.rst index f7c87011b..a4befc7b3 100644 --- a/user_guide_src/source/general/ancillary_classes.rst +++ b/user_guide_src/source/general/ancillary_classes.rst @@ -7,31 +7,35 @@ controllers but have the ability to utilize all of CodeIgniter's resources. This is easily possible as you'll see. get_instance() -=============== +============== -**Any class that you instantiate within your controller functions can +.. php:function:: get_instance() + + :returns: object of class CI_Controller + +**Any class that you instantiate within your controller methods can access CodeIgniter's native resources** simply by using the -get_instance() function. This function returns the main CodeIgniter -object. +``get_instance()`` function. This function returns the main +CodeIgniter object. -Normally, to call any of the available CodeIgniter functions requires -you to use the $this construct:: +Normally, to call any of the available CodeIgniter methods requires +you to use the ``$this`` construct:: $this->load->helper('url'); $this->load->library('session'); $this->config->item('base_url'); // etc. -$this, however, only works within your controllers, your models, or your -views. If you would like to use CodeIgniter's classes from within your -own custom classes you can do so as follows: +``$this``, however, only works within your controllers, your models, +or your views. If you would like to use CodeIgniter's classes from +within your own custom classes you can do so as follows: First, assign the CodeIgniter object to a variable:: $CI =& get_instance(); Once you've assigned the object to a variable, you'll use that variable -*instead* of $this:: +*instead* of ``$this``:: $CI =& get_instance(); @@ -40,10 +44,45 @@ Once you've assigned the object to a variable, you'll use that variable $CI->config->item('base_url'); // etc. -.. note:: You'll notice that the above get_instance() function is being +.. note:: You'll notice that the above get_instance() ``function`` is being passed by reference:: $CI =& get_instance(); This is very important. Assigning by reference allows you to use the original CodeIgniter object rather than creating a copy of it. + +Furthermore, if you'll be using ``get_intance()`` inside anoter class, +then it would be better if you assign it to a property. This way, you +won't need to call ``get_instance()`` in every single method. + +Example:: + +class Example { + + protected $CI; + + // We'll use a constructor, as you can't directly call a function + // from a property definition. + public function __construct() + { + // Assign the CodeIgniter super-object + $this->CI =& get_instance(); + } + + public function foo() + { + $this->CI->load->helper('url'); + redirect(); + } + + public function bar() + { + $this->CI->config_item('base_url'); + } + +} + +In the above example, both methods ``foo()`` and ``bar()`` will work +after you instantiate the Example class, without the need to call +``get_instance()`` in each of them.
\ No newline at end of file diff --git a/user_guide_src/source/general/autoloader.rst b/user_guide_src/source/general/autoloader.rst index 259a4987e..e5cec723b 100644 --- a/user_guide_src/source/general/autoloader.rst +++ b/user_guide_src/source/general/autoloader.rst @@ -9,15 +9,15 @@ application you should consider auto-loading them for convenience. The following items can be loaded automatically: -- Core classes found in the "libraries" folder -- Helper files found in the "helpers" folder -- Custom config files found in the "config" folder -- Language files found in the "system/language" folder -- Models found in the "models" folder +- Classes found in the *libraries/* directory +- Helper files found in the *helpers/* directory +- Custom config files found in the *config/* directory +- Language files found in the *system/language/* directory +- Models found in the *models/* folder -To autoload resources, open the application/config/autoload.php file and -add the item you want loaded to the autoload array. You'll find -instructions in that file corresponding to each type of item. +To autoload resources, open the *application/config/autoload.php* +file and add the item you want loaded to the autoload array. You'll +find instructions in that file corresponding to each type of item. .. note:: Do not include the file extension (.php) when adding items to - the autoload array. + the autoload array.
\ No newline at end of file diff --git a/user_guide_src/source/general/caching.rst b/user_guide_src/source/general/caching.rst index bf6ed50f6..c40f652ac 100644 --- a/user_guide_src/source/general/caching.rst +++ b/user_guide_src/source/general/caching.rst @@ -23,36 +23,38 @@ will be retrieved and sent to the requesting user's browser. If it has expired, it will be deleted and refreshed before being sent to the browser. -Note: The Benchmark tag is not cached so you can still view your page -load speed when caching is enabled. +.. note: The Benchmark tag is not cached so you can still view your page + load speed when caching is enabled. Enabling Caching ================ To enable caching, put the following tag in any of your controller -functions:: +methods:: - $this->output->cache(n); + $this->output->cache($n); -Where n is the number of **minutes** you wish the page to remain cached -between refreshes. +Where ``$n`` is the number of **minutes** you wish the page to remain +cached between refreshes. -The above tag can go anywhere within a function. It is not affected by +The above tag can go anywhere within a method. It is not affected by the order that it appears, so place it wherever it seems most logical to you. Once the tag is in place, your pages will begin being cached. .. important:: Because of the way CodeIgniter stores content for output, - caching will only work if you are generating display for your controller - with a :doc:`view <./views>`. + caching will only work if you are generating display for your + controller with a :doc:`view <./views>`. .. note:: Before the cache files can be written you must set the file - permissions on your application/cache folder such that it is writable. + permissions on your *application/cache/* directory such that + it is writable. Deleting Caches =============== If you no longer wish to cache a file you can remove the caching tag and -it will no longer be refreshed when it expires. Note: Removing the tag -will not delete the cache immediately. It will have to expire normally. -If you need to remove it earlier you will need to manually delete it -from your cache folder. +it will no longer be refreshed when it expires. + +.. note:: Removing the tag will not delete the cache immediately. It will + have to expire normally. If you need to remove it earlier you + will need to manually delete it from your cache directory.
\ No newline at end of file diff --git a/user_guide_src/source/general/cli.rst b/user_guide_src/source/general/cli.rst index 7dc1ca319..998d2a907 100644 --- a/user_guide_src/source/general/cli.rst +++ b/user_guide_src/source/general/cli.rst @@ -21,7 +21,7 @@ Why run via the command-line? There are many reasons for running CodeIgniter from the command-line, but they are not always obvious. -- Run your cron-jobs without needing to use wget or curl +- Run your cron-jobs without needing to use *wget* or *curl* - Make your cron-jobs inaccessible from being loaded in the URL by checking for ``$this->input->is_cli_request()`` - Make interactive "tasks" that can do things like set permissions, @@ -44,15 +44,14 @@ in it:: echo "Hello {$to}!".PHP_EOL; } } - ?> -Then save the file to your application/controllers/ folder. +Then save the file to your *application/controllers/* folder. Now normally you would visit the your site using a URL similar to this:: example.com/index.php/tools/message/to -Instead, we are going to open Terminal in Mac/Lunix or go to Run > "cmd" +Instead, we are going to open Terminal in Mac/Linux or go to Run > "cmd" in Windows and navigate to our CodeIgniter project. .. code-block:: bash @@ -60,19 +59,20 @@ in Windows and navigate to our CodeIgniter project. $ cd /path/to/project; $ php index.php tools message -If you did it right, you should see Hello World!. +If you did it right, you should see *Hello World!* printed. .. code-block:: bash $ php index.php tools message "John Smith" Here we are passing it a argument in the same way that URL parameters -work. "John Smith" is passed as a argument and output is: Hello John -Smith!. +work. "John Smith" is passed as a argument and output is:: + + Hello John Smith! That's it! ========== That, in a nutshell, is all there is to know about controllers on the command line. Remember that this is just a normal controller, so routing -and _remap works fine. +and ``_remap()`` works fine.
\ No newline at end of file diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst index 70563b8d2..66dabd95e 100644 --- a/user_guide_src/source/general/common_functions.rst +++ b/user_guide_src/source/general/common_functions.rst @@ -6,58 +6,118 @@ CodeIgniter uses a few functions for its operation that are globally defined, and are available to you at any point. These do not require loading any libraries or helpers. -is_php('version_number') -========================== +is_php() +======== -is_php() determines of the PHP version being used is greater than the -supplied version_number. +.. php:function:: is_php($version = '5.3.0') -:: + :param string $version: Version number + :returns: bool - if (is_php('5.3.0')) +Determines of the PHP version being used is greater than the +supplied version number. + +Example:: + + if (is_php('5.3')) { - $str = quoted_printable_encode($str); + $str = quoted_printable_encode($str); } Returns boolean TRUE if the installed version of PHP is equal to or greater than the supplied version number. Returns FALSE if the installed version of PHP is lower than the supplied version number. -is_really_writable('path/to/file') -==================================== +is_really_writable() +==================== + +.. php:function:: is_really_writeable($file) + + :param string $file: File path + :returns: bool -is_writable() returns TRUE on Windows servers when you really can't +``is_writable()`` returns TRUE on Windows servers when you really can't write to the file as the OS reports to PHP as FALSE only if the -read-only attribute is marked. This function determines if a file is -actually writable by attempting to write to it first. Generally only -recommended on platforms where this information may be unreliable. +read-only attribute is marked. + +This function determines if a file is actually writable by attempting +to write to it first. Generally only recommended on platforms where +this information may be unreliable. -:: +Example:: if (is_really_writable('file.txt')) { - echo "I could write to this if I wanted to"; + echo "I could write to this if I wanted to"; } else { - echo "File is not writable"; + echo "File is not writable"; } -config_item('item_key') -========================= +config_item() +============= + +.. php:function:: config_item($key) + + :param string $key: Config item key + :returns: mixed + +The :doc:`Config Library <../libraries/config>` is the preferred way of +accessing configuration information, however ``config_item()`` can be used +to retrieve single keys. See :doc:`Config Library <../libraries/config>` +documentation for more information. + +.. important:: This function only returns values set in your configuration + files. It does not take into account config values that are + dynamically set at runtime. + +show_error() +============ -The :doc:`Config library <../libraries/config>` is the preferred way of -accessing configuration information, however config_item() can be used -to retrieve single keys. See Config library documentation for more -information. +.. php:function:: show_error($message, $status_code, $heading = 'An Error Was Encountered') -show_error('message'), show_404('page'), log_message('level', 'message') -======================================================================== + :param mixed $message: Error message + :param int $status_code: HTTP Response status code + :param string $heading: Error page heading + :returns: void -These are each outlined on the :doc:`Error Handling <errors>` page. +This function calls ``CI_Exception::show_error()``. For more info, +please see the :doc:`Error Handling <errors>` documentation. -set_status_header(code, 'text'); -================================ +show_404() +========== + +.. php:function:: show_404($page = '', $log_error = TRUE) + + :param string $page: URI string + :param bool $log_error: Whether to log the error + :returns: void + +This function calls ``CI_Exception::show_404()``. For more info, +please see the :doc:`Error Handling <errors>` documentation. + +log_message() +============= + +.. php:function:: log_message($level = 'error', $message, $php_error = FALSE) + + :param string $level: Log level + :param string $message: Message to log + :param bool $php_error: Whether we're loggin a native PHP error message + :returns: void + +This function is an alias for ``CI_Log::write_log()``. For more info, +please see the :doc:`Error Handling <errors>` documentation. + +set_status_header() +=============================== + +.. php:function:: set_status_header($code, $text = '') + + :param int $code: HTTP Reponse status code + :param string $text: A custom message to set with the status code + :returns: void Permits you to manually set a server status header. Example:: @@ -67,15 +127,71 @@ Permits you to manually set a server status header. Example:: `See here <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>`_ for a full list of headers. -remove_invisible_characters($str) -=================================== +remove_invisible_characters() +============================= + +.. php:function:: remove_invisible_characters($str, $url_encoded = TRUE) -This function prevents inserting null characters between ascii + :param string $str: Input string + :param bool $url_encoded: Whether to remove URL-encoded characters as well + :returns: string + +This function prevents inserting NULL characters between ASCII characters, like Java\\0script. -html_escape($mixed) -==================== +Example:: + + remove_invisible_characters('Java\\0script'); + // Returns: 'Javascript' + +html_escape() +============= + +.. php:function:: html_escape($var) + + :param mixed $var: Variable to escape + (string or array) + :returns: mixed + +This function acts as an alias for PHP's native ``htmlspecialchars()`` +function, with the advantage of being able to accept an array of strings. + +It is useful in preventing Cross Site Scripting (XSS). + +get_mimes() +=========== + +.. php:function:: get_mimes() + + :returns: array + +This function returns a *reference* to the MIMEs array from +*application/config/mimes.php*. + +is_https() +========== + +.. php:function:: is_https() + + :returns: bool + +Returns TRUE if a secure (HTTPS) connection is used and FALSE +in any other case (including non-HTTP requests). + +function_usable($function_name) +=============================== + +.. php:function:: function_usable($function_name) + + :param string $function_name: Function name + :returns: bool + +Returns TRUE if a function exists and is usable, FALSE otherwise. + +This function runs a ``function_exists()`` check and if the +`Suhosin extension <http://www.hardened-php.net/suhosin/>` is loaded, +checks if it doesn't disable the function being checked. -This function provides short cut for htmlspecialchars() function. It -accepts string and array. To prevent Cross Site Scripting (XSS), it is -very useful. +It is useful if you want to check for the availability of functions +such as ``eval()`` and ``exec()``, which are dangerous and might be +disabled on servers with highly restrictive security policies.
\ No newline at end of file diff --git a/user_guide_src/source/general/controllers.rst b/user_guide_src/source/general/controllers.rst index 6e5079419..729b08417 100644 --- a/user_guide_src/source/general/controllers.rst +++ b/user_guide_src/source/general/controllers.rst @@ -38,50 +38,49 @@ in it:: echo 'Hello World!'; } } - ?> -Then save the file to your application/controllers/ folder. +Then save the file to your *application/controllers/* directory. Now visit the your site using a URL similar to this:: example.com/index.php/blog/ -If you did it right, you should see Hello World!. +If you did it right, you should see: -Note: Class names must start with an uppercase letter. In other words, -this is valid:: + Hello World! + +.. important:: Class names must start with an uppercase letter. + +This is valid:: <?php class Blog extends CI_Controller { } - ?> - This is **not** valid:: <?php class blog extends CI_Controller { } - ?> Also, always make sure your controller extends the parent controller -class so that it can inherit all its functions. +class so that it can inherit all its methods. -Functions -========= +Methods +======= -In the above example the function name is index(). The "index" function +In the above example the method name is ``index()``. The "index" method is always loaded by default if the **second segment** of the URI is empty. Another way to show your "Hello World" message would be this:: example.com/index.php/blog/index/ -**The second segment of the URI determines which function in the +**The second segment of the URI determines which method in the controller gets called.** -Let's try it. Add a new function to your controller:: +Let's try it. Add a new method to your controller:: <?php class Blog extends CI_Controller { @@ -96,39 +95,37 @@ Let's try it. Add a new function to your controller:: echo 'Look at this!'; } } - ?> -Now load the following URL to see the comment function:: +Now load the following URL to see the comment method:: example.com/index.php/blog/comments/ You should see your new message. -Passing URI Segments to your Functions -====================================== +Passing URI Segments to your methods +==================================== If your URI contains more then two segments they will be passed to your -function as parameters. +method as parameters. For example, lets say you have a URI like this:: example.com/index.php/products/shoes/sandals/123 -Your function will be passed URI segments 3 and 4 ("sandals" and "123"):: +Your method will be passed URI segments 3 and 4 ("sandals" and "123"):: <?php class Products extends CI_Controller { - public function shoes($sandals, $id) - { - echo $sandals; - echo $id; - } + public function shoes($sandals, $id) + { + echo $sandals; + echo $id; + } } - ?> .. important:: If you are using the :doc:`URI Routing <routing>` - feature, the segments passed to your function will be the re-routed + feature, the segments passed to your method will be the re-routed ones. Defining a Default Controller @@ -139,59 +136,59 @@ present, as will be the case when only your site root URL is requested. To specify a default controller, open your **application/config/routes.php** file and set this variable:: - $route['default_controller'] = 'Blog'; + $route['default_controller'] = 'blog'; Where Blog is the name of the controller class you want used. If you now load your main index.php file without specifying any URI segments you'll see your Hello World message by default. -Remapping Function Calls -======================== +Remapping Method Calls +====================== As noted above, the second segment of the URI typically determines which -function in the controller gets called. CodeIgniter permits you to -override this behavior through the use of the _remap() function:: +method in the controller gets called. CodeIgniter permits you to override +this behavior through the use of the ``_remap()`` method:: public function _remap() { - // Some code here... + // Some code here... } -.. important:: If your controller contains a function named _remap(), +.. important:: If your controller contains a method named _remap(), it will **always** get called regardless of what your URI contains. It - overrides the normal behavior in which the URI determines which function - is called, allowing you to define your own function routing rules. + overrides the normal behavior in which the URI determines which method + is called, allowing you to define your own method routing rules. -The overridden function call (typically the second segment of the URI) -will be passed as a parameter to the _remap() function:: +The overridden method call (typically the second segment of the URI) will +be passed as a parameter to the ``_remap()`` method:: public function _remap($method) { - if ($method == 'some_method') - { - $this->$method(); - } - else - { - $this->default_method(); - } + if ($method === 'some_method') + { + $this->$method(); + } + else + { + $this->default_method(); + } } -Any extra segments after the method name are passed into _remap() as an +Any extra segments after the method name are passed into ``_remap()`` as an optional second parameter. This array can be used in combination with -PHP's `call_user_func_array <http://php.net/call_user_func_array>`_ +PHP's `call_user_func_array() <http://php.net/call_user_func_array>`_ to emulate CodeIgniter's default behavior. -:: +Example:: public function _remap($method, $params = array()) { - $method = 'process_'.$method; - if (method_exists($this, $method)) - { - return call_user_func_array(array($this, $method), $params); - } - show_404(); + $method = 'process_'.$method; + if (method_exists($this, $method)) + { + return call_user_func_array(array($this, $method), $params); + } + show_404(); } Processing Output @@ -199,69 +196,75 @@ Processing Output CodeIgniter has an output class that takes care of sending your final rendered data to the web browser automatically. More information on this -can be found in the :doc:`Views <views>` and :doc:`Output class <../libraries/output>` pages. In some cases, however, you -might want to post-process the finalized data in some way and send it to -the browser yourself. CodeIgniter permits you to add a function named -_output() to your controller that will receive the finalized output -data. +can be found in the :doc:`Views <views>` and :doc:`Output Class +<../libraries/output>` pages. In some cases, however, you might want to +post-process the finalized data in some way and send it to the browser +yourself. CodeIgniter permits you to add a method named ``_output()`` +to your controller that will receive the finalized output data. -.. important:: If your controller contains a function named _output(), - it will **always** be called by the output class instead of echoing the - finalized data directly. The first parameter of the function will - contain the finalized output. +.. important:: If your controller contains a method named ``_output()``, + it will **always** be called by the output class instead of + echoing the finalized data directly. The first parameter of the + method will contain the finalized output. Here is an example:: public function _output($output) { - echo $output; + echo $output; } -.. note:: Please note that your _output() function will receive the data in its - finalized state. Benchmark and memory usage data will be rendered, cache - files written (if you have caching enabled), and headers will be sent - (if you use that :doc:`feature <../libraries/output>`) before it is - handed off to the _output() function. - To have your controller's output cached properly, its _output() method - can use:: +.. note:: Please note that your ``_output()`` method will receive the + data in its finalized state. Benchmark and memory usage data + will be rendered, cache files written (if you have caching + enabled), and headers will be sent (if you use that + :doc:`feature <../libraries/output>`) before it is handed off + to the ``_output()`` method. + To have your controller's output cached properly, its + ``_output()`` method can use:: if ($this->output->cache_expiration > 0) { - $this->output->_write_cache($output); + $this->output->_write_cache($output); } - If you are using this feature the page execution timer and memory usage - stats might not be perfectly accurate since they will not take into - acccount any further processing you do. For an alternate way to control - output *before* any of the final processing is done, please see the - available methods in the :doc:`Output Class <../libraries/output>`. + If you are using this feature the page execution timer and + memory usage stats might not be perfectly accurate since they + will not take into account any further processing you do. + For an alternate way to control output *before* any of the + final processing is done, please see the available methods + in the :doc:`Output Library <../libraries/output>`. -Private Functions -================= +Private methods +=============== -In some cases you may want certain functions hidden from public access. -To make a function private, simply add an underscore as the name prefix -and it will not be served via a URL request. For example, if you were to -have a function like this:: +In some cases you may want certain methods hidden from public access. +In order to achieve this, simply declare the method as being private +or protected and it will not be served via a URL request. For example, +if you were to have a method like this:: private function _utility() { - // some code + // some code } Trying to access it via the URL, like this, will not work:: example.com/index.php/blog/_utility/ -Organizing Your Controllers into Sub-folders -============================================ +.. note:: Prefixing method names with an underscore will also prevent + them from being called. This is a legacy feature that is left + for backwards-compatibility. + +Organizing Your Controllers into Sub-directories +================================================ If you are building a large application you might find it convenient to -organize your controllers into sub-folders. CodeIgniter permits you to -do this. +organize your controllers into sub-directories. CodeIgniter permits you +to do this. -Simply create folders within your application/controllers directory and -place your controller classes within them. +Simply create folders within your *application/controllers/* directory +and place your controller classes within them. .. note:: When using this feature the first segment of your URI must specify the folder. For example, lets say you have a controller located @@ -273,9 +276,9 @@ place your controller classes within them. example.com/index.php/products/shoes/show/123 -Each of your sub-folders may contain a default controller which will be +Each of your sub-directories may contain a default controller which will be called if the URL contains only the sub-folder. Simply name your default -controller as specified in your application/config/routes.php file +controller as specified in your *application/config/routes.php* file. CodeIgniter also permits you to remap your URIs using its :doc:`URI Routing <routing>` feature. @@ -292,33 +295,38 @@ The reason this line is necessary is because your local constructor will be overriding the one in the parent controller class so we need to manually call it. -:: +Example:: <?php class Blog extends CI_Controller { - public function __construct() - { - parent::__construct(); - // Your own constructor code - } + public function __construct() + { + parent::__construct(); + // Your own constructor code + } } - ?> Constructors are useful if you need to set some default values, or run a default process when your class is instantiated. Constructors can't return a value, but they can do some default work. -Reserved Function Names -======================= +Reserved method names +===================== Since your controller classes will extend the main application -controller you must be careful not to name your functions identically to +controller you must be careful not to name your methods identically to the ones used by that class, otherwise your local functions will override them. See :doc:`Reserved Names <reserved_names>` for a full list. +.. important:: You should also never have a method named identically + to its class name. If you do, and there is no ``__construct()`` + method in the same class, then your e.g. ``Index::index()`` + method will be executed as a class constructor! This is a PHP4 + backwards-compatibility feature. + That's it! ========== -That, in a nutshell, is all there is to know about controllers. +That, in a nutshell, is all there is to know about controllers.
\ No newline at end of file diff --git a/user_guide_src/source/general/core_classes.rst b/user_guide_src/source/general/core_classes.rst index ac41407f7..ce57aeef0 100644 --- a/user_guide_src/source/general/core_classes.rst +++ b/user_guide_src/source/general/core_classes.rst @@ -31,6 +31,7 @@ time CodeIgniter runs: - Log - Output - Router +- Security - URI - Utf8 @@ -38,9 +39,9 @@ Replacing Core Classes ====================== To use one of your own system classes instead of a default one simply -place your version inside your local application/core directory:: +place your version inside your local *application/core/* directory:: - application/core/some-class.php + application/core/some_class.php If this directory does not exist you can create it. @@ -58,7 +59,7 @@ Extending Core Class ==================== If all you need to do is add some functionality to an existing library - -perhaps add a function or two - then it's overkill to replace the entire +perhaps add a method or two - then it's overkill to replace the entire library with your version. In this case it's better to simply extend the class. Extending a class is nearly identical to replacing a class with a couple exceptions: @@ -74,19 +75,19 @@ application/core/MY_Input.php, and declare your class with:: } -Note: If you need to use a constructor in your class make sure you +.. note:: If you need to use a constructor in your class make sure you extend the parent constructor:: class MY_Input extends CI_Input { - function __construct() - { - parent::__construct(); - } + public function __construct() + { + parent::__construct(); + } } **Tip:** Any functions in your class that are named identically to the -functions in the parent class will be used instead of the native ones +methods in the parent class will be used instead of the native ones (this is known as "method overriding"). This allows you to substantially alter the CodeIgniter core. @@ -97,24 +98,24 @@ your new class in your application controller's constructors. class Welcome extends MY_Controller { - function __construct() - { - parent::__construct(); - } + public function __construct() + { + parent::__construct(); + } - function index() - { - $this->load->view('welcome_message'); - } + public function index() + { + $this->load->view('welcome_message'); + } } Setting Your Own Prefix ----------------------- To set your own sub-class prefix, open your -application/config/config.php file and look for this item:: +*application/config/config.php* file and look for this item:: $config['subclass_prefix'] = 'MY_'; -Please note that all native CodeIgniter libraries are prefixed with CI\_ -so DO NOT use that as your prefix. +Please note that all native CodeIgniter libraries are prefixed +with CI\_ so DO NOT use that as your prefix.
\ No newline at end of file diff --git a/user_guide_src/source/general/creating_drivers.rst b/user_guide_src/source/general/creating_drivers.rst index 0e22e4f14..cf4ea5d7f 100644 --- a/user_guide_src/source/general/creating_drivers.rst +++ b/user_guide_src/source/general/creating_drivers.rst @@ -16,5 +16,6 @@ Sample driver directory and file structure layout: - Driver_name_subclass_2.php - Driver_name_subclass_3.php -**NOTE:** In order to maintain compatibility on case-sensitive file -systems, the Driver_name directory must be ucfirst() +.. note:: In order to maintain compatibility on case-sensitive + file systems, the Driver_name directory must be + named in the format returned by ``ucfirst()``.
\ No newline at end of file diff --git a/user_guide_src/source/general/creating_libraries.rst b/user_guide_src/source/general/creating_libraries.rst index 673fbd4bb..8bafd4532 100644 --- a/user_guide_src/source/general/creating_libraries.rst +++ b/user_guide_src/source/general/creating_libraries.rst @@ -12,7 +12,7 @@ your local resources and the global framework resources. As an added bonus, CodeIgniter permits your libraries to extend native classes if you simply need to add some functionality to an existing library. Or you can even replace native libraries just by placing -identically named versions in your application/libraries folder. +identically named versions in your *application/libraries* directory. In summary: @@ -28,8 +28,8 @@ The page below explains these three concepts in detail. Storage ======= -Your library classes should be placed within your application/libraries -folder, as this is where CodeIgniter will look for them when they are +Your library classes should be placed within your *application/libraries* +directory, as this is where CodeIgniter will look for them when they are initialized. Naming Conventions @@ -49,9 +49,9 @@ Someclass purely as an example):: class Someclass { - public function some_function() - { - } + public function some_method() + { + } } /* End of file Someclass.php */ @@ -59,7 +59,7 @@ Someclass purely as an example):: Using Your Class ================ -From within any of your :doc:`Controller <controllers>` functions you +From within any of your :doc:`Controller <controllers>` methods you can initialize your class using the standard:: $this->load->library('someclass'); @@ -70,12 +70,12 @@ doesn't care. Once loaded you can access your class using the lower case version:: - $this->someclass->some_function(); // Object instances will always be lower case + $this->someclass->some_method(); // Object instances will always be lower case Passing Parameters When Initializing Your Class =============================================== -In the library loading function you can dynamically pass data as an +In the library loading method you can dynamically pass data as an array via the second parameter and it will be passed to your class constructor:: @@ -86,21 +86,19 @@ constructor:: If you use this feature you must set up your class constructor to expect data:: - <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); + <?php defined('BASEPATH') OR exit('No direct script access allowed'); class Someclass { - public function __construct($params) - { - // Do something with $params - } + public function __construct($params) + { + // Do something with $params + } } - ?> - You can also pass parameters stored in a config file. Simply create a config file named identically to the class file name and store it in -your application/config/ folder. Note that if you dynamically pass +your *application/config/* directory. Note that if you dynamically pass parameters as described above, the config file option will not be available. @@ -108,18 +106,18 @@ Utilizing CodeIgniter Resources within Your Library =================================================== To access CodeIgniter's native resources within your library use the -get_instance() function. This function returns the CodeIgniter super +``get_instance()`` method. This method returns the CodeIgniter super object. -Normally from within your controller functions you will call any of the -available CodeIgniter functions using the $this construct:: +Normally from within your controller methods you will call any of the +available CodeIgniter methods using the ``$this`` construct:: $this->load->helper('url'); $this->load->library('session'); $this->config->item('base_url'); // etc. -$this, however, only works directly within your controllers, your +``$this``, however, only works directly within your controllers, your models, or your views. If you would like to use CodeIgniter's classes from within your own custom classes you can do so as follows: @@ -128,7 +126,7 @@ First, assign the CodeIgniter object to a variable:: $CI =& get_instance(); Once you've assigned the object to a variable, you'll use that variable -*instead* of $this:: +*instead* of ``$this``:: $CI =& get_instance(); @@ -137,7 +135,7 @@ Once you've assigned the object to a variable, you'll use that variable $CI->config->item('base_url'); // etc. -.. note:: You'll notice that the above get_instance() function is being +.. note:: You'll notice that the above ``get_instance()`` function is being passed by reference:: $CI =& get_instance(); @@ -145,6 +143,36 @@ Once you've assigned the object to a variable, you'll use that variable This is very important. Assigning by reference allows you to use the original CodeIgniter object rather than creating a copy of it. +However, since a library is a class, it would be better if you +take full advantage of the OOP principles. So, in order to +be able to use the CodeIgniter super-object in all of the class +methods, you're encouraged to assign it to a property instead:: + +class Example_library { + + protected $CI; + + // We'll use a constructor, as you can't directly call a function + // from a property definition. + public function __construct() + { + // Assign the CodeIgniter super-object + $this->CI =& get_instance(); + } + + public function foo() + { + $this->CI->load->helper('url'); + redirect(); + } + + public function bar() + { + echo $this->CI->config_item('base_url'); + } + +} + Replacing Native Libraries with Your Versions ============================================= @@ -152,8 +180,8 @@ Simply by naming your class files identically to a native library will cause CodeIgniter to use it instead of the native one. To use this feature you must name the file and the class declaration exactly the same as the native library. For example, to replace the native Email -library you'll create a file named application/libraries/Email.php, and -declare your class with:: +library you'll create a file named *application/libraries/Email.php*, +and declare your class with:: class CI_Email { @@ -161,7 +189,7 @@ declare your class with:: Note that most native classes are prefixed with CI\_. -To load your library you'll see the standard loading function:: +To load your library you'll see the standard loading method:: $this->load->library('email'); @@ -172,7 +200,7 @@ Extending Native Libraries ========================== If all you need to do is add some functionality to an existing library - -perhaps add a function or two - then it's overkill to replace the entire +perhaps add a method or two - then it's overkill to replace the entire library with your version. In this case it's better to simply extend the class. Extending a class is nearly identical to replacing a class with a couple exceptions: @@ -182,7 +210,7 @@ couple exceptions: item is configurable. See below.). For example, to extend the native Email class you'll create a file named -application/libraries/MY_Email.php, and declare your class with:: +*application/libraries/MY_Email.php*, and declare your class with:: class MY_Email extends CI_Email { @@ -200,8 +228,7 @@ extend the parent constructor:: } -.. note:: - Not all of the libraries have the same (or any) parameters +.. note:: Not all of the libraries have the same (or any) parameters in their constructor. Take a look at the library that you're extending first to see how it should be implemented. @@ -218,15 +245,15 @@ Once loaded you will use the class variable as you normally would for the class you are extending. In the case of the email class all calls will use:: - $this->email->some_function(); + $this->email->some_method(); Setting Your Own Prefix ----------------------- To set your own sub-class prefix, open your -application/config/config.php file and look for this item:: +*application/config/config.php* file and look for this item:: $config['subclass_prefix'] = 'MY_'; Please note that all native CodeIgniter libraries are prefixed with CI\_ -so DO NOT use that as your prefix. +so DO NOT use that as your prefix.
\ No newline at end of file diff --git a/user_guide_src/source/general/credits.rst b/user_guide_src/source/general/credits.rst index 2c7459894..03ee83dd6 100644 --- a/user_guide_src/source/general/credits.rst +++ b/user_guide_src/source/general/credits.rst @@ -16,4 +16,4 @@ of the Reactor Team. A hat tip goes to Ruby on Rails for inspiring us to create a PHP framework, and for bringing frameworks into the general consciousness of -the web community. +the web community.
\ No newline at end of file diff --git a/user_guide_src/source/general/drivers.rst b/user_guide_src/source/general/drivers.rst index e2ded62e2..b64b0e75e 100644 --- a/user_guide_src/source/general/drivers.rst +++ b/user_guide_src/source/general/drivers.rst @@ -8,18 +8,18 @@ parent class, but not their siblings. Drivers provide an elegant syntax in your :doc:`controllers <controllers>` for libraries that benefit from or require being broken down into discrete classes. -Drivers are found in the system/libraries folder, in their own folder -which is identically named to the parent library class. Also inside that -folder is a subfolder named drivers, which contains all of the possible -child class files. +Drivers are found in the *system/libraries/* directory, in their own +sub-directory which is identically named to the parent library class. +Also inside that directory is a subdirectory named drivers, which +contains all of the possible child class files. To use a driver you will initialize it within a controller using the -following initialization function:: +following initialization method:: - $this->load->driver('class name'); + $this->load->driver('class_name'); Where class name is the name of the driver class you want to invoke. For -example, to load a driver named "Some Parent" you would do this:: +example, to load a driver named "Some_parent" you would do this:: $this->load->driver('some_parent'); @@ -37,4 +37,4 @@ Creating Your Own Drivers ========================= Please read the section of the user guide that discusses how to :doc:`create -your own drivers <creating_drivers>`. +your own drivers <creating_drivers>`.
\ No newline at end of file diff --git a/user_guide_src/source/general/environments.rst b/user_guide_src/source/general/environments.rst index 40725feba..d74ebb8d5 100644 --- a/user_guide_src/source/general/environments.rst +++ b/user_guide_src/source/general/environments.rst @@ -11,10 +11,16 @@ when "live". The ENVIRONMENT Constant ======================== -By default, CodeIgniter comes with the environment constant set to +By default, CodeIgniter comes with the environment constant set to use +the value provided in ``$_SERVER['CI_ENV']``, otherwise defaults to 'development'. At the top of index.php, you will see:: - define('ENVIRONMENT', 'development'); + define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development'); + +This server variable can be set in your .htaccess file, or Apache +config using `SetEnv <https://httpd.apache.org/docs/2.2/mod/mod_env.html#setenv>`_. +Alternative methods are available for nginx and other servers, or you can +remove this logic entirely and set the constant based on the HTTP_HOST or IP. In addition to affecting some basic framework behavior (see the next section), you may use this constant in your own development to @@ -43,4 +49,4 @@ Optionally, you can have CodeIgniter load environment-specific configuration files. This may be useful for managing things like differing API keys across multiple environments. This is described in more detail in the environment section of the `Config -Class <../libraries/config.html#environments>`_ documentation. +Class <../libraries/config.html#environments>`_ documentation.
\ No newline at end of file diff --git a/user_guide_src/source/general/errors.rst b/user_guide_src/source/general/errors.rst index 91b59140f..8c941aadb 100644 --- a/user_guide_src/source/general/errors.rst +++ b/user_guide_src/source/general/errors.rst @@ -20,47 +20,69 @@ without having to worry about class/function scoping. The following functions let you generate errors: -show_error('message' [, int $status_code= 500 ] ) -=================================================== +show_error() +============ + +.. php:function:: show_error($message, $status_code, $heading = 'An Error Was Encountered') + + :param mixed $message: Error message + :param int $status_code: HTTP Response status code + :param string $heading: Error page heading + :returns: void This function will display the error message supplied to it using the -following error template: +following error template:: + + application/errors/error_general.php + +The optional parameter ``$status_code`` determines what HTTP status +code should be sent with the error. -application/errors/error_general.php +show_404() +========== -The optional parameter $status_code determines what HTTP status code -should be sent with the error. +.. php:function:: show_404($page = '', $log_error = TRUE) -show_404('page' [, 'log_error']) -================================== + :param string $page: URI string + :param bool $log_error: Whether to log the error + :returns: void This function will display the 404 error message supplied to it using -the following error template: +the following error template:: -application/errors/error_404.php + application/errors/error_404.php The function expects the string passed to it to be the file path to the page that isn't found. Note that CodeIgniter automatically shows 404 messages if controllers are not found. -CodeIgniter automatically logs any show_404() calls. Setting the +CodeIgniter automatically logs any ``show_404()`` calls. Setting the optional second parameter to FALSE will skip logging. -log_message('level', 'message') -================================ +log_message() +============= + +.. php:function:: log_message($level = 'error', $message, $php_error = FALSE) + + :param string $level: Log level + :param string $message: Message to log + :param bool $php_error: Whether we're loggin a native PHP error message + :returns: void This function lets you write messages to your log files. You must supply one of three "levels" in the first parameter, indicating what type of message it is (debug, error, info), with the message itself in the -second parameter. Example:: +second parameter. + +Example:: - if ($some_var == "") + if ($some_var == '') { - log_message('error', 'Some variable did not contain a value.'); + log_message('error', 'Some variable did not contain a value.'); } else { - log_message('debug', 'Some variable was correctly set'); + log_message('debug', 'Some variable was correctly set'); } log_message('info', 'The purpose of some variable is to provide some value.'); @@ -77,8 +99,8 @@ There are three message types: natively generate any info messages but you may want to in your application. -.. note:: In order for the log file to actually be written, the "logs" - folder must be writable. In addition, you must set the "threshold" for - logging in application/config/config.php. You might, for example, only - want error messages to be logged, and not the other two types. If you - set it to zero logging will be disabled. +.. note:: In order for the log file to actually be written, the *logs* + directory must be writable. In addition, you must set the "threshold" + for logging in *application/config/config.php*. You might, for example, + only want error messages to be logged, and not the other two types. + If you set it to zero logging will be disabled.
\ No newline at end of file diff --git a/user_guide_src/source/general/helpers.rst b/user_guide_src/source/general/helpers.rst index 3a98311a6..d171aa8ed 100644 --- a/user_guide_src/source/general/helpers.rst +++ b/user_guide_src/source/general/helpers.rst @@ -23,12 +23,12 @@ Helpers are typically stored in your **system/helpers**, or **application/helpers directory**. CodeIgniter will look first in your **application/helpers directory**. If the directory does not exist or the specified helper is not located there CI will instead look in your -global system/helpers folder. +global *system/helpers/* directory. Loading a Helper ================ -Loading a helper file is quite simple using the following function:: +Loading a helper file is quite simple using the following method:: $this->load->helper('name'); @@ -40,15 +40,15 @@ For example, to load the **URL Helper** file, which is named $this->load->helper('url'); -A helper can be loaded anywhere within your controller functions (or +A helper can be loaded anywhere within your controller methods (or even within your View files, although that's not a good practice), as long as you load it before you use it. You can load your helpers in your controller constructor so that they become available automatically in any function, or you can load a helper in a specific function that needs it. -Note: The Helper loading function above does not return a value, so -don't try to assign it to a variable. Just use it as shown. +.. note:: The Helper loading method above does not return a value, so + don't try to assign it to a variable. Just use it as shown. Loading Multiple Helpers ======================== @@ -56,14 +56,16 @@ Loading Multiple Helpers If you need to load more than one helper you can specify them in an array, like this:: - $this->load->helper( array('helper1', 'helper2', 'helper3') ); + $this->load->helper( + array('helper1', 'helper2', 'helper3') + ); Auto-loading Helpers ==================== If you find that you need a particular helper globally throughout your application, you can tell CodeIgniter to auto-load it during system -initialization. This is done by opening the **application/config/autoload.php** +initialization. This is done by opening the **application/config/autoload.php** file and adding the helper to the autoload array. Using a Helper @@ -72,13 +74,13 @@ Using a Helper Once you've loaded the Helper File containing the function you intend to use, you'll call it the way you would a standard PHP function. -For example, to create a link using the anchor() function in one of your -view files you would do this:: +For example, to create a link using the ``anchor()`` function in one of +your view files you would do this:: <?php echo anchor('blog/comments', 'Click Here');?> Where "Click Here" is the name of the link, and "blog/comments" is the -URI to the controller/function you wish to link to. +URI to the controller/method you wish to link to. "Extending" Helpers =================== @@ -91,11 +93,11 @@ If all you need to do is add some functionality to an existing helper - perhaps add a function or two, or change how a particular helper function operates - then it's overkill to replace the entire helper with your version. In this case it's better to simply "extend" the Helper. -The term "extend" is used loosely since Helper functions are procedural -and discrete and cannot be extended in the traditional programmatic -sense. Under the hood, this gives you the ability to add to the -functions a Helper provides, or to modify how the native Helper -functions operate. + +.. note:: The term "extend" is used loosely since Helper functions are + procedural and discrete and cannot be extended in the traditional + programmatic sense. Under the hood, this gives you the ability to + add to or or to replace the functions a Helper provides. For example, to extend the native **Array Helper** you'll create a file named **application/helpers/MY_array_helper.php**, and add or override @@ -104,31 +106,31 @@ functions:: // any_in_array() is not in the Array Helper, so it defines a new function function any_in_array($needle, $haystack) { - $needle = (is_array($needle)) ? $needle : array($needle); - - foreach ($needle as $item) - { - if (in_array($item, $haystack)) - { - return TRUE; - } + $needle = is_array($needle) ? $needle : array($needle); + + foreach ($needle as $item) + { + if (in_array($item, $haystack)) + { + return TRUE; + } } - return FALSE; + return FALSE; } // random_element() is included in Array Helper, so it overrides the native function function random_element($array) { - shuffle($array); - return array_pop($array); + shuffle($array); + return array_pop($array); } Setting Your Own Prefix ----------------------- The filename prefix for "extending" Helpers is the same used to extend -libraries and Core classes. To set your own prefix, open your +libraries and core classes. To set your own prefix, open your **application/config/config.php** file and look for this item:: $config['subclass_prefix'] = 'MY_'; @@ -140,4 +142,4 @@ Now What? ========= In the Table of Contents you'll find a list of all the available Helper -Files. Browse each one to see what they do. +Files. Browse each one to see what they do.
\ No newline at end of file diff --git a/user_guide_src/source/general/hooks.rst b/user_guide_src/source/general/hooks.rst index 65696f6c7..fc5da5b80 100644 --- a/user_guide_src/source/general/hooks.rst +++ b/user_guide_src/source/general/hooks.rst @@ -16,25 +16,26 @@ Enabling Hooks ============== The hooks feature can be globally enabled/disabled by setting the -following item in the application/config/config.php file:: +following item in the **application/config/config.php** file:: $config['enable_hooks'] = TRUE; Defining a Hook =============== -Hooks are defined in application/config/hooks.php file. Each hook is -specified as an array with this prototype:: +Hooks are defined in **application/config/hooks.php** file. +Each hook is specified as an array with this prototype:: $hook['pre_controller'] = array( - 'class' => 'MyClass', - 'function' => 'Myfunction', - 'filename' => 'Myclass.php', - 'filepath' => 'hooks', - 'params' => array('beer', 'wine', 'snacks') - ); + 'class' => 'MyClass', + 'function' => 'Myfunction', + 'filename' => 'Myclass.php', + 'filepath' => 'hooks', + 'params' => array('beer', 'wine', 'snacks') + ); **Notes:** + The array index correlates to the name of the particular hook point you want to use. In the above example the hook point is pre_controller. A list of hook points is found below. The following items should be @@ -42,14 +43,15 @@ defined in your associative hook array: - **class** The name of the class you wish to invoke. If you prefer to use a procedural function instead of a class, leave this item blank. -- **function** The function name you wish to call. +- **function** The function (or method) name you wish to call. - **filename** The file name containing your class/function. -- **filepath** The name of the directory containing your script. Note: - Your script must be located in a directory INSIDE your application - folder, so the file path is relative to that folder. For example, if - your script is located in application/hooks, you will simply use - hooks as your filepath. If your script is located in - application/hooks/utilities you will use hooks/utilities as your +- **filepath** The name of the directory containing your script. + Note: + Your script must be located in a directory INSIDE your *application/* + directory, so the file path is relative to that directory. For example, + if your script is located in *application/hooks/*, you will simply use + 'hooks' as your filepath. If your script is located in + *application/hooks/utilities/* you will use 'hooks/utilities' as your filepath. No trailing slash. - **params** Any parameters you wish to pass to your script. This item is optional. @@ -61,20 +63,20 @@ If want to use the same hook point with more then one script, simply make your array declaration multi-dimensional, like this:: $hook['pre_controller'][] = array( - 'class' => 'MyClass', - 'function' => 'Myfunction', - 'filename' => 'Myclass.php', - 'filepath' => 'hooks', - 'params' => array('beer', 'wine', 'snacks') - ); + 'class' => 'MyClass', + 'function' => 'MyMethod', + 'filename' => 'Myclass.php', + 'filepath' => 'hooks', + 'params' => array('beer', 'wine', 'snacks') + ); $hook['pre_controller'][] = array( - 'class' => 'MyOtherClass', - 'function' => 'MyOtherfunction', - 'filename' => 'Myotherclass.php', - 'filepath' => 'hooks', - 'params' => array('red', 'yellow', 'blue') - ); + 'class' => 'MyOtherClass', + 'function' => 'MyOtherMethod', + 'filename' => 'Myotherclass.php', + 'filepath' => 'hooks', + 'params' => array('red', 'yellow', 'blue') + ); Notice the brackets after each array index:: @@ -101,18 +103,17 @@ The following is a list of available hook points. - **post_controller** Called immediately after your controller is fully executed. - **display_override** - Overrides the _display() function, used to send the finalized page + Overrides the ``_display()`` method, used to send the finalized page to the web browser at the end of system execution. This permits you to use your own display methodology. Note that you will need to - reference the CI superobject with $this->CI =& get_instance() and + reference the CI superobject with ``$this->CI =& get_instance()`` and then the finalized data will be available by calling - $this->CI->output->get_output() + ``$this->CI->output->get_output()``. - **cache_override** - Enables you to call your own function instead of the - _display_cache() function in the output class. This permits you to - use your own cache display mechanism. + Enables you to call your own method instead of the ``_display_cache()`` + method in the :doc:`Output Library <../libraries/output>`. This permits + you to use your own cache display mechanism. - **post_system** Called after the final rendered page is sent to the browser, at the end of system execution after the finalized data is sent to the - browser. - + browser.
\ No newline at end of file diff --git a/user_guide_src/source/general/index.rst b/user_guide_src/source/general/index.rst index 2162b8140..2bc684a1d 100644 --- a/user_guide_src/source/general/index.rst +++ b/user_guide_src/source/general/index.rst @@ -29,4 +29,4 @@ General Topics environments alternative_php security - PHP Style Guide <styleguide> + PHP Style Guide <styleguide>
\ No newline at end of file diff --git a/user_guide_src/source/general/libraries.rst b/user_guide_src/source/general/libraries.rst index 954a5b8f8..6e1c8b6dd 100644 --- a/user_guide_src/source/general/libraries.rst +++ b/user_guide_src/source/general/libraries.rst @@ -2,30 +2,31 @@ Using CodeIgniter Libraries ########################### -All of the available libraries are located in your system/libraries -folder. In most cases, to use one of these classes involves initializing +All of the available libraries are located in your *system/libraries/* +directory. In most cases, to use one of these classes involves initializing it within a :doc:`controller <controllers>` using the following -initialization function:: +initialization method:: - $this->load->library('class name'); + $this->load->library('class_name'); -Where class name is the name of the class you want to invoke. For -example, to load the form validation class you would do this:: +Where 'class_name' is the name of the class you want to invoke. For +example, to load the :doc:`Form Validation Library +<../libraries/form_validation>` you would do this:: - $this->load->library('form_validation'); + $this->load->library('form_validation'); Once initialized you can use it as indicated in the user guide page corresponding to that class. Additionally, multiple libraries can be loaded at the same time by -passing an array of libraries to the load function. +passing an array of libraries to the load method. -:: +Example:: $this->load->library(array('email', 'table')); Creating Your Own Libraries =========================== -Please read the section of the user guide that discusses how to :doc:`create -your own libraries <creating_libraries>` +Please read the section of the user guide that discusses how to +:doc:`create your own libraries <creating_libraries>`. diff --git a/user_guide_src/source/general/managing_apps.rst b/user_guide_src/source/general/managing_apps.rst index 996481354..afb1aba2e 100644 --- a/user_guide_src/source/general/managing_apps.rst +++ b/user_guide_src/source/general/managing_apps.rst @@ -3,41 +3,39 @@ Managing your Applications ########################## By default it is assumed that you only intend to use CodeIgniter to -manage one application, which you will build in your application/ +manage one application, which you will build in your *application/* directory. It is possible, however, to have multiple sets of applications that share a single CodeIgniter installation, or even to -rename or relocate your application folder. +rename or relocate your application directory. -Renaming the Application Folder -=============================== - -If you would like to rename your application folder you may do so as -long as you open your main index.php file and set its name using the -$application_folder variable:: +Renaming the Application Directory +================================== - $application_folder = "application"; +If you would like to rename your application directory you may do so +as long as you open your main index.php file and set its name using +the ``$application_folder`` variable:: -Relocating your Application Folder -================================== + $application_folder = 'application'; -It is possible to move your application folder to a different location -on your server than your system folder. To do so open your main -index.php and set a *full server path* in the $application_folder -variable. +Relocating your Application Directory +===================================== -:: +It is possible to move your application directory to a different +location on your server than your system directory. To do so open +your main index.php and set a *full server path* in the +``$application_folder`` variable:: - $application_folder = "/Path/to/your/application"; + $application_folder = '/path/to/your/application'; Running Multiple Applications with one CodeIgniter Installation =============================================================== If you would like to share a common CodeIgniter installation to manage several different applications simply put all of the directories located -inside your application folder into their own sub-folder. +inside your application directory into their own sub-directory. -For example, let's say you want to create two applications, "foo" and -"bar". You could structure your application folders like this:: +For example, let's say you want to create two applications, named "foo" +and "bar". You could structure your application directories like this:: applications/foo/ applications/foo/config/ @@ -55,11 +53,11 @@ For example, let's say you want to create two applications, "foo" and applications/bar/views/ To select a particular application for use requires that you open your -main index.php file and set the $application_folder variable. For +main index.php file and set the ``$application_folder`` variable. For example, to select the "foo" application for use you would do this:: - $application_folder = "applications/foo"; + $application_folder = 'applications/foo'; .. note:: Each of your applications will need its own index.php file which calls the desired application. The index.php file can be named - anything you want. + anything you want.
\ No newline at end of file diff --git a/user_guide_src/source/general/models.rst b/user_guide_src/source/general/models.rst index b816f958a..a028a9569 100644 --- a/user_guide_src/source/general/models.rst +++ b/user_guide_src/source/general/models.rst @@ -16,66 +16,68 @@ blog. You might have a model class that contains functions to insert, update, and retrieve your blog data. Here is an example of what such a model class might look like:: - class Blogmodel extends CI_Model { - - var $title = ''; - var $content = ''; - var $date = ''; - - function __construct() - { - // Call the Model constructor - parent::__construct(); - } - - function get_last_ten_entries() - { - $query = $this->db->get('entries', 10); - return $query->result(); - } - - function insert_entry() - { - $this->title = $_POST['title']; // please read the below note - $this->content = $_POST['content']; - $this->date = time(); - - $this->db->insert('entries', $this); - } - - function update_entry() - { - $this->title = $_POST['title']; - $this->content = $_POST['content']; - $this->date = time(); - - $this->db->update('entries', $this, array('id' => $_POST['id'])); - } + class Blog_model extends CI_Model { + + public $title; + public $content; + public $date; + + public function __construct() + { + // Call the CI_Model constructor + parent::__construct(); + } + + public function get_last_ten_entries() + { + $query = $this->db->get('entries', 10); + return $query->result(); + } + + public function insert_entry() + { + $this->title = $_POST['title']; // please read the below note + $this->content = $_POST['content']; + $this->date = time(); + + $this->db->insert('entries', $this); + } + + public function update_entry() + { + $this->title = $_POST['title']; + $this->content = $_POST['content']; + $this->date = time(); + + $this->db->update('entries', $this, array('id' => $_POST['id'])); + } } -.. note:: The functions in the above example use the :doc:`Active - Record <../database/active_record>` database functions. +.. note:: The methods in the above example use the :doc:`Query Builder + <../database/query_builder>` database methods. -.. note:: For the sake of simplicity in this example we're using $_POST +.. note:: For the sake of simplicity in this example we're using ``$_POST`` directly. This is generally bad practice, and a more common approach - would be to use the :doc:`Input Class <../libraries/input>` - $this->input->post('title') + would be to use the :doc:`Input Library <../libraries/input>` + ``$this->input->post('title')``. Anatomy of a Model ================== -Model classes are stored in your **application/models/ folder**. They can be -nested within sub-folders if you want this type of organization. +Model classes are stored in your **application/models/** directory. +They can be nested within sub-directories if you want this type of +organization. The basic prototype for a model class is this:: class Model_name extends CI_Model { - function __construct() - { - parent::__construct(); - } + public function __construct() + { + parent::__construct(); + } + } Where **Model_name** is the name of your class. Class names **must** have @@ -87,10 +89,11 @@ example, if your class is this:: class User_model extends CI_Model { - function __construct() - { - parent::__construct(); - } + public function __construct() + { + parent::__construct(); + } + } Your file will be this:: @@ -101,44 +104,44 @@ Loading a Model =============== Your models will typically be loaded and called from within your -:doc:`controller <controllers>` functions. To load a model you will use -the following function:: +:doc:`controller <controllers>` methods. To load a model you will use +the following method:: - $this->load->model('Model_name'); + $this->load->model('model_name'); -If your model is located in a sub-folder, include the relative path from -your models folder. For example, if you have a model located at -application/models/blog/queries.php you'll load it using:: +If your model is located in a sub-directory, include the relative path +from your models directory. For example, if you have a model located at +*application/models/blog/queries.php* you'll load it using:: $this->load->model('blog/queries'); -Once loaded, you will access your model functions using an object with -the same name as your class:: +Once loaded, you will access your model methods using an object with the +same name as your class:: - $this->load->model('Model_name'); + $this->load->model('model_name'); - $this->Model_name->function(); + $this->model_name->method(); If you would like your model assigned to a different object name you can -specify it via the second parameter of the loading function:: +specify it via the second parameter of the loading method:: - $this->load->model('Model_name', 'fubar'); + $this->load->model('model_name', 'foobar'); - $this->fubar->function(); + $this->foobar->method(); Here is an example of a controller, that loads a model, then serves a view:: class Blog_controller extends CI_Controller { - function blog() - { - $this->load->model('Blog'); + public function blog() + { + $this->load->model('blog'); - $data['query'] = $this->Blog->get_last_ten_entries(); + $data['query'] = $this->Blog->get_last_ten_entries(); - $this->load->view('blog', $data); - } + $this->load->view('blog', $data); + } } @@ -160,25 +163,22 @@ database. The following options for connecting are available to you: - You can connect using the standard database methods :doc:`described here <../database/connecting>`, either from within your Controller class or your Model class. -- You can tell the model loading function to auto-connect by passing - TRUE (boolean) via the third parameter, and connectivity settings, as - defined in your database config file will be used: - :: +- You can tell the model loading method to auto-connect by passing + TRUE (boolean) via the third parameter, and connectivity settings, + as defined in your database config file will be used:: - $this->load->model('Model_name', '', TRUE); + $this->load->model('model_name', '', TRUE); - You can manually pass database connectivity settings via the third parameter:: - $config['hostname'] = "localhost"; - $config['username'] = "myusername"; - $config['password'] = "mypassword"; - $config['database'] = "mydatabase"; - $config['dbdriver'] = "mysql"; - $config['dbprefix'] = ""; + $config['hostname'] = 'localhost'; + $config['username'] = 'myusername'; + $config['password'] = 'mypassword'; + $config['database'] = 'mydatabase'; + $config['dbdriver'] = 'mysqli'; + $config['dbprefix'] = ''; $config['pconnect'] = FALSE; $config['db_debug'] = TRUE; - $this->load->model('Model_name', '', $config); - - + $this->load->model('Model_name', '', $config);
\ No newline at end of file diff --git a/user_guide_src/source/general/profiling.rst b/user_guide_src/source/general/profiling.rst index 437635289..6dbd0be16 100644 --- a/user_guide_src/source/general/profiling.rst +++ b/user_guide_src/source/general/profiling.rst @@ -3,7 +3,7 @@ Profiling Your Application ########################## The Profiler Class will display benchmark results, queries you have run, -and $_POST data at the bottom of your pages. This information can be +and ``$_POST`` data at the bottom of your pages. This information can be useful during development in order to help with debugging and optimization. @@ -11,14 +11,14 @@ Initializing the Class ====================== .. important:: This class does NOT need to be initialized. It is loaded - automatically by the :doc:`Output Class <../libraries/output>` if - profiling is enabled as shown below. + automatically by the :doc:`Output Library <../libraries/output>` + if profiling is enabled as shown below. Enabling the Profiler ===================== -To enable the profiler place the following function anywhere within your -:doc:`Controller <controllers>` functions:: +To enable the profiler place the following line anywhere within your +:doc:`Controller <controllers>` methods:: $this->output->enable_profiler(TRUE); @@ -35,8 +35,8 @@ Setting Benchmark Points In order for the Profiler to compile and display your benchmark data you must name your mark points using specific syntax. -Please read the information on setting Benchmark points in :doc:`Benchmark -Class <../libraries/benchmark>` page. +Please read the information on setting Benchmark points in the +:doc:`Benchmark Library <../libraries/benchmark>` page. Enabling and Disabling Profiler Sections ======================================== @@ -44,21 +44,21 @@ Enabling and Disabling Profiler Sections Each section of Profiler data can be enabled or disabled by setting a corresponding config variable to TRUE or FALSE. This can be done one of two ways. First, you can set application wide defaults with the -application/config/profiler.php config file. +*application/config/profiler.php* config file. -:: +Example:: $config['config'] = FALSE; $config['queries'] = FALSE; In your controllers, you can override the defaults and config file -values by calling the set_profiler_sections() method of the :doc:`Output -class <../libraries/output>`:: +values by calling the ``set_profiler_sections()`` method of the +:doc:`Output Library <../libraries/output>`:: $sections = array( - 'config' => TRUE, - 'queries' => TRUE - ); + 'config' => TRUE, + 'queries' => TRUE + ); $this->output->set_profiler_sections($sections); diff --git a/user_guide_src/source/general/quick_reference.rst b/user_guide_src/source/general/quick_reference.rst deleted file mode 100644 index b9108a528..000000000 --- a/user_guide_src/source/general/quick_reference.rst +++ /dev/null @@ -1,11 +0,0 @@ -##################### -Quick Reference Chart -##################### - -For a PDF version of this chart, `click -here <http://codeigniter.com/download_files/ci_quick_ref.pdf>`_. - -.. figure:: ../images/ci_quick_ref.png - :align: center - :alt: - diff --git a/user_guide_src/source/general/requirements.rst b/user_guide_src/source/general/requirements.rst index d97b7b4b2..104923625 100644 --- a/user_guide_src/source/general/requirements.rst +++ b/user_guide_src/source/general/requirements.rst @@ -3,6 +3,13 @@ Server Requirements ################### - `PHP <http://www.php.net/>`_ version 5.2.4 or newer. -- A Database is required for most web application programming. Current - supported databases are MySQL (5.1+), MySQLi, MS SQL, SQLSRV, Oracle, - PostgreSQL, SQLite, SQLite3, CUBRID, Interbase, ODBC and PDO. +- A Database is required for most web application programming. + Currently supported databases are: + - MySQL (5.1+) via the *mysql* (deprecated), *mysqli* and *pdo* drivers + - Oracle via the *oci8* and *pdo* drivers + - PostgreSQL via the *postgre* and *pdo* drivers + - MS SQL via the *mssql*, *sqlsrv* (version 2005 and above only) and *pdo* drivers + - SQLite via the *sqlite* (version 2), *sqlite3* (version 3) and *pdo* drivers + - CUBRID via the *cubrid* and *pdo* drivers + - Interbase/Firebird via the *ibase* and *pdo* drivers + - ODBC via the *odbc* and *pdo* drivers (you should know that ODBC is actually an abstraction layer)
\ No newline at end of file diff --git a/user_guide_src/source/general/reserved_names.rst b/user_guide_src/source/general/reserved_names.rst index 5ce7fc2ff..d91292363 100644 --- a/user_guide_src/source/general/reserved_names.rst +++ b/user_guide_src/source/general/reserved_names.rst @@ -2,16 +2,17 @@ Reserved Names ############## -In order to help out, CodeIgniter uses a series of functions and names -in its operation. Because of this, some names cannot be used by a -developer. Following is a list of reserved names that cannot be used. +In order to help out, CodeIgniter uses a series of function, method, +class and variable names in its operation. Because of this, some names +cannot be used by a developer. Following is a list of reserved names +that cannot be used. Controller names ---------------- Since your controller classes will extend the main application -controller you must be careful not to name your functions identically to -the ones used by that class, otherwise your local functions will +controller you must be careful not to name your methods identically to +the ones used by that class, otherwise your local methods will override them. The following is a list of reserved names. Do not name your controller any of these: @@ -24,32 +25,35 @@ your controller any of these: Functions --------- -- is_really_writable() -- load_class() -- get_config() -- config_item() -- show_error() -- show_404() -- log_message() -- _exception_handler() -- get_instance() +- :php:func:`is_really_writable()` +- ``load_class()`` +- ``get_config()`` +- :php:func:`config_item()` +- :php:func:`show_error()` +- :php:func:`show_404()` +- :php:func:`log_message()` +- :php:func:`get_mimes()` +- :php:func:`html_escape()` +- :php:func:`get_instance()` +- ``_exception_handler()`` +- ``_stringify_attributes()`` Variables --------- -- $config -- $mimes -- $lang +- ``$config`` +- ``$db`` +- ``$lang`` Constants --------- - ENVIRONMENT -- EXT - FCPATH - SELF - BASEPATH - APPPATH +- VIEWPATH - CI_VERSION - FILE_READ_MODE - FILE_WRITE_MODE @@ -62,5 +66,4 @@ Constants - FOPEN_WRITE_CREATE - FOPEN_READ_WRITE_CREATE - FOPEN_WRITE_CREATE_STRICT -- FOPEN_READ_WRITE_CREATE_STRICT - +- FOPEN_READ_WRITE_CREATE_STRICT
\ No newline at end of file diff --git a/user_guide_src/source/general/routing.rst b/user_guide_src/source/general/routing.rst index 45950fc11..2a0332088 100644 --- a/user_guide_src/source/general/routing.rst +++ b/user_guide_src/source/general/routing.rst @@ -9,34 +9,34 @@ normally follow this pattern:: example.com/class/function/id/ In some instances, however, you may want to remap this relationship so -that a different class/function can be called instead of the one +that a different class/method can be called instead of the one corresponding to the URL. -For example, lets say you want your URLs to have this prototype: +For example, lets say you want your URLs to have this prototype:: -example.com/product/1/ -example.com/product/2/ -example.com/product/3/ -example.com/product/4/ + example.com/product/1/ + example.com/product/2/ + example.com/product/3/ + example.com/product/4/ -Normally the second segment of the URL is reserved for the function -name, but in the example above it instead has a product ID. To overcome -this, CodeIgniter allows you to remap the URI handler. +Normally the second segment of the URL is reserved for the method +name, but in the example above it instead has a product ID. To +overcome this, CodeIgniter allows you to remap the URI handler. Setting your own routing rules ============================== -Routing rules are defined in your application/config/routes.php file. In -it you'll see an array called $route that permits you to specify your -own routing criteria. Routes can either be specified using wildcards or -Regular Expressions +Routing rules are defined in your *application/config/routes.php* file. +In it you'll see an array called ``$route`` that permits you to specify +your own routing criteria. Routes can either be specified using wildcards +or Regular Expressions. Wildcards ========= A typical wildcard route might look something like this:: - $route['product/:num'] = "catalog/product_lookup"; + $route['product/:num'] = 'catalog/product_lookup'; In a route, the array key contains the URI to be matched, while the array value contains the destination it should be re-routed to. In the @@ -47,31 +47,40 @@ segment of the URL, and a number is found in the second segment, the You can match literal values or you can use two wildcard types: **(:num)** will match a segment containing only numbers. - **(:any)** will match a segment containing any character. +**(:any)** will match a segment containing any character (except for '/', which is the segment delimiter). + +.. note:: Wildcards are actually aliases for regular expressions, with + **:any** being translated to **[^/]+** and **:num** to **[0-9]+**, + respectively. .. note:: Routes will run in the order they are defined. Higher routes will always take precedence over lower ones. +.. note:: Route rules are not filters! Setting a rule of e.g. + 'foo/bar/(:num)' will not prevent controller *Foo* and method + *bar* to be called with a non-numeric value if that is a valid + route. + Examples ======== Here are a few routing examples:: - $route['journals'] = "blogs"; + $route['journals'] = 'blogs'; A URL containing the word "journals" in the first segment will be remapped to the "blogs" class. :: - $route['blog/joe'] = "blogs/users/34"; + $route['blog/joe'] = 'blogs/users/34'; A URL containing the segments blog/joe will be remapped to the "blogs" class and the "users" method. The ID will be set to "34". :: - $route['product/(:any)'] = "catalog/product_lookup"; + $route['product/(:any)'] = 'catalog/product_lookup'; A URL with "product" as the first segment, and anything in the second will be remapped to the "catalog" class and the "product_lookup" @@ -79,12 +88,12 @@ method. :: - $route['product/(:num)'] = "catalog/product_lookup_by_id/$1"; + $route['product/(:num)'] = 'catalog/product_lookup_by_id/$1'; A URL with "product" as the first segment, and a number in the second will be remapped to the "catalog" class and the "product_lookup_by_id" method passing in the match as a variable to -the function. +the method. .. important:: Do not use leading/trailing slashes. @@ -99,12 +108,39 @@ rules. Any valid regular expression is allowed, as are back-references. A typical RegEx route might look something like this:: - $route['products/([a-z]+)/(\d+)'] = "$1/id_$2"; + $route['products/([a-z]+)/(\d+)'] = '$1/id_$2'; In the above example, a URI similar to products/shirts/123 would instead -call the shirts controller class and the id_123 function. +call the "shirts" controller class and the "id_123" method. + +With regular expressions, you can also catch a segment containing a +forward slash ('/'), which would usually represent the delimiter between +multiple segments. +For example, if a user accesses a password protected area of your web +application and you wish to be able to redirect them back to the same +page after they log in, you may find this example useful:: + + $route['login/(.+)'] = 'auth/login/$1'; + +That will call the "auth" controller class and its ``login()`` method, +passing everything contained in the URI after *login/* as a parameter. + +For those of you who don't know regular expressions and want to learn +more about them, `regular-expressions.info <http://www.regular-expressions.info/>` +might be a good starting point. + +..note:: You can also mix and match wildcards with regular expressions. + +Callbacks +========= + +If you are using PHP >= 5.3 you can use callbacks in place of the normal +routing rules to process the back-references. Example:: -You can also mix and match wildcards with regular expressions. + $route['products/([a-z]+)/edit/(\d+)'] = function ($product_type, $id) + { + return 'catalog/product_edit/' . strtolower($product_type) . '/' . $id; + }; Reserved Routes =============== @@ -125,9 +161,9 @@ appear by default. This route indicates which controller class should be loaded if the requested controller is not found. It will override the default 404 -error page. It won't affect to the show_404() function, which will -continue loading the default error_404.php file at -application/errors/error_404.php. +error page. It won't affect to the ``show_404()`` function, which will +continue loading the default *error_404.php* file at +*application/errors/error_404.php*. .. important:: The reserved routes must come before any wildcard or - regular expression routes. + regular expression routes.
\ No newline at end of file diff --git a/user_guide_src/source/general/security.rst b/user_guide_src/source/general/security.rst index 4d7a213d1..984ca840b 100644 --- a/user_guide_src/source/general/security.rst +++ b/user_guide_src/source/general/security.rst @@ -13,38 +13,40 @@ in your URI strings in order to help minimize the possibility that malicious data can be passed to your application. URIs may only contain the following: -- Alpha-numeric text +- Alpha-numeric text (latin characters only) - Tilde: ~ - Period: . - Colon: : - Underscore: \_ - Dash: - +- Pipe: | Register_globals ================= During system initialization all global variables are unset, except -those found in the $_GET, $_POST, and $_COOKIE arrays. The unsetting -routine is effectively the same as register_globals = off. +those found in the ``$_GET``, ``$_POST``, and ``$_COOKIE`` arrays. +The unsetting routine is effectively the same as +*register_globals = off*. -error_reporting -================ +display_errors +============== -In production environments, it is typically desirable to disable PHP's -error reporting by setting the internal error_reporting flag to a value +In production environments, it is typically desirable to "disable" PHP's +error reporting by setting the internal *display_errors* flag to a value of 0. This disables native PHP errors from being rendered as output, which may potentially contain sensitive information. Setting CodeIgniter's **ENVIRONMENT** constant in index.php to a value of **\'production\'** will turn off these errors. In development mode, it is recommended that a value of 'development' is used. More information -about differentiating between environments can be found on the :doc:`Handling -Environments <environments>` page. +about differentiating between environments can be found on the +:doc:`Handling Environments <environments>` page. magic_quotes_runtime -====================== +==================== -The magic_quotes_runtime directive is turned off during system +The *magic_quotes_runtime* directive is turned off during system initialization so that you don't have to remove slashes when retrieving data from your database. @@ -68,7 +70,7 @@ XSS Filtering ============= CodeIgniter comes with a Cross Site Scripting filter. This filter -looks for commonly used techniques to embed malicious Javascript into +looks for commonly used techniques to embed malicious JavaScript into your data, or other types of code that attempt to hijack cookies or do other malicious things. The XSS Filter is described :doc:`here <../libraries/security>`. @@ -76,15 +78,32 @@ do other malicious things. The XSS Filter is described Validate the data ================= -CodeIgniter has a :doc:`Form Validation -Class <../libraries/form_validation>` that assists you in +CodeIgniter has a :doc:`Form Validation Library +<../libraries/form_validation>` that assists you in validating, filtering, and prepping your data. Escape all data before database insertion ========================================= Never insert information into your database without escaping it. -Please see the section that discusses -:doc:`queries <../database/queries>` for more information. +Please see the section that discusses :doc:`database queries +<../database/queries>` for more information. +Hide your files +=============== +Another good security practice is to only leave your *index.php* +and "assets" (e.g. .js, css and image files) under your server's +*webroot* directory (most commonly named "htdocs/"). These are +the only files that you would need to be accessible from the web. + +Allowing your visitors to see anything else would potentially +allow them to access sensitive data, execute scripts, etc. + +If you're not allowed to do that, you can try using a .htaccess +file to restrict access to those resources. + +CodeIgniter will have an index.html file in all of its +directories in an attempt to hide some of this data, but have +it in mind that this is not enough to prevent a serious +attacker.
\ No newline at end of file diff --git a/user_guide_src/source/general/styleguide.rst b/user_guide_src/source/general/styleguide.rst index 2b91d1cc0..7c0a59791 100644 --- a/user_guide_src/source/general/styleguide.rst +++ b/user_guide_src/source/general/styleguide.rst @@ -149,7 +149,7 @@ months down the line. There is not a required format for comments, but the following are recommended. `DocBlock <http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_phpDocumentor.howto.pkg.html#basics.docblock>`_ -style comments preceding class and method declarations so they can be +style comments preceding class, method, and property declarations so they can be picked up by IDEs:: /** @@ -168,11 +168,20 @@ picked up by IDEs:: /** * Encodes string for use in XML * - * @param string + * @param string $str Input string * @return string */ function xml_encode($str) +:: + + /** + * Data for class manipulation + * + * @var array + */ + public $data = array(); + Use single line comments within code, leaving a blank line between large comment blocks and code. @@ -297,8 +306,8 @@ Use **===** and **!==** as necessary. } -See also information regarding -`typecasting <http://us3.php.net/manual/en/language.types.type-juggling.php#language.types.typecasting>`_, +See also information regarding `typecasting +<http://php.net/manual/en/language.types.type-juggling.php#language.types.typecasting>`_, which can be quite useful. Typecasting has a slightly different effect which may be desirable. When casting a variable as a string, for instance, NULL and boolean FALSE variables become empty strings, 0 (and @@ -327,7 +336,6 @@ begin before CodeIgniter outputs its content, leading to errors and an inability for CodeIgniter to send proper headers. In the examples below, select the text with your mouse to reveal the incorrect whitespace. - Compatibility ============= @@ -548,16 +556,16 @@ code abstraction, should be prefixed with an underscore. :: - convert_text() // public method - _convert_text() // private method + public function convert_text() + private function _convert_text() PHP Errors ========== Code must run error free and not rely on warnings and notices to be hidden to meet this requirement. For instance, never access a variable -that you did not set yourself (such as $_POST array keys) without first -checking to see that it isset(). +that you did not set yourself (such as ``$_POST`` array keys) without first +checking to see that it ``isset()``. Make sure that while developing your add-on, error reporting is enabled for ALL users, and that display_errors is enabled in the PHP @@ -568,22 +576,22 @@ environment. You can check this setting with:: exit "Enabled"; } -On some servers where display_errors is disabled, and you do not have +On some servers where *display_errors* is disabled, and you do not have the ability to change this in the php.ini, you can often enable it with:: ini_set('display_errors', 1); -**NOTE:** Setting the -`display_errors <http://us.php.net/manual/en/ref.errorfunc.php#ini.display-errors>`_ -setting with ini_set() at runtime is not identical to having it enabled -in the PHP environment. Namely, it will not have any effect if the -script has fatal errors +.. note:: Setting the `display_errors + <http://php.net/manual/en/ref.errorfunc.php#ini.display-errors>`_ + setting with ``ini_set()`` at runtime is not identical to having + it enabled in the PHP environment. Namely, it will not have any + effect if the script has fatal errors. Short Open Tags =============== Always use full PHP opening tags, in case a server does not have -short_open_tag enabled. +*short_open_tag* enabled. **INCORRECT**:: @@ -595,6 +603,8 @@ short_open_tag enabled. <?php echo $foo; ?> +.. note:: PHP 5.4 will always have the **<?=** tag available. + One Statement Per Line ====================== @@ -634,7 +644,7 @@ characters. SQL Queries =========== -MySQL keywords are always capitalized: SELECT, INSERT, UPDATE, WHERE, +SQL keywords are always capitalized: SELECT, INSERT, UPDATE, WHERE, AS, JOIN, ON, IN, etc. Break up long queries into multiple lines for legibility, preferably @@ -663,5 +673,4 @@ Whenever appropriate, provide function argument defaults, which helps prevent PHP errors with mistaken calls and provides common fallback values which can save a few lines of code. Example:: - function foo($bar = '', $baz = FALSE) - + function foo($bar = '', $baz = FALSE)
\ No newline at end of file diff --git a/user_guide_src/source/general/urls.rst b/user_guide_src/source/general/urls.rst index 6b390b559..d678e4a0a 100644 --- a/user_guide_src/source/general/urls.rst +++ b/user_guide_src/source/general/urls.rst @@ -20,7 +20,6 @@ approach, usually represent:: example.com/class/function/ID - #. The first segment represents the controller **class** that should be invoked. #. The second segment represents the class **function**, or method, that @@ -28,9 +27,28 @@ approach, usually represent:: #. The third, and any additional segments, represent the ID and any variables that will be passed to the controller. -The :doc:`URI Class <../libraries/uri>` and the :doc:`URL Helper <../helpers/url_helper>` contain functions that make it -easy to work with your URI data. In addition, your URLs can be remapped -using the :doc:`URI Routing <routing>` feature for more flexibility. +The :doc:`URI Library <../libraries/uri>` and the :doc:`URL Helper +<../helpers/url_helper>` contain functions that make it easy to work +with your URI data. In addition, your URLs can be remapped using the +:doc:`URI Routing <routing>` feature for more flexibility. + +Friendly URLs +============= + +As you might guess, since there's a straight relationship between +URI segments and the controller/method pair that's being called, +those two determining segments must represent a valid class and +method name. +You may however also use dashes in the class/method-representing +segments, and they will automatically be translated to underscores +in order to be valid routed segments. + +For example:: + + example.com/my-settings/change-password/ + +The above example will route to the ``My_settings`` controller and +its method ``change_password()``. Removing the index.php file =========================== @@ -39,7 +57,7 @@ By default, the **index.php** file will be included in your URLs:: example.com/index.php/news/article/my_article -If your Apache server has mod_rewrite enabled, you can easily remove this +If your Apache server has *mod_rewrite* enabled, you can easily remove this file by using a .htaccess file with some simple rules. Here is an example of such a file, using the "negative" method in which everything is redirected except the specified items: @@ -54,7 +72,10 @@ except the specified items: In the above example, any HTTP request other than those for existing directories and existing files is treated as a request for your index.php file. -.. note:: Note: These specific rules might not work for all server configurations. +.. note:: These specific rules might not work for all server configurations. + +.. note:: Make sure to also exclude from the above rule any assets that you + might need to be accessible from the outside world. Adding a URL Suffix =================== @@ -91,7 +112,7 @@ active. Your controllers and functions will then be accessible using the index.php?c=controller&m=method -.. note:: If you are using query strings you will have to build - your own URLs, rather than utilizing the URL helpers (and other helpers - that generate URLs, like some of the form helpers) as these are designed - to work with segment based URLs. +.. note:: If you are using query strings you will have to build your own + URLs, rather than utilizing the URL helpers (and other helpers + that generate URLs, like some of the form helpers) as these are + designed to work with segment based URLs.
\ No newline at end of file diff --git a/user_guide_src/source/general/views.rst b/user_guide_src/source/general/views.rst index 9b7c9daaa..4b1ab3c34 100644 --- a/user_guide_src/source/general/views.rst +++ b/user_guide_src/source/general/views.rst @@ -31,20 +31,22 @@ in it:: </body> </html> -Then save the file in your application/views/ folder. +Then save the file in your *application/views/* directory. Loading a View ============== -To load a particular view file you will use the following function:: +To load a particular view file you will use the following method:: $this->load->view('name'); -Where name is the name of your view file. Note: The .php file extension -does not need to be specified unless you use something other than .php. +Where name is the name of your view file. + +.. note:: The .php file extension does not need to be specified + unless you use something other than .php. Now, open the controller file you made earlier called blog.php, and -replace the echo statement with the view loading function:: +replace the echo statement with the view loading method:: <?php class Blog extends CI_Controller { @@ -54,7 +56,6 @@ replace the echo statement with the view loading function:: $this->load->view('blogview'); } } - ?> If you visit your site using the URL you did earlier you should see your new view. The URL was similar to this:: @@ -65,7 +66,7 @@ Loading multiple views ====================== CodeIgniter will intelligently handle multiple calls to -$this->load->view from within a controller. If more than one call +``$this->load->view()`` from within a controller. If more than one call happens they will be appended together. For example, you may wish to have a header view, a menu view, a content view, and a footer view. That might look something like this:: @@ -84,32 +85,31 @@ might look something like this:: } } - ?> In the example above, we are using "dynamically added data", which you will see below. -Storing Views within Sub-folders -================================ +Storing Views within Sub-directories +==================================== -Your view files can also be stored within sub-folders if you prefer that -type of organization. When doing so you will need to include the folder -name loading the view. Example:: +Your view files can also be stored within sub-directories if you prefer +that type of organization. When doing so you will need to include the +directory name loading the view. Example:: - $this->load->view('folder_name/file_name'); + $this->load->view('directory_name/file_name'); Adding Dynamic Data to the View =============================== Data is passed from the controller to the view by way of an **array** or -an **object** in the second parameter of the view loading function. Here +an **object** in the second parameter of the view loading method. Here is an example using an array:: $data = array( - 'title' => 'My Title', - 'heading' => 'My Heading', - 'message' => 'My Message' - ); + 'title' => 'My Title', + 'heading' => 'My Heading', + 'message' => 'My Message' + ); $this->load->view('blogview', $data); @@ -118,8 +118,8 @@ And here's an example using an object:: $data = new Someclass(); $this->load->view('blogview', $data); -Note: If you use an object, the class variables will be turned into -array elements. +.. note:: If you use an object, the class variables will be turned + into array elements. Let's try it with your controller file. Open it add this code:: @@ -134,7 +134,6 @@ Let's try it with your controller file. Open it add this code:: $this->load->view('blogview', $data); } } - ?> Now open your view file and change the text to variables that correspond to the array keys in your data:: @@ -174,7 +173,6 @@ Here's a simple example. Add this to your controller:: $this->load->view('blogview', $data); } } - ?> Now open your view file and create a loop:: @@ -200,17 +198,16 @@ Now open your view file and create a loop:: .. note:: You'll notice that in the example above we are using PHP's alternative syntax. If you are not familiar with it you can read about - it :doc:`here </general/alternative_php>`. + it :doc:`here <alternative_php>`. Returning views as data ======================= There is a third **optional** parameter lets you change the behavior of -the function so that it returns data as a string rather than sending it +the method so that it returns data as a string rather than sending it to your browser. This can be useful if you want to process the data in -some way. If you set the parameter to true (boolean) it will return +some way. If you set the parameter to TRUE (boolean) it will return data. The default behavior is false, which sends it to your browser. Remember to assign it to a variable if you want the data returned:: - $string = $this->load->view('myfile', '', true); - + $string = $this->load->view('myfile', '', TRUE);
\ No newline at end of file diff --git a/user_guide_src/source/general/welcome.rst b/user_guide_src/source/general/welcome.rst new file mode 100644 index 000000000..b6f473c2b --- /dev/null +++ b/user_guide_src/source/general/welcome.rst @@ -0,0 +1,32 @@ +###################### +Welcome to CodeIgniter +###################### + +CodeIgniter is an Application Development Framework - a toolkit - for +people who build web sites using PHP. Its goal is to enable you to +develop projects much faster than you could if you were writing code +from scratch, by providing a rich set of libraries for commonly needed +tasks, as well as a simple interface and logical structure to access +these libraries. CodeIgniter lets you creatively focus on your project +by minimizing the amount of code needed for a given task. + +*********************** +Who is CodeIgniter For? +*********************** + +CodeIgniter is right for you if: + +- You want a framework with a small footprint. +- You need exceptional performance. +- You need broad compatibility with standard hosting accounts that run + a variety of PHP versions and configurations. +- You want a framework that requires nearly zero configuration. +- You want a framework that does not require you to use the command + line. +- You want a framework that does not require you to adhere to + restrictive coding rules. +- You are not interested in large-scale monolithic libraries like PEAR. +- You do not want to be forced to learn a templating language (although + a template parser is optionally available if you desire one). +- You eschew complexity, favoring simple solutions. +- You need clear, thorough documentation.
\ No newline at end of file diff --git a/user_guide_src/source/helpers/array_helper.rst b/user_guide_src/source/helpers/array_helper.rst index 4308753bb..9435b3ac7 100644 --- a/user_guide_src/source/helpers/array_helper.rst +++ b/user_guide_src/source/helpers/array_helper.rst @@ -10,9 +10,7 @@ arrays. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('array'); @@ -21,20 +19,19 @@ The following functions are available: element() ========= -.. php:method:: element($item, $array, $default = FALSE) - - :param string $item: Item to fetch from the array - :param array $array: Input array - :param boolean $default: What to return if the array isn't valid - :returns: FALSE on failure or the array item. +.. php:function:: element($item, $array, $default = NULL) + :param string $item: Item to fetch from the array + :param array $array: Input array + :param bool $default: What to return if the array isn't valid + :returns: NULL on failure or the array item. Lets you fetch an item from an array. The function tests whether the array index is set and whether it has a value. If a value exists it is -returned. If a value does not exist it returns FALSE, or whatever you've -specified as the default value via the third parameter. Example +returned. If a value does not exist it returns NULL, or whatever you've +specified as the default value via the third parameter. -:: +Example:: $array = array( 'color' => 'red', @@ -43,65 +40,58 @@ specified as the default value via the third parameter. Example ); echo element('color', $array); // returns "red" - echo element('size', $array, NULL); // returns NULL + echo element('size', $array, 'foobar'); // returns "foobar" elements() ========== +.. php:function:: elements($items, $array, $default = NULL) + + :param string $item: Item to fetch from the array + :param array $array: Input array + :param bool $default: What to return if the array isn't valid + :returns: NULL on failure or the array item. + Lets you fetch a number of items from an array. The function tests whether each of the array indices is set. If an index does not exist it -is set to FALSE, or whatever you've specified as the default value via +is set to NULL, or whatever you've specified as the default value via the third parameter. -.. php:method:: elements($items, $array, $default = FALSE) - - :param string $item: Item to fetch from the array - :param array $array: Input array - :param boolean $default: What to return if the array isn't valid - :returns: FALSE on failure or the array item. - -Example - -:: +Example:: $array = array( - 'color' => 'red', - 'shape' => 'round', - 'radius' => '10', + 'color' => 'red', + 'shape' => 'round', + 'radius' => '10', 'diameter' => '20' ); $my_shape = elements(array('color', 'shape', 'height'), $array); -The above will return the following array - -:: +The above will return the following array:: array( - 'color' => 'red', - 'shape' => 'round', - 'height' => FALSE + 'color' => 'red', + 'shape' => 'round', + 'height' => NULL ); -You can set the third parameter to any default value you like - +You can set the third parameter to any default value you like. :: - $my_shape = elements(array('color', 'shape', 'height'), $array, NULL); + $my_shape = elements(array('color', 'shape', 'height'), $array, 'foobar'); -The above will return the following array - -:: +The above will return the following array:: array( - 'color' => 'red', - 'shape' => 'round', - 'height' => NULL + 'color' => 'red', + 'shape' => 'round', + 'height' => 'foobar' ); -This is useful when sending the $_POST array to one of your Models. +This is useful when sending the ``$_POST`` array to one of your Models. This prevents users from sending additional POST data to be entered into -your tables +your tables. :: @@ -116,15 +106,14 @@ updated. random_element() ================ -Takes an array as input and returns a random element from it. Usage -example +.. php:function:: random_element($array) -.. php:method:: random_element($array) + :param array $array: Input array + :returns: string (a random element from the array) - :param array $array: Input array - :returns: String - Random element from the array. +Takes an array as input and returns a random element from it. -:: +Usage example:: $quotes = array( "I find that the harder I work, the more luck I seem to have. - Thomas Jefferson", @@ -135,5 +124,4 @@ example "Chance favors the prepared mind - Louis Pasteur" ); - echo random_element($quotes); - + echo random_element($quotes);
\ No newline at end of file diff --git a/user_guide_src/source/helpers/captcha_helper.rst b/user_guide_src/source/helpers/captcha_helper.rst index 48095a11d..17462a8de 100644 --- a/user_guide_src/source/helpers/captcha_helper.rst +++ b/user_guide_src/source/helpers/captcha_helper.rst @@ -11,78 +11,72 @@ Loading this Helper =================== This helper is loaded using the following code - :: $this->load->helper('captcha'); The following functions are available: -create_captcha($data) -===================== +create_captcha() +================ + +.. php:function:: function create_captcha($data = '', $img_path = '', $img_url = '', $font_path = '') + + :param array $data: Array of data for the CAPTCHA + :param string $img_path: Path to create the image in + :param string $img_url: URL to the CAPTCHA image folder + :param string $font_path: Server path to font + :returns: array('word' => $word, 'time' => $now, 'image' => $img) Takes an array of information to generate the CAPTCHA as input and creates the image to your specifications, returning an array of associative data about the image. -.. php:method:: function create_captcha($data = '', $img_path = '', $img_url = '', $font_path = '') - - :param array $data: array of data for the CAPTCHA - :param string $img_path: path to create the image in - :param string $img_url: URL to the CAPTCHA image folder - :param string $font_path: server path to font - :returns: array('word' => $word, 'time' => $now, 'image' => $img) - - :: - [array] ( - 'image' => IMAGE TAG - 'time' => TIMESTAMP (in microtime) - 'word' => CAPTCHA WORD ) + array( + 'image' => IMAGE TAG + 'time' => TIMESTAMP (in microtime) + 'word' => CAPTCHA WORD + ) -The "image" is the actual image tag: - -:: +The **image** is the actual image tag:: <img src="http://example.com/captcha/12345.jpg" width="140" height="50" /> - -The "time" is the micro timestamp used as the image name without the +The **time** is the micro timestamp used as the image name without the file extension. It will be a number like this: 1139612155.3422 -The "word" is the word that appears in the captcha image, which if not +The **word** is the word that appears in the captcha image, which if not supplied to the function, will be a random string. Using the CAPTCHA helper ------------------------ -Once loaded you can generate a captcha like this - -:: +Once loaded you can generate a captcha like this:: - $vals = array( - 'word' => 'Random word', - 'img_path' => './captcha/', - 'img_url' => 'http://example.com/captcha/', - 'font_path' => './path/to/fonts/texb.ttf', - 'img_width' => '150', - 'img_height' => 30, - 'expiration' => 7200 + $vals = array( + 'word' => 'Random word', + 'img_path' => './captcha/', + 'img_url' => 'http://example.com/captcha/', + 'font_path' => './path/to/fonts/texb.ttf', + 'img_width' => '150', + 'img_height' => 30, + 'expiration' => 7200 ); - $cap = create_captcha($vals); echo $cap['image']; - + $cap = create_captcha($vals); + echo $cap['image']; - The captcha function requires the GD image library. -- Only the img_path and img_url are required. -- If a "word" is not supplied, the function will generate a random +- Only the **img_path** and **img_url** are required. +- If a **word** is not supplied, the function will generate a random ASCII string. You might put together your own word library that you can draw randomly from. - If you do not specify a path to a TRUE TYPE font, the native ugly GD font will be used. - The "captcha" folder must be writable (666, or 777) -- The "expiration" (in seconds) signifies how long an image will remain +- The **expiration** (in seconds) signifies how long an image will remain in the captcha folder before it will be deleted. The default is two hours. @@ -90,28 +84,24 @@ Adding a Database ----------------- In order for the captcha function to prevent someone from submitting, -you will need to add the information returned from create_captcha() -function to your database. Then, when the data from the form is -submitted by the user you will need to verify that the data exists in -the database and has not expired. +you will need to add the information returned from ``create_captcha()`` +to your database. Then, when the data from the form is submitted by +the user you will need to verify that the data exists in the database +and has not expired. -Here is a table prototype - -:: +Here is a table prototype:: CREATE TABLE captcha ( captcha_id bigint(13) unsigned NOT NULL auto_increment, captcha_time int(10) unsigned NOT NULL, - ip_address varchar(16) default '0' NOT NULL, + ip_address varchar(45) NOT NULL, word varchar(20) NOT NULL, PRIMARY KEY `captcha_id` (`captcha_id`), KEY `word` (`word`) ); Here is an example of usage with a database. On the page where the -CAPTCHA will be shown you'll have something like this - -:: +CAPTCHA will be shown you'll have something like this:: $this->load->helper('captcha'); $vals = array( @@ -134,23 +124,20 @@ CAPTCHA will be shown you'll have something like this echo '<input type="text" name="captcha" value="" />'; Then, on the page that accepts the submission you'll have something like -this - -:: +this:: // First, delete old captchas $expiration = time() - 7200; // Two hour limit $this->db->where('captcha_time < ', $expiration) - ->delete('captcha'); + ->delete('captcha'); // Then see if a captcha exists: - $sql = "SELECT COUNT(*) AS count FROM captcha WHERE word = ? AND ip_address = ? AND captcha_time > ?"; + $sql = 'SELECT COUNT(*) AS count FROM captcha WHERE word = ? AND ip_address = ? AND captcha_time > ?'; $binds = array($_POST['captcha'], $this->input->ip_address(), $expiration); $query = $this->db->query($sql, $binds); $row = $query->row(); if ($row->count == 0) { - echo "You must submit the word that appears in the image"; - } - + echo 'You must submit the word that appears in the image.'; + }
\ No newline at end of file diff --git a/user_guide_src/source/helpers/cookie_helper.rst b/user_guide_src/source/helpers/cookie_helper.rst index 30e601c32..c41193c3c 100644 --- a/user_guide_src/source/helpers/cookie_helper.rst +++ b/user_guide_src/source/helpers/cookie_helper.rst @@ -10,9 +10,7 @@ cookies. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('cookie'); @@ -21,52 +19,53 @@ The following functions are available: set_cookie() ============ +.. php:function:: set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE) + + :param string $name: Cookie name + :param string $value: Cookie value + :param int $expire: Number of seconds until expiration + :param string $domain: Cookie domain (usually: .yourdomain.com) + :param string $path: Cookie path + :param string $prefix: Cookie name prefix + :param bool $secure: Whether to only send the cookie through HTTPS + :param bool $httponly: Whether to hide the cookie from JavaScript + :returns: void + This helper function gives you view file friendly syntax to set browser -cookies. Refer to the :doc:`Input class <../libraries/input>` for a -description of use, as this function is an alias to -`$this->input->set_cookie()`. - -.. php:method:: set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE) - - :param string $name: the name of the cookie - :param string $value: the value of the cookie - :param string $expire: the number of seconds until expiration - :param string $domain: the cookie domain. Usually: .yourdomain.com - :param string $path: the cookie path - :param string $prefix: the cookie prefix - :param boolean $secure: secure cookie or not. - :returns: void +cookies. Refer to the :doc:`Input Library <../libraries/input>` for a +description of its use, as this function is an alias for +``CI_Input::set_cookie()``. get_cookie() ============ -This helper function gives you view file friendly syntax to get browser -cookies. Refer to the :doc:`Input class <../libraries/input>` for a -description of use, as this function is an alias to `$this->input->cookie()`. +.. php:function:: get_cookie($index = '', $xss_clean = FALSE) -.. php:method:: get_cookie($index = '', $xss_clean = FALSE) + :param string $index: Cookie name + :param bool $xss_clean: Whether to apply XSS filtering to the returned value + :returns: mixed - :param string $index: the name of the cookie - :param boolean $xss_clean: If the resulting value should be xss_cleaned or not - :returns: mixed +This helper function gives you view file friendly syntax to get browser +cookies. Refer to the :doc:`Input Library <../libraries/input>` for a +description of itsuse, as this function is an alias for ``CI_Input::cookie()``. delete_cookie() =============== -Lets you delete a cookie. Unless you've set a custom path or other -values, only the name of the cookie is needed - -.. php:method:: delete_cookie($name = '', $domain = '', $path = '/', $prefix = '') +.. php:function:: delete_cookie($name = '', $domain = '', $path = '/', $prefix = '') - :param string $name: the name of the cookie - :param string $domain: cookie domain (ususally .example.com) - :param string $path: cookie path - :param string $prefix: cookie prefix + :param string $name: Cookie name + :param string $domain: Cookie domain (usually: .yourdomain.com) + :param string $path: Cookie path + :param string $prefix: Cookie name prefix :returns: void +Lets you delete a cookie. Unless you've set a custom path or other +values, only the name of the cookie is needed. + :: - delete_cookie("name"); + delete_cookie('name'); This function is otherwise identical to ``set_cookie()``, except that it does not have the value and expiration parameters. You can submit an diff --git a/user_guide_src/source/helpers/date_helper.rst b/user_guide_src/source/helpers/date_helper.rst index b21d147bd..3a3454edc 100644 --- a/user_guide_src/source/helpers/date_helper.rst +++ b/user_guide_src/source/helpers/date_helper.rst @@ -9,9 +9,7 @@ The Date Helper file contains functions that help you work with dates. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('date'); @@ -20,36 +18,45 @@ The following functions are available: now() ===== -Returns the current time as a Unix timestamp, referenced either to your -server's local time or GMT, based on the "time reference" setting in -your config file. If you do not intend to set your master time reference -to GMT (which you'll typically do if you run a site that lets each user -set their own timezone settings) there is no benefit to using this -function over PHP's time() function. +.. php:function:: now($timezone = NULL) + + :param string $timezone: Timezone + :returns: int -.. php:method:: now() +Returns the current time as a UNIX timestamp, referenced either to your server's +local time or any PHP suported timezone, based on the "time reference" setting +in your config file. If you do not intend to set your master time reference to +any other PHP supported timezone (which you'll typically do if you run a site +that lets each user set their own timezone settings) there is no benefit to using +this function over PHP's ``time()`` function. + +:: + + echo now('Australia/Victoria'); + +If a timezone is not provided, it will return ``time()`` based on the +**time_reference** setting. mdate() ======= -This function is identical to PHPs `date() <http://www.php.net/date>`_ +.. php:function:: mdate($datestr = '', $time = '') + + :param string $datestr: Date string + :param int $time: UNIX timestamp + :returns: int + +This function is identical to PHP's `date() <http://www.php.net/date>`_ function, except that it lets you use MySQL style date codes, where each -code letter is preceded with a percent sign: %Y %m %d etc. +code letter is preceded with a percent sign, e.g. `%Y %m %d` The benefit of doing dates this way is that you don't have to worry about escaping any characters that are not date codes, as you would -normally have to do with the date() function. Example +normally have to do with the ``date()`` function. -.. php:method:: mdate($datestr = '', $time = '') +Example:: - :param string $datestr: Date String - :param integer $time: time - :returns: integer - - -:: - - $datestring = "Year: %Y Month: %m Day: %d - %h:%i %a"; + $datestring = 'Year: %Y Month: %m Day: %d - %h:%i %a'; $time = time(); echo mdate($datestring, $time); @@ -59,87 +66,77 @@ will be used. standard_date() =============== -Lets you generate a date string in one of several standardized formats. -Example +.. php:function:: standard_date($fmt = 'DATE_RFC822', $time = NULL) -.. php:method:: standard_date($fmt = 'DATE_RFC822', $time = '') + :param string $fmt: Date format + :param int $time: UNIX timestamp + :returns: string - :param string $fmt: the chosen format - :param string $time: Unix timestamp - :returns: string +Lets you generate a date string in one of several standardized formats. -:: +Example:: $format = 'DATE_RFC822'; $time = time(); echo standard_date($format, $time); -The first parameter must contain the format, the second parameter must -contain the date as a Unix timestamp. - -Supported formats: - -+----------------+------------------------+-----------------------------------+ -| Constant | Description | Example | -+================+========================+===================================+ -| DATE_ATOM | Atom | 2005-08-15T16:13:03+0000 | -+----------------+------------------------+-----------------------------------+ -| DATE_COOKIE | HTTP Cookies | Sun, 14 Aug 2005 16:13:03 UTC | -+----------------+------------------------+-----------------------------------+ -| DATE_ISO8601 | ISO-8601 | 2005-08-14T16:13:03+00:00 | -+----------------+------------------------+-----------------------------------+ -| DATE_RFC822 | RFC 822 | Sun, 14 Aug 05 16:13:03 UTC | -+----------------+------------------------+-----------------------------------+ -| DATE_RFC850 | RFC 850 | Sunday, 14-Aug-05 16:13:03 UTC | -+----------------+------------------------+-----------------------------------+ -| DATE_RFC1036 | RFC 1036 | Sunday, 14-Aug-05 16:13:03 UTC | -+----------------+------------------------+-----------------------------------+ -| DATE_RFC1123 | RFC 1123 | Sun, 14 Aug 2005 16:13:03 UTC | -+----------------+------------------------+-----------------------------------+ -| DATE_RFC2822 | RFC 2822 | Sun, 14 Aug 2005 16:13:03 +0000 | -+----------------+------------------------+-----------------------------------+ -| DATE_RSS | RSS | Sun, 14 Aug 2005 16:13:03 UTC | -+----------------+------------------------+-----------------------------------+ -| DATE_W3C | W3C | 2005-08-14T16:13:03+0000 | -+----------------+------------------------+-----------------------------------+ - +.. note:: This function is DEPRECATED.Use the native ``date()`` combined with + `DateTime's format constants + <http://www.php.net/manual/en/class.datetime.php#datetime.constants.types>`_ + instead: + + | + | echo date(DATE_RFC822, time()); + +Supported formats +----------------- + +=============== ======================= ====================================== +Constant Description Example +=============== ======================= ====================================== +DATE_ATOM Atom 2005-08-15T16:13:03+0000 +DATE_COOKIE HTTP Cookies Sun, 14 Aug 2005 16:13:03 UTC +DATE_ISO8601 ISO-8601 2005-08-14T16:13:03+00:00 +DATE_RFC822 RFC 822 Sun, 14 Aug 05 16:13:03 UTC +DATE_RFC850 RFC 850 Sunday, 14-Aug-05 16:13:03 UTC +DATE_RFC1036 RFC 1036 Sunday, 14-Aug-05 16:13:03 UTC +DATE_RFC1123 RFC 1123 Sun, 14 Aug 2005 16:13:03 UTC +DATE_RFC2822 RFC 2822 Sun, 14 Aug 2005 16:13:03 +0000 +DATE_RSS RSS Sun, 14 Aug 2005 16:13:03 UTC +DATE_W3C W3C 2005-08-14T16:13:03+0000 +=============== ======================= ====================================== local_to_gmt() ============== -Takes a Unix timestamp as input and returns it as GMT. +.. php:function:: local_to_gmt($time = '') -.. php:method:: local_to_gmt($time = '') + :param int $time: UNIX timestamp + :returns: string - :param integer $time: Unix timestamp - :returns: string +Takes a UNIX timestamp as input and returns it as GMT. -Example: +Example:: -:: - - $now = time(); - $gmt = local_to_gmt($now); + $gmt = local_to_gmt(time()); gmt_to_local() ============== -Takes a Unix timestamp (referenced to GMT) as input, and converts it to -a localized timestamp based on the timezone and Daylight Saving time -submitted. +.. php:function:: gmt_to_local($time = '', $timezone = 'UTC', $dst = FALSE) -.. php:method:: gmt_to_local($time = '', $timezone = 'UTC', $dst = FALSE) + :param int $time: UNIX timestamp + :param string $timezone: Timezone + :param bool $dst: Whether DST is active + :returns: int - :param integer $time: Unix timestamp - :param string $timezone: timezone - :param boolean $dst: whether DST is active - :returns: integer - -Example +Takes a UNIX timestamp (referenced to GMT) as input, and converts it to +a localized timestamp based on the timezone and Daylight Saving Time +submitted. -:: +Example:: - $timestamp = '1140153693'; + $timestamp = 1140153693; $timezone = 'UM8'; $daylight_saving = TRUE; echo gmt_to_local($timestamp, $timezone, $daylight_saving); @@ -147,40 +144,32 @@ Example .. note:: For a list of timezones see the reference at the bottom of this page. - mysql_to_unix() =============== -Takes a MySQL Timestamp as input and returns it as Unix. +.. php:function:: mysql_to_unix($time = '') -.. php:method:: mysql_to_unix($time = '') + :param int $time: UNIX timestamp + :returns: int - :param integer $time: Unix timestamp - :returns: integer - -Example +Takes a MySQL Timestamp as input and returns it as a UNIX timestamp. -:: +Example:: - $mysql = '20061124092345'; - $unix = mysql_to_unix($mysql); + $unix = mysql_to_unix('20061124092345'); unix_to_human() =============== -Takes a Unix timestamp as input and returns it in a human readable -format with this prototype +.. php:function:: unix_to_human($time = '', $seconds = FALSE, $fmt = 'us') -.. php:method:: unix_to_human($time = '', $seconds = FALSE, $fmt = 'us') - - :param integer $time: Unix timestamp - :param boolean $seconds: whether to show seconds - :param string $fmt: format: us or euro + :param int $time: UNIX timestamp + :param bool $seconds: Whether to show seconds + :param string $fmt: format (us or euro) :returns: integer -Example - -:: +Takes a UNIX timestamp as input and returns it in a human readable +format with this prototype:: YYYY-MM-DD HH:MM:SS AM/PM @@ -189,9 +178,9 @@ submission. The time can be formatted with or without seconds, and it can be set to European or US format. If only the timestamp is submitted it will return -the time without seconds formatted for the U.S. Examples +the time without seconds formatted for the U.S. -:: +Examples:: $now = time(); echo unix_to_human($now); // U.S. time, no seconds @@ -201,19 +190,17 @@ the time without seconds formatted for the U.S. Examples human_to_unix() =============== -The opposite of the above function. Takes a "human" time as input and -returns it as Unix. This function is useful if you accept "human" -formatted dates submitted via a form. Returns FALSE (boolean) if the -date string passed to it is not formatted as indicated above. +.. php:function:: human_to_unix($datestr = '') -.. php:method:: human_to_unix($datestr = '') - - :param integer $datestr: Date String - :returns: integer + :param int $datestr: Date string + :returns: int UNIX timestamp or FALSE on failure -Example: +The opposite of the :php:func:`unix_to_time()` function. Takes a "human" +time as input and returns it as a UNIX timestamp. This is useful if you +accept "human" formatted dates submitted via a form. Returns boolean FALSE +date string passed to it is not formatted as indicated above. -:: +Example:: $now = time(); $human = unix_to_human($now); @@ -222,54 +209,54 @@ Example: nice_date() =========== +.. php:function:: nice_date($bad_date = '', $format = FALSE) + + :param int $bad_date: The terribly formatted date-like string + :param string $format: Date format to return (same as PHP's ``date()`` function) + :returns: string + This function can take a number poorly-formed date formats and convert them into something useful. It also accepts well-formed dates. -The function will return a Unix timestamp by default. You can, -optionally, pass a format string (the same type as the PHP date function -accepts) as the second parameter. +The function will return a UNIX timestamp by default. You can, optionally, +pass a format string (the same type as the PHP ``date()`` function accepts) +as the second parameter. -.. php:method:: nice_date($bad_date = '', $format = FALSE) +Example:: - :param integer $bad_date: The terribly formatted date-like string - :param string $format: Date format to return (same as php date function) - :returns: string + $bad_date = '199605'; + // Should Produce: 1996-05-01 + $better_date = nice_date($bad_date, 'Y-m-d'); -Example - -:: - - $bad_time = 199605 // Should Produce: 1996-05-01 - $better_time = nice_date($bad_time,'Y-m-d'); - $bad_time = 9-11-2001 // Should Produce: 2001-09-11 - $better_time = nice_date($human,'Y-m-d'); + $bad_date = '9-11-2001'; + // Should Produce: 2001-09-11 + $better_date = nice_date($bad_date, 'Y-m-d'); timespan() ========== -Formats a unix timestamp so that is appears similar to this +.. php:function:: timespan($seconds = 1, $time = '', $units = '') -:: + :param int $seconds: Number of seconds + :param string $time: UNIX timestamp + :param int $units: Number of time units to display + :returns: string - 1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes +Formats a UNIX timestamp so that is appears similar to this:: -The first parameter must contain a Unix timestamp. The second parameter -must contain a timestamp that is greater that the first timestamp. If -the second parameter empty, the current time will be used. The third -parameter is optional and limits the number of time units to display. -The most common purpose for this function is to show how much time has -elapsed from some point in time in the past to now. + 1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes -.. php:method:: timespan($seconds = 1, $time = '', $units = '') +The first parameter must contain a UNIX timestamp. +The second parameter must contain a timestamp that is greater that the +first timestamp. +The thirdparameter is optional and limits the number of time units to display. - :param integer $seconds: a number of seconds - :param string $time: Unix timestamp - :param integer $units: a number of time units to display - :returns: string +If the second parameter empty, the current time will be used. -Example +The most common purpose for this function is to show how much time has +elapsed from some point in time in the past to now. -:: +Example:: $post_date = '1079621429'; $now = time(); @@ -277,89 +264,124 @@ Example echo timespan($post_date, $now, $units); .. note:: The text generated by this function is found in the following language - file: language/<your_lang>/date_lang.php + file: `language/<your_lang>/date_lang.php` days_in_month() =============== -Returns the number of days in a given month/year. Takes leap years into -account. +.. php:function:: days_in_month($month = 0, $year = '') -.. php:method:: days_in_month($month = 0, $year = '') + :param int $month: a numeric month + :param int $year: a numeric year + :returns: int - :param integer $month: a numeric month - :param integer $year: a numeric year - :returns: integer +Returns the number of days in a given month/year. Takes leap years into +account. -Example - -:: +Example:: echo days_in_month(06, 2005); If the second parameter is empty, the current year will be used. +date_range() +============ + +.. php:function:: date_range($unix_start = '', $mixed = '', $is_unix = TRUE, $format = 'Y-m-d') + + :param int $unix_start: UNIX timestamp of the range start date + :param int $mixed: UNIX timestamp of the range end date or interval in days + :param bool $is_unix: set to FALSE if $mixed is not a timestamp + :param string $format: Output date format, same as in ``date()`` + :returns: array + +Returns a list of dates within a specified period. + +Example:: + + $range = date_range('2012-01-01', '2012-01-15'); + echo "First 15 days of 2012:"; + foreach ($range as $date) + { + echo $date."\n"; + } + timezones() =========== +.. php:function:: timezones($tz = '') + + :param string $tz: a numeric timezone + :returns: string + Takes a timezone reference (for a list of valid timezones, see the "Timezone Reference" below) and returns the number of hours offset from UTC. -.. php:method:: timezones($tz = '') - - :param string $tz: a numeric timezone - :returns: string - -Example - -:: +Example:: echo timezones('UM5'); -This function is useful when used with `timezone_menu()`. +This function is useful when used with :php:func:`timezone_menu()`. timezone_menu() =============== -Generates a pull-down menu of timezones, like this one: +.. php:function:: timezone_menu($default = 'UTC', $class = '', $name = 'timezones', $attributes = '') + + :param string $default: Timezone + :param string $class: Class name + :param string $name: Menu name + :param mixed $attributes: HTML attributes + :returns: string +Generates a pull-down menu of timezones, like this one: .. raw:: html <form action="#"> <select name="timezones"> - <option value='UM12'>(UTC - 12:00) Enitwetok, Kwajalien</option> - <option value='UM11'>(UTC - 11:00) Nome, Midway Island, Samoa</option> - <option value='UM10'>(UTC - 10:00) Hawaii</option> - <option value='UM9'>(UTC - 9:00) Alaska</option> - <option value='UM8'>(UTC - 8:00) Pacific Time</option> - <option value='UM7'>(UTC - 7:00) Mountain Time</option> - <option value='UM6'>(UTC - 6:00) Central Time, Mexico City</option> - <option value='UM5'>(UTC - 5:00) Eastern Time, Bogota, Lima, Quito</option> - <option value='UM4'>(UTC - 4:00) Atlantic Time, Caracas, La Paz</option> - <option value='UM25'>(UTC - 3:30) Newfoundland</option> - <option value='UM3'>(UTC - 3:00) Brazil, Buenos Aires, Georgetown, Falkland Is.</option> - <option value='UM2'>(UTC - 2:00) Mid-Atlantic, Ascention Is., St Helena</option> - <option value='UM1'>(UTC - 1:00) Azores, Cape Verde Islands</option> - <option value='UTC' selected='selected'>(UTC) Casablanca, Dublin, Edinburgh, London, Lisbon, Monrovia</option> - <option value='UP1'>(UTC + 1:00) Berlin, Brussels, Copenhagen, Madrid, Paris, Rome</option> - <option value='UP2'>(UTC + 2:00) Kaliningrad, South Africa, Warsaw</option> - <option value='UP3'>(UTC + 3:00) Baghdad, Riyadh, Moscow, Nairobi</option> - <option value='UP25'>(UTC + 3:30) Tehran</option> - <option value='UP4'>(UTC + 4:00) Adu Dhabi, Baku, Muscat, Tbilisi</option> - <option value='UP35'>(UTC + 4:30) Kabul</option> - <option value='UP5'>(UTC + 5:00) Islamabad, Karachi, Tashkent</option> - <option value='UP45'>(UTC + 5:30) Bombay, Calcutta, Madras, New Delhi</option> - <option value='UP6'>(UTC + 6:00) Almaty, Colomba, Dhaka</option> - <option value='UP7'>(UTC + 7:00) Bangkok, Hanoi, Jakarta</option> - <option value='UP8'>(UTC + 8:00) Beijing, Hong Kong, Perth, Singapore, Taipei</option> - <option value='UP9'>(UTC + 9:00) Osaka, Sapporo, Seoul, Tokyo, Yakutsk</option> - <option value='UP85'>(UTC + 9:30) Adelaide, Darwin</option> - <option value='UP10'>(UTC + 10:00) Melbourne, Papua New Guinea, Sydney, Vladivostok</option> - <option value='UP11'>(UTC + 11:00) Magadan, New Caledonia, Solomon Islands</option> - <option value='UP12'>(UTC + 12:00) Auckland, Wellington, Fiji, Marshall Island</option> + <option value='UM12'>(UTC -12:00) Baker/Howland Island</option> + <option value='UM11'>(UTC -11:00) Samoa Time Zone, Niue</option> + <option value='UM10'>(UTC -10:00) Hawaii-Aleutian Standard Time, Cook Islands, Tahiti</option> + <option value='UM95'>(UTC -9:30) Marquesas Islands</option> + <option value='UM9'>(UTC -9:00) Alaska Standard Time, Gambier Islands</option> + <option value='UM8'>(UTC -8:00) Pacific Standard Time, Clipperton Island</option> + <option value='UM7'>(UTC -7:00) Mountain Standard Time</option> + <option value='UM6'>(UTC -6:00) Central Standard Time</option> + <option value='UM5'>(UTC -5:00) Eastern Standard Time, Western Caribbean Standard Time</option> + <option value='UM45'>(UTC -4:30) Venezuelan Standard Time</option> + <option value='UM4'>(UTC -4:00) Atlantic Standard Time, Eastern Caribbean Standard Time</option> + <option value='UM35'>(UTC -3:30) Newfoundland Standard Time</option> + <option value='UM3'>(UTC -3:00) Argentina, Brazil, French Guiana, Uruguay</option> + <option value='UM2'>(UTC -2:00) South Georgia/South Sandwich Islands</option> + <option value='UM1'>(UTC -1:00) Azores, Cape Verde Islands</option> + <option value='UTC' selected='selected'>(UTC) Greenwich Mean Time, Western European Time</option> + <option value='UP1'>(UTC +1:00) Central European Time, West Africa Time</option> + <option value='UP2'>(UTC +2:00) Central Africa Time, Eastern European Time, Kaliningrad Time</option> + <option value='UP3'>(UTC +3:00) Moscow Time, East Africa Time</option> + <option value='UP35'>(UTC +3:30) Iran Standard Time</option> + <option value='UP4'>(UTC +4:00) Azerbaijan Standard Time, Samara Time</option> + <option value='UP45'>(UTC +4:30) Afghanistan</option> + <option value='UP5'>(UTC +5:00) Pakistan Standard Time, Yekaterinburg Time</option> + <option value='UP55'>(UTC +5:30) Indian Standard Time, Sri Lanka Time</option> + <option value='UP575'>(UTC +5:45) Nepal Time</option> + <option value='UP6'>(UTC +6:00) Bangladesh Standard Time, Bhutan Time, Omsk Time</option> + <option value='UP65'>(UTC +6:30) Cocos Islands, Myanmar</option> + <option value='UP7'>(UTC +7:00) Krasnoyarsk Time, Cambodia, Laos, Thailand, Vietnam</option> + <option value='UP8'>(UTC +8:00) Australian Western Standard Time, Beijing Time, Irkutsk Time</option> + <option value='UP875'>(UTC +8:45) Australian Central Western Standard Time</option> + <option value='UP9'>(UTC +9:00) Japan Standard Time, Korea Standard Time, Yakutsk Time</option> + <option value='UP95'>(UTC +9:30) Australian Central Standard Time</option> + <option value='UP10'>(UTC +10:00) Australian Eastern Standard Time, Vladivostok Time</option> + <option value='UP105'>(UTC +10:30) Lord Howe Island</option> + <option value='UP11'>(UTC +11:00) Magadan Time, Solomon Islands, Vanuatu</option> + <option value='UP115'>(UTC +11:30) Norfolk Island</option> + <option value='UP12'>(UTC +12:00) Fiji, Gilbert Islands, Kamchatka Time, New Zealand Standard Time</option> + <option value='UP1275'>(UTC +12:45) Chatham Islands Standard Time</option> + <option value='UP13'>(UTC +13:00) Phoenix Islands Time, Tonga</option> + <option value='UP14'>(UTC +14:00) Line Islands</option> </select> </form> @@ -368,18 +390,7 @@ This menu is useful if you run a membership site in which your users are allowed to set their local timezone value. The first parameter lets you set the "selected" state of the menu. For -example, to set Pacific time as the default you will do this - -.. php:method:: timezone_menu($default = 'UTC', $class = "", $name = 'timezones') - - :param string $default: timezone - :param string $class: classname - :param string $name: menu name - :returns: string - -Example: - -:: +example, to set Pacific time as the default you will do this:: echo timezone_menu('UM8'); @@ -387,6 +398,8 @@ Please see the timezone reference below to see the values of this menu. The second parameter lets you set a CSS class name for the menu. +The fourth parameter lets you set one or more attributes on the generated select tag. + .. note:: The text contained in the menu is found in the following language file: `language/<your_lang>/date_lang.php` @@ -396,66 +409,49 @@ Timezone Reference The following table indicates each timezone and its location. -+------------+----------------------------------------------------------------+ -| Time Zone | Location | -+============+================================================================+ -| UM12 | (UTC - 12:00) Enitwetok, Kwajalien | -+------------+----------------------------------------------------------------+ -| UM11 | (UTC - 11:00) Nome, Midway Island, Samoa | -+------------+----------------------------------------------------------------+ -| UM10 | (UTC - 10:00) Hawaii | -+------------+----------------------------------------------------------------+ -| UM9 | (UTC - 9:00) Alaska | -+------------+----------------------------------------------------------------+ -| UM8 | (UTC - 8:00) Pacific Time | -+------------+----------------------------------------------------------------+ -| UM7 | (UTC - 7:00) Mountain Time | -+------------+----------------------------------------------------------------+ -| UM6 | (UTC - 6:00) Central Time, Mexico City | -+------------+----------------------------------------------------------------+ -| UM5 | (UTC - 5:00) Eastern Time, Bogota, Lima, Quito | -+------------+----------------------------------------------------------------+ -| UM4 | (UTC - 4:00) Atlantic Time, Caracas, La Paz | -+------------+----------------------------------------------------------------+ -| UM25 | (UTC - 3:30) Newfoundland | -+------------+----------------------------------------------------------------+ -| UM3 | (UTC - 3:00) Brazil, Buenos Aires, Georgetown, Falkland Is. | -+------------+----------------------------------------------------------------+ -| UM2 | (UTC - 2:00) Mid-Atlantic, Ascention Is., St Helena | -+------------+----------------------------------------------------------------+ -| UM1 | (UTC - 1:00) Azores, Cape Verde Islands | -+------------+----------------------------------------------------------------+ -| UTC | (UTC) Casablanca, Dublin, Edinburgh, London, Lisbon, Monrovia | -+------------+----------------------------------------------------------------+ -| UP1 | (UTC + 1:00) Berlin, Brussels, Copenhagen, Madrid, Paris, Rome | -+------------+----------------------------------------------------------------+ -| UP2 | (UTC + 2:00) Kaliningrad, South Africa, Warsaw | -+------------+----------------------------------------------------------------+ -| UP3 | (UTC + 3:00) Baghdad, Riyadh, Moscow, Nairobi | -+------------+----------------------------------------------------------------+ -| UP25 | (UTC + 3:30) Tehran | -+------------+----------------------------------------------------------------+ -| UP4 | (UTC + 4:00) Adu Dhabi, Baku, Muscat, Tbilisi | -+------------+----------------------------------------------------------------+ -| UP35 | (UTC + 4:30) Kabul | -+------------+----------------------------------------------------------------+ -| UP5 | (UTC + 5:00) Islamabad, Karachi, Tashkent | -+------------+----------------------------------------------------------------+ -| UP45 | (UTC + 5:30) Bombay, Calcutta, Madras, New Delhi | -+------------+----------------------------------------------------------------+ -| UP6 | (UTC + 6:00) Almaty, Colomba, Dhaka | -+------------+----------------------------------------------------------------+ -| UP7 | (UTC + 7:00) Bangkok, Hanoi, Jakarta | -+------------+----------------------------------------------------------------+ -| UP8 | (UTC + 8:00) Beijing, Hong Kong, Perth, Singapore, Taipei | -+------------+----------------------------------------------------------------+ -| UP9 | (UTC + 9:00) Osaka, Sapporo, Seoul, Tokyo, Yakutsk | -+------------+----------------------------------------------------------------+ -| UP85 | (UTC + 9:30) Adelaide, Darwin | -+------------+----------------------------------------------------------------+ -| UP10 | (UTC + 10:00) Melbourne, Papua New Guinea, Sydney, Vladivostok | -+------------+----------------------------------------------------------------+ -| UP11 | (UTC + 11:00) Magadan, New Caledonia, Solomon Islands | -+------------+----------------------------------------------------------------+ -| UP12 | (UTC + 12:00) Auckland, Wellington, Fiji, Marshall Island | -+------------+----------------------------------------------------------------+ +Note some of the location lists have been abridged for clarity and formatting. + +=========== ===================================================================== +Time Zone Location +=========== ===================================================================== +UM2 (UTC - 12:00) Baker/Howland Island +UM1 (UTC - 11:00) Samoa Time Zone, Niue +UM0 (UTC - 10:00) Hawaii-Aleutian Standard Time, Cook Islands +UM95 (UTC - 09:30) Marquesas Islands +UM9 (UTC - 09:00) Alaska Standard Time, Gambier Islands +UM8 (UTC - 08:00) Pacific Standard Time, Clipperton Island +UM7 (UTC - 11:00) Mountain Standard Time +UM6 (UTC - 06:00) Central Standard Time +UM5 (UTC - 05:00) Eastern Standard Time, Western Caribbean +UM45 (UTC - 04:30) Venezuelan Standard Time +UM4 (UTC - 04:00) Atlantic Standard Time, Eastern Caribbean +UM35 (UTC - 03:30) Newfoundland Standard Time +UM3 (UTC - 03:00) Argentina, Brazil, French Guiana, Uruguay +UM2 (UTC - 02:00) South Georgia/South Sandwich Islands +UM (UTC -1:00) Azores, Cape Verde Islands +UTC (UTC) Greenwich Mean Time, Western European Time +UP1 (UTC +1:00) Central European Time, West Africa Time +UP2 (UTC +2:00) Central Africa Time, Eastern European Time +UP3 (UTC +3:00) Moscow Time, East Africa Time +UP35 (UTC +3:30) Iran Standard Time +UP4 (UTC +4:00) Azerbaijan Standard Time, Samara Time +UP45 (UTC +4:30) Afghanistan +UP5 (UTC +5:00) Pakistan Standard Time, Yekaterinburg Time +UP55 (UTC +5:30) Indian Standard Time, Sri Lanka Time +UP575 (UTC +5:45) Nepal Time +UP6 (UTC +6:00) Bangladesh Standard Time, Bhutan Time, Omsk Time +UP65 (UTC +6:30) Cocos Islands, Myanmar +UP7 (UTC +7:00) Krasnoyarsk Time, Cambodia, Laos, Thailand, Vietnam +UP8 (UTC +8:00) Australian Western Standard Time, Beijing Time +UP875 (UTC +8:45) Australian Central Western Standard Time +UP9 (UTC +9:00) Japan Standard Time, Korea Standard Time, Yakutsk +UP95 (UTC +9:30) Australian Central Standard Time +UP10 (UTC +10:00) Australian Eastern Standard Time, Vladivostok Time +UP105 (UTC +10:30) Lord Howe Island +UP11 (UTC +11:00) Magadan Time, Solomon Islands, Vanuatu +UP115 (UTC +11:30) Norfolk Island +UP12 (UTC +12:00) Fiji, Gilbert Islands, Kamchatka, New Zealand +UP1275 (UTC +12:45) Chatham Islands Standard Time +UP1 (UTC +13:00) Phoenix Islands Time, Tonga +UP14 (UTC +14:00) Line Islands +=========== =====================================================================
\ No newline at end of file diff --git a/user_guide_src/source/helpers/directory_helper.rst b/user_guide_src/source/helpers/directory_helper.rst index fd169886c..a785ebc8c 100644 --- a/user_guide_src/source/helpers/directory_helper.rst +++ b/user_guide_src/source/helpers/directory_helper.rst @@ -57,9 +57,9 @@ be numerically indexed. Here is an example of a typical array:: ( [0] => benchmark.html [1] => config.html - [database] => Array + ["database/"] => Array ( - [0] => active_record.html + [0] => query_builder.html [1] => binds.html [2] => configuration.html [3] => connecting.html @@ -76,5 +76,4 @@ be numerically indexed. Here is an example of a typical array:: [7] => loader.html [8] => pagination.html [9] => uri.html - ) - + )
\ No newline at end of file diff --git a/user_guide_src/source/helpers/download_helper.rst b/user_guide_src/source/helpers/download_helper.rst index e6094dc6b..1e9ec21ea 100644 --- a/user_guide_src/source/helpers/download_helper.rst +++ b/user_guide_src/source/helpers/download_helper.rst @@ -9,34 +9,40 @@ The Download Helper lets you download data to your desktop. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('download'); The following functions are available: -force_download('filename', 'data') -================================== +force_download() +================ + +.. php:function:: force_download($filename = '', $data = '', $set_mime = FALSE) + + :param string $filename: Filename + :param string $data: File contents + :param bool $set_mime: Whether to try to send the actual MIME type + :returns: void Generates server headers which force data to be downloaded to your desktop. Useful with file downloads. The first parameter is the **name you want the downloaded file to be named**, the second parameter is the -file data. Example +file data. + +If you set the third parameter to boolean TRUE, then the actual file MIME type +(based on the filename extension) will be sent, so that if your browser has a +handler for that type - it can use it. -:: +Example:: $data = 'Here is some text!'; $name = 'mytext.txt'; force_download($name, $data); If you want to download an existing file from your server you'll need to -read the file into a string +read the file into a string:: -:: - - $data = file_get_contents("/path/to/photo.jpg"); // Read the file's contents + $data = file_get_contents('/path/to/photo.jpg'); // Read the file's contents $name = 'myphoto.jpg'; - force_download($name, $data); - + force_download($name, $data);
\ No newline at end of file diff --git a/user_guide_src/source/helpers/email_helper.rst b/user_guide_src/source/helpers/email_helper.rst index d4e94b1ed..10adf1d0e 100644 --- a/user_guide_src/source/helpers/email_helper.rst +++ b/user_guide_src/source/helpers/email_helper.rst @@ -8,6 +8,8 @@ Class <../libraries/email>`. .. contents:: Page Contents +.. important:: The Email helper is DEPRECATED. + Loading this Helper =================== @@ -15,21 +17,21 @@ This helper is loaded using the following code:: $this->load->helper('email'); - The following functions are available: -valid_email('email') -==================== +valid_email() +============= -Checks if an email is a correctly formatted email. Note that is doesn't -actually prove the email will recieve mail, simply that it is a validly -formed address. +.. php:function:: valid_email($email) -It returns TRUE/FALSE + :param string $email: Email address + :returns: bool -:: +Checks if the input is a correctly formatted e-mail address. Note that is +doesn't actually prove that the address will be able recieve mail, but +simply that it is a validly formed address. - $this->load->helper('email'); +Example:: if (valid_email('email@somesite.com')) { @@ -40,10 +42,26 @@ It returns TRUE/FALSE echo 'email is not valid'; } -send_email('recipient', 'subject', 'message') -============================================= +.. note:: All that this function does is to use PHP's native ``filter_var()``: + | + | (bool) filter_var($email, FILTER_VALIDATE_EMAIL); -Sends an email using PHP's native -`mail() <http://www.php.net/function.mail>`_ function. For a more robust -email solution, see CodeIgniter's :doc:`Email -Class <../libraries/email>`. +send_email() +============ + +.. php:function:: send_email($recipient, $subject, $message) + + :param string $recipient: E-mail address + :param string $subject: Mail subject + :param string $message: Message body + :returns: bool + +Sends an email using PHP's native `mail() <http://www.php.net/function.mail>`_ +function. + +.. note:: All that this function does is to use PHP's native ``mail``: + | + | mail($recipient, $subject, $message); + +For a more robust email solution, see CodeIgniter's :doc:`Email Library +<../libraries/email>`. diff --git a/user_guide_src/source/helpers/file_helper.rst b/user_guide_src/source/helpers/file_helper.rst index bfc271eb3..194d4348f 100644 --- a/user_guide_src/source/helpers/file_helper.rst +++ b/user_guide_src/source/helpers/file_helper.rst @@ -9,20 +9,23 @@ The File Helper file contains functions that assist in working with files. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('file'); The following functions are available: -read_file('path') -================= +read_file() +=========== -Returns the data contained in the file specified in the path. Example +.. php:function:: read_file($file) -:: + :param string $file: File path + :returns: string or FALSE on failure + +Returns the data contained in the file specified in the path. + +Example:: $string = read_file('./path/to/file.php'); @@ -32,14 +35,27 @@ The path can be a relative or full server path. Returns FALSE (boolean) on failu controller or view files. CodeIgniter uses a front controller so paths are always relative to the main site index. -If your server is running an `open_basedir` restriction this function might not work if you are trying to access a file above the calling script. +.. note:: This function is DEPRECATED. Use the native ``file_get_contents()`` + instead. -write_file('path', $data) -========================= +.. important:: If your server is running an **open_basedir** restriction this + function might not work if you are trying to access a file above the + calling script. -Writes data to the file specified in the path. If the file does not exist the function will create it. Example +write_file() +============ -:: +.. php:function:: write_file($path, $data, $mode = 'wb') + + :param string $path: File path + :param string $data: Data to write to file + :param string $mode: ``fopen()`` mode + :returns: bool + +Writes data to the file specified in the path. If the file does not exist then the +function will create it. + +Example:: $data = 'Some file data'; if ( ! write_file('./path/to/file.php', $data)) @@ -51,85 +67,150 @@ Writes data to the file specified in the path. If the file does not exist the fu echo 'File written!'; } -You can optionally set the write mode via the third parameter - -:: +You can optionally set the write mode via the third parameter:: write_file('./path/to/file.php', $data, 'r+'); -The default mode is wb. Please see the `PHP user guide <http://php.net/fopen>`_ for mode options. +The default mode is 'wb'. Please see the `PHP user guide <http://php.net/fopen>`_ +for mode options. -Note: In order for this function to write data to a file its file permissions must be set such that it is writable (666, 777, etc.). If the file does not already exist, the directory containing it must be writable. +.. note: In order for this function to write data to a file, its permissions must + be set such that it is writable (666, 777, etc.). If the file does not + already exist, the directory containing it must be writable. .. note:: The path is relative to your main site index.php file, NOT your controller or view files. CodeIgniter uses a front controller so paths are always relative to the main site index. -delete_files('path') -==================== +.. note:: This function acquires an exclusive lock on the file while writing to it. -Deletes ALL files contained in the supplied path. Example +delete_files() +============== -:: +.. php:function:: delete_files($path, $del_dir = FALSE, $htdocs = FALSE) + + :param string $path: Directory path + :param bool $del_dir: Whether to also delete directories + :param bool $htdocs: Whether to skip deleting .htaccess and index page files + :returns: bool + +Deletes ALL files contained in the supplied path. + +Example:: delete_files('./path/to/directory/'); -If the second parameter is set to true, any directories contained within the supplied root path will be deleted as well. Example +If the second parameter is set to TRUE, any directories contained within the supplied +root path will be deleted as well. -:: +Example:: delete_files('./path/to/directory/', TRUE); .. note:: The files must be writable or owned by the system in order to be deleted. -get_filenames('path/to/directory/') -=================================== +get_filenames() +=============== -Takes a server path as input and returns an array containing the names of all files contained within it. The file path can optionally be added to the file names by setting the second parameter to TRUE. +.. php:function:: get_filenames($source_dir, $include_path = FALSE) -get_dir_file_info('path/to/directory/', $top_level_only = TRUE) -=============================================================== + :param string $source_dir: Directory path + :param bool $include_path: Whether to include the path as part of the filenames + :returns: array -Reads the specified directory and builds an array containing the filenames, filesize, dates, and permissions. Sub-folders contained within the specified path are only read if forced by sending the second parameter, $top_level_only to FALSE, as this can be an intensive operation. +Takes a server path as input and returns an array containing the names of all files +contained within it. The file path can optionally be added to the file names by setting +the second parameter to TRUE. -get_file_info('path/to/file', $file_information) -================================================ +Example:: -Given a file and path, returns the name, path, size, date modified. Second parameter allows you to explicitly declare what information you want returned; options are: `name`, `server_path`, `size`, `date`, `readable`, `writable`, `executable`, `fileperms`. Returns FALSE if the file cannot be found. + $controllers = get_filenames(APPPATH.'controllers/'); + +get_dir_file_info() +=================== -.. note:: The "writable" uses the PHP function is_writable() which is known - to have issues on the IIS webserver. Consider using fileperms instead, - which returns information from PHP's fileperms() function. +.. php:function:: get_dir_file_info($source_dir, $top_level_only) -get_mime_by_extension('file') -============================= + :param string $source_dir: Directory path + :param bool $top_level_only: Whether to look only at the specified directory + (excluding sub-directories) + :returns: array -Translates a file extension into a mime type based on config/mimes.php. Returns FALSE if it can't determine the type, or open the mime config file. +Reads the specified directory and builds an array containing the filenames, filesize, +dates, and permissions. Sub-folders contained within the specified path are only read +if forced by sending the second parameter to FALSE, as this can be an intensive +operation. + +Example:: + + $models_info = get_dir_file_info(APPPATH.'models/'); + +get_file_info() +=============== + +.. php:function: get_file_info($file, $returned_values = array('name', 'server_path', 'size', 'date')) + + :param string $file: File path + :param array $returned_values: What type of info to return + :returns: array or FALSE on failure + +Given a file and path, returns (optionally) the *name*, *path*, *size* and *date modified* +information attributes for a file. Second parameter allows you to explicitly declare what +information you want returned. + +Valid ``$returned_values`` options are: `name`, `size`, `date`, `readable`, `writeable`, +`executable` and `fileperms`. + +.. note:: The *writable* attribute is checked via PHP's ``is_writeable()`` function, which + known to have issues on the IIS webserver. Consider using *fileperms* instead, + which returns information from PHP's ``fileperms()`` function. + +get_mime_by_extension() +======================= + +.. php:function:: get_mime_by_extension($filename) + + :param string $filename: File name + :returns: string or FALSE on failure + +Translates a filename extension into a MIME type based on *config/mimes.php*. +Returns FALSE if it can't determine the type, or read the MIME config file. :: - $file = "somefile.png"; - echo $file . ' is has a mime type of ' . get_mime_by_extension($file); + $file = 'somefile.png'; + echo $file.' is has a mime type of '.get_mime_by_extension($file); + +.. note:: This is not an accurate way of determining file MIME types, and + is here strictly for convenience. It should not be used for security + purposes. +symbolic_permissions() +====================== -.. note:: This is not an accurate way of determining file mime types, and - is here strictly as a convenience. It should not be used for security. +.. php:function:: symbolic_permissions($perms) -symbolic_permissions($perms) -============================ + :param int $perms: Permissions + :returns: string -Takes numeric permissions (such as is returned by `fileperms()` and returns standard symbolic notation of file permissions. +Takes numeric permissions (such as is returned by ``fileperms()``) and returns +standard symbolic notation of file permissions. :: echo symbolic_permissions(fileperms('./index.php')); // -rw-r--r-- -octal_permissions($perms) -========================= +octal_permissions() +=================== -Takes numeric permissions (such as is returned by fileperms() and returns a three character octal notation of file permissions. +.. php:function:: octal_permissions($perms) -:: + :param int $perms: Permissions + :returns: string - echo octal_permissions(fileperms('./index.php')); // 644 +Takes numeric permissions (such as is returned by ``fileperms()``) and returns +a three character octal notation of file permissions. + +:: + echo octal_permissions(fileperms('./index.php')); // 644
\ No newline at end of file diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst index a110f3c14..b2a9b6f0f 100644 --- a/user_guide_src/source/helpers/form_helper.rst +++ b/user_guide_src/source/helpers/form_helper.rst @@ -10,9 +10,7 @@ forms. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('form'); @@ -21,19 +19,27 @@ The following functions are available: form_open() =========== -Creates an opening form tag with a base URL **built from your config preferences**. It will optionally let you add form attributes and hidden input fields, and will always add the attribute accept-charset based on the charset value in your config file. +.. php:function:: form_open($action = '', $attributes = '', $hidden = array()) -The main benefit of using this tag rather than hard coding your own HTML is that it permits your site to be more portable in the event your URLs ever change. + :param string $action: Form action/target URI string + :param string $attributes: HTML attributes + :param array $hidden: An array of hidden fields' definitions + :returns: string -Here's a simple example +Creates an opening form tag with a base URL **built from your config preferences**. +It will optionally let you add form attributes and hidden input fields, and +will always add the `accept-charset` attribute based on the charset value in your +config file. -:: +The main benefit of using this tag rather than hard coding your own HTML is that +it permits your site to be more portable in the event your URLs ever change. + +Here's a simple example:: echo form_open('email/send'); -The above example would create a form that points to your base URL plus the "email/send" URI segments, like this - -:: +The above example would create a form that points to your base URL plus the +"email/send" URI segments, like this:: <form method="post" accept-charset="utf-8" action="http://example.com/index.php/email/send" /> @@ -41,32 +47,25 @@ Adding Attributes ^^^^^^^^^^^^^^^^^ Attributes can be added by passing an associative array to the second -parameter, like this - -:: +parameter, like this:: $attributes = array('class' => 'email', 'id' => 'myform'); echo form_open('email/send', $attributes); -The above example would create a form similar to this - -:: +The above example would create a form similar to this:: <form method="post" accept-charset="utf-8" action="http://example.com/index.php/email/send" class="email" id="myform" /> Adding Hidden Input Fields ^^^^^^^^^^^^^^^^^^^^^^^^^^ -Hidden fields can be added by passing an associative array to the third parameter, like this - -:: +Hidden fields can be added by passing an associative array to the +third parameter, like this:: - $hidden = array('username' => 'Joe', 'member_id' => '234'); + $hidden = array('username' => 'Joe', 'member_id' => '234'); echo form_open('email/send', '', $hidden); -The above example would create a form similar to this - -:: +The above example would create a form similar to this:: <form method="post" accept-charset="utf-8" action="http://example.com/index.php/email/send"> <input type="hidden" name="username" value="Joe" /> @@ -75,29 +74,38 @@ The above example would create a form similar to this form_open_multipart() ===================== -This function is absolutely identical to the `form_open()` tag above -except that it adds a multipart attribute, which is necessary if you +.. php:function:: form_open_multipart($action = '', $attributes = array(), $hidden = array()) + + :param string $action: Form action/target URI string + :param string $attributes: HTML attributes + :param array $hidden: An array of hidden fields' definitions + :returns: string + +This function is absolutely identical to :php:func:`form_open()` above, +except that it adds a *multipart* attribute, which is necessary if you would like to use the form to upload files with. form_hidden() ============= -Lets you generate hidden input fields. You can either submit a -name/value string to create one field +.. php:function:: form_hidden($name, $value = '') -:: + :param string $name: Field name + :param string $value: Field value + :returns: string + +Lets you generate hidden input fields. You can either submit a +name/value string to create one field:: form_hidden('username', 'johndoe'); // Would produce: <input type="hidden" name="username" value="johndoe" /> -Or you can submit an associative array to create multiple fields - -:: +... or you can submit an associative array to create multiple fields:: $data = array( - 'name' => 'John Doe', - 'email' => 'john@example.com', - 'url' => 'http://example.com' + 'name' => 'John Doe', + 'email' => 'john@example.com', + 'url' => 'http://example.com' ); echo form_hidden($data); @@ -109,35 +117,32 @@ Or you can submit an associative array to create multiple fields <input type="hidden" name="url" value="http://example.com" /> */ -Or pass an associative array to the value field. - -:: +You can also pass an associative array to the value field:: $data = array( - 'name' => 'John Doe', - 'email' => 'john@example.com', - 'url' => 'http://example.com' + 'name' => 'John Doe', + 'email' => 'john@example.com', + 'url' => 'http://example.com' ); echo form_hidden('my_array', $data); /* Would produce: + <input type="hidden" name="my_array[name]" value="John Doe" /> <input type="hidden" name="my_array[email]" value="john@example.com" /> <input type="hidden" name="my_array[url]" value="http://example.com" /> */ -If you want to create hidden input fields with extra attributes - -:: +If you want to create hidden input fields with extra attributes:: $data = array( - 'type' => 'hidden', - 'name' => 'email', - 'id' => 'hiddenemail', - 'value' => 'john@example.com', - 'class' => 'hiddenemail' + 'type' => 'hidden', + 'name' => 'email', + 'id' => 'hiddenemail', + 'value' => 'john@example.com', + 'class' => 'hiddenemail' ); echo form_input($data); @@ -151,25 +156,28 @@ If you want to create hidden input fields with extra attributes form_input() ============ -Lets you generate a standard text input field. You can minimally pass -the field name and value in the first and second parameter +.. php:function:: form_input($data = '', $value = '', $extra = '') -:: + :param array $data: Field attributes data + :param string $value: Field value + :param string $extra: Extra attributes to be added to the tag *as is* + :returns: string + +Lets you generate a standard text input field. You can minimally pass +the field name and value in the first and second parameter:: echo form_input('username', 'johndoe'); Or you can pass an associative array containing any data you wish your -form to contain - -:: +form to contain:: $data = array( - 'name' => 'username', - 'id' => 'username', - 'value' => 'johndoe', - 'maxlength' => '100', - 'size' => '50', - 'style' => 'width:50%' + 'name' => 'username', + 'id' => 'username', + 'value' => 'johndoe', + 'maxlength' => '100', + 'size' => '50', + 'style' => 'width:50%' ); echo form_input($data); @@ -181,9 +189,7 @@ form to contain */ If you would like your form to contain some additional data, like -Javascript, you can pass it as a string in the third parameter - -:: +JavaScript, you can pass it as a string in the third parameter:: $js = 'onClick="some_function()"'; echo form_input('username', 'johndoe', $js); @@ -191,34 +197,70 @@ Javascript, you can pass it as a string in the third parameter form_password() =============== -This function is identical in all respects to the `form_input()` function above except that it uses the "password" input type. +.. php:function:: form_password($data = '', $value = '', $extra = '') + + :param array $data: Field attributes data + :param string $value: Field value + :param string $extra: Extra attributes to be added to the tag *as is* + :returns: string + +This function is identical in all respects to the :php:func:`form_input()` +function above except that it uses the "password" input type. form_upload() ============= -This function is identical in all respects to the `form_input()` function above except that it uses the "file" input type, allowing it to be used to upload files. +.. php:function:: form_upload($data = '', $value = '', $extra = '') + + :param array $data: Field attributes data + :param string $value: Field value + :param string $extra: Extra attributes to be added to the tag *as is* + :returns: string + +This function is identical in all respects to the :php:func:`form_input()` +function above except that it uses the "file" input type, allowing it to +be used to upload files. form_textarea() =============== -This function is identical in all respects to the `form_input()` function above except that it generates a "textarea" type. Note: Instead of the "maxlength" and "size" attributes in the above example, you will instead specify "rows" and "cols". +.. php:function:: form_textarea($data = '', $value = '', $extra = '') + + :param array $data: Field attributes data + :param string $value: Field value + :param string $extra: Extra attributes to be added to the tag *as is* + :returns: string + +This function is identical in all respects to the :php:func:`form_input()` +function above except that it generates a "textarea" type. + +.. note: Instead of the *maxlength* and *size* attributes in the above example, + you will instead specify *rows* and *cols*. form_dropdown() =============== +.. php:function:: form_dropdown($name = '', $options = array(), $selected = array(), $extra = '') + + :param string $name: Field name + :param array $options: An associative array of options to be listed + :param array $selected: List of fields to mark with the *selected* attribute + :param string $extra: Extra attributes to be added to the tag *as is* + :returns: string + Lets you create a standard drop-down field. The first parameter will contain the name of the field, the second parameter will contain an associative array of options, and the third parameter will contain the value you wish to be selected. You can also pass an array of multiple items through the third parameter, and CodeIgniter will create a -multiple select for you. Example +multiple select for you. -:: +Example:: $options = array( - 'small' => 'Small Shirt', - 'med' => 'Medium Shirt', - 'large' => 'Large Shirt', + 'small' => 'Small Shirt', + 'med' => 'Medium Shirt', + 'large' => 'Large Shirt', 'xlarge' => 'Extra Large Shirt', ); @@ -251,33 +293,47 @@ multiple select for you. Example If you would like the opening <select> to contain additional data, like an id attribute or JavaScript, you can pass it as a string in the fourth -parameter - -:: +parameter:: $js = 'id="shirts" onChange="some_function();"'; echo form_dropdown('shirts', $options, 'large', $js); -If the array passed as $options is a multidimensional array, -`form_dropdown()` will produce an <optgroup> with the array key as the +If the array passed as ``$options`` is a multidimensional array, then +``form_dropdown()`` will produce an <optgroup> with the array key as the label. form_multiselect() ================== +.. php:function:: form_multiselect($name = '', $options = array(), $selected = array(), $extra = '') + + :param string $name: Field name + :param array $options: An associative array of options to be listed + :param array $selected: List of fields to mark with the *selected* attribute + :param string $extra: Extra attributes to be added to the tag *as is* + :returns: string + Lets you create a standard multiselect field. The first parameter will contain the name of the field, the second parameter will contain an associative array of options, and the third parameter will contain the -value or values you wish to be selected. The parameter usage is -identical to using form_dropdown() above, except of course that the -name of the field will need to use POST array syntax, e.g. foo[]. +value or values you wish to be selected. + +The parameter usage is identical to using :php:func:`form_dropdown()` above, +except of course that the name of the field will need to use POST array +syntax, e.g. foo[]. form_fieldset() -================ +=============== + +.. php:function:: form_fieldset($legend_text = '', $attributes = array()) + + :param string $legend_text: Text to put in the <legend> tag + :param array $attributes: Attributes to be set on the <fieldset> tag + :returns: string Lets you generate fieldset/legend fields. -:: +Example:: echo form_fieldset('Address Information'); echo "<p>fieldset content here</p>\n"; @@ -285,6 +341,7 @@ Lets you generate fieldset/legend fields. /* Produces: + <fieldset> <legend>Address Information</legend> <p>form content here</p> @@ -292,13 +349,11 @@ Lets you generate fieldset/legend fields. */ Similar to other functions, you can submit an associative array in the -second parameter if you prefer to set additional attributes. - -:: +second parameter if you prefer to set additional attributes:: $attributes = array( - 'id' => 'address_info', - 'class' => 'address_info' + 'id' => 'address_info', + 'class' => 'address_info' ); echo form_fieldset('Address Information', $attributes); @@ -317,22 +372,33 @@ second parameter if you prefer to set additional attributes. form_fieldset_close() ===================== +.. php:function:: form_fieldset_close($extra = '') + + :param string $extra: Anything to append after the closing tag, *as is* + :returns: string + Produces a closing </fieldset> tag. The only advantage to using this function is it permits you to pass data to it which will be added below the tag. For example :: - $string = "</div></div>"; + $string = '</div></div>'; echo form_fieldset_close($string); // Would produce: </fieldset></div></div> form_checkbox() =============== -Lets you generate a checkbox field. Simple example +.. php:function:: form_checkbox($data = '', $value = '', $checked = FALSE, $extra = '') -:: + :param array $data: Field attributes data + :param string $value: Field value + :param bool $checked: Whether to mark the checkbox as being *checked* + :param string $extra: Extra attributes to be added to the tag *as is* + :returns: string + +Lets you generate a checkbox field. Simple example:: echo form_checkbox('newsletter', 'accept', TRUE); // Would produce: <input type="checkbox" name="newsletter" value="accept" checked="checked" /> @@ -346,21 +412,19 @@ array of attributes to the function :: $data = array( - 'name' => 'newsletter', - 'id' => 'newsletter', - 'value' => 'accept', - 'checked' => TRUE, - 'style' => 'margin:10px', + 'name' => 'newsletter', + 'id' => 'newsletter', + 'value' => 'accept', + 'checked' => TRUE, + 'style' => 'margin:10px' ); echo form_checkbox($data); // Would produce: <input type="checkbox" name="newsletter" id="newsletter" value="accept" checked="checked" style="margin:10px" /> -As with other functions, if you would like the tag to contain additional -data, like JavaScript, you can pass it as a string in the fourth -parameter - -:: +Also as with other functions, if you would like the tag to contain +additional data like JavaScript, you can pass it as a string in the +fourth parameter:: $js = 'onClick="some_function()"'; echo form_checkbox('newsletter', 'accept', TRUE, $js) @@ -368,29 +432,28 @@ parameter form_radio() ============ -This function is identical in all respects to the `form_checkbox()` -function above except that it uses the "radio" input type. - -form_submit() -============= - -Lets you generate a standard submit button. Simple example +.. php:function:: form_radio($data = '', $value = '', $checked = FALSE, $extra = '') -:: - - echo form_submit('mysubmit', 'Submit Post!'); - // Would produce: <input type="submit" name="mysubmit" value="Submit Post!" /> + :param array $data: Field attributes data + :param string $value: Field value + :param bool $checked: Whether to mark the radio button as being *checked* + :param string $extra: Extra attributes to be added to the tag *as is* + :returns: string -Similar to other functions, you can submit an associative array in the -first parameter if you prefer to set your own attributes. The third -parameter lets you add extra data to your form, like JavaScript. +This function is identical in all respects to the :php:func:`form_checkbox()` +function above except that it uses the "radio" input type. form_label() ============ -Lets you generate a <label>. Simple example +.. php:function:: form_label($label_text = '', $id = '', $attributes = array()) -:: + :param string $label_text: Text to put in the <label> tag + :param string $id: ID of the form element that we're making a label for + :param string $attributes: HTML attributes + :returns: string + +Lets you generate a <label>. Simple example:: echo form_label('What is your Name', 'username'); // Would produce: <label for="username">What is your Name</label> @@ -398,7 +461,7 @@ Lets you generate a <label>. Simple example Similar to other functions, you can submit an associative array in the third parameter if you prefer to set additional attributes. -:: +Example:: $attributes = array( 'class' => 'mycustomclass', @@ -408,77 +471,110 @@ third parameter if you prefer to set additional attributes. echo form_label('What is your Name', 'username', $attributes); // Would produce: <label for="username" class="mycustomclass" style="color: #000;">What is your Name</label> +form_submit() +============= + +.. php:function:: form_submit($data = '', $value = '', $extra = '') + + :param string $data: Button name + :param string $value: Button value + :param string $extra: Extra attributes to be added to the tag *as is* + :returns: string + +Lets you generate a standard submit button. Simple example:: + + echo form_submit('mysubmit', 'Submit Post!'); + // Would produce: <input type="submit" name="mysubmit" value="Submit Post!" /> + +Similar to other functions, you can submit an associative array in the +first parameter if you prefer to set your own attributes. The third +parameter lets you add extra data to your form, like JavaScript. form_reset() ============ +.. php:function:: form_reset($data = '', $value = '', $extra = '') + + :param string $data: Button name + :param string $value: Button value + :param string $extra: Extra attributes to be added to the tag *as is* + :returns: string + Lets you generate a standard reset button. Use is identical to -`form_submit()`. +:php:func:`form_submit()`. form_button() ============= -Lets you generate a standard button element. You can minimally pass the -button name and content in the first and second parameter +.. php:function:: form_button($data = '', $content = '', $extra = '') -:: + :param string $data: Button name + :param string $content: Button label + :param string $extra: Extra attributes to be added to the tag *as is* + :returns: string - echo form_button('name','content'); - // Would produce <button name="name" type="button">Content</button> +Lets you generate a standard button element. You can minimally pass the +button name and content in the first and second parameter:: -Or you can pass an associative array containing any data you wish your -form to contain: + echo form_button('name','content'); + // Would produce: <button name="name" type="button">Content</button> -:: +Or you can pass an associative array containing any data you wish your +form to contain:: $data = array( - 'name' => 'button', - 'id' => 'button', - 'value' => 'true', - 'type' => 'reset', - 'content' => 'Reset' + 'name' => 'button', + 'id' => 'button', + 'value' => 'true', + 'type' => 'reset', + 'content' => 'Reset' ); echo form_button($data); // Would produce: <button name="button" id="button" value="true" type="reset">Reset</button> If you would like your form to contain some additional data, like -JavaScript, you can pass it as a string in the third parameter: +JavaScript, you can pass it as a string in the third parameter:: -:: - - $js = 'onClick="some_function()"'; + $js = 'onClick="some_function()"'; echo form_button('mybutton', 'Click Me', $js); form_close() ============ +.. php:function:: form_close($extra = '') + + :param string $extra: Anything to append after the closing tag, *as is* + :returns: string + Produces a closing </form> tag. The only advantage to using this function is it permits you to pass data to it which will be added below -the tag. For example - -:: +the tag. For example:: - $string = "</div></div>"; + $string = '</div></div>'; echo form_close($string); // Would produce: </form> </div></div> form_prep() =========== +.. php:function:: form_prep($str = '', $is_textarea = FALSE) + + :param string $str: Value to escape + :param bool $is_textarea: Whether we're preparing for <textarea> or a regular input tag + :returns: string + Allows you to safely use HTML and characters such as quotes within form -elements without breaking out of the form. Consider this example +elements without breaking out of the form. -:: +Consider this example:: $string = 'Here is a string containing "quoted" text.'; <input type="text" name="myform" value="$string" /> Since the above string contains a set of quotes it will cause the form -to break. The `form_prep()` function converts HTML so that it can be used -safely - -:: +to break. The ``form_prep()`` function converts HTML so that it can be used +safely:: <input type="text" name="myform" value="<?php echo form_prep($string); ?>" /> @@ -489,29 +585,42 @@ safely set_value() =========== +.. php:function:: set_value($field = '', $default = '', $is_textarea = FALSE) + + :param string $field: Field name + :param string $default: Default value + :param bool $is_textarea: Whether we're setting <textarea> content + :returns: string + Permits you to set the value of an input form or textarea. You must supply the field name via the first parameter of the function. The second (optional) parameter allows you to set a default value for the -form. Example +form. -:: +Example:: - <input type="text" name="quantity" value="<?php echo set_value('quantity', '0'); ?>" size="50" /> + <input type="text" name="quantity" value="<?=set_value('quantity', '0');?>" size="50" /> The above form will show "0" when loaded for the first time. set_select() ============ +.. php:function:: set_select($field = '', $value = '', $default = FALSE) + + :param string $field: Field name + :param string $value: Value to check for + :param string $default: Whether the value is also a default one + :returns: string + If you use a <select> menu, this function permits you to display the -menu item that was selected. The first parameter must contain the name -of the select menu, the second parameter must contain the value of each -item, and the third (optional) parameter lets you set an item as the -default (use boolean TRUE/FALSE). +menu item that was selected. -Example +The first parameter must contain the name of the select menu, the second +parameter must contain the value of each item, and the third (optional) +parameter lets you set an item as the default (use boolean TRUE/FALSE). -:: +Example:: <select name="myselect"> <option value="one" <?php echo set_select('myselect', 'one', TRUE); ?> >One</option> @@ -522,12 +631,20 @@ Example set_checkbox() ============== -Permits you to display a checkbox in the state it was submitted. The -first parameter must contain the name of the checkbox, the second +.. php:function:: set_checkbox($field = '', $value = '', $default = FALSE) + + :param string $field: Field name + :param string $value: Value to check for + :param string $default: Whether the value is also a default one + :returns: string + +Permits you to display a checkbox in the state it was submitted. + +The first parameter must contain the name of the checkbox, the second parameter must contain its value, and the third (optional) parameter -lets you set an item as the default (use boolean TRUE/FALSE). Example +lets you set an item as the default (use boolean TRUE/FALSE). -:: +Example:: <input type="checkbox" name="mycheck" value="1" <?php echo set_checkbox('mycheck', '1'); ?> /> <input type="checkbox" name="mycheck" value="2" <?php echo set_checkbox('mycheck', '2'); ?> /> @@ -535,11 +652,71 @@ lets you set an item as the default (use boolean TRUE/FALSE). Example set_radio() =========== +.. php:function:: set_radio($field = '', $value = '', $default = FALSE) + + :param string $field: Field name + :param string $value: Value to check for + :param string $default: Whether the value is also a default one + :returns: string + Permits you to display radio buttons in the state they were submitted. -This function is identical to the **set_checkbox()** function above. +This function is identical to the :php:func:`set_checkbox()` function above. -:: +Example:: <input type="radio" name="myradio" value="1" <?php echo set_radio('myradio', '1', TRUE); ?> /> <input type="radio" name="myradio" value="2" <?php echo set_radio('myradio', '2'); ?> /> +.. note:: If you are using the Form Validation class, you must always specify + a rule for your field, even if empty, in order for the ``set_*()`` + functions to work. This is because if a Form Validation object is + defined, the control for ``set_*()`` is handed over to a method of the + class instead of the generic helper function. + +form_error() +============ + +.. php:function:: form_error($field = '', $prefix = '', $suffix = '') + + :param string $field: Field name + :param string $prefix: Error opening tag + :param string $suffix: Error closing tag + :returns: string + +Returns a validation error message from the :doc:`Form Validation Library +<../libraries/form_validation>`, associated with the specified field name. +You can optionally specify opening and closing tag(s) to put around the error +message. + +Example:: + + // Assuming that the 'username' field value was incorrect: + echo form_error('myfield', '<div class="error">', '</div>'); + + // Would produce: <div class="error">Error message associated with the "username" field.</div> + +validation_errors() +=================== + +.. php:function:: validation_errors($prefix = '', $suffix = '') + + :param string $prefix: Error opening tag + :param string $suffix: Error closing tag + :returns: string + +Similarly to the :php:func:`form_error()` function, returns all validation +error messages produced by the :doc:`Form Validation Library +<../libraries/form_validation>`, with optional opening and closing tags +around each of the messages. + +Example:: + + echo validation_errors('<span class="error">', '</span>'); + + /* + Would produce, e.g.: + + <span class="error">The "email" field doesn't contain a valid e-mail address!</span> + <span class="error">The "password" field doesn't match the "repeat_password" field!</span> + + */
\ No newline at end of file diff --git a/user_guide_src/source/helpers/html_helper.rst b/user_guide_src/source/helpers/html_helper.rst index 17c28cd2a..df53ebd2f 100644 --- a/user_guide_src/source/helpers/html_helper.rst +++ b/user_guide_src/source/helpers/html_helper.rst @@ -19,6 +19,11 @@ The following functions are available: br() ==== +.. php:function:: br($count = 1) + + :param int $count: Number of times to repeat the tag + :returns: string + Generates line break tags (<br />) based on the number you submit. Example:: @@ -29,7 +34,14 @@ The above would produce: <br /><br /><br /> heading() ========= -Lets you create HTML <h1> tags. The first parameter will contain the +.. php:function:: heading($data = '', $h = '1', $attributes = '') + + :param string $data: Content + :param string $h: Heading level + :param array $attributes: HTML attributes + :returns: string + +Lets you create HTML heading tags. The first parameter will contain the data, the second the size of the heading. Example:: echo heading('Welcome!', 3); @@ -37,9 +49,7 @@ data, the second the size of the heading. Example:: The above would produce: <h3>Welcome!</h3> Additionally, in order to add attributes to the heading tag such as HTML -classes, ids or inline styles, a third parameter is available. - -:: +classes, ids or inline styles, a third parameter is available:: echo heading('Welcome!', 3, 'class="pink"') @@ -48,28 +58,31 @@ The above code produces: <h3 class="pink">Welcome!<<h3> img() ===== -Lets you create HTML <img /> tags. The first parameter contains the -image source. Example +.. php:function:: img($src = '', $index_page = FALSE, $attributes = '') -:: + :param string $src: Image source data + :param bool $index_page: Whether to treat $src as a routed URI string + :param array $attributes: HTML attributes + :returns: string + +Lets you create HTML <img /> tags. The first parameter contains the +image source. Example:: echo img('images/picture.jpg'); // gives <img src="http://site.com/images/picture.jpg" /> There is an optional second parameter that is a TRUE/FALSE value that -specifics if the src should have the page specified by -$config['index_page'] added to the address it creates. Presumably, this -would be if you were using a media controller. - -:: +specifics if the *src* should have the page specified by +``$config['index_page']`` added to the address it creates. +Presumably, this would be if you were using a media controller:: echo img('images/picture.jpg', TRUE); // gives <img src="http://site.com/index.php/images/picture.jpg" alt="" /> -Additionally, an associative array can be passed to the img() function -for complete control over all attributes and values. If an alt attribute +Additionally, an associative array can be passed to the ``img()`` function +for complete control over all attributes and values. If an *alt* attribute is not provided, CodeIgniter will generate an empty string. -:: +Example:: $image_properties = array( 'src' => 'images/picture.jpg', @@ -81,128 +94,136 @@ is not provided, CodeIgniter will generate an empty string. 'rel' => 'lightbox' ); - img($image_properties); // <img src="http://site.com/index.php/images/picture.jpg" alt="Me, demonstrating how to eat 4 slices of pizza at one time" class="post_images" width="200" height="200" title="That was quite a night" rel="lightbox" /> + img($image_properties); + // <img src="http://site.com/index.php/images/picture.jpg" alt="Me, demonstrating how to eat 4 slices of pizza at one time" class="post_images" width="200" height="200" title="That was quite a night" rel="lightbox" /> link_tag() -=========== +========== -Lets you create HTML <link /> tags. This is useful for stylesheet links, -as well as other links. The parameters are href, with optional rel, -type, title, media and index_page. index_page is a TRUE/FALSE value -that specifics if the href should have the page specified by -$config['index_page'] added to the address it creates. +.. php:function:: ling_tag($href = '', $rel = 'stylesheet', $type = 'text/css', $title = '', $media = '', $index_page = FALSE) -:: + :param string $href: What are we linking to + :param string $rel: Relation type + :param string $type: Type of the related document + :param string $title: Link title + :param string $media: Media type + :param bool $index_page: Whether to treat $src as a routed URI string + :returns: string - echo link_tag('css/mystyles.css'); // gives <link href="http://site.com/css/mystyles.css" rel="stylesheet" type="text/css" /> +Lets you create HTML <link /> tags. This is useful for stylesheet links, +as well as other links. The parameters are *href*, with optional *rel*, +*type*, *title*, *media* and *index_page*. + +*index_page* is a boolean value that specifies if the *href* should have +the page specified by ``$config['index_page']`` added to the address it creates. +Example:: -Further examples + echo link_tag('css/mystyles.css'); + // gives <link href="http://site.com/css/mystyles.css" rel="stylesheet" type="text/css" /> -:: - echo link_tag('favicon.ico', 'shortcut icon', 'image/ico'); // <link href="http://site.com/favicon.ico" rel="shortcut icon" type="image/ico" /> +Further examples:: - echo link_tag('feed', 'alternate', 'application/rss+xml', 'My RSS Feed'); // <link href="http://site.com/feed" rel="alternate" type="application/rss+xml" title="My RSS Feed" /> + echo link_tag('favicon.ico', 'shortcut icon', 'image/ico'); + // <link href="http://site.com/favicon.ico" rel="shortcut icon" type="image/ico" /> -Additionally, an associative array can be passed to the link() function -for complete control over all attributes and values. + echo link_tag('feed', 'alternate', 'application/rss+xml', 'My RSS Feed'); + // <link href="http://site.com/feed" rel="alternate" type="application/rss+xml" title="My RSS Feed" /> -:: +Additionally, an associative array can be passed to the ``link()`` function +for complete control over all attributes and values:: $link = array( - 'href' => 'css/printer.css', - 'rel' => 'stylesheet', - 'type' => 'text/css', - 'media' => 'print' + 'href' => 'css/printer.css', + 'rel' => 'stylesheet', + 'type' => 'text/css', + 'media' => 'print' ); - echo link_tag($link); // <link href="http://site.com/css/printer.css" rel="stylesheet" type="text/css" media="print" /> - + echo link_tag($link); + // <link href="http://site.com/css/printer.css" rel="stylesheet" type="text/css" media="print" /> nbs() ===== -Generates non-breaking spaces ( ) based on the number you submit. -Example +.. php:function:: nbs($num = 1) -:: + :param int $num: Number of space entities to produce + :returns: string - echo nbs(3); +Generates non-breaking spaces ( ) based on the number you submit. +Example:: -The above would produce + echo nbs(3); -:: +The above would produce:: -ol() and ul() +ul() and ol() ============= -Permits you to generate ordered or unordered HTML lists from simple or -multi-dimensional arrays. Example +.. php:function:: ul($list, $attributes = '') -:: + :param array $list: List entries + :param array $attributes: HTML attributes + :returns: string - $this->load->helper('html'); +Permits you to generate ordered or unordered HTML lists from simple or +multi-dimensional arrays. Example:: - $list = array( - 'red', - 'blue', - 'green', - 'yellow' + $list = array( + 'red', + 'blue', + 'green', + 'yellow' ); - $attributes = array( - 'class' => 'boldlist', - 'id' => 'mylist' + $attributes = array( + 'class' => 'boldlist', + 'id' => 'mylist' ); echo ul($list, $attributes); -The above code will produce this - -:: +The above code will produce this:: - <ul class="boldlist" id="mylist"> - <li>red</li> - <li>blue</li> - <li>green</li> + <ul class="boldlist" id="mylist"> + <li>red</li> + <li>blue</li> + <li>green</li> <li>yellow</li> </ul> -Here is a more complex example, using a multi-dimensional array - -:: - - $this->load->helper('html'); +Here is a more complex example, using a multi-dimensional array:: - $attributes = array( - 'class' => 'boldlist', - 'id' => 'mylist' + $attributes = array( + 'class' => 'boldlist', + 'id' => 'mylist' ); - $list = array( - 'colors' => array( - 'red', - 'blue', - 'green' + $list = array( + 'colors' => array( + 'red', + 'blue', + 'green' ), - 'shapes' => array( - 'round', - 'square', - 'circles' => array( + 'shapes' => array( + 'round', + 'square', + 'circles' => array( 'ellipse', 'oval', 'sphere' - ) - ), - 'moods' => array( - 'happy', - 'upset' => array( + ) + ), + 'moods' => array( + 'happy', + 'upset' => array( 'defeated' => array( - 'dejected', + 'dejected', 'disheartened', 'depressed' ), @@ -215,59 +236,74 @@ Here is a more complex example, using a multi-dimensional array echo ul($list, $attributes); -The above code will produce this - -:: - - <ul class="boldlist" id="mylist"> - <li>colors - <ul> - <li>red</li> - <li>blue</li> - <li>green</li> - </ul> - </li> - <li>shapes - <ul> - <li>round</li> - <li>suare</li> - <li>circles - <ul> - <li>elipse</li> - <li>oval</li> - <li>sphere</li> - </ul> - </li> - </ul> - </li> - <li>moods - <ul> - <li>happy</li> - <li>upset - <ul> - <li>defeated - <ul> +The above code will produce this:: + + <ul class="boldlist" id="mylist"> + <li>colors + <ul> + <li>red</li> + <li>blue</li> + <li>green</li> + </ul> + </li> + <li>shapes + <ul> + <li>round</li> + <li>suare</li> + <li>circles + <ul> + <li>elipse</li> + <li>oval</li> + <li>sphere</li> + </ul> + </li> + </ul> + </li> + <li>moods + <ul> + <li>happy</li> + <li>upset + <ul> + <li>defeated + <ul> <li>dejected</li> <li>disheartened</li> <li>depressed</li> </ul> </li> <li>annoyed</li> - <li>cross</li> - <li>angry</li> - </ul> - </li> - </ul> + <li>cross</li> + <li>angry</li> + </ul> + </li> + </ul> </li> </ul> +.. php:function:: ol($list, $attributes = '') + + :param array $list: List entries + :param array $attributes: HTML attributes + :returns: string + +Identical to :php:func:`ul()`, only it produces the <ol> tag for +ordered lists instead of <ul>. + meta() ====== +.. php:function:: meta($name = '', $content = '', $type = 'name', $newline = "\n") + + :param string $name: Meta name + :param string $content: Meta content + :param string $type: Meta type + :param string $newline: Newline character + :returns: string + Helps you generate meta tags. You can pass strings to the function, or -simple arrays, or multidimensional ones. Examples +simple arrays, or multidimensional ones. -:: +Examples:: echo meta('description', 'My Great site'); // Generates: <meta name="description" content="My Great Site" /> @@ -279,7 +315,7 @@ simple arrays, or multidimensional ones. Examples echo meta(array('name' => 'robots', 'content' => 'no-cache')); // Generates: <meta name="robots" content="no-cache" /> - $meta = array( + $meta = array( array( 'name' => 'robots', 'content' => 'no-cache' @@ -291,7 +327,7 @@ simple arrays, or multidimensional ones. Examples array( 'name' => 'keywords', 'content' => 'love, passion, intrigue, deception' - ), + ), array( 'name' => 'robots', 'content' => 'no-cache' @@ -313,10 +349,14 @@ simple arrays, or multidimensional ones. Examples doctype() ========= +.. php:function:: doctype($type = 'xhtml1-strict') + + :param string $type: Doctype name + Helps you generate document type declarations, or DTD's. XHTML 1.0 Strict is used by default, but many doctypes are available. -:: +Example:: echo doctype(); // <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> diff --git a/user_guide_src/source/helpers/inflector_helper.rst b/user_guide_src/source/helpers/inflector_helper.rst index cc46a1851..1f54b76c0 100644 --- a/user_guide_src/source/helpers/inflector_helper.rst +++ b/user_guide_src/source/helpers/inflector_helper.rst @@ -10,9 +10,7 @@ words to plural, singular, camel case, etc. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('inflector'); @@ -21,65 +19,81 @@ The following functions are available: singular() ========== -Changes a plural word to singular. Example +.. php:function:: singular($str) + + :param string $str: Input string + :returns: string -:: +Changes a plural word to singular. Example:: - $word = "dogs"; - echo singular($word); // Returns "dog" + echo singular('dogs'); // Prints 'dog' plural() ======== -Changes a singular word to plural. Example - -:: - - $word = "dog"; - echo plural($word); // Returns "dogs" +.. php:function:: plural($str) -To force a word to end with "es" use a second "true" argument. + :param string $str: Input string + :returns: string -:: +Changes a singular word to plural. Example:: - $word = "pass"; - echo plural($word, TRUE); // Returns "passes" + echo plural('dog'); // Prints 'dogs' camelize() ========== -Changes a string of words separated by spaces or underscores to camel -case. Example +.. php:function:: camelize($str) + + :param string $str: Input string + :returns: string -:: +Changes a string of words separated by spaces or underscores to camel +case. Example:: - $word = "my_dog_spot"; - echo camelize($word); // Returns "myDogSpot" + echo camelize('my_dog_spot'); // Prints 'myDogSpot' underscore() ============ -Takes multiple words separated by spaces and underscores them. Example +.. php:function:: camelize($str) -:: + :param string $str: Input string + :returns: string - $word = "my dog spot"; - echo underscore($word); // Returns "my_dog_spot" +Takes multiple words separated by spaces and underscores them. +Example:: + + echo underscore('my dog spot'); // Prints 'my_dog_spot' humanize() ========== +.. php:function:: camelize($str) + + :param string $str: Input string + :param string $separator: Input separator + :returns: string + Takes multiple words separated by underscores and adds spaces between -them. Each word is capitalized. Example +them. Each word is capitalized. + +Example:: + + echo humanize('my_dog_spot'); // Prints 'My Dog Spot' + +To use dashes instead of underscores:: + + echo humanize('my-dog-spot', '-'); // Prints 'My Dog Spot' -:: +is_countable() +============== - $word = "my_dog_spot"; - echo humanize($word); // Returns "My Dog Spot" +.. php:function:: is_countable($word) -To use dashes instead of underscores + :param string $word: Input string + :returns: bool -:: +Checks if the given word has a plural version. Example:: - $word = "my-dog-spot"; - echo humanize($word, '-'); // Returns "My Dog Spot"
\ No newline at end of file + is_countable('equipment'); // Returns FALSE
\ No newline at end of file diff --git a/user_guide_src/source/helpers/language_helper.rst b/user_guide_src/source/helpers/language_helper.rst index b7b23d149..8b039374d 100644 --- a/user_guide_src/source/helpers/language_helper.rst +++ b/user_guide_src/source/helpers/language_helper.rst @@ -10,24 +10,27 @@ language files. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('language'); The following functions are available: -lang('language line', 'element id') -=================================== +lang() +====== + +.. php:function:: lang($line, $id = '') + + :param string $line: Language line key + :param string $id: ID of the element we're creating a label for + :returns: string This function returns a line of text from a loaded language file with -simplified syntax that may be more desirable for view files than calling -`$this->lang->line()`. The optional second parameter will also output a -form label for you. Example +simplified syntax that may be more desirable for view files than +``CI_Lang::line()``. +The optional second parameter will also output a form label for you. -:: +Example:: echo lang('language_key', 'form_item_id'); - // becomes <label for="form_item_id">language_key</label> - + // becomes <label for="form_item_id">language_key</label>
\ No newline at end of file diff --git a/user_guide_src/source/helpers/number_helper.rst b/user_guide_src/source/helpers/number_helper.rst index af6cdad57..8e0ebda5e 100644 --- a/user_guide_src/source/helpers/number_helper.rst +++ b/user_guide_src/source/helpers/number_helper.rst @@ -10,9 +10,7 @@ numeric data. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('number'); @@ -21,25 +19,27 @@ The following functions are available: byte_format() ============= -Formats a numbers as bytes, based on size, and adds the appropriate -suffix. Examples +.. php:function:: byte_format($num, $precision = 1) + + :param mixed $num: Number of bytes + :param int $precision: Floating point precision + :returns: string -:: +Formats numbers as bytes, based on size, and adds the appropriate +suffix. Examples:: - echo byte_format(456); // Returns 456 Bytes - echo byte_format(4567); // Returns 4.5 KB - echo byte_format(45678); // Returns 44.6 KB - echo byte_format(456789); // Returns 447.8 KB - echo byte_format(3456789); // Returns 3.3 MB - echo byte_format(12345678912345); // Returns 1.8 GB + echo byte_format(456); // Returns 456 Bytes + echo byte_format(4567); // Returns 4.5 KB + echo byte_format(45678); // Returns 44.6 KB + echo byte_format(456789); // Returns 447.8 KB + echo byte_format(3456789); // Returns 3.3 MB + echo byte_format(12345678912345); // Returns 1.8 GB echo byte_format(123456789123456789); // Returns 11,228.3 TB An optional second parameter allows you to set the precision of the -result. - -:: +result:: echo byte_format(45678, 2); // Returns 44.61 KB .. note:: The text generated by this function is found in the following - language file: language/<your_lang>/number_lang.php + language file: `language/<your_lang>/number_lang.php`
\ No newline at end of file diff --git a/user_guide_src/source/helpers/path_helper.rst b/user_guide_src/source/helpers/path_helper.rst index 847f5a08b..3a271b28f 100644 --- a/user_guide_src/source/helpers/path_helper.rst +++ b/user_guide_src/source/helpers/path_helper.rst @@ -10,9 +10,7 @@ file paths on the server. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('path'); @@ -21,23 +19,28 @@ The following functions are available: set_realpath() ============== -Checks to see if the path exists. This function will return a server -path without symbolic links or relative directory structures. An -optional second argument will cause an error to be triggered if the path -cannot be resolved. +.. php:function:: set_realpath($path, $check_existance = FALSE) + + :param string $path: Path + :param bool $check_existance: Whether to check if the path actually exists + :returns: string + +This function will return a server path without symbolic links or +relative directory structures. An optional second argument will +cause an error to be triggered if the path cannot be resolved. -:: +Examples:: $file = '/etc/php5/apache2/php.ini'; - echo set_realpath($file); // returns "/etc/php5/apache2/php.ini" + echo set_realpath($file); // Prints '/etc/php5/apache2/php.ini' $non_existent_file = '/path/to/non-exist-file.txt'; - echo set_realpath($non_existent_file, TRUE); // shows an error, as the path cannot be resolved - echo set_realpath($non_existent_file, FALSE); // returns "/path/to/non-exist-file.txt" + echo set_realpath($non_existent_file, TRUE); // Shows an error, as the path cannot be resolved + echo set_realpath($non_existent_file, FALSE); // Prints '/path/to/non-exist-file.txt' $directory = '/etc/php5'; - echo set_realpath($directory); // returns "/etc/php5/" + echo set_realpath($directory); // Prints '/etc/php5/' $non_existent_directory = '/path/to/nowhere'; - echo set_realpath($non_existent_directory, TRUE); // shows an error, as the path cannot be resolved - echo set_realpath($non_existent_directory, FALSE); // returns "/path/to/nowhere" + echo set_realpath($non_existent_directory, TRUE); // Shows an error, as the path cannot be resolved + echo set_realpath($non_existent_directory, FALSE); // Prints '/path/to/nowhere'
\ No newline at end of file diff --git a/user_guide_src/source/helpers/security_helper.rst b/user_guide_src/source/helpers/security_helper.rst index b1bcf2b4a..21bf53490 100644 --- a/user_guide_src/source/helpers/security_helper.rst +++ b/user_guide_src/source/helpers/security_helper.rst @@ -9,9 +9,7 @@ The Security Helper file contains security related functions. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('security'); @@ -20,49 +18,87 @@ The following functions are available: xss_clean() =========== -Provides Cross Site Script Hack filtering. This function is an alias to -the one in the :doc:`Input class <../libraries/input>`. More info can -be found there. +.. php:function:: xss_clean($str, $is_image = FALSE) + + :param string $str: Input data + :param bool $is_image: Whether we're dealing with an image + :returns: string + +Provides Cross Site Script Hack filtering. + +This function is an alias for ``CI_Input::xss_clean()``. For more info, +please see the :doc:`Input Library <../libraries/input>` documentation. sanitize_filename() =================== -Provides protection against directory traversal. This function is an -alias to the one in the :doc:`Security class <../libraries/security>`. -More info can be found there. +.. php:function:: sanitize_filename($filename) + + :param string $filename: Filename + :returns: string + +Provides protection against directory traversal. + +This function is an alias for ``CI_Security::sanitize_filename()``. +For more info, please see the :doc:`Security Library <../libraries/security>` +documentation. do_hash() ========= +.. php:function:: do_hash($str, $type = 'sha1') + + :param string $str: Input + :param string $type: Algorithm + :returns: string + Permits you to create one way hashes suitable for encrypting -passwords. Will create SHA1 by default. See `hash_algos() <http://php.net/function.hash_algos>`_ +passwords. Will use SHA1 by default. + +See `hash_algos() <http://php.net/function.hash_algos>`_ for a full list of supported algorithms. -:: +Examples:: $str = do_hash($str); // SHA1 $str = do_hash($str, 'md5'); // MD5 -.. note:: This function was formerly named dohash(), which has been - removed in favor of `do_hash()`. +.. note:: This function was formerly named ``dohash()``, which has been + removed in favor of ``do_hash()``. + +.. note:: This function is DEPRECATED. Use the native ``hash()`` instead. strip_image_tags() ================== -This is a security function that will strip image tags from a string. It -leaves the image URL as plain text. +.. php:function:: strip_image_tags($str) + + :param string $str: Input + :returns: string -:: +This is a security function that will strip image tags from a string. +It leaves the image URL as plain text. + +Example:: $string = strip_image_tags($string); +This function is an alias for ``CI_Security::strip_image_tags()``. For +more info, please see the :doc:`Security Library <../libraries/security>` +documentation. + encode_php_tags() ================= -This is a security function that converts PHP tags to entities. Note: If -you use the XSS filtering function it does this automatically. +.. php:function:: encode_php_tags($str) + + :param string $str: Input + :returns: string + +This is a security function that converts PHP tags to entities. -:: +.. note: :php:func:`xss_clean()` does this automatically, if you use it. - $string = encode_php_tags($string); +Example:: + $string = encode_php_tags($string);
\ No newline at end of file diff --git a/user_guide_src/source/helpers/smiley_helper.rst b/user_guide_src/source/helpers/smiley_helper.rst index 941ba11e3..13841e8bd 100644 --- a/user_guide_src/source/helpers/smiley_helper.rst +++ b/user_guide_src/source/helpers/smiley_helper.rst @@ -10,9 +10,7 @@ The Smiley Helper file contains functions that let you manage smileys Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('smiley'); @@ -36,10 +34,11 @@ smileys next to a form field. This example requires that you first download and install the smiley images, then create a controller and the View as described. -.. important:: Before you begin, please `download the smiley images <http://codeigniter.com/download_files/smileys.zip>`_ - and put them in a publicly accessible place on your server. This helper - also assumes you have the smiley replacement array located at - `application/config/smileys.php` +.. important:: Before you begin, please `download the smiley images + <http://codeigniter.com/download_files/smileys.zip>`_ + and put them in a publicly accessible place on your server. + This helper also assumes you have the smiley replacement array + located at `application/config/smileys.php` The Controller -------------- @@ -47,18 +46,17 @@ The Controller In your `application/controllers/` folder, create a file called smileys.php and place the code below in it. -.. important:: Change the URL in the `get_clickable_smileys()` +.. important:: Change the URL in the :php:func:`get_clickable_smileys()` function below so that it points to your smiley folder. -You'll notice that in addition to the smiley helper we are using the :doc:`Table Class <../libraries/table>`. - -:: +You'll notice that in addition to the smiley helper, we are also using +the :doc:`Table Class <../libraries/table>`:: <?php class Smileys extends CI_Controller { - function index() + public function index() { $this->load->helper('smiley'); $this->load->library('table'); @@ -69,12 +67,11 @@ You'll notice that in addition to the smiley helper we are using the :doc:`Table $data['smiley_table'] = $this->table->generate($col_array); $this->load->view('smiley_view', $data); } + } In your `application/views/` folder, create a file called `smiley_view.php` -and place this code in it: - -:: +and place this code in it:: <html> <head> @@ -102,59 +99,66 @@ links a generic name that will be tied to a specific id in your view. $image_array = get_smiley_links("http://example.com/images/smileys/", "comment_textarea_alias"); -To map the alias to the field id, pass them both into the `smiley_js` -function - -:: +To map the alias to the field id, pass them both into the +:php:func:`smiley_js()` function:: $image_array = smiley_js("comment_textarea_alias", "comments"); -****************** -Function Reference -****************** - get_clickable_smileys() ======================= +.. php:function:: get_clickable_smileys($image_url, $alias = '', $smileys = NULL) + + :param string $image_url: URL path to the smileys directory + :param string $alias: Field alias + :returns: array + Returns an array containing your smiley images wrapped in a clickable link. You must supply the URL to your smiley folder and a field id or field alias. -:: +Example:: $image_array = get_smiley_links("http://example.com/images/smileys/", "comment"); -Note: Usage of this function without the second parameter, in -combination with `js_insert_smiley` has been deprecated. - smiley_js() =========== +.. php:function:: smiley_js($alias = '', $field_id = '', $inline = TRUE) + + :param string $alias: Field alias + :param string $field_id: Field ID + :param bool $inline: Whether we're inserting an inline smiley + Generates the JavaScript that allows the images to be clicked and inserted into a form field. If you supplied an alias instead of an id when generating your smiley links, you need to pass the alias and corresponding form id into the function. This function is designed to be placed into the <head> area of your web page. -:: +Example:: <?php echo smiley_js(); ?> -Note: This function replaces `js_insert_smiley`, which has been -deprecated. - parse_smileys() =============== +.. php:function:: parse_smileys($str = '', $image_url = '', $smileys = NULL) + + :param string $str: Text containing smiley codes + :param string $image_url: URL path to the smileys directory + :param array $smileys: An array of smileys + :returns: string + Takes a string of text as input and replaces any contained plain text smileys into the image equivalent. The first parameter must contain your string, the second must contain the URL to your smiley folder -:: +Example:: $str = 'Here are some simileys: :-) ;-)'; $str = parse_smileys($str, "http://example.com/images/smileys/"); echo $str; -.. |smile!| image:: ../images/smile.gif +.. |smile!| image:: ../images/smile.gif
\ No newline at end of file diff --git a/user_guide_src/source/helpers/string_helper.rst b/user_guide_src/source/helpers/string_helper.rst index 2d23fb00c..d0d302476 100644 --- a/user_guide_src/source/helpers/string_helper.rst +++ b/user_guide_src/source/helpers/string_helper.rst @@ -10,9 +10,7 @@ strings. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('string'); @@ -21,40 +19,48 @@ The following functions are available: random_string() =============== +.. php:function:: random_string($type = 'alnum', $len = 8) + + :param string $type: Randomization type + :param int $len: Output string length + :returns: string + Generates a random string based on the type and length you specify. Useful for creating passwords or generating random hashes. The first parameter specifies the type of string, the second parameter specifies the length. The following choices are available: -alpha, alunum, numeric, nozero, unique, md5, encrypt and sha1 - - **alpha**: A string with lower and uppercase letters only. - **alnum**: Alpha-numeric string with lower and uppercase characters. +- **basic**: A random number based on ``mt_rand()``. - **numeric**: Numeric string. - **nozero**: Numeric string with no zeros. -- **unique**: Encrypted with MD5 and uniqid(). Note: The length - parameter is not available for this type. Returns a fixed length 32 - character string. -- **sha1**: An encrypted random number based on do_hash() from the - :doc:`security helper <security_helper>`. - -Usage example +- **md5**: An encrypted random number based on ``md5()`` (fixed length of 32). +- **sha1**: An encrypted random number based on ``sha1()`` (fixed length of 40). -:: +Usage example:: echo random_string('alnum', 16); +.. note:: Usage of the *unique* and *encrypt* types is DEPRECATED. They + are just aliases for *md5* and *sha1* respectively. + increment_string() ================== +.. php:function:: increment_string($str, $separator = '_', $first = 1) + + :param string $str: Input string + :param string $separator: Separator to append a duplicate number with + :param int $first: Starting number + :returns: string + Increments a string by appending a number to it or increasing the number. Useful for creating "copies" or a file or duplicating database content which has unique titles or slugs. -Usage example - -:: +Usage example:: echo increment_string('file', '_'); // "file_1" echo increment_string('file', '-', 2); // "file-2" @@ -63,10 +69,13 @@ Usage example alternator() ============ -Allows two or more items to be alternated between, when cycling through -a loop. Example +.. php:function:: alternator($args) -:: + :param mixed $args: A variable number of arguments + :returns: mixed + +Allows two or more items to be alternated between, when cycling through +a loop. Example:: for ($i = 0; $i < 10; $i++) { @@ -89,21 +98,34 @@ your loop the next item will be returned. repeater() ========== -Generates repeating copies of the data you submit. Example +.. php:function:: repeater($data, $num = 1) -:: + :param string $data: Input + :param int $num: Number of times to repeat + :returns: string + +Generates repeating copies of the data you submit. Example:: - $string = "\n"; echo repeater($string, 30); + $string = "\n"; + echo repeater($string, 30); The above would generate 30 newlines. +.. note:: This function is DEPRECATED. Use the native ``str_repeat()`` + instead. + reduce_double_slashes() ======================= +.. php:function:: reduce_double_slashes($str) + + :param string $str: Input string + :returns: string + Converts double slashes in a string to a single slash, except those -found in http://. Example +found in URL protocol prefixes (e.g. http://). -:: +Example:: $string = "http://example.com//index.php"; echo reduce_double_slashes($string); // results in "http://example.com/index.php" @@ -111,16 +133,14 @@ found in http://. Example strip_slashes() =============== -Removes any slashes from a string. Example - -:: +.. php:function:: strip_slashes($data) - $str = "Is your name O\'reilly?"; - echo strip_slashes($str); // results in Is your name O'reilly? + :param array $data: Input + :returns: array -You can also use an array. Example +Removes any slashes from an array of strings. -:: +Example:: $str = array( 'question' => 'Is your name O\'reilly?', @@ -129,60 +149,66 @@ You can also use an array. Example $str = strip_slashes($str); -The above will return the following array: - -:: +The above will return the following array:: array( 'question' => "Is your name O'reilly?", 'answer' => "No, my name is O'connor." ); +.. note:: For historical reasons, this function will also accept + and handle string inputs. This however makes it just an + alias for ``stripslashes()``. + trim_slashes() ============== -Removes any leading/trailing slashes from a string. Example +.. php:function:: trim_slashes($str) -:: + :param string $str: Input string + :returns: string + +Removes any leading/trailing slashes from a string. Example:: $string = "/this/that/theother/"; echo trim_slashes($string); // results in this/that/theother +.. note:: This function is DEPRECATED. Use the native ``trim()`` instead: + | + | trim($str, '/'); reduce_multiples() ================== +.. php:function:: reduce_multiples($str, $character = '', $trim = FALSE) + + :param string $str: Text to search in + :param string $character: Character to reduce + :param bool $trim: Whether to also trim the specified character + :returns: string + Reduces multiple instances of a particular character occuring directly after each other. Example:: $string = "Fred, Bill,, Joe, Jimmy"; $string = reduce_multiples($string,","); //results in "Fred, Bill, Joe, Jimmy" -The function accepts the following parameters: - -:: - - reduce_multiples(string: text to search in, string: character to reduce, boolean: whether to remove the character from the front and end of the string) - -The first parameter contains the string in which you want to reduce the -multiplies. The second parameter contains the character you want to have -reduced. The third parameter is FALSE by default; if set to TRUE it will -remove occurences of the character at the beginning and the end of the -string. Example: - -:: +If the third parameter is set to TRUE it will remove occurences of the +character at the beginning and the end of the string. Example:: $string = ",Fred, Bill,, Joe, Jimmy,"; $string = reduce_multiples($string, ", ", TRUE); //results in "Fred, Bill, Joe, Jimmy" - quotes_to_entities() ==================== -Converts single and double quotes in a string to the corresponding HTML -entities. Example +.. php:function:: quotes_to_entities($str) -:: + :param string $str: Input string + :returns: string + +Converts single and double quotes in a string to the corresponding HTML +entities. Example:: $string = "Joe's \"dinner\""; $string = quotes_to_entities($string); //results in "Joe's "dinner"" @@ -190,8 +216,12 @@ entities. Example strip_quotes() ============== +.. php:function:: strip_quotes($str) + + :param string $str: Input string + :returns: string + Removes single and double quotes from a string. Example:: $string = "Joe's \"dinner\""; - $string = strip_quotes($string); //results in "Joes dinner" - + $string = strip_quotes($string); //results in "Joes dinner"
\ No newline at end of file diff --git a/user_guide_src/source/helpers/text_helper.rst b/user_guide_src/source/helpers/text_helper.rst index 8cb2d6f96..aec36c9a7 100644 --- a/user_guide_src/source/helpers/text_helper.rst +++ b/user_guide_src/source/helpers/text_helper.rst @@ -10,9 +10,7 @@ text. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('text'); @@ -21,7 +19,14 @@ The following functions are available: word_limiter() ============== -Truncates a string to the number of **words** specified. Example:: +.. php:function:: word_limiter($str, $limit = 100, $end_char = '…') + + :param string $str: Input string + :param int $limit: Limit + :param string $end_char: End character (usually an ellipsis) + :returns: string + +Truncates a string to the number of *words* specified. Example:: $string = "Here is a nice text string consisting of eleven words."; $string = word_limiter($string, 4); @@ -33,11 +38,18 @@ default it adds an ellipsis. character_limiter() =================== -Truncates a string to the number of **characters** specified. It +.. php:function:: character_limiter($str, $n = 500, $end_char = '…') + + :param string $str: Input string + :param int $n: Number of characters + :param string $end_char: End character (usually an ellipsis) + :returns: string + +Truncates a string to the number of *characters* specified. It maintains the integrity of words so the character count may be slightly -more or less then what you specify. Example +more or less then what you specify. -:: +Example:: $string = "Here is a nice text string consisting of eleven words."; $string = character_limiter($string, 20); @@ -46,55 +58,78 @@ more or less then what you specify. Example The third parameter is an optional suffix added to the string, if undeclared this helper uses an ellipsis. -**Note:** If you need to truncate to an exact number of characters please see -the :ref:`ellipsize` function below. +.. note:: If you need to truncate to an exact number of characters please + see the :ref:`ellipsize()` function below. ascii_to_entities() =================== +.. php:function:: ascii_to_entities($str) + + :param string $str: Input string + :returns: string + Converts ASCII values to character entities, including high ASCII and MS Word characters that can cause problems when used in a web page, so that they can be shown consistently regardless of browser settings or stored reliably in a database. There is some dependence on your server's supported character sets, so it may not be 100% reliable in all cases, but for the most part it should correctly identify characters outside -the normal range (like accented characters). Example +the normal range (like accented characters). -:: +Example:: $string = ascii_to_entities($string); entities_to_ascii() =================== -This function does the opposite of the previous one; it turns character -entities back into ASCII. +.. php:function::entities_to_ascii($str, $all = TRUE) + + :param string $str: Input string + :param bool $all: Whether to convert unsafe entities as well + :returns: string + +This function does the opposite of :php:func:`ascii_to_entities()`. +It turns character entities back into ASCII. convert_accented_characters() ============================= -Transliterates high ASCII characters to low ASCII equivalents, useful +.. php:function:: convert_accented_characters($str) + + :param string $str: Input string + :returns: string + +Transliterates high ASCII characters to low ASCII equivalents. Useful when non-English characters need to be used where only standard ASCII characters are safely used, for instance, in URLs. -:: +Example:: $string = convert_accented_characters($string); -This function uses a companion config file -`application/config/foreign_chars.php` to define the to and from array -for transliteration. +.. note:: This function uses a companion config file + `application/config/foreign_chars.php` to define the to and + from array for transliteration. word_censor() ============= +.. php:function:: word_censor($str, $censored, $replacement = '') + + :param string $str: Input string + :param array $censored: List of bad words to censor + :param string $replacement: What to replace bad words with + :returns: string + Enables you to censor words within a text string. The first parameter will contain the original string. The second will contain an array of -words which you disallow. The third (optional) parameter can contain a -replacement value for the words. If not specified they are replaced with -pound signs: ####. Example +words which you disallow. The third (optional) parameter can contain +a replacement value for the words. If not specified they are replaced +with pound signs: ####. -:: +Example:: $disallowed = array('darn', 'shucks', 'golly', 'phooey'); $string = word_censor($string, $disallowed, 'Beep!'); @@ -102,48 +137,76 @@ pound signs: ####. Example highlight_code() ================ +.. php:function:: highlight_code($str) + + :param string $str: Input string + :returns: string + Colorizes a string of code (PHP, HTML, etc.). Example:: $string = highlight_code($string); -The function uses PHP's highlight_string() function, so the colors used -are the ones specified in your php.ini file. +The function uses PHP's ``highlight_string()`` function, so the +colors used are the ones specified in your php.ini file. highlight_phrase() ================== +.. php:function:: highlight_phrase($str, $phrase, $tag_open = '<strong>', $tag_close = '</strong>') + + :param string $str: Input string + :param string $phrase: Phrase to highlight + :param string $tag_open: Opening tag used for the highlight + :param string $tag_close: Closing tag for the highlight + :returns: string + Will highlight a phrase within a text string. The first parameter will contain the original string, the second will contain the phrase you wish to highlight. The third and fourth parameters will contain the -opening/closing HTML tags you would like the phrase wrapped in. Example +opening/closing HTML tags you would like the phrase wrapped in. -:: +Example:: $string = "Here is a nice text string about nothing in particular."; - $string = highlight_phrase($string, "nice text", '<span style="color:#990000">', '</span>'); + echo highlight_phrase($string, "nice text", '<span style="color:#990000;">', '</span>'); -The above text returns: +The above code prints:: -Here is a nice text string about nothing in particular. + Here is a <span style="color:#990000;">nice text</span> string about nothing in particular. word_wrap() =========== -Wraps text at the specified **character** count while maintaining -complete words. Example +.. php:function:: word_wrap($str, $charlim = 76) + + :param string $str: Input string + :param int $charlim: Character limit + :returns: string -:: +Wraps text at the specified *character* count while maintaining +complete words. + +Example:: $string = "Here is a simple string of text that will help us demonstrate this function."; echo word_wrap($string, 25); // Would produce: Here is a simple string of text that will help us demonstrate this function -.. _ellipsize: +.. _ellipsize(): ellipsize() =========== +.. php:function:: ellipsize($str, $max_length, $position = 1, $ellipsis = '…') + + :param string $str: Input string + :param int $max_length: String length limit + :param mixed $position: Position to split at + (int or float) + :param string $ellipsis: What to use as the ellipsis character + :returns: string + This function will strip tags from a string, split it at a defined maximum length, and insert an ellipsis. @@ -156,14 +219,11 @@ string, .5 in the middle, and 0 at the left. An optional forth parameter is the kind of ellipsis. By default, … will be inserted. -:: +Example:: $str = 'this_string_is_entirely_too_long_and_might_break_my_design.jpg'; echo ellipsize($str, 32, .5); -Produces: - -:: - - this_string_is_e…ak_my_design.jpg +Produces:: + this_string_is_e…ak_my_design.jpg
\ No newline at end of file diff --git a/user_guide_src/source/helpers/typography_helper.rst b/user_guide_src/source/helpers/typography_helper.rst index f3202603a..3c81687ac 100644 --- a/user_guide_src/source/helpers/typography_helper.rst +++ b/user_guide_src/source/helpers/typography_helper.rst @@ -10,9 +10,7 @@ in semantically relevant ways. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('typography'); @@ -21,9 +19,18 @@ The following functions are available: auto_typography() ================= +.. php:function:: auto_typography($str, $reduce_linebreaks = FALSE) + + :param string $str: Input string + :param bool $reduce_linebreaks: Whether to reduce multiple instances of double newlines to two + :returns: string + Formats text so that it is semantically and typographically correct -HTML. Please see the :doc:`Typography Class <../libraries/typography>` -for more info. +HTML. + +This function is an alias for ``CI_Typography::auto_typography``. +For more info, please see the :doc:`Typography Library +<../libraries/typography>` documentation. Usage example:: @@ -31,18 +38,34 @@ Usage example:: .. note:: Typographic formatting can be processor intensive, particularly if you have a lot of content being formatted. If you choose to use this - function you may want to consider `caching </general/caching>` your pages. + function you may want to consider `caching <../general/caching>` your + pages. nl2br_except_pre() ================== -Converts newlines to <br /> tags unless they appear within <pre> tags. -This function is identical to the native PHP nl2br() function, except -that it ignores <pre> tags. +.. php:function:: nl2br_except_pre($str) -Usage example + :param string $str: Input string + :returns: string -:: +Converts newlines to <br /> tags unless they appear within <pre> tags. +This function is identical to the native PHP ``nl2br()`` function, +except that it ignores <pre> tags. + +Usage example:: $string = nl2br_except_pre($string); +entity_decode() +=============== + +.. php:function:: entity_decode($str, $charset = NULL) + + :param string $str: Input string + :param string $charset: Character set + :returns: string + +This function is an alias for ``CI_Security::entity_decode()``. +Fore more info, please see the :doc:`Security Library +<../libraries/security>` documentation.
\ No newline at end of file diff --git a/user_guide_src/source/helpers/url_helper.rst b/user_guide_src/source/helpers/url_helper.rst index e6d51b22b..5b8fa5f44 100644 --- a/user_guide_src/source/helpers/url_helper.rst +++ b/user_guide_src/source/helpers/url_helper.rst @@ -9,9 +9,7 @@ The URL Helper file contains functions that assist in working with URLs. Loading this Helper =================== -This helper is loaded using the following code - -:: +This helper is loaded using the following code:: $this->load->helper('url'); @@ -20,119 +18,135 @@ The following functions are available: site_url() ========== +.. php:function:: site_url($uri = '') + + :param string $uri: URI string + :returns: string + Returns your site URL, as specified in your config file. The index.php -file (or whatever you have set as your site index_page in your config +file (or whatever you have set as your site **index_page** in your config file) will be added to the URL, as will any URI segments you pass to the -function, and the url_suffix as set in your config file. +function, plus the **url_suffix** as set in your config file. You are encouraged to use this function any time you need to generate a local URL so that your pages become more portable in the event your URL changes. Segments can be optionally passed to the function as a string or an -array. Here is a string example +array. Here is a string example:: -:: - - echo site_url("news/local/123"); + echo site_url('news/local/123'); The above example would return something like: -http://example.com/index.php/news/local/123 - -Here is an example of segments passed as an array +*http://example.com/index.php/news/local/123* -:: +Here is an example of segments passed as an array:: $segments = array('news', 'local', '123'); echo site_url($segments); +This function is an alias for ``CI_Config::site_url()``. For more info, +please see the :doc:`Config Library <../libraries/config>` documentation. + base_url() =========== -Returns your site base URL, as specified in your config file. Example +.. php:function:: base_url($uri = '') -:: + :param string $uri: URI string + :returns: string - echo base_url(); +Returns your site base URL, as specified in your config file. Example:: -This function returns the same thing as `site_url`, without the -index_page or url_suffix being appended. + echo base_url(); -Also like site_url, you can supply segments as a string or an array. -Here is a string example +This function returns the same thing as :php:func:`site_url()`, without +the *index_page* or *url_suffix* being appended. -:: +Also like :php:func:`site_url()`, you can supply segments as a string or +an array. Here is a string example:: echo base_url("blog/post/123"); The above example would return something like: -http://example.com/blog/post/123 - -This is useful because unlike `site_url()`, you can supply a string to a -file, such as an image or stylesheet. For example +*http://example.com/blog/post/123* -:: +This is useful because unlike :php:func:`site_url()`, you can supply a +string to a file, such as an image or stylesheet. For example:: echo base_url("images/icons/edit.png"); This would give you something like: -http://example.com/images/icons/edit.png +*http://example.com/images/icons/edit.png* + +This function is an alias for ``CI_Config::base_url()``. For more info, +please see the :doc:`Config Library <../libraries/config>` documentation. current_url() ============= +.. php:function:: current_url() + + :returns: string + Returns the full URL (including segments) of the page being currently viewed. +.. note:: Calling this function is the same as doing this: + | + | site_url(uri_string()); + uri_string() ============ -Returns the URI segments of any page that contains this function. For -example, if your URL was this +.. php:function:: uri_string() -:: + :returns: string - http://some-site.com/blog/comments/123 +Returns the URI segments of any page that contains this function. +For example, if your URL was this:: -The function would return + http://some-site.com/blog/comments/123 -:: +The function would return:: /blog/comments/123 +This function is an alias for ``CI_Config::uri_string()``. For more info, +please see the :doc:`Config Library <../libraries/config>` documentation. + index_page() ============ -Returns your site "index" page, as specified in your config file. -Example +.. php:function:: index_page() -:: + :returns: string + +Returns your site **index_page**, as specified in your config file. +Example:: echo index_page(); anchor() ======== -Creates a standard HTML anchor link based on your local site URL - -:: - - <a href="http://example.com">Click Here</a> +.. php:function:: anchor($uri = '', $title = '', $attributes = '') -The tag has three optional parameters + :param string $uri: URI string + :param string $title: Anchor title + :param mixed $attributes: HTML attributes + :returns: string -:: - - anchor(uri segments, text, attributes) +Creates a standard HTML anchor link based on your local site URL. The first parameter can contain any segments you wish appended to the -URL. As with the site_url() function above, segments can be a string or -an array. +URL. As with the :php:func:`site_url()` function above, segments can +be a string or an array. .. note:: If you are building links that are internal to your application - do not include the base URL (http://...). This will be added automatically - from the information specified in your config file. Include only the - URI segments you wish appended to the URL. + do not include the base URL (http://...). This will be added + automatically from the information specified in your config file. + Include only the URI segments you wish appended to the URL. The second segment is the text you would like the link to say. If you leave it blank, the URL will be used. @@ -141,163 +155,208 @@ The third parameter can contain a list of attributes you would like added to the link. The attributes can be a simple string or an associative array. -Here are some examples - -:: +Here are some examples:: echo anchor('news/local/123', 'My News', 'title="News title"'); - -Would produce: <a href="http://example.com/index.php/news/local/123" -title="News title">My News</a> - -:: + // Prints: <a href="http://example.com/index.php/news/local/123" title="News title">My News</a> echo anchor('news/local/123', 'My News', array('title' => 'The best news!')); + // Prints: <a href="http://example.com/index.php/news/local/123" title="The best news!">My News</a> -Would produce: <a href="http://example.com/index.php/news/local/123" -title="The best news!">My News</a> + echo anchor('', 'Click here'); + // Prints: <a href="http://example.com">Click Here</a> anchor_popup() ============== -Nearly identical to the anchor() function except that it opens the URL -in a new window. You can specify JavaScript window attributes in the -third parameter to control how the window is opened. If the third -parameter is not set it will simply open a new window with your own -browser settings. Here is an example with attributes - -:: - - $atts = array( - 'width' => '800', - 'height' => '600', - 'scrollbars' => 'yes', - 'status' => 'yes', - 'resizable' => 'yes', - 'screenx' => '0', - 'screeny' => '0' +.. php:function:: anchor_popup($uri = '', $title = '', $attributes = FALSE) + + :param string $uri: URI string + :param string $title: Anchor title + :param mixed $attributes: HTML attributes + :returns: string + +Nearly identical to the :php:func:``anchor()`` function except that it +opens the URL in a new window. You can specify JavaScript window +attributes in the third parameter to control how the window is opened. +If the third parameter is not set it will simply open a new window with +your own browser settings. + +Here is an example with attributes:: + + $atts = array( + 'width' => 800, + 'height' => 600, + 'scrollbars' => 'yes', + 'status' => 'yes', + 'resizable' => 'yes', + 'screenx' => 0, + 'screeny' => 0, + 'window_name' => '_blank' ); echo anchor_popup('news/local/123', 'Click Me!', $atts); -Note: The above attributes are the function defaults so you only need to -set the ones that are different from what you need. If you want the -function to use all of its defaults simply pass an empty array in the -third parameter +.. note:: The above attributes are the function defaults so you only need to + set the ones that are different from what you need. If you want the + function to use all of its defaults simply pass an empty array in the + third parameter: + | + | echo anchor_popup('news/local/123', 'Click Me!', array()); -:: +.. note:: The **window_name** is not really an attribute, but an argument to + the JavaScript `window.open() <http://www.w3schools.com/jsref/met_win_open.asp>` + method, which accepts either a window name or a window target. - echo anchor_popup('news/local/123', 'Click Me!', array()); +.. note:: Any other attribute than the listed above will be parsed as an + HTML attribute to the anchor tag. mailto() ======== -Creates a standard HTML email link. Usage example +.. php:function:: mailto($email, $title = '', $attributes = '') + + :param string $email: E-mail address + :param string $title: Anchor title + :param mixed $attributes: HTML attributes + :returns: string -:: +Creates a standard HTML e-mail link. Usage example:: echo mailto('me@my-site.com', 'Click Here to Contact Me'); -As with the anchor() tab above, you can set attributes using the third -parameter. +As with the :php:func:`anchor()` tab above, you can set attributes using the +third parameter:: + + $attributes = array('title' => 'Mail me'); + echo mailto('me@my-site.com', 'Contact Me', $attributes); safe_mailto() ============= -Identical to the above function except it writes an obfuscated version -of the mailto tag using ordinal numbers written with JavaScript to help -prevent the email address from being harvested by spam bots. +.. php:function:: safe_mailto($email, $title = '', $attributes = '') + + :param string $email: E-mail address + :param string $title: Anchor title + :param mixed $attributes: HTML attributes + :returns: string + +Identical to the :php:func:`mailto()` function except it writes an obfuscated +version of the *mailto* tag using ordinal numbers written with JavaScript to +help prevent the e-mail address from being harvested by spam bots. auto_link() =========== -Automatically turns URLs and email addresses contained in a string into -links. Example +.. php:function:: auto_link($str, $type = 'both', $popup = FALSE) -:: + :param string $str: Input string + :param string $type: Link type ('email', 'url' or 'both') + :param bool $popup: Whether to create popup links + :returns: string + +Automatically turns URLs and e-mail addresses contained in a string into +links. Example:: $string = auto_link($string); -The second parameter determines whether URLs and emails are converted or +The second parameter determines whether URLs and e-mails are converted or just one or the other. Default behavior is both if the parameter is not -specified. Email links are encoded as safe_mailto() as shown above. - -Converts only URLs +specified. E-mail links are encoded as :php:func:`safe_mailto()` as shown +above. -:: +Converts only URLs:: $string = auto_link($string, 'url'); -Converts only Email addresses - -:: +Converts only e-mail addresses:: $string = auto_link($string, 'email'); The third parameter determines whether links are shown in a new window. -The value can be TRUE or FALSE (boolean) - -:: +The value can be TRUE or FALSE (boolean):: $string = auto_link($string, 'both', TRUE); url_title() =========== +.. php:function:: url_title($str, $separator = '-', $lowercase = FALSE) + + :param string $str: Input string + :param string $separator: Word separator + :param string $lowercase: Whether to transform the output string to lower-case + :returns: string + Takes a string as input and creates a human-friendly URL string. This is useful if, for example, you have a blog in which you'd like to use the -title of your entries in the URL. Example - -:: +title of your entries in the URL. Example:: $title = "What's wrong with CSS?"; - $url_title = url_title($title); // Produces: Whats-wrong-with-CSS + $url_title = url_title($title); + // Produces: Whats-wrong-with-CSS The second parameter determines the word delimiter. By default dashes -are used. Options are: dash, or underscore +are used. Preferred options are: **-** (dash) or **_** (underscore) -:: +Example:: $title = "What's wrong with CSS?"; - $url_title = url_title($title, 'underscore'); // Produces: Whats_wrong_with_CSS + $url_title = url_title($title, 'underscore'); + // Produces: Whats_wrong_with_CSS + +.. note:: Old usage of 'dash' and 'underscore' as the second parameter + is DEPRECATED. The third parameter determines whether or not lowercase characters are -forced. By default they are not. Options are boolean TRUE/FALSE +forced. By default they are not. Options are boolean TRUE/FALSE. -:: +Example:: $title = "What's wrong with CSS?"; - $url_title = url_title($title, 'underscore', TRUE); // Produces: whats_wrong_with_css + $url_title = url_title($title, 'underscore', TRUE); + // Produces: whats_wrong_with_css prep_url() ---------- -This function will add http:// in the event that a scheme is missing -from a URL. Pass the URL string to the function like this +.. php:function:: prep_url($str = '') + + :param string $str: URL string + :returns: string + +This function will add http:// in the event that a protocol prefix +is missing from a URL. -:: +Pass the URL string to the function like this:: - $url = "example.com"; - $url = prep_url($url); + $url = prep_url('example.com'); redirect() ========== +.. php:function:: redirect($uri = '', $method = 'auto', $code = NULL) + + :param string $uri: URI string + :param string $method: Redirect method ('auto', 'location' or 'refresh') + :param string $code: HTTP Response code (usually 302 or 303) + :returns: void + Does a "header redirect" to the URI specified. If you specify the full site URL that link will be built, but for local links simply providing the URI segments to the controller you want to direct to will create the link. The function will build the URL based on your config file values. The optional second parameter allows you to force a particular redirection -method. The available methods are "location" or "refresh", with location -being faster but less reliable on Windows servers. The default is "auto", -which will attempt to intelligently choose the method based on the server -environment. +method. The available methods are **auto**, **location** and **refresh**, +with location being faster but less reliable on IIS servers. +The default is **auto**, which will attempt to intelligently choose the +method based on the server environment. The optional third parameter allows you to send a specific HTTP Response Code - this could be used for example to create 301 redirects for search engine purposes. The default Response Code is 302. The third parameter is -*only* available with 'location' redirects, and not 'refresh'. Examples:: +*only* available with **location** redirects, and not *refresh*. Examples:: if ($logged_in == FALSE) { @@ -311,4 +370,14 @@ engine purposes. The default Response Code is 302. The third parameter is is outputted to the browser since it utilizes server headers. .. note:: For very fine grained control over headers, you should use the - `Output Library </libraries/output>` set_header() function. + `Output Library </libraries/output>` ``set_header()`` method. + +.. note:: To IIS users: if you hide the `Server` HTTP header, the *auto* + method won't detect IIS, in that case it is advised you explicitly + use the **refresh** method. + +.. note:: When the **location** method is used, an HTTP status code of 303 + will *automatically* be selected when the page is currently accessed + via POST and HTTP/1.1 is used. + +.. important:: This function will terminate script execution.
\ No newline at end of file diff --git a/user_guide_src/source/images/ci_quick_ref.png b/user_guide_src/source/images/ci_quick_ref.png Binary files differdeleted file mode 100644 index c07d6b469..000000000 --- a/user_guide_src/source/images/ci_quick_ref.png +++ /dev/null diff --git a/user_guide_src/source/images/codeigniter_1.7.1_helper_reference.pdf b/user_guide_src/source/images/codeigniter_1.7.1_helper_reference.pdf Binary files differdeleted file mode 100644 index baec6bcfb..000000000 --- a/user_guide_src/source/images/codeigniter_1.7.1_helper_reference.pdf +++ /dev/null diff --git a/user_guide_src/source/images/codeigniter_1.7.1_helper_reference.png b/user_guide_src/source/images/codeigniter_1.7.1_helper_reference.png Binary files differdeleted file mode 100644 index 15a7c1576..000000000 --- a/user_guide_src/source/images/codeigniter_1.7.1_helper_reference.png +++ /dev/null diff --git a/user_guide_src/source/images/codeigniter_1.7.1_library_reference.pdf b/user_guide_src/source/images/codeigniter_1.7.1_library_reference.pdf Binary files differdeleted file mode 100644 index 312d020eb..000000000 --- a/user_guide_src/source/images/codeigniter_1.7.1_library_reference.pdf +++ /dev/null diff --git a/user_guide_src/source/images/codeigniter_1.7.1_library_reference.png b/user_guide_src/source/images/codeigniter_1.7.1_library_reference.png Binary files differdeleted file mode 100644 index 554ae2eed..000000000 --- a/user_guide_src/source/images/codeigniter_1.7.1_library_reference.png +++ /dev/null diff --git a/user_guide_src/source/index.rst b/user_guide_src/source/index.rst index 6cdeb2442..09bf770fc 100644 --- a/user_guide_src/source/index.rst +++ b/user_guide_src/source/index.rst @@ -1,34 +1,106 @@ -Welcome to CodeIgniter -====================== - -CodeIgniter is an Application Development Framework - a toolkit - for -people who build web sites using PHP. Its goal is to enable you to -develop projects much faster than you could if you were writing code -from scratch, by providing a rich set of libraries for commonly needed -tasks, as well as a simple interface and logical structure to access -these libraries. CodeIgniter lets you creatively focus on your project -by minimizing the amount of code needed for a given task. - -Who is CodeIgniter For? -======================= - -CodeIgniter is right for you if: - -- You want a framework with a small footprint. -- You need exceptional performance. -- You need broad compatibility with standard hosting accounts that run - a variety of PHP versions and configurations. -- You want a framework that requires nearly zero configuration. -- You want a framework that does not require you to use the command - line. -- You want a framework that does not require you to adhere to - restrictive coding rules. -- You are not interested in large-scale monolithic libraries like PEAR. -- You do not want to be forced to learn a templating language (although - a template parser is optionally available if you desire one). -- You eschew complexity, favoring simple solutions. -- You need clear, thorough documentation. +###################### +CodeIgniter User Guide +###################### +- :doc:`License Agreement <license>` +- :doc:`Change Log <changelog>` + +.. contents:: + :local: + :depth: 2 + +******* +Welcome +******* + +- :doc:`general/welcome` + +********** +Basic Info +********** + +- :doc:`general/requirements` +- :doc:`general/credits` + +************ +Installation +************ + +- :doc:`installation/downloads` +- :doc:`installation/index` +- :doc:`installation/upgrading` +- :doc:`installation/troubleshooting` + +************ +Introduction +************ + +- :doc:`overview/getting_started` +- :doc:`overview/at_a_glance` +- :doc:`overview/features` +- :doc:`overview/appflow` +- :doc:`overview/mvc` +- :doc:`overview/goals` + +******** +Tutorial +******** + +- :doc:`tutorial/index` +- :doc:`tutorial/static_pages` +- :doc:`tutorial/news_section` +- :doc:`tutorial/create_news_items` +- :doc:`tutorial/conclusion` + +************** +General Topics +************** + +.. toctree:: + :glob: + :titlesonly: + + general/index + +***************** +Library Reference +***************** + +.. toctree:: + :glob: + :titlesonly: + + libraries/index + +**************** +Driver Reference +**************** + +- :doc:`libraries/caching` +- :doc:`database/index` +- :doc:`libraries/javascript` +- :doc:`libraries/sessions` + +**************** +Helper Reference +**************** + +.. toctree:: + :glob: + :titlesonly: + + helpers/index + +*************************** +Contributing to CodeIgniter +*************************** + +.. toctree:: + :glob: + :titlesonly: + + contributing/index + DCO .. toctree:: :glob: @@ -38,6 +110,7 @@ CodeIgniter is right for you if: * overview/index general/requirements + general/welcome installation/index general/index libraries/index @@ -45,5 +118,4 @@ CodeIgniter is right for you if: database/index documentation/index tutorial/index - general/quick_reference - general/credits
\ No newline at end of file + general/credits diff --git a/user_guide_src/source/installation/downloads.rst b/user_guide_src/source/installation/downloads.rst index a4a6b7fbe..45a8f80a7 100644 --- a/user_guide_src/source/installation/downloads.rst +++ b/user_guide_src/source/installation/downloads.rst @@ -2,9 +2,15 @@ Downloading CodeIgniter ####################### -- `CodeIgniter V 2.1.0 (Current +- `CodeIgniter V 3.0.0 (Current version) <http://codeigniter.com/downloads/>`_ - `CodeIgniter V + 2.1.2 <http://codeigniter.com/download_files/reactor/CodeIgniter_2.1.2.zip>`_ +- `CodeIgniter V + 2.1.1 <http://codeigniter.com/download_files/reactor/CodeIgniter_2.1.1.zip>`_ +- `CodeIgniter V + 2.1.0 <http://codeigniter.com/download_files/reactor/CodeIgniter_2.1.0.zip>`_ +- `CodeIgniter V 2.0.3 <http://codeigniter.com/download_files/reactor/CodeIgniter_2.0.3.zip>`_ - `CodeIgniter V 2.0.2 <http://codeigniter.com/download_files/reactor/CodeIgniter_2.0.2.zip>`_ diff --git a/user_guide_src/source/installation/upgrade_200.rst b/user_guide_src/source/installation/upgrade_200.rst index b39f4fd23..29f44bd9e 100644 --- a/user_guide_src/source/installation/upgrade_200.rst +++ b/user_guide_src/source/installation/upgrade_200.rst @@ -87,7 +87,14 @@ All native CodeIgniter classes now use the PHP 5 \__construct() convention. Please update extended libraries to call parent::\__construct(). -Step 8: Update your user guide +Step 8: Move any core extensions to application/core +==================================================== + +Any extensions to core classes (e.g. MY_Controller.php) in your +application/libraries folder must be moved to the new +application/core folder. + +Step 9: Update your user guide ============================== Please replace your local copy of the user guide with the new version, diff --git a/user_guide_src/source/installation/upgrade_210.rst b/user_guide_src/source/installation/upgrade_210.rst index 9d7e1a265..5874bfc86 100644 --- a/user_guide_src/source/installation/upgrade_210.rst +++ b/user_guide_src/source/installation/upgrade_210.rst @@ -8,15 +8,19 @@ replacing the index.php file with a static one. Step 1: Update your CodeIgniter files ===================================== -Replace all files and directories in your "system" folder and replace -your index.php file. If any modifications were made to your index.php -they will need to be made fresh in this new one. +Replace all files and directories in your "system" folder. + +.. note:: If you have any custom developed files in these folders please + make copies of them first. Step 2: Replace config/user_agents.php ====================================== This config file has been updated to contain more user agent types, -please copy it to application/config/user_agents.php. +please copy it to _application/config/user_agents.php*. -.. note:: If you have any custom developed files in these folders please - make copies of them first.
\ No newline at end of file +Step 3: Update your user guide +============================== + +Please also replace your local copy of the user guide with the new +version.
\ No newline at end of file diff --git a/user_guide_src/source/installation/upgrade_211.rst b/user_guide_src/source/installation/upgrade_211.rst new file mode 100644 index 000000000..f0e70f6dc --- /dev/null +++ b/user_guide_src/source/installation/upgrade_211.rst @@ -0,0 +1,31 @@ +############################# +Upgrading from 2.1.0 to 2.1.1 +############################# + +Before performing an update you should take your site offline by +replacing the index.php file with a static one. + +Step 1: Update your CodeIgniter files +===================================== + +Replace all files and directories in your "system" folder. + +.. note:: If you have any custom developed files in these folders please + make copies of them first. + +Step 2: Replace config/mimes.php +================================ + +This config file has been updated to contain more user mime-types, please copy +it to _application/config/mimes.php*. + +Step 3: Update your IP address tables +===================================== + +This upgrade adds support for IPv6 IP addresses. In order to store them, you need +to enlarge your ip_address columns to 45 characters. For example, CodeIgniter's +session table will need to change + +:: + + ALTER TABLE ci_sessions CHANGE ip_address ip_address varchar(45) default '0' NOT NULL
\ No newline at end of file diff --git a/user_guide_src/source/installation/upgrade_212.rst b/user_guide_src/source/installation/upgrade_212.rst new file mode 100644 index 000000000..4b76482e3 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_212.rst @@ -0,0 +1,20 @@ +############################# +Upgrading from 2.1.1 to 2.1.2 +############################# + +Before performing an update you should take your site offline by +replacing the index.php file with a static one. + +Step 1: Update your CodeIgniter files +===================================== + +Replace all files and directories in your "system" folder. + +.. note:: If you have any custom developed files in these folders please + make copies of them first. + +Step 2: Update your user guide +============================== + +Please also replace your local copy of the user guide with the new +version.
\ No newline at end of file diff --git a/user_guide_src/source/installation/upgrade_213.rst b/user_guide_src/source/installation/upgrade_213.rst new file mode 100644 index 000000000..3a3497ccb --- /dev/null +++ b/user_guide_src/source/installation/upgrade_213.rst @@ -0,0 +1,20 @@ +############################# +Upgrading from 2.1.2 to 2.1.3 +############################# + +Before performing an update you should take your site offline by +replacing the index.php file with a static one. + +Step 1: Update your CodeIgniter files +===================================== + +Replace all files and directories in your "system" folder. + +.. note:: If you have any custom developed files in these folders please + make copies of them first. + +Step 2: Update your user guide +============================== + +Please also replace your local copy of the user guide with the new +version.
\ No newline at end of file diff --git a/user_guide_src/source/installation/upgrade_300.rst b/user_guide_src/source/installation/upgrade_300.rst index 4c594ab17..0af21b11e 100644 --- a/user_guide_src/source/installation/upgrade_300.rst +++ b/user_guide_src/source/installation/upgrade_300.rst @@ -1,15 +1,14 @@ ############################# -Upgrading from 2.1.0 to 3.0.0 +Upgrading from 2.1.2 to 3.0.0 ############################# .. note:: These upgrade notes are for a version that is yet to be released. +Before performing an update you should take your site offline by replacing the index.php file with a static one. -Before performing an update you should take your site offline by -replacing the index.php file with a static one. - +************************************* Step 1: Update your CodeIgniter files -===================================== +************************************* Replace all files and directories in your "system" folder and replace your index.php file. If any modifications were made to your index.php @@ -18,16 +17,301 @@ they will need to be made fresh in this new one. .. note:: If you have any custom developed files in these folders please make copies of them first. -Step 2: Change References to the SHA Library -============================================ - -The previously deprecated SHA library has been removed in CodeIgniter 3.0. -Alter your code to use the native `sha1()` PHP function to generate a sha1 hash. +******************************** +Step 2: Replace config/mimes.php +******************************** -Additionally, the `sha1()` method in the :doc:`Encryption Library <../libraries/encryption>` has been removed. +This config file has been updated to contain more user mime-types, please copy +it to _application/config/mimes.php*. +************************************************************** Step 3: Remove $autoload['core'] from your config/autoload.php -============================================================== +************************************************************** + +Use of the ``$autoload['core']`` config array has been deprecated as of CodeIgniter 1.4.1 and is now removed. +Move any entries that you might have listed there to ``$autoload['libraries']`` instead. + +*************************************************** +Step 4: Move your Log class overrides or extensions +*************************************************** + +The Log Class is considered as a "core" class and is now located in the +**system/core/** directory. Therefore, in order for your Log class overrides +or extensions to work, you need to move them to **application/core/**:: + + application/libraries/Log.php -> application/core/Log.php + application/libraries/MY_Log.php -> application/core/MY_log.php + +************************************************************** +Step 5: Add new session driver items to your config/config.php +************************************************************** + +With the change from a single Session Library to the new Session Driver, two new config items have been added: + + - ``$config['sess_driver']`` selects which driver to initially load. Options are: + - 'cookie' (the default) for classic CodeIgniter cookie-based sessions + - 'native' for native PHP Session support + - the name of a custom driver you have provided (see :doc:`Session Driver <../libraries/sessions>` for more info) + - ``$config['sess_valid_drivers']`` provides an array of additional custom drivers to make available for loading + +As the new Session Driver library loads the classic Cookie driver by default and always makes 'cookie' and 'native' +available as valid drivers, neither of these configuration items are required. However, it is recommended that you +add them for clarity and ease of configuration in the future. + +*************************************** +Step 6: Update your config/database.php +*************************************** + +Due to 3.0.0's renaming of Active Record to Query Builder, inside your `config/database.php`, you will +need to rename the `$active_record` variable to `$query_builder` +:: + + $active_group = 'default'; + // $active_record = TRUE; + $query_builder = TRUE; + +******************************* +Step 7: Move your errors folder +******************************* + +In version 3.0.0, the errors folder has been moved from _application/errors* to _application/views/errors*. + +******************************************************* +Step 8: Update your config/routes.php containing (:any) +******************************************************* + +Historically, CodeIgniter has always provided the **:any** wildcard in routing, +with the intention of providing a way to match any character **within** an URI segment. + +However, the **:any** wildcard is actually just an alias for a regular expression +and used to be executed in that manner as **.+**. This is considered a bug, as it +also matches the / (forward slash) character, which is the URI segment delimiter +and that was never the intention. In CodeIgniter 3, the **:any** wildcard will now +represent **[^/]+**, so that it will not match a forward slash. + +There are certainly many developers that have utilized this bug as an actual feature. +If you're one of them and want to match a forward slash, please use the **.+** +regular expression:: + + (.+) // matches ANYTHING + (:any) // matches any character, except for '/' + + +**************************************************************************** +Step 9: Check the calls to Array Helper's element() and elements() functions +**************************************************************************** + +The default return value of these functions, when the required elements +don't exist, has been changed from FALSE to NULL. + +************************************************************* +Step 10: Update usage of Database Forge's drop_table() method +************************************************************* + +Up until now, ``drop_table()`` added an IF EXISTS clause by default or it didn't work +at all with some drivers. In CodeIgniter 3.0, the IF EXISTS condition is no longer added +by default and has an optional second parameter that allows that instead and is set to +FALSE by default. + +If your application relies on IF EXISTS, you'll have to change its usage. + +:: + + // Now produces just DROP TABLE `table_name` + $this->dbforge->drop_table('table_name'); + + // Produces DROP TABLE IF EXISTS `table_name` + $this->dbforge->drop_table('table_name', TRUE); + +.. note:: The given example users MySQL-specific syntax, but it should work across + all drivers with the exception of ODBC. + +*********************************************************** +Step 11: Change usage of Email library with multiple emails +*********************************************************** + +The :doc:`Email library <../libraries/email>` will automatically clear the +set parameters after successfully sending emails. To override this behaviour, +pass FALSE as the first parameter in the ``send()`` method: + +:: + + if ($this->email->send(FALSE)) + { + // Parameters won't be cleared + } + + +**************************************************************** +Step 12: Remove usage of (previously) deprecated functionalities +**************************************************************** + +In addition to the ``$autoload['core']`` configuration setting, there's a number of other functionalities +that have been removed in CodeIgniter 3.0.0: + +The SHA1 library +================ + +The previously deprecated SHA1 library has been removed, alter your code to use PHP's native +``sha1()`` function to generate a SHA1 hash. + +Additionally, the ``sha1()`` method in the :doc:`Encryption Library <../libraries/encryption>` has been removed. + +The EXT constant +================ + +Usage of the ``EXT`` constant has been deprecated since dropping support for PHP 4. There's no +longer a need to maintain different filename extensions and in this new CodeIgniter version, +the ``EXT`` constant has been removed. Use just '.php' instead. + +Smiley helper js_insert_smiley() +================================ + +:doc:`Smiley Helper <../helpers/smiley_helper>` function ``js_insert_smiley()`` has been deprecated +since CodeIgniter 1.7.2 and is now removed. You'll need to switch to ``smiley_js()`` instead. + +Security helper do_hash() +========================= + +:doc:`Security Helper <../helpers/security_helper>` function ``do_hash()`` is now just an alias for +PHP's native ``hash()`` function. It is deprecated and scheduled for removal in CodeIgniter 3.1+. + +.. note:: This function is still available, but you're strongly encouraged to remove it's usage sooner + rather than later. + +File helper read_file() +======================= + +:doc:`File Helper <../helpers/file_helper>` function ``read_file()`` is now just an alias for +PHP's native ``file_get_contents()`` function. It is deprecated and scheduled for removal in +CodeIgniter 3.1+. + +.. note:: This function is still available, but you're strongly encouraged to remove it's usage sooner + rather than later. + +String helper repeater() +======================== + +:doc:`String Helper <../helpers/string_helper>` function :php:func:`repeater()` is now just an alias for +PHP's native ``str_repeat()`` function. It is deprecated and scheduled for removal in CodeIgniter 3.1+. + +.. note:: This function is still available, but you're strongly encouraged to remove it's usage sooner + rather than later. + +String helper trim_slashes() +============================ + +:doc:`String Helper <../helpers/string_helper>` function :php:func:`trim_slashes()` is now just an alias +for PHP's native ``trim()`` function (with a slash passed as its second argument). It is deprecated and +scheduled for removal in CodeIgniter 3.1+. + +.. note:: This function is still available, but you're strongly encouraged to remove it's usage sooner + rather than later. + +Email helper functions +====================== + +:doc:`Email Helper <../helpers/email_helper>` only has two functions + + - :php:func:`valid_email()` + - :php:func:`send_email()` + +Both of them are now aliases for PHP's native ``filter_var()`` and ``mail()`` functions, respectively. +Therefore the :doc:`Email Helper <../helpers/email_helper>` altogether is being deprecated and +is scheduled for removal in CodeIgniter 3.1+. + +.. note:: These functions are still available, but you're strongly encouraged to remove their usage + sooner rather than later. + +Date helper standard_date() +=========================== + +:doc:`Date Helper <../helpers/date_helper>` function ``standard_date()`` is being deprecated due +to the availability of native PHP `constants <http://www.php.net/manual/en/class.datetime.php#datetime.constants.types>`_, +which when combined with ``date()`` provide the same functionality. Furthermore, they have the +exact same names as the ones supported by ``standard_date()``. Here are examples of how to replace +it's usage: + +:: + + // Old way + standard_date(); // defaults to standard_date('DATE_RFC822', now()); + + // Replacement + date(DATE_RFC822, now()); + + // Old way + standard_date('DATE_ATOM', $time); + + // Replacement + date(DATE_ATOM, $time); + +.. note:: This function is still available, but you're strongly encouraged to remove its' usage sooner + rather than later as it is scheduled for removal in CodeIgniter 3.1+. + +Pagination library 'anchor_class' setting +========================================= + +The :doc:`Pagination Library <../libraries/pagination>` now supports adding pretty much any HTML +attribute to your anchors via the 'attributes' configuration setting. This includes passing the +'class' attribute and using the separate 'anchor_class' setting no longer makes sense. +As a result of that, the 'anchor_class' setting is now deprecated and scheduled for removal in +CodeIgniter 3.1+. + +.. note:: This setting is still available, but you're strongly encouraged to remove its' usage sooner + rather than later. + +String helper random_string() types 'unique' and 'encrypt' +========================================================== + +When using the :doc:`String Helper <helpers/string_helper>` function :php:func:`random_string()`, +you should no longer pass the **unique** and **encrypt** randomization types. They are only +aliases for **md5** and **sha1** respectively and are now deprecated and scheduled for removal +in CodeIgniter 3.1+. + +.. note:: These options are still available, but you're strongly encouraged to remove their usage + sooner rather than later. + +URL helper url_title() separators 'dash' and 'underscore' +========================================================= + +When using the :doc:`URL Helper <helpers/url_helper>` function :php:func:`url_title()`, you +should no longer pass **dash** or **underscore** as the word separator. This function will +now accept any character and you should just pass the chosen character directly, so you +should write '-' instead of 'dash' and '_' instead of 'underscore'. + +**dash** and **underscore** now act as aliases and are deprecated and scheduled for removal +in CodeIgniter 3.1+. + +.. note:: These options are still available, but you're strongly encouraged to remove their usage + sooner rather than later. + +Database Forge method add_column() with an AFTER clause +======================================================= + +If you have used the **third parameter** for :doc:`Database Forge <database/forge>` method +``add_column()`` to add a field for an AFTER clause, then you should change its usage. + +That third parameter has been deprecated and scheduled for removal in CodeIgniter 3.1+. + +You should now put AFTER clause field names in the field definition array instead:: + + // Old usage: + $field = array( + 'new_field' => array('type' => 'TEXT') + ); + + $this->dbforge->add_column('table_name', $field, 'another_field'); + + // New usage: + $field = array( + 'new_field' => array('type' => 'TEXT', 'after' => 'another_field') + ); + + $this->dbforge->add_column('table_name', $field); + +.. note:: The parameter is still available, but you're strongly encouraged to remove its usage + sooner rather than later. -Use of the `$autoload['core']` config array has been deprecated as of CodeIgniter 1.4.1 and is now removed. -Move any entries that you might have listed there to `$autoload['libraries']` instead. +.. note:: This is for MySQL and CUBRID databases only! Other drivers don't support this + clause and will silently ignore it. diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index 2badffc93..4f276207c 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -5,6 +5,10 @@ Upgrading From a Previous Version Please read the upgrade notes corresponding to the version you are upgrading from. +- :doc:`Upgrading from 2.1.3 to 3.0.0 <upgrade_300>` +- :doc:`Upgrading from 2.1.2 to 2.1.3 <upgrade_213>` +- :doc:`Upgrading from 2.1.1 to 2.1.2 <upgrade_212>` +- :doc:`Upgrading from 2.1.0 to 2.1.1 <upgrade_211>` - :doc:`Upgrading from 2.0.3 to 2.1.0 <upgrade_210>` - :doc:`Upgrading from 2.0.2 to 2.0.3 <upgrade_203>` - :doc:`Upgrading from 2.0.1 to 2.0.2 <upgrade_202>` diff --git a/user_guide_src/source/libraries/caching.rst b/user_guide_src/source/libraries/caching.rst index 2f06d29f9..8d7b4c440 100644 --- a/user_guide_src/source/libraries/caching.rst +++ b/user_guide_src/source/libraries/caching.rst @@ -32,6 +32,17 @@ available in the hosting environment. echo $foo; +You can also prefix cache item names via the **key_prefix** setting, which is useful +to avoid collisions when you're running multiple applications on the same environment. + +:: + + $this->load->driver('cache', + array('adapter' => 'apc', 'backup' => 'file', 'key_prefix' => 'my_') + ); + + $this->cache->get('foo'); // Will get the cache entry named 'my_foo' + ****************** Function Reference ****************** @@ -39,7 +50,7 @@ Function Reference .. php:class:: CI_Cache is_supported() -=============== +============== .. php:method:: is_supported ( $driver ) @@ -130,7 +141,7 @@ clean() $this->cache->clean(); cache_info() -============= +============ .. php:method:: cache_info ( ) @@ -148,7 +159,7 @@ cache_info() get_metadata() -=============== +============== .. php:method:: get_metadata ( $id ) @@ -166,7 +177,6 @@ get_metadata() .. note:: The information returned and the structure of the data is dependent on which adapter is being used. - ******* Drivers ******* @@ -181,7 +191,7 @@ specific adapter to the driver loader as follows:: $this->cache->apc->save('foo', 'bar', 10); For more information on APC, please see -`http://php.net/apc <http://php.net/apc>`_ +`http://php.net/apc <http://php.net/apc>`_. File-based Caching ================== @@ -201,20 +211,49 @@ Memcached Caching ================= Multiple Memcached servers can be specified in the memcached.php -configuration file, located in the application/config/ directory. +configuration file, located in the _application/config/* directory. -All of the functions listed above can be accessed without passing a +All of the methods listed above can be accessed without passing a specific adapter to the driver loader as follows:: $this->load->driver('cache'); $this->cache->memcached->save('foo', 'bar', 10); For more information on Memcached, please see -`http://php.net/memcached <http://php.net/memcached>`_ +`http://php.net/memcached <http://php.net/memcached>`_. + +WinCache Caching +================ + +Under Windows, you can also utilize the WinCache driver. + +All of the functions listed above can be accessed without passing a +specific adapter to the driver loader as follows:: + + $this->load->driver('cache'); + $this->cache->wincache->save('foo', 'bar', 10); + +For more information on WinCache, please see +`http://php.net/wincache <http://php.net/wincache>`_. + +Redis Caching +============= + +All of the methods listed above can be accessed without passing a +specific adapter to the driver loader as follows:: + + $this->load->driver('cache'); + $this->cache->redis->save('foo', 'bar', 10); + +.. important:: Redis may require one or more of the following options: + **host**, **post**, **timeout**, **password**. + +The Redis PHP extension repository is located at +`https://github.com/nicolasff/phpredis <https://github.com/nicolasff/phpredis>`_. Dummy Cache =========== This is a caching backend that will always 'miss.' It stores no data, but lets you keep your caching code in place in environments that don't -support your chosen cache. +support your chosen cache.
\ No newline at end of file diff --git a/user_guide_src/source/libraries/cart.rst b/user_guide_src/source/libraries/cart.rst index 6594b3b9a..716e94bcb 100644 --- a/user_guide_src/source/libraries/cart.rst +++ b/user_guide_src/source/libraries/cart.rst @@ -279,16 +279,22 @@ by which this is returned by passing it "true" where the contents will be sorted from newest to oldest, by leaving this function blank, you'll automatically just get first added to the basket to last added to the basket. -$this->cart->has_options(rowid); -******************************** +$this->cart->get_item($row_id); +******************************* + +Returns an array containing data for the item matching the specified row ID, +or FALSE if no such item exists. + +$this->cart->has_options($row_id); +********************************** Returns TRUE (boolean) if a particular row in the cart contains options. This function is designed to be used in a loop with $this->cart->contents(), since you must pass the rowid to this function, as shown in the Displaying the Cart example above. -$this->cart->product_options(rowid); -************************************ +$this->cart->product_options($row_id); +************************************** Returns an array of options for a particular product. This function is designed to be used in a loop with $this->cart->contents(), since you diff --git a/user_guide_src/source/libraries/config.rst b/user_guide_src/source/libraries/config.rst index c81cad7b3..08d9c2905 100644 --- a/user_guide_src/source/libraries/config.rst +++ b/user_guide_src/source/libraries/config.rst @@ -149,11 +149,13 @@ folders: - Your own custom configuration files .. note:: - CodeIgniter always tries to load the configuration files for - the current environment first. If the file does not exist, the global - config file (i.e., the one in application/config/) is loaded. This means - you are not obligated to place **all** of your configuration files in an - environment folder − only the files that change per environment. + CodeIgniter always loads the global config file first (i.e., the one in application/config/), + then tries to load the configuration files for the current environment. + This means you are not obligated to place **all** of your configuration files in an + environment folder. Only the files that change per environment. Additionally you don't + have to copy **all** the config items in the environment config file. Only the config items + that you wish to change for your environment. The config items declared in your environment + folders always overwrite those in your global config files. Helper Functions ================ diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst index daf000907..da3bf2616 100644 --- a/user_guide_src/source/libraries/email.rst +++ b/user_guide_src/source/libraries/email.rst @@ -97,7 +97,7 @@ Preference Default Value Options Descript **mailtype** text text or html Type of mail. If you send HTML email you must send it as a complete web page. Make sure you don't have any relative links or relative image paths otherwise they will not work. -**charset** utf-8 Character set (utf-8, iso-8859-1, etc.). +**charset** ``$config['charset']`` Character set (utf-8, iso-8859-1, etc.). **validate** FALSE TRUE or FALSE (boolean) Whether to validate the email address. **priority** 3 1, 2, 3, 4, 5 Email Priority. 1 = highest. 5 = lowest. 3 = normal. **crlf** \\n "\\r\\n" or "\\n" or "\\r" Newline character. (Use "\\r\\n" to comply with RFC 822). @@ -117,6 +117,13 @@ Sets the email address and name of the person sending the email:: $this->email->from('you@example.com', 'Your Name'); +You can also set a Return-Path, to help redirect undelivered mail:: + + $this->email->from('you@example.com', 'Your Name', 'returned_emails@example.com'); + +.. note:: Return-Path can't be used if you've configured + 'smtp' as your protocol. + $this->email->reply_to() ------------------------- @@ -182,6 +189,14 @@ formatting which is added to the header string for people who do not accept HTML email. If you do not set your own message CodeIgniter will extract the message from your HTML email and strip the tags. +$this->email->set_header() +-------------------------- + +Appends additional headers to the e-mail:: + + $this->email->set_header('Header1', 'Value1'); + $this->email->set_header('Header2', 'Value2'); + $this->email->clear() --------------------- @@ -218,6 +233,14 @@ success or failure, enabling it to be used conditionally:: // Generate error } +This function will automatically clear all parameters if the request was +successful. To stop this behaviour pass FALSE:: + + if ($this->email->send(FALSE)) + { + // Parameters won't be cleared + } + $this->email->attach() ---------------------- diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst index 28bdca203..a38122203 100644 --- a/user_guide_src/source/libraries/encryption.rst +++ b/user_guide_src/source/libraries/encryption.rst @@ -26,7 +26,7 @@ key security so you may want to think carefully before using it for anything that requires high security, like storing credit card numbers. To take maximum advantage of the encryption algorithm, your key should -be 32 characters in length (128 bits). The key should be as random a +be 32 characters in length (256 bits). The key should be as random a string as you can concoct, with numbers and uppercase and lowercase letters. Your key should **not** be a simple text string. In order to be cryptographically secure it needs to be as random as possible. diff --git a/user_guide_src/source/libraries/file_uploading.rst b/user_guide_src/source/libraries/file_uploading.rst index d573fc770..1698dcbb9 100644 --- a/user_guide_src/source/libraries/file_uploading.rst +++ b/user_guide_src/source/libraries/file_uploading.rst @@ -197,6 +197,7 @@ Preference Default Value Options Descripti Separate multiple types with a pipe. **file_name** None Desired file name If set CodeIgniter will rename the uploaded file to this name. The extension provided in the file name must also be an allowed file type. + If no extension is provided in the original file_name will be used. **overwrite** FALSE TRUE/FALSE (boolean) If set to true, if a file with the same name as the one you are uploading exists, it will be overwritten. If set to false, a number will be appended to the filename if another with the same name exists. @@ -215,6 +216,9 @@ Preference Default Value Options Descripti that can not be discerned by the person uploading it. **remove_spaces** TRUE TRUE/FALSE (boolean) If set to TRUE, any spaces in the file name will be converted to underscores. This is recommended. +**detect_mime** TRUE TRUE/FALSE (boolean) If set to TRUE, a server side detection of the file type will be + performed to avoid code injection attacks. DO NOT disable this option + unless you have no other option as that would cause a security risk. ============================ ================= ======================= ====================================================================== Setting preferences in a config file @@ -287,6 +291,10 @@ data related to the file you uploaded. Here is the array prototype:: [image_size_str] => width="800" height="200" ) +To return one element from the array:: + + $this->upload->data('file_name'); // Returns: mypic.jpg + Explanation *********** diff --git a/user_guide_src/source/libraries/form_validation.rst b/user_guide_src/source/libraries/form_validation.rst index 028b61c4c..a3a35b499 100644 --- a/user_guide_src/source/libraries/form_validation.rst +++ b/user_guide_src/source/libraries/form_validation.rst @@ -254,30 +254,30 @@ Setting Rules Using an Array Before moving on it should be noted that the rule setting function can be passed an array if you prefer to set all your rules in one action. If -you use this approach you must name your array keys as indicated:: +you use this approach, you must name your array keys as indicated:: $config = array( - array( - 'field' => 'username', - 'label' => 'Username', - 'rules' => 'required' - ), - array( - 'field' => 'password', - 'label' => 'Password', - 'rules' => 'required' - ), - array( - 'field' => 'passconf', - 'label' => 'Password Confirmation', - 'rules' => 'required' - ), - array( - 'field' => 'email', - 'label' => 'Email', - 'rules' => 'required' - ) - ); + array( + 'field' => 'username', + 'label' => 'Username', + 'rules' => 'required' + ), + array( + 'field' => 'password', + 'label' => 'Password', + 'rules' => 'required' + ), + array( + 'field' => 'passconf', + 'label' => 'Password Confirmation', + 'rules' => 'required' + ), + array( + 'field' => 'email', + 'label' => 'Email', + 'rules' => 'required' + ) + ); $this->form_validation->set_rules($config); @@ -288,10 +288,9 @@ CodeIgniter lets you pipe multiple rules together. Let's try it. Change your rules in the third parameter of rule setting function, like this:: $this->form_validation->set_rules('username', 'Username', 'required|min_length[5]|max_length[12]|is_unique[users.username]'); - $this->form_validation->set_rules('password', 'Password', 'required|matches[passconf]'); - $this->form_validation->set_rules('passconf', 'Password Confirmation', 'required'); + $this->form_validation->set_rules('password', 'Password', 'required'); + $this->form_validation->set_rules('passconf', 'Password Confirmation', 'required|matches[password]'); $this->form_validation->set_rules('email', 'Email', 'required|valid_email|is_unique[users.email]'); - The above code sets the following rules: @@ -304,6 +303,10 @@ Give it a try! Submit your form without the proper data and you'll see new error messages that correspond to your new rules. There are numerous rules available which you can read about in the validation reference. +.. note:: You can also pass an array of rules to set_rules(), instead of a string. Example:: + + $this->form_validation->set_rules('username', 'Username', array('required', 'min_length[5]')); + Prepping Data ============= @@ -312,8 +315,8 @@ can also prep your data in various ways. For example, you can set up rules like this:: $this->form_validation->set_rules('username', 'Username', 'trim|required|min_length[5]|max_length[12]|xss_clean'); - $this->form_validation->set_rules('password', 'Password', 'trim|required|matches[passconf]|md5'); - $this->form_validation->set_rules('passconf', 'Password Confirmation', 'trim|required'); + $this->form_validation->set_rules('password', 'Password', 'trim|required|md5'); + $this->form_validation->set_rules('passconf', 'Password Confirmation', 'trim|required|matches[password]'); $this->form_validation->set_rules('email', 'Email', 'trim|required|valid_email'); In the above example, we are "trimming" the fields, converting the @@ -395,7 +398,7 @@ The validation system supports callbacks to your own validation functions. This permits you to extend the validation class to meet your needs. For example, if you need to run a database query to see if the user is choosing a unique username, you can create a callback function -that does that. Let's create a example of this. +that does that. Let's create an example of this. In your controller, change the "username" rule to this:: @@ -484,6 +487,17 @@ the name of the function:: $this->form_validation->set_message('username_check') +If you are using an error message that can accept two $s in your error string, +such as: +:: + + $this->form_validation->set_message('min_length', 'The $s field must contain at least $s characters.'); + +Then you can also use %1$s and %2$s: +:: + + $this->form_validation->set_message('min_length', 'This field must contain at least %2$s characters.'); + You can also override any error message found in the language file. For example, to change the message for the "required" rule you will do this:: @@ -545,11 +559,10 @@ globally, individually, or change the defaults in a config file. #. **Set delimiters in a config file** You can add your error delimiters in application/config/form_validation.php as follows:: - + $config['error_prefix'] = '<div class="error_prefix">'; $config['error_suffix'] = '</div>'; - Showing Errors Individually =========================== @@ -577,8 +590,8 @@ Try it! Change your form so that it looks like this:: If there are no errors, nothing will be shown. If there is an error, the message will appear. -**Important Note:** If you use an array as the name of a form field, you -must supply it as an array to the function. Example:: +.. important:: If you use an array as the name of a form field, you + must supply it as an array to the function. Example:: <?php echo form_error('options[size]'); ?> <input type="text" name="options[size]" value="<?php echo set_value("options[size]"); ?>" size="50" /> @@ -588,20 +601,20 @@ For more info please see the :ref:`using-arrays-as-field-names` section below. Validating an Array (other than $_POST) ======================================= -Sometimes you may want to validate an array that does not originate from $_POST data. +Sometimes you may want to validate an array that does not originate from ``$_POST`` data. In this case, you can specify the array to be validated:: - + $data = array( - 'username' => 'johndoe', - 'password' => 'mypassword', - 'passconf' => 'mypassword' - ); + 'username' => 'johndoe', + 'password' => 'mypassword', + 'passconf' => 'mypassword' + ); $this->form_validation->set_data($data); -Creating validation rules, running the validation and retrieving error messages works the same whether you are -validating $_POST data or an array. +Creating validation rules, running the validation and retrieving error messages works the +same whether you are validating ``$_POST`` data or an array. **Important Note:** If you want to validate more than one array during a single execution, then you should call the reset_validation() function before setting up rules and validating the new array. @@ -629,32 +642,32 @@ you will place an array named $config with your rules. As shown earlier, the validation array will have this prototype:: $config = array( - array( - 'field' => 'username', - 'label' => 'Username', - 'rules' => 'required' - ), - array( - 'field' => 'password', - 'label' => 'Password', - 'rules' => 'required' - ), - array( - 'field' => 'passconf', - 'label' => 'Password Confirmation', - 'rules' => 'required' - ), - array( - 'field' => 'email', - 'label' => 'Email', - 'rules' => 'required' - ) - ); + array( + 'field' => 'username', + 'label' => 'Username', + 'rules' => 'required' + ), + array( + 'field' => 'password', + 'label' => 'Password', + 'rules' => 'required' + ), + array( + 'field' => 'passconf', + 'label' => 'Password Confirmation', + 'rules' => 'required' + ), + array( + 'field' => 'email', + 'label' => 'Email', + 'rules' => 'required' + ) + ); Your validation rule file will be loaded automatically and used when you -call the run() function. +call the ``run()`` method. -Please note that you MUST name your array $config. +Please note that you MUST name your ``$config`` array. Creating Sets of Rules ====================== @@ -714,45 +727,44 @@ You can name your rules anything you want:: Calling a Specific Rule Group ============================= -In order to call a specific group you will pass its name to the run() -function. For example, to call the signup rule you will do this:: +In order to call a specific group you will pass its name to the ``run()`` +method. For example, to call the signup rule you will do this:: if ($this->form_validation->run('signup') == FALSE) { - $this->load->view('myform'); + $this->load->view('myform'); } else { - $this->load->view('formsuccess'); + $this->load->view('formsuccess'); } Associating a Controller Function with a Rule Group =================================================== An alternate (and more automatic) method of calling a rule group is to -name it according to the controller class/function you intend to use it +name it according to the controller class/method you intend to use it with. For example, let's say you have a controller named Member and a -function named signup. Here's what your class might look like:: +method named signup. Here's what your class might look like:: <?php class Member extends CI_Controller { - function signup() - { - $this->load->library('form_validation'); - - if ($this->form_validation->run() == FALSE) - { - $this->load->view('myform'); - } - else - { - $this->load->view('formsuccess'); - } - } + function signup() + { + $this->load->library('form_validation'); + + if ($this->form_validation->run() == FALSE) + { + $this->load->view('myform'); + } + else + { + $this->load->view('formsuccess'); + } + } } - ?> In your validation config file, you will name your rule group member/signup:: @@ -857,8 +869,10 @@ Rule Parameter Description ========================= ========== ============================================================================================= ======================= **required** No Returns FALSE if the form element is empty. **matches** Yes Returns FALSE if the form element does not match the one in the parameter. matches[form_item] -**is_unique** Yes Returns FALSE if the form element is not unique to the is_unique[table.field] - table and field name in the parameter. is_unique[table.field] +**differs** Yes Returns FALSE if the form element does not differ from the one in the parameter. differs[form_item] +**is_unique** Yes Returns FALSE if the form element is not unique to the table and field name in the is_unique[table.field] + parameter. Note: This rule requires :doc:`Query Builder <../database/query_builder>` to be + enabled in order to work. **max_length** Yes Returns FALSE if the form element is longer then the parameter value. max_length[12] **exact_length** Yes Returns FALSE if the form element is not exactly the parameter value. exact_length[8] **greater_than** Yes Returns FALSE if the form element is less than or equal to the parameter value or not greater_than[8] @@ -880,10 +894,10 @@ Rule Parameter Description 0, 1, 2, 3, etc. **is_natural_no_zero** No Returns FALSE if the form element contains anything other than a natural number, but not zero: 1, 2, 3, etc. -**is_unique** Yes Returns FALSE if the form element is not unique in a database table. is_unique[table.field] **valid_email** No Returns FALSE if the form element does not contain a valid email address. **valid_emails** No Returns FALSE if any value provided in a comma separated list is not a valid email. **valid_ip** No Returns FALSE if the supplied IP is not valid. + Accepts an optional parameter of 'ipv4' or 'ipv6' to specify an IP format. **valid_base64** No Returns FALSE if the supplied string contains anything other than valid Base64 characters. ========================= ========== ============================================================================================= ======================= @@ -928,15 +942,15 @@ The following functions are intended for use in your controller functions. $this->form_validation->set_rules(); -====================================== +==================================== .. php:method:: set_rules ($field, $label = '', $rules = '') :param string $field: The field name :param string $label: The field label - :param string $rules: The rules, seperated by a pipe "|" + :param mixed $rules: The rules, as a string with rules separated by a pipe "|", or an array or rules. :rtype: Object - + Permits you to set validation rules, as described in the tutorial sections above: @@ -944,19 +958,19 @@ $this->form_validation->set_rules(); - :ref:`saving-groups` $this->form_validation->run(); -=============================== +============================== .. php:method:: run ($group = '') :param string $group: The name of the validation group to run :rtype: Boolean - + Runs the validation routines. Returns boolean TRUE on success and FALSE on failure. You can optionally pass the name of the validation group via the function, as described in: :ref:`saving-groups` $this->form_validation->set_message(); -======================================== +====================================== .. php:method:: set_message ($lang, $val = '') @@ -967,7 +981,7 @@ $this->form_validation->set_message(); Permits you to set custom error messages. See :ref:`setting-error-messages` $this->form_validation->set_data(); -======================================== +=================================== .. php:method:: set_data ($data = '') @@ -979,13 +993,13 @@ $this->form_validation->set_data(); $this->form_validation->reset_validation(); =========================================== - .. php:method:: reset_validation () + .. php:method:: reset_validation () - Permits you to reset the validation when you validate more than one array. - This function should be called before validating each new array. + Permits you to reset the validation when you validate more than one array. + This method should be called before validating each new array. $this->form_validation->error_array(); -======================================== +====================================== .. php:method:: error_array () @@ -1004,7 +1018,7 @@ containing your forms. Note that these are procedural functions, so they **do not** require you to prepend them with $this->form_validation. form_error() -============= +============ Shows an individual error message associated with the field name supplied to the function. Example:: @@ -1015,7 +1029,7 @@ The error delimiters can be optionally specified. See the :ref:`changing-delimiters` section above. validation_errors() -==================== +=================== Shows all error messages as a string: Example:: @@ -1025,7 +1039,7 @@ The error delimiters can be optionally specified. See the :ref:`changing-delimiters` section above. set_value() -============ +=========== Permits you to set the value of an input form or textarea. You must supply the field name via the first parameter of the function. The @@ -1037,7 +1051,7 @@ form. Example:: The above form will show "0" when loaded for the first time. set_select() -============= +============ If you use a <select> menu, this function permits you to display the menu item that was selected. The first parameter must contain the name @@ -1054,7 +1068,7 @@ Example:: </select> set_checkbox() -=============== +============== Permits you to display a checkbox in the state it was submitted. The first parameter must contain the name of the checkbox, the second @@ -1065,7 +1079,7 @@ lets you set an item as the default (use boolean TRUE/FALSE). Example:: <input type="checkbox" name="mycheck[]" value="2" <?php echo set_checkbox('mycheck[]', '2'); ?> /> set_radio() -============ +=========== Permits you to display radio buttons in the state they were submitted. This function is identical to the **set_checkbox()** function above. @@ -1073,4 +1087,4 @@ This function is identical to the **set_checkbox()** function above. :: <input type="radio" name="myradio" value="1" <?php echo set_radio('myradio', '1', TRUE); ?> /> - <input type="radio" name="myradio" value="2" <?php echo set_radio('myradio', '2'); ?> /> + <input type="radio" name="myradio" value="2" <?php echo set_radio('myradio', '2'); ?> />
\ No newline at end of file diff --git a/user_guide_src/source/libraries/ftp.rst b/user_guide_src/source/libraries/ftp.rst index 20b11a5c8..05a3fdcc8 100644 --- a/user_guide_src/source/libraries/ftp.rst +++ b/user_guide_src/source/libraries/ftp.rst @@ -26,7 +26,7 @@ Usage Examples In this example a connection is opened to the FTP server, and a local file is read and uploaded in ASCII mode. The file permissions are set to -755. Note: Setting permissions requires PHP 5. +755. :: @@ -136,8 +136,7 @@ Example:: **Mode options are:** ascii, binary, and auto (the default). If auto is used it will base the mode on the file extension of the source file. -Permissions are available if you are running PHP 5 and can be passed as -an octal value in the fourth parameter. +If set, permissions have to be passed as an octal value. $this->ftp->download() ====================== diff --git a/user_guide_src/source/libraries/image_lib.rst b/user_guide_src/source/libraries/image_lib.rst index ed6575c62..dcdccbd92 100644 --- a/user_guide_src/source/libraries/image_lib.rst +++ b/user_guide_src/source/libraries/image_lib.rst @@ -91,9 +91,9 @@ error upon failure, like this:: echo $this->image_lib->display_errors(); } -Note: You can optionally specify the HTML formatting to be applied to -the errors, by submitting the opening/closing tags in the function, like -this:: +.. note:: You can optionally specify the HTML formatting to be applied to + the errors, by submitting the opening/closing tags in the function, + like this:: $this->image_lib->display_errors('<p>', '</p>'); @@ -225,8 +225,7 @@ pixels) specifying where to crop, like this:: $config['y_axis'] = '40'; All preferences listed in the table above are available for this -function except these: rotation_angle, width, height, create_thumb, -new_image. +function except these: rotation_angle, create_thumb, new_image. Here's an example showing how you might crop an image:: @@ -243,11 +242,11 @@ Here's an example showing how you might crop an image:: echo $this->image_lib->display_errors(); } -Note: Without a visual interface it is difficult to crop images, so this -function is not very useful unless you intend to build such an -interface. That's exactly what we did using for the photo gallery module -in ExpressionEngine, the CMS we develop. We added a JavaScript UI that -lets the cropping area be selected. +.. note:: Without a visual interface it is difficult to crop images, so this + function is not very useful unless you intend to build such an + interface. That's exactly what we did using for the photo gallery module + in ExpressionEngine, the CMS we develop. We added a JavaScript UI that + lets the cropping area be selected. $this->image_lib->rotate() =========================== @@ -338,8 +337,8 @@ The above example will use a 16 pixel True Type font to create the text bottom/center of the image, 20 pixels from the bottom of the image. .. note:: In order for the image class to be allowed to do any - processing, the image file must have "write" file permissions. For - example, 777. + processing, the image file must have "write" file permissions + For example, 777. Watermarking Preferences ======================== diff --git a/user_guide_src/source/libraries/input.rst b/user_guide_src/source/libraries/input.rst index 1f2ea650a..177f5cb64 100644 --- a/user_guide_src/source/libraries/input.rst +++ b/user_guide_src/source/libraries/input.rst @@ -5,8 +5,7 @@ Input Class The Input Class serves two purposes: #. It pre-processes global input data for security. -#. It provides some helper functions for fetching input data and - pre-processing it. +#. It provides some helper methods for fetching input data and pre-processing it. .. note:: This class is initialized automatically by the system so there is no need to do it manually. @@ -14,11 +13,11 @@ The Input Class serves two purposes: Security Filtering ================== -The security filtering function is called automatically when a new +The security filtering method is called automatically when a new :doc:`controller <../general/controllers>` is invoked. It does the following: -- If $config['allow_get_array'] is FALSE(default is TRUE), destroys +- If $config['allow_get_array'] is FALSE (default is TRUE), destroys the global GET array. - Destroys all global variables in the event register_globals is turned on. @@ -42,33 +41,27 @@ this:: Please refer to the :doc:`Security class <security>` documentation for information on using XSS Filtering in your application. -Using POST, COOKIE, or SERVER Data -================================== +Using POST, GET, COOKIE, or SERVER Data +======================================= -CodeIgniter comes with three helper functions that let you fetch POST, +CodeIgniter comes with four helper methods that let you fetch POST, GET, COOKIE or SERVER items. The main advantage of using the provided -functions rather than fetching an item directly ($_POST['something']) -is that the functions will check to see if the item is set and return -false (boolean) if not. This lets you conveniently use data without +methods rather than fetching an item directly (``$_POST['something']``) +is that the methods will check to see if the item is set and return +NULL if not. This lets you conveniently use data without having to test whether an item exists first. In other words, normally you might do something like this:: - if ( ! isset($_POST['something'])) - { - $something = FALSE; - } - else - { - $something = $_POST['something']; - } + $something = isset($_POST['something']) ? $_POST['something'] : NULL; -With CodeIgniter's built in functions you can simply do this:: +With CodeIgniter's built in methods you can simply do this:: $something = $this->input->post('something'); -The three functions are: +The four methods are: - $this->input->post() +- $this->input->get() - $this->input->cookie() - $this->input->server() @@ -80,8 +73,8 @@ looking for:: $this->input->post('some_data'); -The function returns FALSE (boolean) if the item you are attempting to -retrieve does not exist. +The method returns NULL if the item you are attempting to retrieve +does not exist. The second optional parameter lets you run the data through the XSS filter. It's enabled by setting the second parameter to boolean TRUE; @@ -95,7 +88,7 @@ To return an array of all POST items call without any parameters. To return all POST items and pass them through the XSS filter set the first parameter NULL while setting the second parameter to boolean; -The function returns FALSE (boolean) if there are no items in the POST. +The method returns NULL if there are no items in the POST. :: @@ -105,8 +98,8 @@ The function returns FALSE (boolean) if there are no items in the POST. $this->input->get() =================== -This function is identical to the post function, only it fetches get -data:: +This method is identical to the post method, only it fetches get data +:: $this->input->get('some_data', TRUE); @@ -115,7 +108,7 @@ To return an array of all GET items call without any parameters. To return all GET items and pass them through the XSS filter set the first parameter NULL while setting the second parameter to boolean; -The function returns FALSE (boolean) if there are no items in the GET. +The method returns NULL if there are no items in the GET. :: @@ -124,9 +117,9 @@ The function returns FALSE (boolean) if there are no items in the GET. $this->input->get_post() -========================= +======================== -This function will search through both the post and get streams for +This method will search through both the post and get streams for data, looking first in post, and then in get:: $this->input->get_post('some_data', TRUE); @@ -134,24 +127,53 @@ data, looking first in post, and then in get:: $this->input->cookie() ====================== -This function is identical to the post function, only it fetches cookie -data:: +This method is identical to the post method, only it fetches cookie data +:: + + $this->input->cookie('some_cookie'); + $this->input->cookie('some_cookie, TRUE); // with XSS filter - $this->input->cookie('some_data', TRUE); $this->input->server() ====================== -This function is identical to the above functions, only it fetches +This method is identical to the above methods, only it fetches server server data:: $this->input->server('some_data'); +Using the php://input stream +============================ + +If you want to utilize the PUT, DELETE, PATCH or other exotic request +methods, they can only be accessed via a special input stream, that +can only be read once. This isn't as easy as just reading from e.g. +the ``$_POST`` array, because it will always exist and you can try +and access multiple variables without caring that you might only have +one shot at all of the POST data. + +CodeIgniter will take care of that for you, and you can access data +from the **php://input** stream at any time, just by calling the +``input_stream()`` method:: + + $this->input->input_stream('key'); + +Similar to the methods above, if the requested data is not found, it +will return NULL and you can also decide whether to run the data +through ``xss_clean()`` by passing a boolean value as the second +parameter:: + + $this->input->input_stream('key', TRUE); // XSS Clean + $this->input->input_stream('key', FALSE); // No XSS filter + +.. note:: You can utilize method() in order to know if you're reading + PUT, DELETE or PATCH data. + $this->input->set_cookie() -=========================== +========================== Sets a cookie containing the values you specify. There are two ways to -pass information to this function so that a cookie can be set: Array +pass information to this method so that a cookie can be set: Array Method, and Discrete Parameters: Array Method @@ -186,7 +208,7 @@ For site-wide cookies regardless of how your site is requested, add your URL to the **domain** starting with a period, like this: .your-domain.com -The path is usually not needed since the function sets a root path. +The path is usually not needed since the method sets a root path. The prefix is only needed if you need to avoid name collisions with other identically named cookies for your server. @@ -202,41 +224,25 @@ parameters:: $this->input->set_cookie($name, $value, $expire, $domain, $path, $prefix, $secure); -$this->input->cookie() -====================== - -Lets you fetch a cookie. The first parameter will contain the name of -the cookie you are looking for (including any prefixes):: - - cookie('some_cookie'); - -The function returns FALSE (boolean) if the item you are attempting to -retrieve does not exist. - -The second optional parameter lets you run the data through the XSS -filter. It's enabled by setting the second parameter to boolean TRUE; - -:: - - cookie('some_cookie', TRUE); - $this->input->ip_address() -=========================== +========================== Returns the IP address for the current user. If the IP address is not -valid, the function will return an IP of: 0.0.0.0 +valid, the method will return an IP of: 0.0.0.0 :: echo $this->input->ip_address(); $this->input->valid_ip($ip) -============================ +=========================== Takes an IP address as input and returns TRUE or FALSE (boolean) if it -is valid or not. Note: The $this->input->ip_address() function above -validates the IP automatically. +is valid or not. + +.. note:: The $this->input->ip_address() method above automatically + validates the IP address. :: @@ -249,8 +255,11 @@ validates the IP automatically. echo 'Valid'; } +Accepts an optional second string parameter of 'ipv4' or 'ipv6' to specify +an IP format. The default checks for both formats. + $this->input->user_agent() -=========================== +========================== Returns the user agent (web browser) being used by the current user. Returns FALSE if it's not available. @@ -263,7 +272,7 @@ See the :doc:`User Agent Class <user_agent>` for methods which extract information from the user agent string. $this->input->request_headers() -================================ +=============================== Useful if running in a non-Apache environment where `apache_request_headers() <http://php.net/apache_request_headers>`_ @@ -273,8 +282,8 @@ will not be supported. Returns an array of headers. $headers = $this->input->request_headers(); -$this->input->get_request_header(); -===================================== +$this->input->get_request_header() +================================== Returns a single member of the request headers array. @@ -283,13 +292,13 @@ Returns a single member of the request headers array. $this->input->get_request_header('some-header', TRUE); $this->input->is_ajax_request() -================================= +=============================== Checks to see if the HTTP_X_REQUESTED_WITH server header has been set, and returns a boolean response. $this->input->is_cli_request() -================================ +============================== Checks to see if the STDIN constant is set, which is a failsafe way to see if PHP is being run on the command line. @@ -298,8 +307,8 @@ see if PHP is being run on the command line. $this->input->is_cli_request() -$this->input->method(); -===================================== +$this->input->method() +====================== Returns the $_SERVER['REQUEST_METHOD'], optional set uppercase or lowercase (default lowercase). @@ -307,4 +316,4 @@ Returns the $_SERVER['REQUEST_METHOD'], optional set uppercase or lowercase (def echo $this->input->method(TRUE); // Outputs: POST echo $this->input->method(FALSE); // Outputs: post - echo $this->input->method(); // Outputs: post + echo $this->input->method(); // Outputs: post
\ No newline at end of file diff --git a/user_guide_src/source/libraries/javascript.rst b/user_guide_src/source/libraries/javascript.rst index 5e80fb998..393d4e321 100644 --- a/user_guide_src/source/libraries/javascript.rst +++ b/user_guide_src/source/libraries/javascript.rst @@ -86,14 +86,14 @@ The jQuery Class To initialize the jQuery class manually in your controller constructor, use the $this->load->library function:: - $this->load->library('jquery'); + $this->load->library('javascript/jquery'); You may send an optional parameter to determine whether or not a script tag for the main jQuery file will be automatically included when loading the library. It will be created by default. To prevent this, load the library as follows:: - $this->load->library('jquery', FALSE); + $this->load->library('javascript/jquery', FALSE); Once loaded, the jQuery library object will be available using: $this->jquery @@ -192,7 +192,7 @@ and triggered by a click using the jQuery library's click() event. 'width' => '50%', 'marginLeft' => 125 ); - $this->jquery->click('#trigger', $this->jquery->animate('#note', $params, normal)); + $this->jquery->click('#trigger', $this->jquery->animate('#note', $params, 'normal')); fadeIn() / fadeOut() -------------------- diff --git a/user_guide_src/source/libraries/language.rst b/user_guide_src/source/libraries/language.rst index ec678cd21..b231f14a3 100644 --- a/user_guide_src/source/libraries/language.rst +++ b/user_guide_src/source/libraries/language.rst @@ -54,7 +54,9 @@ first. Loading a language file is done with the following code:: Where filename is the name of the file you wish to load (without the file extension), and language is the language set containing it (ie, english). If the second parameter is missing, the default language set -in your application/config/config.php file will be used. +in your *application/config/config.php* file will be used. + +.. note:: The *language* parameter can only consist of letters. Fetching a Line of Text ======================= @@ -67,8 +69,7 @@ text using this function:: Where language_key is the array key corresponding to the line you wish to show. -Note: This function simply returns the line. It does not echo it for -you. +.. note:: This method simply returns the line. It does not echo it. Using language lines as form labels ----------------------------------- diff --git a/user_guide_src/source/libraries/loader.rst b/user_guide_src/source/libraries/loader.rst index 2090404bf..615aba1c2 100644 --- a/user_guide_src/source/libraries/loader.rst +++ b/user_guide_src/source/libraries/loader.rst @@ -4,6 +4,7 @@ Loader Class Loader, as the name suggests, is used to load elements. These elements can be libraries (classes) :doc:`View files <../general/views>`, +:doc:`Drivers <../general/drivers>`, :doc:`Helpers <../general/helpers>`, :doc:`Models <../general/models>`, or your own files. @@ -74,6 +75,70 @@ Assigning a Library to a different object name If the third (optional) parameter is blank, the library will usually be assigned to an object with the same name as the library. For example, if +the library is named Calendar, it will be assigned to a variable named +$this->calendar. + +If you prefer to set your own class names you can pass its value to the +third parameter:: + + $this->load->library('calendar', '', 'my_calendar'); + + // Calendar class is now accessed using: + + $this->my_calendar + +Please take note, when multiple libraries are supplied in an array for +the first parameter, this parameter is discarded. + +$this->load->driver('parent_name', $config, 'object name') +=========================================================== + +This function is used to load driver libraries. Where parent_name is the +name of the parent class you want to load. + +As an example, if you would like to use sessions with CodeIgniter, the first +step is to load the session driver within your controller:: + + $this->load->driver('session'); + +Once loaded, the library will be ready for use, using +$this->session->*some_function*(). + +Driver files must be stored in a subdirectory within the main +"libraries" folder, or within your personal application/libraries +folder. The subdirectory must match the parent class name. Read the +:doc:`Drivers <../general/drivers>` description for details. + +Additionally, multiple driver libraries can be loaded at the same time by +passing an array of drivers to the load function. + +:: + + $this->load->driver(array('session', 'cache')); + +Setting options +--------------- + +The second (optional) parameter allows you to optionally pass +configuration settings. You will typically pass these as an array:: + + $config = array ( + 'sess_driver' => 'cookie', + 'sess_encrypt_cookie' => true, + 'encryption_key' => 'mysecretkey' + ); + + $this->load->driver('session', $config); + +Config options can usually also be set via a config file. Each library +is explained in detail in its own page, so please read the information +regarding each one you would like to use. + +Assigning a Driver to a different object name +---------------------------------------------- + +If the third (optional) parameter is blank, the library will be assigned +to an object with the same name as the parent class. For example, if the library is named Session, it will be assigned to a variable named $this->session. @@ -86,8 +151,8 @@ third parameter:: $this->my_session -Please take note, when multiple libraries are supplied in an array for -the first parameter, this parameter is discarded. +.. note:: Driver libraries may also be loaded with the library() method, + but it is faster to use driver() $this->load->view('file_name', $data, true/false) ================================================== @@ -116,12 +181,12 @@ assign it to a variable if you want the data returned:: $string = $this->load->view('myfile', '', true); -$this->load->model('Model_name'); +$this->load->model('model_name'); ================================== :: - $this->load->model('Model_name'); + $this->load->model('model_name'); If your model is located in a sub-folder, include the relative path from @@ -134,7 +199,7 @@ application/models/blog/queries.php you'll load it using:: If you would like your model assigned to a different object name you can specify it via the second parameter of the loading function:: - $this->load->model('Model_name', 'fubar'); + $this->load->model('model_name', 'fubar'); $this->fubar->function(); @@ -279,6 +344,6 @@ calling add_package_path(). $this->load->remove_package_path(APPPATH.'my_app'); // Again without the second parameter: - $this->load->add_package_path(APPPATH.'my_app', TRUE); + $this->load->add_package_path(APPPATH.'my_app'); $this->load->view('my_app_index'); // Loads - $this->load->view('welcome_message'); // Loads
\ No newline at end of file + $this->load->view('welcome_message'); // Loads diff --git a/user_guide_src/source/libraries/migration.rst b/user_guide_src/source/libraries/migration.rst index 5192f1f29..1a73fb78d 100644 --- a/user_guide_src/source/libraries/migration.rst +++ b/user_guide_src/source/libraries/migration.rst @@ -2,4 +2,162 @@ Migrations Class ################ -Coming soon.
\ No newline at end of file +Migrations are a convenient way for you to alter your database in a +structured and organized manner. You could edit fragments of SQL by hand +but you would then be responsible for telling other developers that they +need to go and run them. You would also have to keep track of which changes +need to be run against the production machines next time you deploy. + +The database table **migration** tracks which migrations have already been +run so all you have to do is update your application files and +call **$this->migrate->current()** to work out which migrations should be run. +The current version is found in **config/migration.php**. + +******************** +Migration file names +******************** + +Each Migration is run in numeric order forward or backwards depending on the +method taken. Two numbering styles are available: + +* **Sequential:** each migration is numbered in sequence, starting with **001**. + Each number must be three digits, and there must not be any gaps in the + sequence. (This was the numbering scheme prior to CodeIgniter 3.0.) +* **Timestamp:** each migration is numbered using the timestamp when the migration + was created, in **YYYYMMDDHHIISS** format (e.g. **20121031100537**). This + helps prevent numbering conflicts when working in a team environment, and is + the preferred scheme in CodeIgniter 3.0 and later. + +The desired style may be selected using the **$config['migration_type']** +setting in your **migration.php** config file. + +Regardless of which numbering style you choose to use, prefix your migration +files with the migration number followed by an underscore and a descriptive +name for the migration. For example: + +* **001_add_blog.php** (sequential numbering) +* **20121031100537_add_blog.php** (timestamp numbering) + +****************** +Create a Migration +****************** + +This will be the first migration for a new site which has a blog. All +migrations go in the folder **application/migrations/** and have names such +as **20121031100537_add_blog.php**.:: + + <?php + + defined('BASEPATH') OR exit('No direct script access allowed'); + + class Migration_Add_blog extends CI_Migration { + + public function up() + { + $this->dbforge->add_field(array( + 'blog_id' => array( + 'type' => 'INT', + 'constraint' => 5, + 'unsigned' => TRUE, + 'auto_increment' => TRUE + ), + 'blog_title' => array( + 'type' => 'VARCHAR', + 'constraint' => '100', + ), + 'blog_description' => array( + 'type' => 'TEXT', + 'null' => TRUE, + ), + )); + $this->dbforge->add_key('blog_id', TRUE); + $this->dbforge->create_table('blog'); + } + + public function down() + { + $this->dbforge->drop_table('blog'); + } + } + +Then in **application/config/migration.php** set **$config['migration_version'] = 1;**. + +************* +Usage Example +************* + +In this example some simple code is placed in **application/controllers/migrate.php** +to update the schema.:: + + <?php + + class Migrate extends CI_Controller + { + public function index() + { + $this->load->library('migration'); + + if ($this->migration->current() === FALSE) + { + show_error($this->migration->error_string()); + } + } + } + +****************** +Function Reference +****************** + +$this->migration->current() +============================ + +The current migration is whatever is set for **$config['migration_version']** in +**application/config/migration.php**. + +$this->migration->error_string() +================================= + +This returns a string of errors while performing a migration. + +$this->migration->find_migrations() +==================================== + +An array of migration filenames are returned that are found in the **migration_path** +property. + +$this->migration->latest() +=========================== + +This works much the same way as current() but instead of looking for +the **$config['migration_version']** the Migration class will use the very +newest migration found in the filesystem. + +$this->migration->version() +============================ + +Version can be used to roll back changes or step forwards programmatically to +specific versions. It works just like current but ignores **$config['migration_version']**.:: + + $this->load->library('migration'); + + $this->migration->version(5); + +********************* +Migration Preferences +********************* + +The following is a table of all the config options for migrations. + +========================== ====================== ========================== ============================================= +Preference Default Options Description +========================== ====================== ========================== ============================================= +**migration_enabled** FALSE TRUE / FALSE Enable or disable migrations. +**migration_path** APPPATH.'migrations/' None The path to your migrations folder. +**migration_version** 0 None The current version your database should use. +**migration_table** migrations None The table name for storing the schema + version number. +**migration_auto_latest** FALSE TRUE / FALSE Enable or disable automatically + running migrations. +**migration_type** 'timestamp' 'timestamp' / 'sequential' The type of numeric identifier used to name + migration files. +========================== ====================== ========================== ============================================= diff --git a/user_guide_src/source/libraries/output.rst b/user_guide_src/source/libraries/output.rst index baceaae7b..82b1a56a5 100644 --- a/user_guide_src/source/libraries/output.rst +++ b/user_guide_src/source/libraries/output.rst @@ -49,6 +49,10 @@ data, JPEG's, XML, etc easily. .. important:: Make sure any non-mime string you pass to this method exists in config/mimes.php or it will have no effect. +You can also set the character set of the document, by passing a second argument:: + + $this->output->set_content_type('css', 'utf-8'); + $this->output->get_content_type(); ========================================== @@ -101,6 +105,9 @@ Permits you to manually set a server status header. Example:: `See here <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>`_ for a full list of headers. +.. note:: This method is an alias for :doc:`Common function <../general/common_functions>` + ``set_status_header()``. + $this->output->enable_profiler(); ================================== diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index f1653c913..d9d3f5092 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -21,9 +21,9 @@ Here is a simple example showing how to create pagination in one of your $config['base_url'] = 'http://example.com/index.php/test/page/'; $config['total_rows'] = 200; - $config['per_page'] = 20; + $config['per_page'] = 20; - $this->pagination->initialize($config); + $this->pagination->initialize($config); echo $this->pagination->create_links(); @@ -80,8 +80,8 @@ The number of "digit" links you would like before and after the selected page number. For example, the number 2 will place two digits on either side, as in the example links at the very top of this page. -$config['use_page_number'] = TRUE; -================================== +$config['use_page_numbers'] = TRUE; +=================================== By default, the URI segment will use the starting index for the items you are paginating. If you prefer to show the the actual page number, @@ -112,6 +112,33 @@ the pagination link will become. Note that "per_page" is the default query string passed, however can be configured using $config['query_string_segment'] = 'your_string' +$config['reuse_query_string'] = FALSE; +====================================== + +By default your Query String arguments (nothing to do with other +query string options) will be ignored. Setting this config to +TRUE will add existing query string arguments back into the +URL after the URI segment and before the suffix + +:: + + http://example.com/index.php/test/page/20?query=search%term + +This helps you mix together normal :doc:`URI Segments <../general/urls>` +as well as query string arguments, which until 3.0 was not possible. + +$config['prefix'] = ''; +================================== + +A custom prefix added to the path. The prefix value will be right before +the offset segment. + +$config['suffix'] = ''; +================================== + +A custom suffix added to the path. The sufix value will be right after +the offset segment. + *********************** Adding Enclosing Markup *********************** @@ -247,10 +274,30 @@ adding:: $config['display_pages'] = FALSE; -****************************** -Adding a class to every anchor -****************************** +**************************** +Adding attributes to anchors +**************************** + +If you want to add an extra attribute to be added to every link rendered +by the pagination class, you can set them as key/value pairs in the +"attributes" config + +:: + + // Produces: class="myclass" + $config['attributes'] = array('class' => 'myclass'); + +.. note:: Usage of the old method of setting classes via "anchor_class" + is deprecated. + +***************************** +Disabling the "rel" attribute +***************************** + +By default the rel attribute is dynamically generated and appended to +the appropriate anchors. If for some reason you want to turn it off, +you can pass boolean FALSE as a regular attribute + +:: -If you want to add a class attribute to every link rendered by the -pagination class, you can set the config "anchor_class" equal to the -classname you want. + $config['attributes']['rel'] = FALSE;
\ No newline at end of file diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index e7d25555f..05553142f 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -26,7 +26,7 @@ processing since it requires a fair amount of processing overhead. To filter data through the XSS filter use this function: $this->security->xss_clean() -============================= +============================ Here is an usage example:: @@ -56,7 +56,7 @@ browser may attempt to execute. } $this->security->sanitize_filename() -===================================== +==================================== When accepting filenames from user input, it is best to sanitize them to prevent directory traversal and other security related issues. To do so, @@ -76,16 +76,35 @@ parameter, $relative_path to TRUE. Cross-site request forgery (CSRF) ================================= -You can enable csrf protection by opening your +You can enable CSRF protection by opening your application/config/config.php file and setting this:: $config['csrf_protection'] = TRUE; -If you use the :doc:`form helper <../helpers/form_helper>` the -form_open() function will automatically insert a hidden csrf field in -your forms. +If you use the :doc:`form helper <../helpers/form_helper>`, then +``form_open()`` will automatically insert a hidden csrf field in +your forms. If not, then you can use ``csrf_get_token_name()`` +and ``csrf_get_hash()`` -Tokens may be either regenerated on every submission (default) or kept the same throughout the life of the CSRF cookie. The default regeneration of tokens provides stricter security but may result in usability concerns as other tokens become invalid (back/forward navigation, multiple tabs/windows, asynchronous actions, etc). You may alter this behavior by editing the following config parameter:: +:: + + $csrf = array( + 'name' => $this->security->csrf_get_token_name(), + 'hash' => $this->security->csrf_get_hash() + ); + + ... + + <input type="hidden" name="<?=$csrf['name'];?>" value="<?=$csrf['hash'];?>" /> + +Tokens may be either regenerated on every submission (default) or +kept the same throughout the life of the CSRF cookie. The default +regeneration of tokens provides stricter security, but may result +in usability concerns as other tokens become invalid (back/forward +navigation, multiple tabs/windows, asynchronous actions, etc). You +may alter this behavior by editing the following config parameter + +:: $config['csrf_regeneration'] = TRUE; @@ -95,3 +114,15 @@ by editing the 'csrf_exclude_uris' config parameter:: $config['csrf_exclude_uris'] = array('api/person/add'); +$this->security->get_csrf_token_name() +====================================== + +Returns the CSRF token name, which is set by +``$config['csrf_token_name']``. + +$this->security->get_csrf_hash() +================================ + +Returns the CSRF hash value. Useful in combination with +``get_csrf_token_name()`` for manually building forms or +sending valid AJAX POST requests.
\ No newline at end of file diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index e8332ee97..ee7fb0b1c 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -1,29 +1,19 @@ -############# -Session Class -############# +############## +Session Driver +############## The Session class permits you maintain a user's "state" and track their -activity while they browse your site. The Session class stores session -information for each user as serialized (and optionally encrypted) data -in a cookie. It can also store the session data in a database table for -added security, as this permits the session ID in the user's cookie to -be matched against the stored session ID. By default only the cookie is -saved. If you choose to use the database option you'll need to create -the session table as indicated below. - -.. note:: The Session class does **not** utilize native PHP sessions. It - generates its own session data, offering more flexibility for - developers. - -.. note:: Even if you are not using encrypted sessions, you must set - an :doc:`encryption key <./encryption>` in your config file which is used - to aid in preventing session data manipulation. +activity while they browse your site. CodeIgniter offers two default +session drivers: the classic `Cookie Driver`_, and the `Native Driver`_, +which supports usage of the native PHP Session mechanism. In addition, +you may create your own `Custom Drivers`_ to store session data however +you wish, while still taking advantage of the features of the Session class. Initializing a Session ====================== Sessions will typically run globally with each page load, so the session -class must either be :doc:`initialized <../general/libraries>` in your +class must either be :doc:`initialized <../general/drivers>` in your :doc:`controller <../general/controllers>` constructors, or it can be :doc:`auto-loaded <../general/autoloader>` by the system. For the most part the session class will run unattended in the background, so simply @@ -31,22 +21,25 @@ initializing the class will cause it to read, create, and update sessions. To initialize the Session class manually in your controller constructor, -use the $this->load->library function:: +use the $this->load->driver function:: - $this->load->library('session'); + $this->load->driver('session'); Once loaded, the Sessions library object will be available using: $this->session +.. note:: For backward compatibility, the Session class may stil be loaded + using the $this->load->library function, but converting your applications + to use $this->load->driver is strongly recommended. + How do Sessions work? ===================== When a page is loaded, the session class will check to see if valid -session data exists in the user's session cookie. If sessions data does -**not** exist (or if it has expired) a new session will be created and -saved in the cookie. If a session does exist, its information will be -updated and the cookie will be updated. With each update, the -session_id will be regenerated. +session data exists in the user's session. If sessions data does **not** +exist (or if it has expired) a new session will be created and saved. +If a session does exist, its information will be updated. With each update, +the session_id will be regenerated. It's important for you to understand that once initialized, the Session class runs automatically. There is nothing you need to do to cause the @@ -79,19 +72,12 @@ prototype:: 'last_activity' => timestamp ) -If you have the encryption option enabled, the serialized array will be -encrypted before being stored in the cookie, making the data highly -secure and impervious to being read or altered by someone. More info -regarding encryption can be :doc:`found here <encryption>`, although -the Session class will take care of initializing and encrypting the data -automatically. - -Note: Session cookies are only updated every five minutes by default to -reduce processor load. If you repeatedly reload a page you'll notice -that the "last activity" time only updates if five minutes or more has -passed since the last time the cookie was written. This time is -configurable by changing the $config['sess_time_to_update'] line in -your system/config/config.php file. +.. note:: Sessions are only updated every five minutes by default to + reduce processor load. If you repeatedly reload a page you'll notice + that the "last activity" time only updates if five minutes or more has + passed since the last time the cookie was written. This time is + configurable by changing the $config['sess_time_to_update'] line in + your system/config/config.php file. Retrieving Session Data ======================= @@ -106,7 +92,7 @@ fetch. For example, to fetch the session ID you will do this:: $session_id = $this->session->userdata('session_id'); -.. note:: The function returns FALSE (boolean) if the item you are +.. note:: The function returns NULL if the item you are trying to access does not exist. Adding Custom Session Data @@ -117,7 +103,7 @@ to it and it will be stored in the user's cookie. Why would you want to do this? Here's one example: Let's say a particular user logs into your site. Once authenticated, you -could add their username and email address to the session cookie, making +could add their username and email address to the session, making that data globally available to you without having to run a database query when you need it. @@ -144,11 +130,11 @@ supports this syntax. $this->session->set_userdata('some_name', 'some_value'); +If you want to verify that a userdata value exists, call has_userdata(). -.. note:: Cookies can only hold 4KB of data, so be careful not to exceed - the capacity. The encryption process in particular produces a longer - data string than the original so keep careful track of how much data you - are storing. +:: + + $this->session->has_userdata('some_name'); Retrieving All Session Data =========================== @@ -195,8 +181,8 @@ available for the next server request, and are then automatically cleared. These can be very useful, and are typically used for informational or status messages (for example: "record 2 deleted"). -Note: Flash variables are prefaced with "flash\_" so avoid this prefix -in your own session names. +.. note:: Flash variables are prefaced with "flash\_" so avoid this prefix + in your own session names. To add flashdata:: @@ -222,9 +208,162 @@ additional request, you can do so using the keep_flashdata() function. $this->session->keep_flashdata('item'); +Tempdata +======== + +CodeIgniter also supports "tempdata", or session data with a specific +expiration time. After the value expires, or the session expires or is +deleted, the value is automatically removed. + +To add tempdata:: + + $expire = 300; // Expire in 5 minutes + + $this->session->set_tempdata('item', 'value', $expire); + +You can also pass an array to set_tempdata():: + + $tempdata = array('newuser' => TRUE, 'message' => 'Thanks for joining!'); + + $this->session->set_tempdata($tempdata, '', $expire); + +.. note:: If the expiration is omitted or set to 0, the default expiration of + 5 minutes will be used. + +To read a tempdata variable:: + + $this->session->tempdata('item'); + +If you need to remove a tempdata value before it expires, +use unset_tempdata():: + + $this->session->unset_tempdata('item'); + +Destroying a Session +==================== + +To clear the current session:: + + $this->session->sess_destroy(); + +.. note:: This function should be the last one called, and even flash + variables will no longer be available. If you only want some items + destroyed and not all, use unset_userdata(). + +Session Preferences +=================== + +You'll find the following Session related preferences in your +application/config/config.php file: + +=========================== =============== =========================== ========================================================================== +Preference Default Options Description +=========================== =============== =========================== ========================================================================== +**sess_driver** cookie cookie/native/*custom* The initial session driver to load. +**sess_valid_drivers** cookie, native None Additional valid drivers which may be loaded. +**sess_cookie_name** ci_session None The name you want the session cookie saved as (data for Cookie driver or + session ID for Native driver). +**sess_expiration** 7200 None The number of seconds you would like the session to last. The default + value is 2 hours (7200 seconds). If you would like a non-expiring + session set the value to zero: 0 +**sess_expire_on_close** FALSE TRUE/FALSE (boolean) Whether to cause the session to expire automatically when the browser + window is closed. +**sess_encrypt_cookie** FALSE TRUE/FALSE (boolean) Whether to encrypt the session data (Cookie driver only). +**sess_use_database** FALSE TRUE/FALSE (boolean) Whether to save the session data to a database. You must create the + table before enabling this option (Cookie driver only). +**sess_table_name** ci_sessions Any valid SQL table name The name of the session database table (Cookie driver only). +**sess_time_to_update** 300 Time in seconds This options controls how often the session class will regenerate itself + and create a new session id. +**sess_match_ip** FALSE TRUE/FALSE (boolean) Whether to match the user's IP address when reading the session data. + Note that some ISPs dynamically changes the IP, so if you want a + non-expiring session you will likely set this to FALSE. +**sess_match_useragent** TRUE TRUE/FALSE (boolean) Whether to match the User Agent when reading the session data. +=========================== =============== =========================== ========================================================================== + +In addition to the values above, the cookie and native drivers apply the +following configuration values shared by the :doc:`Input <input>` and +:doc:`Security <security>` classes: + +=========================== =============== ========================================================================== +Preference Default Description +=========================== =============== ========================================================================== +**cookie_prefix** '' Set a cookie name prefix in order to avoid name collisions +**cookie_domain** '' The domain for which the session is applicable +**cookie_path** / The path to which the session is applicable +=========================== =============== ========================================================================== + +Session Drivers +=============== + +By default, the `Cookie Driver`_ is loaded when a session is initialized. +However, any valid driver may be selected with the $config['sess_driver'] +line in your config.php file. + +The session driver library comes with the cookie and native drivers +installed, and `Custom Drivers`_ may also be installed by the user. + +Typically, only one driver will be used at a time, but CodeIgniter does +support loading multiple drivers. If a specific valid driver is called, it +will be automatically loaded. Or, an additional driver may be explicitly +loaded by calling load_driver():: + + $this->session->load_driver('native'); + +The Session library keeps track of the most recently selected driver to call +for driver methods. Normally, session class methods are called directly on +the parent class, as illustrated above. However, any methods called through +a specific driver will select that driver before invoking the parent method. + +So, alternation between multiple drivers can be achieved by specifying which +driver to use for each call:: + + $this->session->native->set_userdata('foo', 'bar'); + + $this->session->cookie->userdata('foo'); + + $this->session->native->unset_userdata('foo'); + +Notice in the previous example that the *native* userdata value 'foo' +would be set to 'bar', which would NOT be returned by the call for +the *cookie* userdata 'foo', nor would the *cookie* value be unset by +the call to unset the *native* 'foo' value. The drivers maintain independent +sets of values, regardless of key names. + +A specific driver may also be explicitly selected for use by pursuant +methods with the select_driver() call:: + + $this->session->select_driver('native'); + + $this->session->userdata('item'); // Uses the native driver + +Cookie Driver +------------- + +The Cookie driver stores session information for each user as serialized +(and optionally encrypted) data in a cookie. It can also store the session +data in a database table for added security, as this permits the session ID +in the user's cookie to be matched against the stored session ID. By default +only the cookie is saved. If you choose to use the database option you'll +need to create the session table as indicated below. + +If you have the encryption option enabled, the serialized array will be +encrypted before being stored in the cookie, making the data highly +secure and impervious to being read or altered by someone. More info +regarding encryption can be :doc:`found here <encryption>`, although +the Session class will take care of initializing and encrypting the data +automatically. + +.. note:: Even if you are not using encrypted sessions, you must set + an :doc:`encryption key <./encryption>` in your config file which is used + to aid in preventing session data manipulation. + +.. note:: Cookies can only hold 4KB of data, so be careful not to exceed + the capacity. The encryption process in particular produces a longer + data string than the original so keep careful track of how much data you + are storing. Saving Session Data to a Database -================================= +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ While the session data array stored in the user's cookie contains a Session ID, unless you store session data in a database there is no way @@ -245,11 +384,11 @@ session class:: CREATE TABLE IF NOT EXISTS `ci_sessions` ( session_id varchar(40) DEFAULT '0' NOT NULL, - ip_address varchar(16) DEFAULT '0' NOT NULL, + ip_address varchar(45) DEFAULT '0' NOT NULL, user_agent varchar(120) NOT NULL, last_activity int(10) unsigned DEFAULT 0 NOT NULL, user_data text NOT NULL, - PRIMARY KEY (session_id), + PRIMARY KEY (session_id, ip_address, user_agent), KEY `last_activity_idx` (`last_activity`) ); @@ -267,44 +406,83 @@ session class:: $config['sess_table_name'] = 'ci_sessions'; -.. note:: The Session class has built-in garbage collection which clears +.. note:: The Cookie driver has built-in garbage collection which clears out expired sessions so you do not need to write your own routine to do it. -Destroying a Session -==================== +Native Driver +------------- -To clear the current session:: +The Native driver relies on native PHP sessions to store data in the +$_SESSION superglobal array. All stored values continue to be available +through $_SESSION, but flash- and temp- data items carry special prefixes. - $this->session->sess_destroy(); +Custom Drivers +-------------- -.. note:: This function should be the last one called, and even flash - variables will no longer be available. If you only want some items - destroyed and not all, use unset_userdata(). +You may also :doc:`create your own <../general/creating_drivers>` custom +session drivers. A session driver basically manages an array of name/value +pairs with some sort of storage mechanism. -Session Preferences -=================== +To make a new driver, extend CI_Session_driver. Overload the initialize() +method and read or create session data. Then implement a save handler to +write changed data to storage (sess_save), a destroy handler to remove +deleted data (sess_destroy), a regenerate handler to make a new session ID +(sess_regenerate), and an access handler to expose the data (get_userdata). +Your initial class might look like:: -You'll find the following Session related preferences in your -application/config/config.php file: + class CI_Session_custom extends CI_Session_driver { + protected function initialize() + { + // Read existing session data or create a new one + } + + public function sess_save() + { + // Save current data to storage + } + + public function sess_destroy() + { + // Destroy the current session and clean up storage + } + + public function sess_regenerate() + { + // Create new session ID + } + + public function &get_userdata() + { + // Return a reference to your userdata array + } + } + +Notice that get_userdata() returns a reference so the parent library is +accessing the same array the driver object is using. This saves memory +and avoids synchronization issues during usage. + +Put your driver in the libraries/Session/drivers folder anywhere in your +package paths. This includes the application directory, the system directory, +or any path you add with $CI->load->add_package_path(). Your driver must be +named CI_Session_<name>, and your filename must be Session_<name>.php, +preferably also capitalized, such as:: + + CI_Session_foo in libraries/Session/drivers/Session_foo.php + +Then specify the driver by setting 'sess_driver' in your config.php file or as a +parameter when loading the CI_Session object:: + + $config['sess_driver'] = 'foo'; + +OR:: + + $CI->load->driver('session', array('sess_driver' => 'foo')); + +The driver specified by 'sess_driver' is automatically included as a valid +driver. However, if you want to make a custom driver available as an option +without making it the initially loaded driver, set 'sess_valid_drivers' in +your config.php file to an array including your driver name:: + + $config['sess_valid_drivers'] = array('sess_driver'); -=========================== =============== =========================== ========================================================================== -Preference Default Options Description -=========================== =============== =========================== ========================================================================== -**sess_cookie_name** ci_session None The name you want the session cookie saved as. -**sess_expiration** 7200 None The number of seconds you would like the session to last. The default - value is 2 hours (7200 seconds). If you would like a non-expiring - session set the value to zero: 0 -**sess_expire_on_close** FALSE TRUE/FALSE (boolean) Whether to cause the session to expire automatically when the browser - window is closed. -**sess_encrypt_cookie** FALSE TRUE/FALSE (boolean) Whether to encrypt the session data. -**sess_use_database** FALSE TRUE/FALSE (boolean) Whether to save the session data to a database. You must create the - table before enabling this option. -**sess_table_name** ci_sessions Any valid SQL table name The name of the session database table. -**sess_time_to_update** 300 Time in seconds This options controls how often the session class will regenerate itself - and create a new session id. -**sess_match_ip** FALSE TRUE/FALSE (boolean) Whether to match the user's IP address when reading the session data. - Note that some ISPs dynamically changes the IP, so if you want a - non-expiring session you will likely set this to FALSE. -**sess_match_useragent** TRUE TRUE/FALSE (boolean) Whether to match the User Agent when reading the session data. -=========================== =============== =========================== ==========================================================================
\ No newline at end of file diff --git a/user_guide_src/source/libraries/trackback.rst b/user_guide_src/source/libraries/trackback.rst index 07b2b2177..f9e0df882 100644 --- a/user_guide_src/source/libraries/trackback.rst +++ b/user_guide_src/source/libraries/trackback.rst @@ -114,7 +114,7 @@ store them. Here is a basic prototype for such a table:: excerpt text NOT NULL, blog_name varchar(100) NOT NULL, tb_date int(10) NOT NULL, - ip_address varchar(16) NOT NULL, + ip_address varchar(45) NOT NULL, PRIMARY KEY `tb_id` (`tb_id`), KEY `entry_id` (`entry_id`) ); diff --git a/user_guide_src/source/libraries/unit_testing.rst b/user_guide_src/source/libraries/unit_testing.rst index 03819b27c..6bd91bf88 100644 --- a/user_guide_src/source/libraries/unit_testing.rst +++ b/user_guide_src/source/libraries/unit_testing.rst @@ -131,7 +131,7 @@ default: - Any notes you entered for the test (notes) You can customize which of these items get displayed by using -$this->unit->set_items(). For example, if you only wanted the test name +$this->unit->set_test_items(). For example, if you only wanted the test name and the result displayed: Customizing displayed tests diff --git a/user_guide_src/source/libraries/uri.rst b/user_guide_src/source/libraries/uri.rst index ee60b77d7..bb959b002 100644 --- a/user_guide_src/source/libraries/uri.rst +++ b/user_guide_src/source/libraries/uri.rst @@ -25,7 +25,7 @@ The segment numbers would be this: #. metro #. crime_is_up -By default the function returns FALSE (boolean) if the segment does not +By default the function returns NULL if the segment does not exist. There is an optional second parameter that permits you to set your own default value if the segment is missing. For example, this would tell the function to return the number zero in the event of @@ -146,7 +146,7 @@ full URL:: The function would return this:: - /news/local/345 + news/local/345 $this->uri->ruri_string() ========================== diff --git a/user_guide_src/source/libraries/user_agent.rst b/user_guide_src/source/libraries/user_agent.rst index 855ece29d..97abd2244 100644 --- a/user_guide_src/source/libraries/user_agent.rst +++ b/user_guide_src/source/libraries/user_agent.rst @@ -72,7 +72,7 @@ Returns TRUE/FALSE (boolean) if the user agent is a known web browser. { echo 'You are using Safari.'; } - else if ($this->agent->is_browser()) + elseif ($this->agent->is_browser()) { echo 'You are using a browser.'; } @@ -94,7 +94,7 @@ Returns TRUE/FALSE (boolean) if the user agent is a known mobile device. { $this->load->view('iphone/home'); } - else if ($this->agent->is_mobile()) + elseif ($this->agent->is_mobile()) { $this->load->view('mobile/home'); } diff --git a/license_afl.rst b/user_guide_src/source/license_afl.rst index ca39be9b6..ca39be9b6 100644 --- a/license_afl.rst +++ b/user_guide_src/source/license_afl.rst diff --git a/user_guide_src/source/overview/cheatsheets.rst b/user_guide_src/source/overview/cheatsheets.rst deleted file mode 100644 index 2e277aa9a..000000000 --- a/user_guide_src/source/overview/cheatsheets.rst +++ /dev/null @@ -1,16 +0,0 @@ -####################### -CodeIgniter Cheatsheets -####################### - -Library Reference -================= - -`|CodeIgniter Library -Reference| <../images/codeigniter_1.7.1_library_reference.pdf>`_ -Helpers Reference -================= - -`|image1| <../images/codeigniter_1.7.1_helper_reference.pdf>`_ - -.. |CodeIgniter Library Reference| image:: ../images/codeigniter_1.7.1_library_reference.png -.. |image1| image:: ../images/codeigniter_1.7.1_helper_reference.png diff --git a/user_guide_src/source/overview/features.rst b/user_guide_src/source/overview/features.rst index 44db08a94..8c27b1436 100644 --- a/user_guide_src/source/overview/features.rst +++ b/user_guide_src/source/overview/features.rst @@ -15,7 +15,7 @@ CodeIgniter's main features. - Model-View-Controller Based System - Extremely Light Weight - Full Featured database classes with support for several platforms. -- Active Record Database Support +- Query Builder Database Support - Form and Data Validation - Security and XSS Filtering - Session Management diff --git a/user_guide_src/source/overview/index.rst b/user_guide_src/source/overview/index.rst index dc91f78c4..d48a0bbe4 100644 --- a/user_guide_src/source/overview/index.rst +++ b/user_guide_src/source/overview/index.rst @@ -9,7 +9,6 @@ The following pages describe the broad concepts behind CodeIgniter: Getting Started <getting_started> CodeIgniter at a Glance <at_a_glance> - CodeIgniter Cheatsheets <cheatsheets> Supported Features <features> Application Flow Chart <appflow> Model-View-Controller <mvc> diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst index 794b67eed..bfaf13537 100644 --- a/user_guide_src/source/tutorial/create_news_items.rst +++ b/user_guide_src/source/tutorial/create_news_items.rst @@ -94,7 +94,7 @@ Model ----- The only thing that remains is writing a method that writes the data to -the database. You'll use the Active Record class to insert the +the database. You'll use the Query Builder class to insert the information and use the input library to get the posted data. Open up the model created earlier and add the following: diff --git a/user_guide_src/source/tutorial/index.rst b/user_guide_src/source/tutorial/index.rst index c959d04d2..b1ab331d1 100644 --- a/user_guide_src/source/tutorial/index.rst +++ b/user_guide_src/source/tutorial/index.rst @@ -16,7 +16,7 @@ This tutorial will primarily focus on: - Model-View-Controller basics - Routing basics - Form validation -- Performing basic database queries using "Active Record" +- Performing basic database queries using "Query Builder" The entire tutorial is split up over several pages, each explaining a small part of the functionality of the CodeIgniter framework. You'll go diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst index 38e4214ca..82b3e3b38 100644 --- a/user_guide_src/source/tutorial/news_section.rst +++ b/user_guide_src/source/tutorial/news_section.rst @@ -54,7 +54,7 @@ seed records. Now that the database and a model have been set up, you'll need a method to get all of our posts from our database. To do this, the database abstraction layer that is included with CodeIgniter — `Active -Record <../database/active_record.html>`_ — is used. This makes it +Record <../database/query_builder.html>`_ — is used. This makes it possible to write your 'queries' once and make them work on `all supported database systems <../general/requirements.html>`_. Add the following code to your model. @@ -76,7 +76,7 @@ following code to your model. With this code you can perform two different queries. You can get all news records, or get a news item by its `slug <#>`_. You might have noticed that the $slug variable wasn't sanitized before running the -query; Active Record does this for you. +query; Query Builder does this for you. Display the news ---------------- |