Compare commits
1 Commits
leenooks-3
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
68c7f4f159 |
@ -1,13 +1,13 @@
|
|||||||
# Developing locally
|
# Developing locally
|
||||||
|
|
||||||
Since Kohana maintains many concurrent versions at once, there is no single `master` branch. All versions have branches named with a prefix of it's version:
|
Since Kohana maintains many concurrent versions at once, there is no single `master` branch. All versions have branches named with a prefix of its version:
|
||||||
|
|
||||||
- 3.2/master
|
- 3.2/master
|
||||||
- 3.2/develop
|
- 3.2/develop
|
||||||
- 3.3/master
|
- 3.3/master
|
||||||
- 3.3/develop
|
- 3.3/develop
|
||||||
|
|
||||||
and so on. All development of versions happens in the develop branch of that version. Before a release, new features are added here. After a major release is actually released, only bugfixes can happen here. New features and api changes must happen in the develop branch of the next version.
|
and so on. All development of versions happens in the develop branch of that version. Before a release, new features are added here. After a major release is actually released, only bugfixes can happen here. New features and API changes must happen in the develop branch of the next version.
|
||||||
|
|
||||||
## Branch name meanings
|
## Branch name meanings
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ and so on. All development of versions happens in the develop branch of that ver
|
|||||||
- **3.3/release/*** - release branches are for maintenance work before a release. This branch should be branched from the develop branch only. Change the version number/code name here, and apply any other maintenance items needed before actually releasing. Merges from master should only come from this branch. It should be merged to develop when it's complete as well. This branch is deleted after it's done.
|
- **3.3/release/*** - release branches are for maintenance work before a release. This branch should be branched from the develop branch only. Change the version number/code name here, and apply any other maintenance items needed before actually releasing. Merges from master should only come from this branch. It should be merged to develop when it's complete as well. This branch is deleted after it's done.
|
||||||
- **3.3/feature/*** - Details on these branches are outlined below. This branch is deleted after it's done.
|
- **3.3/feature/*** - Details on these branches are outlined below. This branch is deleted after it's done.
|
||||||
|
|
||||||
If an bug/issue applies to multiple versions of kohana, it is first fixed in the lowest supported version it applies to, then merged to each higher branch it applies to. Each merge should only happen one version up. 3.1 should merge to 3.2, and 3.2 should merge to 3.3. 3.1 should not merge directly to 3.3.
|
If an bug/issue applies to multiple versions of Kohana, it is first fixed in the lowest supported version it applies to, then merged to each higher branch it applies to. Each merge should only happen one version up. 3.1 should merge to 3.2, and 3.2 should merge to 3.3. 3.1 should not merge directly to 3.3.
|
||||||
|
|
||||||
To work on a specific release branch you need to check it out then check out the appropriate system branch.
|
To work on a specific release branch you need to check it out then check out the appropriate system branch.
|
||||||
Release branch names follow the same convention in both kohana/kohana and kohana/core.
|
Release branch names follow the same convention in both kohana/kohana and kohana/core.
|
||||||
@ -37,7 +37,7 @@ To work on 3.3.x you'd do the following:
|
|||||||
> git submodule foreach "git fetch && git checkout 3.3/develop"
|
> git submodule foreach "git fetch && git checkout 3.3/develop"
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
It's important that you follow the last step, because unlike svn, git submodules point at a
|
It's important that you follow the last step, because unlike SVN, Git submodules point at a
|
||||||
specific commit rather than the tip of a branch. If you cd into the system folder after
|
specific commit rather than the tip of a branch. If you cd into the system folder after
|
||||||
a `git submodule update` and run `git status` you'll be told:
|
a `git submodule update` and run `git status` you'll be told:
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ a `git submodule update` and run `git status` you'll be told:
|
|||||||
|
|
||||||
# Contributing to the project
|
# Contributing to the project
|
||||||
|
|
||||||
All features and bugfixes must be fully tested and reference an issue in the [tracker](http://dev.kohanaframework.org/projects/kohana3), **there are absolutely no exceptions**.
|
All features and bugfixes must be fully tested and reference an issue in [GitHub](https://github.com/kohana/kohana/issues), **there are absolutely no exceptions**.
|
||||||
|
|
||||||
It's highly recommended that you write/run unit tests during development as it can help you pick up on issues early on. See the Unit Testing section below.
|
It's highly recommended that you write/run unit tests during development as it can help you pick up on issues early on. See the Unit Testing section below.
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ The naming convention for feature branches is:
|
|||||||
3.2/feature/4045-rewriting-config-system
|
3.2/feature/4045-rewriting-config-system
|
||||||
|
|
||||||
When a new feature is complete and fully tested it can be merged into its respective release branch using
|
When a new feature is complete and fully tested it can be merged into its respective release branch using
|
||||||
`git pull --no-ff`. The `--no-ff` switch is important as it tells git to always create a commit
|
`git pull --no-ff`. The `--no-ff` switch is important as it tells Git to always create a commit
|
||||||
detailing what branch you're merging from. This makes it a lot easier to analyse a feature's history.
|
detailing what branch you're merging from. This makes it a lot easier to analyse a feature's history.
|
||||||
|
|
||||||
Here's a quick example:
|
Here's a quick example:
|
||||||
@ -81,7 +81,7 @@ Here's a quick example:
|
|||||||
|
|
||||||
> git merge --no-ff 3.2/feature/4045-rewriting-everything
|
> git merge --no-ff 3.2/feature/4045-rewriting-everything
|
||||||
|
|
||||||
**If a change you make intentionally breaks the api then please correct the relevant tests before pushing!**
|
**If a change you make intentionally breaks the API then please correct the relevant tests before pushing!**
|
||||||
|
|
||||||
## Bug fixing
|
## Bug fixing
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ using the `@ticket` notation in the test to reference the bug's issue number
|
|||||||
If you run the unit tests then the one you've just made should fail.
|
If you run the unit tests then the one you've just made should fail.
|
||||||
|
|
||||||
Once you've written the bugfix, run the tests again before you commit to make sure that the
|
Once you've written the bugfix, run the tests again before you commit to make sure that the
|
||||||
fix actually works,then commit both the fix and the test.
|
fix actually works, then commit both the fix and the test.
|
||||||
|
|
||||||
**Bug fixes without tests written will be rejected! There are NO exceptions.**
|
**Bug fixes without tests written will be rejected! There are NO exceptions.**
|
||||||
|
|
||||||
@ -101,11 +101,11 @@ branch is perfectly acceptable.
|
|||||||
|
|
||||||
## Tagging releases
|
## Tagging releases
|
||||||
|
|
||||||
Tag names should be prefixed with a `v`, this helps to separate tag references from branch references in git.
|
Tag names should be prefixed with a `v`, this helps to separate tag references from branch references in Git.
|
||||||
|
|
||||||
For example, if you were creating a tag for the `3.1.0` release the tag name would be `v3.1.0`
|
For example, if you were creating a tag for the `3.1.0` release the tag name would be `v3.1.0`
|
||||||
|
|
||||||
# Merging Changes from Remote Repositories
|
# Merging changes from remote repositories
|
||||||
|
|
||||||
Now that you have a remote repository, you can pull changes in the remote "kohana" repository
|
Now that you have a remote repository, you can pull changes in the remote "kohana" repository
|
||||||
into your local repository:
|
into your local repository:
|
||||||
@ -115,14 +115,14 @@ into your local repository:
|
|||||||
**Note:** Before you pull changes you should make sure that any modifications you've made locally
|
**Note:** Before you pull changes you should make sure that any modifications you've made locally
|
||||||
have been committed.
|
have been committed.
|
||||||
|
|
||||||
Sometimes a commit you've made locally will conflict with one made in the "kohana" one.
|
Sometimes a commit you've made locally will conflict with one made in the remote "kohana" repo.
|
||||||
|
|
||||||
There are a couple of scenarios where this might happen:
|
There are a couple of scenarios where this might happen:
|
||||||
|
|
||||||
## The conflict is to do with a few unrelated commits and you want to keep changes made in both commits
|
## The conflict is due to a few unrelated commits and you want to keep changes made in both commits
|
||||||
|
|
||||||
You'll need to manually modify the files to resolve the conflict, see the "Resolving a merge"
|
You'll need to manually modify the files to resolve the conflict, see the "Resolving a merge"
|
||||||
section [in the git-scm book](http://book.git-scm.com/3_basic_branching_and_merging.html) for more info
|
section [in the Git SCM book](http://book.git-scm.com/3_basic_branching_and_merging.html) for more info
|
||||||
|
|
||||||
## You've fixed something locally which someone else has already done in the remote repo
|
## You've fixed something locally which someone else has already done in the remote repo
|
||||||
|
|
||||||
@ -147,14 +147,14 @@ i.e.
|
|||||||
|
|
||||||
> git rebase -i 57d0b28
|
> git rebase -i 57d0b28
|
||||||
|
|
||||||
A text editor will open with a list of commits, delete the line containing the offending commit
|
A text editor will open with a list of commits. Delete the line containing the offending commit
|
||||||
before saving the file & closing your editor.
|
before saving the file & closing your editor.
|
||||||
|
|
||||||
Git will remove the commit and you can then pull/merge the remote changes.
|
Git will remove the commit and you can then pull/merge the remote changes.
|
||||||
|
|
||||||
# Unit Testing
|
# Unit Testing
|
||||||
|
|
||||||
Kohana currently uses phpunit for unit testing. This is installed with composer.
|
Kohana currently uses PHPUnit for unit testing. This is installed with composer.
|
||||||
|
|
||||||
## How to run the tests
|
## How to run the tests
|
||||||
|
|
||||||
|
151
application/bootstrap.php
Normal file
151
application/bootstrap.php
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<?php defined('SYSPATH') or die('No direct script access.');
|
||||||
|
|
||||||
|
// -- Environment setup --------------------------------------------------------
|
||||||
|
|
||||||
|
// Load the core Kohana class
|
||||||
|
require SYSPATH.'classes/Kohana/Core'.EXT;
|
||||||
|
|
||||||
|
if (is_file(APPPATH.'classes/Kohana'.EXT))
|
||||||
|
{
|
||||||
|
// Application extends the core
|
||||||
|
require APPPATH.'classes/Kohana'.EXT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Load empty core extension
|
||||||
|
require SYSPATH.'classes/Kohana'.EXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default time zone.
|
||||||
|
*
|
||||||
|
* @link http://kohanaframework.org/guide/using.configuration
|
||||||
|
* @link http://www.php.net/manual/timezones
|
||||||
|
*/
|
||||||
|
date_default_timezone_set('America/Chicago');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default locale.
|
||||||
|
*
|
||||||
|
* @link http://kohanaframework.org/guide/using.configuration
|
||||||
|
* @link http://www.php.net/manual/function.setlocale
|
||||||
|
*/
|
||||||
|
setlocale(LC_ALL, 'en_US.utf-8');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the Kohana auto-loader.
|
||||||
|
*
|
||||||
|
* @link http://kohanaframework.org/guide/using.autoloading
|
||||||
|
* @link http://www.php.net/manual/function.spl-autoload-register
|
||||||
|
*/
|
||||||
|
spl_autoload_register(array('Kohana', 'auto_load'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optionally, you can enable a compatibility auto-loader for use with
|
||||||
|
* older modules that have not been updated for PSR-0.
|
||||||
|
*
|
||||||
|
* It is recommended to not enable this unless absolutely necessary.
|
||||||
|
*/
|
||||||
|
//spl_autoload_register(array('Kohana', 'auto_load_lowercase'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the Kohana auto-loader for unserialization.
|
||||||
|
*
|
||||||
|
* @link http://www.php.net/manual/function.spl-autoload-call
|
||||||
|
* @link http://www.php.net/manual/var.configuration#unserialize-callback-func
|
||||||
|
*/
|
||||||
|
ini_set('unserialize_callback_func', 'spl_autoload_call');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the mb_substitute_character to "none"
|
||||||
|
*
|
||||||
|
* @link http://www.php.net/manual/function.mb-substitute-character.php
|
||||||
|
*/
|
||||||
|
mb_substitute_character('none');
|
||||||
|
|
||||||
|
// -- Configuration and initialization -----------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default language
|
||||||
|
*/
|
||||||
|
I18n::lang('en-us');
|
||||||
|
|
||||||
|
if (isset($_SERVER['SERVER_PROTOCOL']))
|
||||||
|
{
|
||||||
|
// Replace the default protocol.
|
||||||
|
HTTP::$protocol = $_SERVER['SERVER_PROTOCOL'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Kohana::$environment if a 'KOHANA_ENV' environment variable has been supplied.
|
||||||
|
*
|
||||||
|
* Note: If you supply an invalid environment name, a PHP warning will be thrown
|
||||||
|
* saying "Couldn't find constant Kohana::<INVALID_ENV_NAME>"
|
||||||
|
*/
|
||||||
|
if (isset($_SERVER['KOHANA_ENV']))
|
||||||
|
{
|
||||||
|
Kohana::$environment = constant('Kohana::'.strtoupper($_SERVER['KOHANA_ENV']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Kohana, setting the default options.
|
||||||
|
*
|
||||||
|
* The following options are available:
|
||||||
|
*
|
||||||
|
* - string base_url path, and optionally domain, of your application NULL
|
||||||
|
* - string index_file name of your index file, usually "index.php" index.php
|
||||||
|
* - string charset internal character set used for input and output utf-8
|
||||||
|
* - string cache_dir set the internal cache directory APPPATH/cache
|
||||||
|
* - integer cache_life lifetime, in seconds, of items cached 60
|
||||||
|
* - boolean errors enable or disable error handling TRUE
|
||||||
|
* - boolean profile enable or disable internal profiling TRUE
|
||||||
|
* - boolean caching enable or disable internal caching FALSE
|
||||||
|
* - boolean expose set the X-Powered-By header FALSE
|
||||||
|
*/
|
||||||
|
Kohana::init(array(
|
||||||
|
'base_url' => '/kohana/',
|
||||||
|
));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach the file write to logging. Multiple writers are supported.
|
||||||
|
*/
|
||||||
|
Kohana::$log->attach(new Log_File(APPPATH.'logs'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach a file reader to config. Multiple readers are supported.
|
||||||
|
*/
|
||||||
|
Kohana::$config->attach(new Config_File);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable modules. Modules are referenced by a relative or absolute path.
|
||||||
|
*/
|
||||||
|
Kohana::modules(array(
|
||||||
|
// 'auth' => MODPATH.'auth', // Basic authentication
|
||||||
|
// 'cache' => MODPATH.'cache', // Caching with multiple backends
|
||||||
|
// 'codebench' => MODPATH.'codebench', // Benchmarking tool
|
||||||
|
// 'database' => MODPATH.'database', // Database access
|
||||||
|
// 'image' => MODPATH.'image', // Image manipulation
|
||||||
|
// 'minion' => MODPATH.'minion', // CLI Tasks
|
||||||
|
// 'orm' => MODPATH.'orm', // Object Relationship Mapping
|
||||||
|
// 'unittest' => MODPATH.'unittest', // Unit testing
|
||||||
|
// 'userguide' => MODPATH.'userguide', // User guide and API documentation
|
||||||
|
));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookie Salt
|
||||||
|
* @see http://kohanaframework.org/3.3/guide/kohana/cookies
|
||||||
|
*
|
||||||
|
* If you have not defined a cookie salt in your Cookie class then
|
||||||
|
* uncomment the line below and define a preferrably long salt.
|
||||||
|
*/
|
||||||
|
// Cookie::$salt = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the routes. Each route must have a minimum of a name, a URI and a set of
|
||||||
|
* defaults for the URI.
|
||||||
|
*/
|
||||||
|
Route::set('default', '(<controller>(/<action>(/<id>)))')
|
||||||
|
->defaults(array(
|
||||||
|
'controller' => 'welcome',
|
||||||
|
'action' => 'index',
|
||||||
|
));
|
10
application/classes/Controller/Welcome.php
Normal file
10
application/classes/Controller/Welcome.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php defined('SYSPATH') or die('No direct script access.');
|
||||||
|
|
||||||
|
class Controller_Welcome extends Controller {
|
||||||
|
|
||||||
|
public function action_index()
|
||||||
|
{
|
||||||
|
$this->response->body('hello, world!');
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End Welcome
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"require": {
|
"require": {
|
||||||
"phpunit/phpunit": "3.7.24",
|
"phpunit/phpunit": "3.7.24 - 4",
|
||||||
"phing/phing": "dev-master"
|
"phing/phing": "dev-master"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
example.htaccess
Normal file
21
example.htaccess
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Turn on URL rewriting
|
||||||
|
RewriteEngine On
|
||||||
|
|
||||||
|
# Installation directory
|
||||||
|
RewriteBase /
|
||||||
|
|
||||||
|
# Protect hidden files from being viewed
|
||||||
|
<Files .*>
|
||||||
|
Order Deny,Allow
|
||||||
|
Deny From All
|
||||||
|
</Files>
|
||||||
|
|
||||||
|
# Protect application and system files from being viewed
|
||||||
|
RewriteRule ^(?:application|modules|system)\b.* index.php/$0 [L]
|
||||||
|
|
||||||
|
# Allow any files or directories that exist to be displayed directly
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
|
||||||
|
# Rewrite all other URLs to index.php/URL
|
||||||
|
RewriteRule .* index.php/$0 [PT]
|
121
index.php
Normal file
121
index.php
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The directory in which your application specific resources are located.
|
||||||
|
* The application directory must contain the bootstrap.php file.
|
||||||
|
*
|
||||||
|
* @link http://kohanaframework.org/guide/about.install#application
|
||||||
|
*/
|
||||||
|
$application = 'application';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The directory in which your modules are located.
|
||||||
|
*
|
||||||
|
* @link http://kohanaframework.org/guide/about.install#modules
|
||||||
|
*/
|
||||||
|
$modules = 'modules';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The directory in which the Kohana resources are located. The system
|
||||||
|
* directory must contain the classes/kohana.php file.
|
||||||
|
*
|
||||||
|
* @link http://kohanaframework.org/guide/about.install#system
|
||||||
|
*/
|
||||||
|
$system = 'system';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default extension of resource files. If you change this, all resources
|
||||||
|
* must be renamed to use the new extension.
|
||||||
|
*
|
||||||
|
* @link http://kohanaframework.org/guide/about.install#ext
|
||||||
|
*/
|
||||||
|
define('EXT', '.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the PHP error reporting level. If you set this in php.ini, you remove this.
|
||||||
|
* @link http://www.php.net/manual/errorfunc.configuration#ini.error-reporting
|
||||||
|
*
|
||||||
|
* When developing your application, it is highly recommended to enable notices
|
||||||
|
* and strict warnings. Enable them by using: E_ALL | E_STRICT
|
||||||
|
*
|
||||||
|
* In a production environment, it is safe to ignore notices and strict warnings.
|
||||||
|
* Disable them by using: E_ALL ^ E_NOTICE
|
||||||
|
*
|
||||||
|
* When using a legacy application with PHP >= 5.3, it is recommended to disable
|
||||||
|
* deprecated notices. Disable with: E_ALL & ~E_DEPRECATED
|
||||||
|
*/
|
||||||
|
error_reporting(E_ALL | E_STRICT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End of standard configuration! Changing any of the code below should only be
|
||||||
|
* attempted by those with a working knowledge of Kohana internals.
|
||||||
|
*
|
||||||
|
* @link http://kohanaframework.org/guide/using.configuration
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Set the full path to the docroot
|
||||||
|
define('DOCROOT', realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR);
|
||||||
|
|
||||||
|
// Make the application relative to the docroot, for symlink'd index.php
|
||||||
|
if ( ! is_dir($application) AND is_dir(DOCROOT.$application))
|
||||||
|
$application = DOCROOT.$application;
|
||||||
|
|
||||||
|
// Make the modules relative to the docroot, for symlink'd index.php
|
||||||
|
if ( ! is_dir($modules) AND is_dir(DOCROOT.$modules))
|
||||||
|
$modules = DOCROOT.$modules;
|
||||||
|
|
||||||
|
// Make the system relative to the docroot, for symlink'd index.php
|
||||||
|
if ( ! is_dir($system) AND is_dir(DOCROOT.$system))
|
||||||
|
$system = DOCROOT.$system;
|
||||||
|
|
||||||
|
// Define the absolute paths for configured directories
|
||||||
|
define('APPPATH', realpath($application).DIRECTORY_SEPARATOR);
|
||||||
|
define('MODPATH', realpath($modules).DIRECTORY_SEPARATOR);
|
||||||
|
define('SYSPATH', realpath($system).DIRECTORY_SEPARATOR);
|
||||||
|
|
||||||
|
// Clean up the configuration vars
|
||||||
|
unset($application, $modules, $system);
|
||||||
|
|
||||||
|
if (file_exists('install'.EXT))
|
||||||
|
{
|
||||||
|
// Load the installation check
|
||||||
|
return include 'install'.EXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the start time of the application, used for profiling.
|
||||||
|
*/
|
||||||
|
if ( ! defined('KOHANA_START_TIME'))
|
||||||
|
{
|
||||||
|
define('KOHANA_START_TIME', microtime(TRUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the memory usage at the start of the application, used for profiling.
|
||||||
|
*/
|
||||||
|
if ( ! defined('KOHANA_START_MEMORY'))
|
||||||
|
{
|
||||||
|
define('KOHANA_START_MEMORY', memory_get_usage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootstrap the application
|
||||||
|
require APPPATH.'bootstrap'.EXT;
|
||||||
|
|
||||||
|
if (PHP_SAPI == 'cli') // Try and load minion
|
||||||
|
{
|
||||||
|
class_exists('Minion_Task') OR die('Please enable the Minion module for CLI support.');
|
||||||
|
set_exception_handler(array('Minion_Exception', 'handler'));
|
||||||
|
|
||||||
|
Minion_Task::factory(Minion_CLI::options())->execute();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Execute the main request. A source of the URI can be passed, eg: $_SERVER['PATH_INFO'].
|
||||||
|
* If no source is specified, the URI will be automatically detected.
|
||||||
|
*/
|
||||||
|
echo Request::factory(TRUE, array(), FALSE)
|
||||||
|
->execute()
|
||||||
|
->send_headers(TRUE)
|
||||||
|
->body();
|
||||||
|
}
|
37
modules/auth/.travis.yml
Normal file
37
modules/auth/.travis.yml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
sudo: false
|
||||||
|
|
||||||
|
language: php
|
||||||
|
|
||||||
|
# Only build the main develop/master branches - feature branches will be covered by PRs
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- /^[0-9\.]+\/(develop|master)$/
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- vendor
|
||||||
|
- $HOME/.composer/cache
|
||||||
|
|
||||||
|
php:
|
||||||
|
- 5.3
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
- 7.0
|
||||||
|
- hhvm
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- php: 5.3
|
||||||
|
env: 'COMPOSER_PHPUNIT="lowest"'
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- composer install --prefer-dist
|
||||||
|
- if [ "$COMPOSER_PHPUNIT" = "lowest" ]; then composer update --prefer-lowest --with-dependencies phpunit/phpunit; fi;
|
||||||
|
- vendor/bin/koharness
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cd /tmp/koharness && ./vendor/bin/phpunit --bootstrap=modules/unittest/bootstrap.php modules/unittest/tests.php
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
@ -1,5 +1,9 @@
|
|||||||
New Age Auth
|
Kohana auth module
|
||||||
---
|
---
|
||||||
|
| ver | Stable | Develop |
|
||||||
|
|-------|------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| 3.3.x | [![Build Status - 3.3/master](https://travis-ci.org/kohana/auth.svg?branch=3.3%2Fmaster)](https://travis-ci.org/kohana/auth) | [![Build Status - 3.3/develop](https://travis-ci.org/kohana/auth.svg?branch=3.3%2Fdevelop)](https://travis-ci.org/kohana/auth) |
|
||||||
|
| 3.4.x | [![Build Status - 3.4/master](https://travis-ci.org/kohana/auth.svg?branch=3.4%2Fmaster)](https://travis-ci.org/kohana/auth) | [![Build Status - 3.4/develop](https://travis-ci.org/kohana/auth.svg?branch=3.4%2Fdevelop)](https://travis-ci.org/kohana/auth) |
|
||||||
|
|
||||||
I've forked the main Auth module because there were some fundamental flaws with it:
|
I've forked the main Auth module because there were some fundamental flaws with it:
|
||||||
|
|
||||||
|
@ -24,10 +24,18 @@
|
|||||||
"kohana/core": ">=3.3",
|
"kohana/core": ">=3.3",
|
||||||
"php": ">=5.3.3"
|
"php": ">=5.3.3"
|
||||||
},
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"kohana/core": "3.3.*@dev",
|
||||||
|
"kohana/unittest": "3.3.*@dev",
|
||||||
|
"kohana/koharness": "*@dev"
|
||||||
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-3.3/develop": "3.3.x-dev",
|
"dev-3.3/develop": "3.3.x-dev",
|
||||||
"dev-3.4/develop": "3.4.x-dev"
|
"dev-3.4/develop": "3.4.x-dev"
|
||||||
|
},
|
||||||
|
"installer-paths": {
|
||||||
|
"vendor/{$vendor}/{$name}": ["type:kohana-module"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
modules/auth/koharness.php
Normal file
8
modules/auth/koharness.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
// Configuration for koharness - builds a standalone skeleton Kohana app for running unit tests
|
||||||
|
return array(
|
||||||
|
'modules' => array(
|
||||||
|
'auth' => __DIR__,
|
||||||
|
'unittest' => __DIR__ . '/vendor/kohana/unittest'
|
||||||
|
),
|
||||||
|
);
|
45
modules/cache/.travis.yml
vendored
Normal file
45
modules/cache/.travis.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
sudo: false
|
||||||
|
|
||||||
|
language: php
|
||||||
|
|
||||||
|
# Only build the main develop/master branches - feature branches will be covered by PRs
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- /^[0-9\.]+\/(develop|master)$/
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- vendor
|
||||||
|
- $HOME/.composer/cache
|
||||||
|
|
||||||
|
php:
|
||||||
|
- 5.3
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
- 7.0
|
||||||
|
- hhvm
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- php: 5.3
|
||||||
|
env: 'COMPOSER_PHPUNIT="lowest"'
|
||||||
|
|
||||||
|
services:
|
||||||
|
- memcached
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- if [[ $TRAVIS_PHP_VERSION != "hhvm" ]]; then INI_FILE=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; else INI_FILE=/etc/hhvm/php.ini; fi;
|
||||||
|
- if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then echo extension = memcache.so >> $INI_FILE; fi;
|
||||||
|
- if [[ $TRAVIS_PHP_VERSION = 5.* ]]; then (echo yes | pecl install -f apcu-4.0.10 && echo apc.enable_cli = 1 >> $INI_FILE); fi;
|
||||||
|
- if [[ $TRAVIS_PHP_VERSION = 7.* ]]; then (echo yes | pecl install -f apcu-5.1.2 && echo apc.enable_cli = 1 >> $INI_FILE); fi;
|
||||||
|
- if [[ $TRAVIS_PHP_VERSION != "hhvm" ]] ; then echo -e 'apc.max_file_size = 0\napc.cache_by_default = 0' >> $INI_FILE ; fi
|
||||||
|
- composer install --prefer-dist
|
||||||
|
- if [ "$COMPOSER_PHPUNIT" = "lowest" ]; then composer update --prefer-lowest --with-dependencies phpunit/phpunit; fi;
|
||||||
|
- vendor/bin/koharness
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cd /tmp/koharness && ./vendor/bin/phpunit --bootstrap=modules/unittest/bootstrap.php modules/unittest/tests.php
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
6
modules/cache/README.md
vendored
6
modules/cache/README.md
vendored
@ -1,6 +1,12 @@
|
|||||||
Kohana Cache library
|
Kohana Cache library
|
||||||
====================
|
====================
|
||||||
|
|
||||||
|
| ver | Stable | Develop |
|
||||||
|
|-------|--------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| 3.3.x | [![Build Status - 3.3/master](https://travis-ci.org/kohana/cache.svg?branch=3.3%2Fmaster)](https://travis-ci.org/kohana/cache) | [![Build Status - 3.3/develop](https://travis-ci.org/kohana/cache.svg?branch=3.3%2Fdevelop)](https://travis-ci.org/kohana/cache) |
|
||||||
|
| 3.4.x | [![Build Status - 3.4/master](https://travis-ci.org/kohana/cache.svg?branch=3.4%2Fmaster)](https://travis-ci.org/kohana/cache) | [![Build Status - 3.4/develop](https://travis-ci.org/kohana/cache.svg?branch=3.4%2Fdevelop)](https://travis-ci.org/kohana/cache) |
|
||||||
|
|
||||||
|
|
||||||
The cache library for Kohana 3 provides a simple interface to the most common cache solutions. Developers are free to add their own caching solutions that follow the cache design pattern defined within this module.
|
The cache library for Kohana 3 provides a simple interface to the most common cache solutions. Developers are free to add their own caching solutions that follow the cache design pattern defined within this module.
|
||||||
|
|
||||||
Supported cache solutions
|
Supported cache solutions
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct script access.');
|
<?php defined('SYSPATH') or die('No direct script access.');
|
||||||
|
|
||||||
class Pagination extends Kohana_Pagination {}
|
class Cache_Apcu extends Kohana_Cache_Apcu {}
|
10
modules/cache/classes/Kohana/Cache.php
vendored
10
modules/cache/classes/Kohana/Cache.php
vendored
@ -36,7 +36,7 @@
|
|||||||
* Below is an example of a _memcache_ server configuration.
|
* Below is an example of a _memcache_ server configuration.
|
||||||
*
|
*
|
||||||
* return array(
|
* return array(
|
||||||
* 'default' => array( // Default group
|
* 'memcache' => array( // Name of group
|
||||||
* 'driver' => 'memcache', // using Memcache driver
|
* 'driver' => 'memcache', // using Memcache driver
|
||||||
* 'servers' => array( // Available server definitions
|
* 'servers' => array( // Available server definitions
|
||||||
* array(
|
* array(
|
||||||
@ -49,8 +49,12 @@
|
|||||||
* ),
|
* ),
|
||||||
* )
|
* )
|
||||||
*
|
*
|
||||||
* In cases where only one cache group is required, if the group is named `default` there is
|
* In cases where only one cache group is required, set `Cache::$default` (in your bootstrap,
|
||||||
* no need to pass the group name when instantiating a cache instance.
|
* or by extending `Kohana_Cache` class) to the name of the group, and use:
|
||||||
|
*
|
||||||
|
* $cache = Cache::instance(); // instead of Cache::instance('memcache')
|
||||||
|
*
|
||||||
|
* It will return the cache instance of the group it has been set in `Cache::$default`.
|
||||||
*
|
*
|
||||||
* #### General cache group configuration settings
|
* #### General cache group configuration settings
|
||||||
*
|
*
|
||||||
|
174
modules/cache/classes/Kohana/Cache/Apcu.php
vendored
Normal file
174
modules/cache/classes/Kohana/Cache/Apcu.php
vendored
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
<?php defined('SYSPATH') or die('No direct script access.');
|
||||||
|
/**
|
||||||
|
* [Kohana Cache](api/Kohana_Cache) APCu data store driver for Kohana Cache
|
||||||
|
* library.
|
||||||
|
*
|
||||||
|
* ### Configuration example
|
||||||
|
*
|
||||||
|
* Below is an example of an _apcu_ server configuration.
|
||||||
|
*
|
||||||
|
* return array(
|
||||||
|
* 'apcu' => array( // Driver group
|
||||||
|
* 'driver' => 'apcu', // using APCu driver
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* In cases where only one cache group is required, if the group is named `default` there is
|
||||||
|
* no need to pass the group name when instantiating a cache instance.
|
||||||
|
*
|
||||||
|
* #### General cache group configuration settings
|
||||||
|
*
|
||||||
|
* Below are the settings available to all types of cache driver.
|
||||||
|
*
|
||||||
|
* Name | Required | Description
|
||||||
|
* -------------- | -------- | ---------------------------------------------------------------
|
||||||
|
* driver | __YES__ | (_string_) The driver type to use
|
||||||
|
*
|
||||||
|
* ### System requirements
|
||||||
|
*
|
||||||
|
* * Kohana 3.0.x
|
||||||
|
* * PHP 5.2.4 or greater
|
||||||
|
* * APCu PHP extension
|
||||||
|
*
|
||||||
|
* @package Kohana/Cache
|
||||||
|
* @category Base
|
||||||
|
* @author Kohana Team
|
||||||
|
* @copyright (c) 2009-2012 Kohana Team
|
||||||
|
* @license http://kohanaphp.com/license
|
||||||
|
*/
|
||||||
|
class Kohana_Cache_Apcu extends Cache implements Cache_Arithmetic {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for existence of the APCu extension This method cannot be invoked externally. The driver must
|
||||||
|
* be instantiated using the `Cache::instance()` method.
|
||||||
|
*
|
||||||
|
* @param array $config configuration
|
||||||
|
* @throws Cache_Exception
|
||||||
|
*/
|
||||||
|
protected function __construct(array $config)
|
||||||
|
{
|
||||||
|
if ( ! extension_loaded('apcu'))
|
||||||
|
{
|
||||||
|
throw new Cache_Exception('PHP APCu extension is not available.');
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a cached value entry by id.
|
||||||
|
*
|
||||||
|
* // Retrieve cache entry from apcu group
|
||||||
|
* $data = Cache::instance('apcu')->get('foo');
|
||||||
|
*
|
||||||
|
* // Retrieve cache entry from apcu group and return 'bar' if miss
|
||||||
|
* $data = Cache::instance('apcu')->get('foo', 'bar');
|
||||||
|
*
|
||||||
|
* @param string $id id of cache to entry
|
||||||
|
* @param string $default default value to return if cache miss
|
||||||
|
* @return mixed
|
||||||
|
* @throws Cache_Exception
|
||||||
|
*/
|
||||||
|
public function get($id, $default = NULL)
|
||||||
|
{
|
||||||
|
$data = apcu_fetch($this->_sanitize_id($id), $success);
|
||||||
|
|
||||||
|
return $success ? $data : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a value to cache with id and lifetime
|
||||||
|
*
|
||||||
|
* $data = 'bar';
|
||||||
|
*
|
||||||
|
* // Set 'bar' to 'foo' in apcu group, using default expiry
|
||||||
|
* Cache::instance('apcu')->set('foo', $data);
|
||||||
|
*
|
||||||
|
* // Set 'bar' to 'foo' in apcu group for 30 seconds
|
||||||
|
* Cache::instance('apcu')->set('foo', $data, 30);
|
||||||
|
*
|
||||||
|
* @param string $id id of cache entry
|
||||||
|
* @param string $data data to set to cache
|
||||||
|
* @param integer $lifetime lifetime in seconds
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function set($id, $data, $lifetime = NULL)
|
||||||
|
{
|
||||||
|
if ($lifetime === NULL)
|
||||||
|
{
|
||||||
|
$lifetime = Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return apcu_store($this->_sanitize_id($id), $data, $lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a cache entry based on id
|
||||||
|
*
|
||||||
|
* // Delete 'foo' entry from the apcu group
|
||||||
|
* Cache::instance('apcu')->delete('foo');
|
||||||
|
*
|
||||||
|
* @param string $id id to remove from cache
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function delete($id)
|
||||||
|
{
|
||||||
|
return apcu_delete($this->_sanitize_id($id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all cache entries.
|
||||||
|
*
|
||||||
|
* Beware of using this method when
|
||||||
|
* using shared memory cache systems, as it will wipe every
|
||||||
|
* entry within the system for all clients.
|
||||||
|
*
|
||||||
|
* // Delete all cache entries in the apcu group
|
||||||
|
* Cache::instance('apcu')->delete_all();
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function delete_all()
|
||||||
|
{
|
||||||
|
return apcu_clear_cache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments a given value by the step value supplied.
|
||||||
|
* Useful for shared counters and other persistent integer based
|
||||||
|
* tracking.
|
||||||
|
*
|
||||||
|
* @param string id of cache entry to increment
|
||||||
|
* @param int step value to increment by
|
||||||
|
* @return integer
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function increment($id, $step = 1)
|
||||||
|
{
|
||||||
|
if (apcu_exists($id)) {
|
||||||
|
return apcu_inc($id, $step);
|
||||||
|
} else {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements a given value by the step value supplied.
|
||||||
|
* Useful for shared counters and other persistent integer based
|
||||||
|
* tracking.
|
||||||
|
*
|
||||||
|
* @param string id of cache entry to decrement
|
||||||
|
* @param int step value to decrement by
|
||||||
|
* @return integer
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function decrement($id, $step = 1)
|
||||||
|
{
|
||||||
|
if (apcu_exists($id)) {
|
||||||
|
return apcu_dec($id, $step);
|
||||||
|
} else {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End Kohana_Cache_Apcu
|
93
modules/cache/classes/Kohana/Cache/File.php
vendored
93
modules/cache/classes/Kohana/Cache/File.php
vendored
@ -140,17 +140,21 @@ class Kohana_Cache_File extends Cache implements Cache_GarbageCollect {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Open the file and parse data
|
// Test the expiry
|
||||||
$created = $file->getMTime();
|
if ($this->_is_expired($file))
|
||||||
$data = $file->openFile();
|
|
||||||
$lifetime = $data->fgets();
|
|
||||||
|
|
||||||
// If we're at the EOF at this point, corrupted!
|
|
||||||
if ($data->eof())
|
|
||||||
{
|
{
|
||||||
throw new Cache_Exception(__METHOD__.' corrupted cache file!');
|
// Delete the file
|
||||||
|
$this->_delete_file($file, FALSE, TRUE);
|
||||||
|
return $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// open the file to read data
|
||||||
|
$data = $file->openFile();
|
||||||
|
|
||||||
|
// Run first fgets(). Cache data starts from the second line
|
||||||
|
// as the first contains the lifetime timestamp
|
||||||
|
$data->fgets();
|
||||||
|
|
||||||
$cache = '';
|
$cache = '';
|
||||||
|
|
||||||
while ($data->eof() === FALSE)
|
while ($data->eof() === FALSE)
|
||||||
@ -158,17 +162,7 @@ class Kohana_Cache_File extends Cache implements Cache_GarbageCollect {
|
|||||||
$cache .= $data->fgets();
|
$cache .= $data->fgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test the expiry
|
return unserialize($cache);
|
||||||
if (($created + (int) $lifetime) < time())
|
|
||||||
{
|
|
||||||
// Delete the file
|
|
||||||
$this->_delete_file($file, NULL, TRUE);
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return unserialize($cache);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -219,14 +213,7 @@ class Kohana_Cache_File extends Cache implements Cache_GarbageCollect {
|
|||||||
// If the directory path is not a directory
|
// If the directory path is not a directory
|
||||||
if ( ! $dir->isDir())
|
if ( ! $dir->isDir())
|
||||||
{
|
{
|
||||||
// Create the directory
|
$this->_make_directory($directory, 0777, TRUE);
|
||||||
if ( ! mkdir($directory, 0777, TRUE))
|
|
||||||
{
|
|
||||||
throw new Cache_Exception(__METHOD__.' unable to create directory : :directory', array(':directory' => $directory));
|
|
||||||
}
|
|
||||||
|
|
||||||
// chmod to solve potential umask issues
|
|
||||||
chmod($directory, 0777);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open file to inspect
|
// Open file to inspect
|
||||||
@ -267,7 +254,7 @@ class Kohana_Cache_File extends Cache implements Cache_GarbageCollect {
|
|||||||
$filename = Cache_File::filename($this->_sanitize_id($id));
|
$filename = Cache_File::filename($this->_sanitize_id($id));
|
||||||
$directory = $this->_resolve_directory($filename);
|
$directory = $this->_resolve_directory($filename);
|
||||||
|
|
||||||
return $this->_delete_file(new SplFileInfo($directory.$filename), NULL, TRUE);
|
return $this->_delete_file(new SplFileInfo($directory.$filename), FALSE, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -337,9 +324,7 @@ class Kohana_Cache_File extends Cache implements Cache_GarbageCollect {
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Assess the file expiry to flag it for deletion
|
// Assess the file expiry to flag it for deletion
|
||||||
$json = $file->openFile('r')->current();
|
$delete = $this->_is_expired($file);
|
||||||
$data = json_decode($json);
|
|
||||||
$delete = $data->expiry < time();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the delete flag is set delete file
|
// If the delete flag is set delete file
|
||||||
@ -375,7 +360,7 @@ class Kohana_Cache_File extends Cache implements Cache_GarbageCollect {
|
|||||||
// Create new file resource
|
// Create new file resource
|
||||||
$fp = new SplFileInfo($files->getRealPath());
|
$fp = new SplFileInfo($files->getRealPath());
|
||||||
// Delete the file
|
// Delete the file
|
||||||
$this->_delete_file($fp);
|
$this->_delete_file($fp, $retain_parent_directory, $ignore_errors, $only_expired);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the file pointer on
|
// Move the file pointer on
|
||||||
@ -446,21 +431,55 @@ class Kohana_Cache_File extends Cache implements Cache_GarbageCollect {
|
|||||||
* `mkdir` to ensure DRY principles
|
* `mkdir` to ensure DRY principles
|
||||||
*
|
*
|
||||||
* @link http://php.net/manual/en/function.mkdir.php
|
* @link http://php.net/manual/en/function.mkdir.php
|
||||||
* @param string $directory
|
* @param string $directory directory path
|
||||||
* @param integer $mode
|
* @param integer $mode chmod mode
|
||||||
* @param boolean $recursive
|
* @param boolean $recursive allows nested directories creation
|
||||||
* @param resource $context
|
* @param resource $context a stream context
|
||||||
* @return SplFileInfo
|
* @return SplFileInfo
|
||||||
* @throws Cache_Exception
|
* @throws Cache_Exception
|
||||||
*/
|
*/
|
||||||
protected function _make_directory($directory, $mode = 0777, $recursive = FALSE, $context = NULL)
|
protected function _make_directory($directory, $mode = 0777, $recursive = FALSE, $context = NULL)
|
||||||
{
|
{
|
||||||
if ( ! mkdir($directory, $mode, $recursive, $context))
|
// call mkdir according to the availability of a passed $context param
|
||||||
|
$mkdir_result = $context ?
|
||||||
|
mkdir($directory, $mode, $recursive, $context) :
|
||||||
|
mkdir($directory, $mode, $recursive);
|
||||||
|
|
||||||
|
// throw an exception if unsuccessful
|
||||||
|
if ( ! $mkdir_result)
|
||||||
{
|
{
|
||||||
throw new Cache_Exception('Failed to create the defined cache directory : :directory', array(':directory' => $directory));
|
throw new Cache_Exception('Failed to create the defined cache directory : :directory', array(':directory' => $directory));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// chmod to solve potential umask issues
|
||||||
chmod($directory, $mode);
|
chmod($directory, $mode);
|
||||||
|
|
||||||
return new SplFileInfo($directory);
|
return new SplFileInfo($directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if cache file is expired
|
||||||
|
*
|
||||||
|
* @param SplFileInfo $file the cache file
|
||||||
|
* @return boolean TRUE if expired false otherwise
|
||||||
|
*/
|
||||||
|
protected function _is_expired(SplFileInfo $file)
|
||||||
|
{
|
||||||
|
// Open the file and parse data
|
||||||
|
$created = $file->getMTime();
|
||||||
|
$data = $file->openFile("r");
|
||||||
|
$lifetime = (int) $data->fgets();
|
||||||
|
|
||||||
|
// If we're at the EOF at this point, corrupted!
|
||||||
|
if ($data->eof())
|
||||||
|
{
|
||||||
|
throw new Cache_Exception(__METHOD__ . ' corrupted cache file!');
|
||||||
|
}
|
||||||
|
|
||||||
|
//close file
|
||||||
|
$data = null;
|
||||||
|
|
||||||
|
// test for expiry and return
|
||||||
|
return (($lifetime !== 0) AND ( ($created + $lifetime) < time()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
6
modules/cache/classes/Kohana/HTTP/Cache.php
vendored
6
modules/cache/classes/Kohana/HTTP/Cache.php
vendored
@ -1,6 +1,6 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct script access.');
|
<?php defined('SYSPATH') or die('No direct script access.');
|
||||||
/**
|
/**
|
||||||
* HTTT Caching adaptor class that provides caching services to the
|
* HTTP Caching adaptor class that provides caching services to the
|
||||||
* [Request_Client] class, using HTTP cache control logic as defined in
|
* [Request_Client] class, using HTTP cache control logic as defined in
|
||||||
* RFC 2616.
|
* RFC 2616.
|
||||||
*
|
*
|
||||||
@ -36,7 +36,7 @@ class Kohana_HTTP_Cache {
|
|||||||
* )
|
* )
|
||||||
* );
|
* );
|
||||||
*
|
*
|
||||||
* @uses [Cache]
|
* @uses Cache
|
||||||
* @param mixed $cache cache engine to use
|
* @param mixed $cache cache engine to use
|
||||||
* @param array $options options to set to this class
|
* @param array $options options to set to this class
|
||||||
* @return HTTP_Cache
|
* @return HTTP_Cache
|
||||||
@ -298,7 +298,7 @@ class Kohana_HTTP_Cache {
|
|||||||
* Controls whether the response can be cached. Uses HTTP
|
* Controls whether the response can be cached. Uses HTTP
|
||||||
* protocol to determine whether the response can be cached.
|
* protocol to determine whether the response can be cached.
|
||||||
*
|
*
|
||||||
* @link RFC 2616 http://www.w3.org/Protocols/rfc2616/
|
* @link http://www.w3.org/Protocols/rfc2616/rfc2616.html RFC 2616
|
||||||
* @param Response $response The Response
|
* @param Response $response The Response
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
|
10
modules/cache/composer.json
vendored
10
modules/cache/composer.json
vendored
@ -24,10 +24,18 @@
|
|||||||
"kohana/core": ">=3.3",
|
"kohana/core": ">=3.3",
|
||||||
"php": ">=5.3.3"
|
"php": ">=5.3.3"
|
||||||
},
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"kohana/core": "3.3.*@dev",
|
||||||
|
"kohana/unittest": "3.3.*@dev",
|
||||||
|
"kohana/koharness": "*@dev"
|
||||||
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-3.3/develop": "3.3.x-dev",
|
"dev-3.3/develop": "3.3.x-dev",
|
||||||
"dev-3.4/develop": "3.4.x-dev"
|
"dev-3.4/develop": "3.4.x-dev"
|
||||||
}
|
},
|
||||||
|
"installer-paths": {
|
||||||
|
"vendor/{$vendor}/{$name}": ["type:kohana-module"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
modules/cache/guide/cache/config.md
vendored
12
modules/cache/guide/cache/config.md
vendored
@ -55,7 +55,7 @@ failure_callback | __NO__ | (_[callback](http://www.php.net/manual/en/language
|
|||||||
'driver' => 'memcache',
|
'driver' => 'memcache',
|
||||||
'default_expire' => 3600,
|
'default_expire' => 3600,
|
||||||
'compression' => FALSE, // Use Zlib compression
|
'compression' => FALSE, // Use Zlib compression
|
||||||
(can cause issues with integers)
|
// (can cause issues with integers)
|
||||||
'servers' => array
|
'servers' => array
|
||||||
(
|
(
|
||||||
'local' => array
|
'local' => array
|
||||||
@ -71,7 +71,7 @@ failure_callback | __NO__ | (_[callback](http://www.php.net/manual/en/language
|
|||||||
'driver' => 'memcachetag',
|
'driver' => 'memcachetag',
|
||||||
'default_expire' => 3600,
|
'default_expire' => 3600,
|
||||||
'compression' => FALSE, // Use Zlib compression
|
'compression' => FALSE, // Use Zlib compression
|
||||||
(can cause issues with integers)
|
// (can cause issues with integers)
|
||||||
'servers' => array
|
'servers' => array
|
||||||
(
|
(
|
||||||
'local' => array
|
'local' => array
|
||||||
@ -91,6 +91,14 @@ failure_callback | __NO__ | (_[callback](http://www.php.net/manual/en/language
|
|||||||
'default_expire' => 3600,
|
'default_expire' => 3600,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
## APCu settings
|
||||||
|
|
||||||
|
'apcu' => array
|
||||||
|
(
|
||||||
|
'driver' => 'apcu',
|
||||||
|
'default_expire' => 3600,
|
||||||
|
),
|
||||||
|
|
||||||
## SQLite settings
|
## SQLite settings
|
||||||
|
|
||||||
'sqlite' => array
|
'sqlite' => array
|
||||||
|
8
modules/cache/guide/cache/index.md
vendored
8
modules/cache/guide/cache/index.md
vendored
@ -6,7 +6,7 @@ instances of cache engines through a grouped singleton pattern.
|
|||||||
|
|
||||||
## Supported cache engines
|
## Supported cache engines
|
||||||
|
|
||||||
* APC ([Cache_Apc])
|
* APC/APCu ([Cache_Apc])
|
||||||
* File ([Cache_File])
|
* File ([Cache_File])
|
||||||
* Memcached ([Cache_Memcache])
|
* Memcached ([Cache_Memcache])
|
||||||
* Memcached-tags ([Cache_Memcachetag])
|
* Memcached-tags ([Cache_Memcachetag])
|
||||||
@ -16,13 +16,13 @@ instances of cache engines through a grouped singleton pattern.
|
|||||||
## Introduction to caching
|
## Introduction to caching
|
||||||
|
|
||||||
Caching should be implemented with consideration. Generally, caching the result of resources
|
Caching should be implemented with consideration. Generally, caching the result of resources
|
||||||
is faster than reprocessing them. Choosing what, how and when to cache is vital. [PHP APC](http://php.net/manual/en/book.apc.php) is one of the fastest caching systems available, closely followed by [Memcached](http://memcached.org/). [SQLite](http://www.sqlite.org/) and File caching are two of the slowest cache methods, however usually faster than reprocessing
|
is faster than reprocessing them. Choosing what, how and when to cache is vital. [PHP APCu](http://php.net/manual/en/book.apcu.php) is one of the fastest caching systems available, closely followed by [Memcached](http://memcached.org/). [SQLite](http://www.sqlite.org/) and File caching are two of the slowest cache methods, however usually faster than reprocessing
|
||||||
a complex set of instructions.
|
a complex set of instructions.
|
||||||
|
|
||||||
Caching engines that use memory are considerably faster than file based alternatives. But
|
Caching engines that use memory are considerably faster than file based alternatives. But
|
||||||
memory is limited whereas disk space is plentiful. If caching large datasets, such as large database result sets, it is best to use file caching.
|
memory is limited whereas disk space is plentiful. If caching large datasets, such as large database result sets, it is best to use file caching.
|
||||||
|
|
||||||
[!!] Cache drivers require the relevant PHP extensions to be installed. APC, eAccelerator, Memecached and Xcache all require non-standard PHP extensions.
|
[!!] Cache drivers require the relevant PHP extensions to be installed. APC, eAccelerator, Memecached and Xcache all require non-standard PHP extensions.
|
||||||
|
|
||||||
## What the Kohana Cache module does (and does not do)
|
## What the Kohana Cache module does (and does not do)
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ Getting and setting values to cache is very simple when using the _Kohana Cache_
|
|||||||
|
|
||||||
Driver | Storage | Speed | Tags | Distributed | Automatic Garbage Collection | Notes
|
Driver | Storage | Speed | Tags | Distributed | Automatic Garbage Collection | Notes
|
||||||
---------------- | ------------ | --------- | -------- | ----------- | ---------------------------- | -----------------------
|
---------------- | ------------ | --------- | -------- | ----------- | ---------------------------- | -----------------------
|
||||||
APC | __Memory__ | Excellent | No | No | Yes | Widely available PHP opcode caching solution, improves php execution performance
|
APC/APCu | __Memory__ | Excellent | No | No | Yes | Widely available PHP opcode caching solution, improves php execution performance
|
||||||
Wincache | __Memory__ | Excellent | No | No | Yes | Windows variant of APC
|
Wincache | __Memory__ | Excellent | No | No | Yes | Windows variant of APC
|
||||||
File | __Disk__ | Poor | No | No | No | Marginally faster than execution
|
File | __Disk__ | Poor | No | No | No | Marginally faster than execution
|
||||||
Memcache (tag) | __Memory__ | Good | No (yes) | Yes | Yes | Generally fast distributed solution, but has a speed hit due to variable network latency and serialization
|
Memcache (tag) | __Memory__ | Good | No (yes) | Yes | Yes | Generally fast distributed solution, but has a speed hit due to variable network latency and serialization
|
||||||
|
10
modules/cache/guide/cache/usage.md
vendored
10
modules/cache/guide/cache/usage.md
vendored
@ -9,7 +9,7 @@ Creating a new _Kohana Cache_ instance is simple, however it must be done using
|
|||||||
// Create a new instance of cache using the default group
|
// Create a new instance of cache using the default group
|
||||||
$cache = Cache::instance();
|
$cache = Cache::instance();
|
||||||
|
|
||||||
The default group will use whatever is set to [Cache::$default] and must have a corresponding [configuration](cache.config) definition for that group.
|
The default group will use whatever is set to [Cache::$default] and must have a corresponding [configuration](config) definition for that group.
|
||||||
|
|
||||||
To create a cache instance using a group other than the _default_, simply provide the group name as an argument.
|
To create a cache instance using a group other than the _default_, simply provide the group name as an argument.
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ To create a cache instance using a group other than the _default_, simply provid
|
|||||||
|
|
||||||
If there is a cache instance already instantiated then you can get it directly from the class member.
|
If there is a cache instance already instantiated then you can get it directly from the class member.
|
||||||
|
|
||||||
[!!] Beware that this can cause issues if you do not test for the instance before trying to access it.
|
[!!] Beware that this can cause issues if you do not test for the instance before trying to access it.
|
||||||
|
|
||||||
// Check for the existance of the cache driver
|
// Check for the existance of the cache driver
|
||||||
if (isset(Cache::$instances['memcache']))
|
if (isset(Cache::$instances['memcache']))
|
||||||
@ -36,11 +36,11 @@ If there is a cache instance already instantiated then you can get it directly f
|
|||||||
|
|
||||||
The cache library supports scalar and object values, utilising object serialization where required (or not supported by the caching engine). This means that the majority or objects can be cached without any modification.
|
The cache library supports scalar and object values, utilising object serialization where required (or not supported by the caching engine). This means that the majority or objects can be cached without any modification.
|
||||||
|
|
||||||
[!!] Serialisation does not work with resource handles, such as filesystem, curl or socket resources.
|
[!!] Serialisation does not work with resource handles, such as filesystem, curl or socket resources.
|
||||||
|
|
||||||
### Setting a value to cache
|
### Setting a value to cache
|
||||||
|
|
||||||
Setting a value to cache using the [Cache::set] method can be done in one of two ways; either using the Cache instance interface, which is good for atomic operations; or getting an instance and using that for multiple operations.
|
Setting a value to cache using the [Cache::set] method can be done in one of two ways: either using the Cache instance interface, which is good for atomic operations, or getting an instance and using that for multiple operations.
|
||||||
|
|
||||||
The first example demonstrates how to quickly load and set a value to the default cache instance.
|
The first example demonstrates how to quickly load and set a value to the default cache instance.
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ In cases where the requested key is not available or the entry has expired, a de
|
|||||||
|
|
||||||
It is possible to retrieve values from cache grouped by tag, using the [Cache::find] method with drivers that support tagging.
|
It is possible to retrieve values from cache grouped by tag, using the [Cache::find] method with drivers that support tagging.
|
||||||
|
|
||||||
[!!] The __Memcachetag__ driver does not support the `Cache::find($tag)` interface and will throw an exception.
|
[!!] The __Memcachetag__ driver does not support the `Cache::find($tag)` interface and will throw an exception.
|
||||||
|
|
||||||
// Get an instance of cache
|
// Get an instance of cache
|
||||||
$cache = Cache::instance('memcachetag');
|
$cache = Cache::instance('memcachetag');
|
||||||
|
9
modules/cache/koharness.php
vendored
Normal file
9
modules/cache/koharness.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
// Configuration for koharness - builds a standalone skeleton Kohana app for running unit tests
|
||||||
|
return array(
|
||||||
|
'kohana_version' => '3.3',
|
||||||
|
'modules' => array(
|
||||||
|
'cache' => __DIR__,
|
||||||
|
'unittest' => __DIR__ . '/vendor/kohana/unittest'
|
||||||
|
),
|
||||||
|
);
|
@ -164,6 +164,17 @@ TESTTEXT;
|
|||||||
),
|
),
|
||||||
'foo bar snafu'
|
'foo bar snafu'
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'id' => 'test ttl 0 means never expire',
|
||||||
|
'value' => 'cache value that should last',
|
||||||
|
'ttl' => 0,
|
||||||
|
'wait' => 1,
|
||||||
|
'type' => 'string',
|
||||||
|
'default' => NULL
|
||||||
|
),
|
||||||
|
'cache value that should last'
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
array(
|
array(
|
||||||
'id' => 'bar',
|
'id' => 'bar',
|
||||||
@ -196,6 +207,28 @@ TESTTEXT;
|
|||||||
'default' => NULL,
|
'default' => NULL,
|
||||||
),
|
),
|
||||||
$html_text
|
$html_text
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'id' => 'test with 60*5',
|
||||||
|
'value' => 'blabla',
|
||||||
|
'ttl' => 60*5,
|
||||||
|
'wait' => FALSE,
|
||||||
|
'type' => 'string',
|
||||||
|
'default' => NULL,
|
||||||
|
),
|
||||||
|
'blabla'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'id' => 'test with 60*50',
|
||||||
|
'value' => 'bla bla',
|
||||||
|
'ttl' => 60*50,
|
||||||
|
'wait' => FALSE,
|
||||||
|
'type' => 'string',
|
||||||
|
'default' => NULL,
|
||||||
|
),
|
||||||
|
'bla bla'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
9
modules/cache/tests/cache/CacheTest.php
vendored
9
modules/cache/tests/cache/CacheTest.php
vendored
@ -90,14 +90,13 @@ class Kohana_CacheTest extends PHPUnit_Framework_TestCase {
|
|||||||
*/
|
*/
|
||||||
public function test_cloning_fails()
|
public function test_cloning_fails()
|
||||||
{
|
{
|
||||||
if ( ! Kohana::$config->load('cache.file'))
|
$cache = $this->getMockBuilder('Cache')
|
||||||
{
|
->disableOriginalConstructor()
|
||||||
$this->markTestSkipped('Unable to load File configuration');
|
->getMockForAbstractClass();
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$cache_clone = clone(Cache::instance('file'));
|
clone($cache);
|
||||||
}
|
}
|
||||||
catch (Cache_Exception $e)
|
catch (Cache_Exception $e)
|
||||||
{
|
{
|
||||||
|
69
modules/cache/tests/cache/FileTest.php
vendored
69
modules/cache/tests/cache/FileTest.php
vendored
@ -30,7 +30,21 @@ class Kohana_Cache_FileTest extends Kohana_CacheBasicMethodsTest {
|
|||||||
|
|
||||||
if ( ! Kohana::$config->load('cache.file'))
|
if ( ! Kohana::$config->load('cache.file'))
|
||||||
{
|
{
|
||||||
$this->markTestSkipped('Unable to load File configuration');
|
Kohana::$config->load('cache')
|
||||||
|
->set(
|
||||||
|
'file',
|
||||||
|
array(
|
||||||
|
'driver' => 'file',
|
||||||
|
'cache_dir' => APPPATH.'cache',
|
||||||
|
'default_expire' => 3600,
|
||||||
|
'ignore_on_delete' => array(
|
||||||
|
'file_we_want_to_keep.cache',
|
||||||
|
'.gitignore',
|
||||||
|
'.git',
|
||||||
|
'.svn'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->cache(Cache::instance('file'));
|
$this->cache(Cache::instance('file'));
|
||||||
@ -45,7 +59,7 @@ class Kohana_Cache_FileTest extends Kohana_CacheBasicMethodsTest {
|
|||||||
{
|
{
|
||||||
$cache = $this->cache();
|
$cache = $this->cache();
|
||||||
$config = Kohana::$config->load('cache')->file;
|
$config = Kohana::$config->load('cache')->file;
|
||||||
$file = $config['cache_dir'].'/.gitignore';
|
$file = $config['cache_dir'].'/file_we_want_to_keep.cache';
|
||||||
|
|
||||||
// Lets pollute the cache folder
|
// Lets pollute the cache folder
|
||||||
file_put_contents($file, 'foobar');
|
file_put_contents($file, 'foobar');
|
||||||
@ -95,4 +109,55 @@ class Kohana_Cache_FileTest extends Kohana_CacheBasicMethodsTest {
|
|||||||
$this->assertSame($expected, $cache->get('utf8'));
|
$this->assertSame($expected, $cache->get('utf8'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests garbage collection.
|
||||||
|
* Tests if non-expired cache files withstand garbage collection
|
||||||
|
*
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function test_garbage_collection()
|
||||||
|
{
|
||||||
|
$cache = $this->cache();
|
||||||
|
$cache->set('persistent', 'dummy persistent data', 3);
|
||||||
|
$cache->set('volatile', 'dummy volatile data', 1);
|
||||||
|
|
||||||
|
$this->assertTrue($this->is_file('persistent'));
|
||||||
|
$this->assertTrue($this->is_file('volatile'));
|
||||||
|
|
||||||
|
// sleep for more than a second
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
$cache->garbage_collect();
|
||||||
|
|
||||||
|
$this->assertTrue($this->is_file('persistent'));
|
||||||
|
$this->assertFalse($this->is_file('volatile'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper method for test_garbage_collection.
|
||||||
|
* Tests if cache file exists given cache id.
|
||||||
|
*
|
||||||
|
* @param string $id cache id
|
||||||
|
* @return boolean TRUE if file exists FALSE otherwise
|
||||||
|
*/
|
||||||
|
protected function is_file($id)
|
||||||
|
{
|
||||||
|
$cache = $this->cache();
|
||||||
|
|
||||||
|
$method_sanitize_id = new ReflectionMethod($cache, '_sanitize_id');
|
||||||
|
$method_sanitize_id->setAccessible(TRUE);
|
||||||
|
$method_filename = new ReflectionMethod($cache, 'filename');
|
||||||
|
$method_filename->setAccessible(TRUE);
|
||||||
|
$method_resolve_directory = new ReflectionMethod($cache, '_resolve_directory');
|
||||||
|
$method_resolve_directory->setAccessible(TRUE);
|
||||||
|
|
||||||
|
$sanitized_id = $method_sanitize_id->invoke($cache, $id);
|
||||||
|
$filename = $method_filename->invoke($cache, $sanitized_id);
|
||||||
|
$directory = $method_resolve_directory->invoke($cache, $filename);
|
||||||
|
|
||||||
|
$file = new SplFileInfo($directory.$filename);
|
||||||
|
|
||||||
|
//var_dump($cache->_is_expired($file));
|
||||||
|
return $file->isFile();
|
||||||
|
}
|
||||||
} // End Kohana_SqliteTest
|
} // End Kohana_SqliteTest
|
||||||
|
11
modules/cache/tests/cache/SqliteTest.php
vendored
11
modules/cache/tests/cache/SqliteTest.php
vendored
@ -35,7 +35,16 @@ class Kohana_SqliteTest extends Kohana_CacheBasicMethodsTest {
|
|||||||
|
|
||||||
if ( ! Kohana::$config->load('cache.sqlite'))
|
if ( ! Kohana::$config->load('cache.sqlite'))
|
||||||
{
|
{
|
||||||
$this->markTestIncomplete('Unable to load sqlite configuration');
|
Kohana::$config->load('cache')
|
||||||
|
->set(
|
||||||
|
'sqlite',
|
||||||
|
array(
|
||||||
|
'driver' => 'sqlite',
|
||||||
|
'default_expire' => 3600,
|
||||||
|
'database' => 'memory',
|
||||||
|
'schema' => 'CREATE TABLE caches(id VARCHAR(127) PRIMARY KEY, tags VARCHAR(255), expiration INTEGER, cache TEXT)',
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->cache(Cache::instance('sqlite'));
|
$this->cache(Cache::instance('sqlite'));
|
||||||
|
72
modules/cache/tests/cache/WincacheTest.php
vendored
72
modules/cache/tests/cache/WincacheTest.php
vendored
@ -1,39 +1,49 @@
|
|||||||
<?php
|
<?php
|
||||||
include_once(Kohana::find_file('tests/cache', 'CacheBasicMethodsTest'));
|
if (isset($_ENV['TRAVIS']))
|
||||||
|
{
|
||||||
/**
|
// This is really hacky, but without it the result is permanently full of noise that makes it impossible to see
|
||||||
* @package Kohana/Cache
|
// any unexpected skipped tests.
|
||||||
* @group kohana
|
print "Skipping all Wincache driver tests as these will never run on Travis.".\PHP_EOL;
|
||||||
* @group kohana.cache
|
return;
|
||||||
* @category Test
|
}
|
||||||
* @author Kohana Team
|
else
|
||||||
* @copyright (c) 2009-2012 Kohana Team
|
{
|
||||||
* @license http://kohanaphp.com/license
|
include_once(Kohana::find_file('tests/cache', 'CacheBasicMethodsTest'));
|
||||||
*/
|
|
||||||
class Kohana_WincacheTest extends Kohana_CacheBasicMethodsTest {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method MUST be implemented by each driver to setup the `Cache`
|
* @package Kohana/Cache
|
||||||
* instance for each test.
|
* @group kohana
|
||||||
*
|
* @group kohana.cache
|
||||||
* This method should do the following tasks for each driver test:
|
* @category Test
|
||||||
*
|
* @author Kohana Team
|
||||||
* - Test the Cache instance driver is available, skip test otherwise
|
* @copyright (c) 2009-2012 Kohana Team
|
||||||
* - Setup the Cache instance
|
* @license http://kohanaphp.com/license
|
||||||
* - Call the parent setup method, `parent::setUp()`
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
*/
|
||||||
public function setUp()
|
class Kohana_WincacheTest extends Kohana_CacheBasicMethodsTest {
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
|
|
||||||
if ( ! extension_loaded('wincache'))
|
/**
|
||||||
|
* This method MUST be implemented by each driver to setup the `Cache`
|
||||||
|
* instance for each test.
|
||||||
|
*
|
||||||
|
* This method should do the following tasks for each driver test:
|
||||||
|
*
|
||||||
|
* - Test the Cache instance driver is available, skip test otherwise
|
||||||
|
* - Setup the Cache instance
|
||||||
|
* - Call the parent setup method, `parent::setUp()`
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUp()
|
||||||
{
|
{
|
||||||
$this->markTestSkipped('Wincache PHP Extension is not available');
|
parent::setUp();
|
||||||
|
|
||||||
|
if ( ! extension_loaded('wincache'))
|
||||||
|
{
|
||||||
|
$this->markTestSkipped('Wincache PHP Extension is not available');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cache(Cache::instance('wincache'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->cache(Cache::instance('wincache'));
|
} // End Kohana_WincacheTest
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End Kohana_WincacheTest
|
|
||||||
|
12
modules/cache/tests/cache/arithmetic/ApcTest.php
vendored
12
modules/cache/tests/cache/arithmetic/ApcTest.php
vendored
@ -39,6 +39,18 @@ class Kohana_ApcTest extends Kohana_CacheArithmeticMethodsTest {
|
|||||||
'place "apc.enable_cli=1" in your php.ini file');
|
'place "apc.enable_cli=1" in your php.ini file');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! Kohana::$config->load('cache.apc'))
|
||||||
|
{
|
||||||
|
Kohana::$config->load('cache')
|
||||||
|
->set(
|
||||||
|
'apc',
|
||||||
|
array(
|
||||||
|
'driver' => 'apc',
|
||||||
|
'default_expire' => 3600,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$this->cache(Cache::instance('apc'));
|
$this->cache(Cache::instance('apc'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
87
modules/cache/tests/cache/arithmetic/ApcuTest.php
vendored
Normal file
87
modules/cache/tests/cache/arithmetic/ApcuTest.php
vendored
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
include_once(Kohana::find_file('tests/cache/arithmetic', 'CacheArithmeticMethods'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @package Kohana/Cache
|
||||||
|
* @group kohana
|
||||||
|
* @group kohana.cache
|
||||||
|
* @category Test
|
||||||
|
* @author Kohana Team
|
||||||
|
* @copyright (c) 2009-2012 Kohana Team
|
||||||
|
* @license http://kohanaphp.com/license
|
||||||
|
*/
|
||||||
|
class Kohana_ApcuTest extends Kohana_CacheArithmeticMethodsTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method MUST be implemented by each driver to setup the `Cache`
|
||||||
|
* instance for each test.
|
||||||
|
*
|
||||||
|
* This method should do the following tasks for each driver test:
|
||||||
|
*
|
||||||
|
* - Test the Cache instance driver is available, skip test otherwise
|
||||||
|
* - Setup the Cache instance
|
||||||
|
* - Call the parent setup method, `parent::setUp()`
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
if ( ! extension_loaded('apcu'))
|
||||||
|
{
|
||||||
|
$this->markTestSkipped('APCu PHP Extension is not available');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! (ini_get('apc.enabled') AND ini_get('apc.enable_cli')))
|
||||||
|
{
|
||||||
|
$this->markTestSkipped('APCu is not enabled. To fix '.
|
||||||
|
'set "apc.enabled=1" and "apc.enable_cli=1" in your php.ini file');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! Kohana::$config->load('cache.apcu'))
|
||||||
|
{
|
||||||
|
Kohana::$config->load('cache')
|
||||||
|
->set(
|
||||||
|
'apcu',
|
||||||
|
array(
|
||||||
|
'driver' => 'apcu',
|
||||||
|
'default_expire' => 3600,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cache(Cache::instance('apcu'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the [Cache::set()] method, testing;
|
||||||
|
*
|
||||||
|
* - The value is cached
|
||||||
|
* - The lifetime is respected
|
||||||
|
* - The returned value type is as expected
|
||||||
|
* - The default not-found value is respected
|
||||||
|
*
|
||||||
|
* This test doesn't test the TTL as there is a known bug/feature
|
||||||
|
* in APCu that prevents the same request from killing cache on timeout.
|
||||||
|
*
|
||||||
|
* @link http://pecl.php.net/bugs/bug.php?id=16814
|
||||||
|
*
|
||||||
|
* @dataProvider provider_set_get
|
||||||
|
*
|
||||||
|
* @param array data
|
||||||
|
* @param mixed expected
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function test_set_get(array $data, $expected)
|
||||||
|
{
|
||||||
|
if ($data['wait'] !== FALSE)
|
||||||
|
{
|
||||||
|
$this->markTestSkipped('Unable to perform TTL test in CLI, see: '.
|
||||||
|
'http://pecl.php.net/bugs/bug.php?id=16814 for more info!');
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::test_set_get($data, $expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End Kohana_ApcuTest
|
@ -35,7 +35,28 @@ class Kohana_CacheArithmeticMemcacheTest extends Kohana_CacheArithmeticMethodsTe
|
|||||||
}
|
}
|
||||||
if ( ! $config = Kohana::$config->load('cache.memcache'))
|
if ( ! $config = Kohana::$config->load('cache.memcache'))
|
||||||
{
|
{
|
||||||
$this->markTestSkipped('Unable to load Memcache configuration');
|
Kohana::$config->load('cache')
|
||||||
|
->set(
|
||||||
|
'memcache',
|
||||||
|
array(
|
||||||
|
'driver' => 'memcache',
|
||||||
|
'default_expire' => 3600,
|
||||||
|
'compression' => FALSE, // Use Zlib compression (can cause issues with integers)
|
||||||
|
'servers' => array(
|
||||||
|
'local' => array(
|
||||||
|
'host' => 'localhost', // Memcache Server
|
||||||
|
'port' => 11211, // Memcache port number
|
||||||
|
'persistent' => FALSE, // Persistent connection
|
||||||
|
'weight' => 1,
|
||||||
|
'timeout' => 1,
|
||||||
|
'retry_interval' => 15,
|
||||||
|
'status' => TRUE,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'instant_death' => TRUE,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$config = Kohana::$config->load('cache.memcache');
|
||||||
}
|
}
|
||||||
|
|
||||||
$memcache = new Memcache;
|
$memcache = new Memcache;
|
||||||
|
37
modules/codebench/.travis.yml
Normal file
37
modules/codebench/.travis.yml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
sudo: false
|
||||||
|
|
||||||
|
language: php
|
||||||
|
|
||||||
|
# Only build the main develop/master branches - feature branches will be covered by PRs
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- /^[0-9\.]+\/(develop|master)$/
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- vendor
|
||||||
|
- $HOME/.composer/cache
|
||||||
|
|
||||||
|
php:
|
||||||
|
- 5.3
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
- 7.0
|
||||||
|
- hhvm
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- php: 5.3
|
||||||
|
env: 'COMPOSER_PHPUNIT="lowest"'
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- composer install --prefer-dist
|
||||||
|
- if [ "$COMPOSER_PHPUNIT" = "lowest" ]; then composer update --prefer-lowest --with-dependencies phpunit/phpunit; fi;
|
||||||
|
- vendor/bin/koharness
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cd /tmp/koharness && ./vendor/bin/phpunit --bootstrap=modules/unittest/bootstrap.php modules/unittest/tests.php
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
@ -24,10 +24,18 @@
|
|||||||
"kohana/core": ">=3.3",
|
"kohana/core": ">=3.3",
|
||||||
"php": ">=5.3.3"
|
"php": ">=5.3.3"
|
||||||
},
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"kohana/core": "3.3.*@dev",
|
||||||
|
"kohana/unittest": "3.3.*@dev",
|
||||||
|
"kohana/koharness": "*@dev"
|
||||||
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-3.3/develop": "3.3.x-dev",
|
"dev-3.3/develop": "3.3.x-dev",
|
||||||
"dev-3.4/develop": "3.4.x-dev"
|
"dev-3.4/develop": "3.4.x-dev"
|
||||||
}
|
},
|
||||||
|
"installer-paths": {
|
||||||
|
"vendor/{$vendor}/{$name}": ["type:kohana-module"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ Throwing valuable benchmark data away every time I needed to optimize another re
|
|||||||
|
|
||||||
Obviously providing a visual representation of the benchmark results, via simple graphs, would make interpreting them easier. Having not to think about Internet Explorer for once, made writing CSS a whole lot more easy and fun. It resulted in some fine graphs which are fully resizable.
|
Obviously providing a visual representation of the benchmark results, via simple graphs, would make interpreting them easier. Having not to think about Internet Explorer for once, made writing CSS a whole lot more easy and fun. It resulted in some fine graphs which are fully resizable.
|
||||||
|
|
||||||
Below are two screenshots of Codebench in action. `Valid_Color` is a class made for benchmarking different ways to validate hexadecimal HTML color values, e.g. `#FFF`. If you are interested in the story behind the actual regular expressions, take a look at [this topic in the Kohana forums](http://forum.kohanaphp.com/comments.php?DiscussionID=2192).
|
Below are two screenshots of Codebench in action. `Valid_Color` is a class made for benchmarking different ways to validate hexadecimal HTML color values, e.g. `#FFF`. If you are interested in the story behind the actual regular expressions, take a look at [this topic in the Kohana forums](http://forum.kohanaframework.org/discussion/2192).
|
||||||
|
|
||||||
![Benchmarking several ways to validate HTML color values](codebench_screenshot1.png)
|
![Benchmarking several ways to validate HTML color values](codebench_screenshot1.png)
|
||||||
**Benchmarking seven ways to validate HTML color values**
|
**Benchmarking seven ways to validate HTML color values**
|
||||||
|
8
modules/codebench/koharness.php
Normal file
8
modules/codebench/koharness.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
// Configuration for koharness - builds a standalone skeleton Kohana app for running unit tests
|
||||||
|
return array(
|
||||||
|
'modules' => array(
|
||||||
|
'codebench' => __DIR__,
|
||||||
|
'unittest' => __DIR__ . '/vendor/kohana/unittest'
|
||||||
|
),
|
||||||
|
);
|
@ -1,86 +0,0 @@
|
|||||||
# Kohana-Cron
|
|
||||||
|
|
||||||
This module provides a way to schedule tasks (jobs) within your Kohana application.
|
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Step 1: Download the module into your modules subdirectory.
|
|
||||||
|
|
||||||
Step 2: Enable the module in your bootstrap file:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable modules. Modules are referenced by a relative or absolute path.
|
|
||||||
*/
|
|
||||||
Kohana::modules(array(
|
|
||||||
'cron' => MODPATH.'cron',
|
|
||||||
// 'auth' => MODPATH.'auth', // Basic authentication
|
|
||||||
// 'codebench' => MODPATH.'codebench', // Benchmarking tool
|
|
||||||
// 'database' => MODPATH.'database', // Database access
|
|
||||||
// 'image' => MODPATH.'image', // Image manipulation
|
|
||||||
// 'orm' => MODPATH.'orm', // Object Relationship Mapping
|
|
||||||
// 'pagination' => MODPATH.'pagination', // Paging of results
|
|
||||||
// 'userguide' => MODPATH.'userguide', // User guide and API documentation
|
|
||||||
));
|
|
||||||
|
|
||||||
|
|
||||||
Step 3: Make sure the settings in `config/cron.php` are correct for your environment.
|
|
||||||
If not, copy the file to `application/config/cron.php` and change the values accordingly.
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
In its simplest form, a task is a [PHP callback][1] and times at which it should run.
|
|
||||||
To configure a task call `Cron::set($name, array($frequency, $callback))` where
|
|
||||||
`$frequency` is a string of date and time fields identical to those found in [crontab][2].
|
|
||||||
For example,
|
|
||||||
|
|
||||||
Cron::set('reindex_catalog', array('@daily', 'Catalog::regenerate_index'));
|
|
||||||
Cron::set('calendar_notifications', array('*/5 * * * *', 'Calendar::send_emails'));
|
|
||||||
|
|
||||||
Configured tasks are run with their appropriate frequency by calling `Cron::run()`. Call
|
|
||||||
this method in your bootstrap file, and you're done!
|
|
||||||
|
|
||||||
|
|
||||||
## Advanced Usage
|
|
||||||
|
|
||||||
A task can also be an instance of `Cron` that extends `next()` and/or `execute()` as
|
|
||||||
needed. Such a task is configured by calling `Cron::set($name, $instance)`.
|
|
||||||
|
|
||||||
If you have access to the system crontab, you can run Cron less (or more) than once
|
|
||||||
every request. You will need to modify the lines where the request is handled in your
|
|
||||||
bootstrap file to prevent extraneous output. The default is:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the main request. A source of the URI can be passed, eg: $_SERVER['PATH_INFO'].
|
|
||||||
* If no source is specified, the URI will be automatically detected.
|
|
||||||
*/
|
|
||||||
echo Request::instance()
|
|
||||||
->execute()
|
|
||||||
->send_headers()
|
|
||||||
->response;
|
|
||||||
|
|
||||||
Change it to:
|
|
||||||
|
|
||||||
if ( ! defined('SUPPRESS_REQUEST'))
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Execute the main request. A source of the URI can be passed, eg: $_SERVER['PATH_INFO'].
|
|
||||||
* If no source is specified, the URI will be automatically detected.
|
|
||||||
*/
|
|
||||||
echo Request::instance()
|
|
||||||
->execute()
|
|
||||||
->send_headers()
|
|
||||||
->response;
|
|
||||||
}
|
|
||||||
|
|
||||||
Then set up a system cron job to run your application's Cron once a minute:
|
|
||||||
|
|
||||||
* * * * * /usr/bin/php -f /path/to/kohana/modules/cron/run.php
|
|
||||||
|
|
||||||
The included `run.php` should work for most cases, but you are free to call `Cron::run()`
|
|
||||||
in any way you see fit.
|
|
||||||
|
|
||||||
|
|
||||||
[1]: http://php.net/manual/language.pseudo-types.php#language.types.callback
|
|
||||||
[2]: http://linux.die.net/man/5/crontab
|
|
@ -1,10 +0,0 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct script access.');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Cron
|
|
||||||
*
|
|
||||||
* @author Chris Bandy
|
|
||||||
* @copyright (c) 2010 Chris Bandy
|
|
||||||
* @license http://www.opensource.org/licenses/isc-license.txt
|
|
||||||
*/
|
|
||||||
class Cron extends Kohana_Cron {}
|
|
@ -1,621 +0,0 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct script access.');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Cron
|
|
||||||
*
|
|
||||||
* @author Chris Bandy
|
|
||||||
* @copyright (c) 2010 Chris Bandy
|
|
||||||
* @license http://www.opensource.org/licenses/isc-license.txt
|
|
||||||
*/
|
|
||||||
class Kohana_Cron
|
|
||||||
{
|
|
||||||
protected static $_jobs = array();
|
|
||||||
protected static $_times = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a job to be run
|
|
||||||
*
|
|
||||||
* @param string Unique name
|
|
||||||
* @param array|Cron Job to run
|
|
||||||
*/
|
|
||||||
public static function set($name, $job)
|
|
||||||
{
|
|
||||||
if (is_array($job))
|
|
||||||
{
|
|
||||||
$job = new Cron(reset($job), next($job));
|
|
||||||
}
|
|
||||||
|
|
||||||
Cron::$_jobs[$name] = $job;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the timestamps of when jobs should run
|
|
||||||
*/
|
|
||||||
protected static function _load()
|
|
||||||
{
|
|
||||||
Cron::$_times = Kohana::cache("Cron::run()");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acquire the Cron mutex
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
protected static function _lock()
|
|
||||||
{
|
|
||||||
$config = Kohana::$config->load('cron');
|
|
||||||
$result = FALSE;
|
|
||||||
|
|
||||||
if (file_exists($config->lock) AND ($stat = @stat($config->lock)) AND time() - $config->window < $stat['mtime'])
|
|
||||||
{
|
|
||||||
// Lock exists and has not expired
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
$fh = fopen($config->lock, 'a');
|
|
||||||
|
|
||||||
if (flock($fh, LOCK_EX))
|
|
||||||
{
|
|
||||||
fseek($fh, 0, SEEK_END);
|
|
||||||
|
|
||||||
if (ftell($fh) === (empty($stat) ? 0 : $stat['size']))
|
|
||||||
{
|
|
||||||
// Current size matches expected size
|
|
||||||
// Claim the file by changing the size
|
|
||||||
fwrite($fh, '.');
|
|
||||||
|
|
||||||
$result = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// else, Another process acquired during flock()
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose($fh);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store the timestamps of when jobs should run next
|
|
||||||
*/
|
|
||||||
protected static function _save()
|
|
||||||
{
|
|
||||||
Kohana::cache("Cron::run()", Cron::$_times, Kohana::$config->load('cron')->window * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Release the Cron mutex
|
|
||||||
*/
|
|
||||||
protected static function _unlock()
|
|
||||||
{
|
|
||||||
return @unlink(Kohana::$config->load('cron')->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return boolean FALSE when another instance is running
|
|
||||||
*/
|
|
||||||
public static function run()
|
|
||||||
{
|
|
||||||
if (empty(Cron::$_jobs))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
if ( ! Cron::_lock())
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Cron::_load();
|
|
||||||
|
|
||||||
$now = time();
|
|
||||||
$threshold = $now - Kohana::$config->load('cron')->window;
|
|
||||||
|
|
||||||
foreach (Cron::$_jobs as $name => $job)
|
|
||||||
{
|
|
||||||
if (empty(Cron::$_times[$name]) OR Cron::$_times[$name] < $threshold)
|
|
||||||
{
|
|
||||||
// Expired
|
|
||||||
|
|
||||||
Cron::$_times[$name] = $job->next($now);
|
|
||||||
|
|
||||||
if ($job->next($threshold) < $now)
|
|
||||||
{
|
|
||||||
// Within the window
|
|
||||||
|
|
||||||
$job->execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif (Cron::$_times[$name] < $now)
|
|
||||||
{
|
|
||||||
// Within the window
|
|
||||||
|
|
||||||
Cron::$_times[$name] = $job->next($now);
|
|
||||||
|
|
||||||
$job->execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception $e) {}
|
|
||||||
|
|
||||||
Cron::_save();
|
|
||||||
Cron::_unlock();
|
|
||||||
|
|
||||||
if (isset($e))
|
|
||||||
throw $e;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected $_callback;
|
|
||||||
protected $_period;
|
|
||||||
|
|
||||||
public function __construct($period, $callback)
|
|
||||||
{
|
|
||||||
$this->_period = $period;
|
|
||||||
$this->_callback = $callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute this job
|
|
||||||
*/
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
call_user_func($this->_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the next timestamp in this period
|
|
||||||
*
|
|
||||||
* @param integer Timestamp from which to calculate
|
|
||||||
* @return integer Next timestamp in this period
|
|
||||||
*/
|
|
||||||
public function next($from)
|
|
||||||
{
|
|
||||||
// PHP >= 5.3.0
|
|
||||||
//if ($this->_period instanceof DatePeriod) { return; }
|
|
||||||
//if (is_string($this->_period) AND preg_match('/^P[\dDHMSTWY]+$/', $period)) { $this->_period = new DateInterval($this->_period); }
|
|
||||||
//if ($this->_period instanceof DateInterval) { return; }
|
|
||||||
|
|
||||||
return $this->_next_crontab($from);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the next timestamp of this crontab period
|
|
||||||
*
|
|
||||||
* @param integer Timestamp from which to calculate
|
|
||||||
* @return integer Next timestamp in this period
|
|
||||||
*/
|
|
||||||
protected function _next_crontab($from)
|
|
||||||
{
|
|
||||||
if (is_string($this->_period))
|
|
||||||
{
|
|
||||||
// Convert string to lists of valid values
|
|
||||||
|
|
||||||
if ($this->_period[0] === '@')
|
|
||||||
{
|
|
||||||
switch (substr($this->_period, 1))
|
|
||||||
{
|
|
||||||
case 'annually':
|
|
||||||
case 'yearly':
|
|
||||||
// '0 0 1 1 *'
|
|
||||||
$this->_period = array('minutes' => array(0), 'hours' => array(0), 'monthdays' => array(1), 'months' => array(1), 'weekdays' => range(0,6));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'daily':
|
|
||||||
case 'midnight':
|
|
||||||
// '0 0 * * *'
|
|
||||||
$this->_period = array('minutes' => array(0), 'hours' => array(0), 'monthdays' => range(1,31), 'months' => range(1,12), 'weekdays' => range(0,6));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'hourly':
|
|
||||||
// '0 * * * *'
|
|
||||||
$this->_period = array('minutes' => array(0), 'hours' => range(0,23), 'monthdays' => range(1,31), 'months' => range(1,12), 'weekdays' => range(0,6));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'monthly':
|
|
||||||
// '0 0 1 * *'
|
|
||||||
$this->_period = array('minutes' => array(0), 'hours' => array(0), 'monthdays' => array(1), 'months' => range(1,12), 'weekdays' => range(0,6));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'weekly':
|
|
||||||
// '0 0 * * 0'
|
|
||||||
$this->_period = array('minutes' => array(0), 'hours' => array(0), 'monthdays' => range(1,31), 'months' => range(1,12), 'weekdays' => array(0));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list($minutes, $hours, $monthdays, $months, $weekdays) = explode(' ', $this->_period);
|
|
||||||
|
|
||||||
$months = strtr(strtolower($months), array(
|
|
||||||
'jan' => 1,
|
|
||||||
'feb' => 2,
|
|
||||||
'mar' => 3,
|
|
||||||
'apr' => 4,
|
|
||||||
'may' => 5,
|
|
||||||
'jun' => 6,
|
|
||||||
'jul' => 7,
|
|
||||||
'aug' => 8,
|
|
||||||
'sep' => 9,
|
|
||||||
'oct' => 10,
|
|
||||||
'nov' => 11,
|
|
||||||
'dec' => 12,
|
|
||||||
));
|
|
||||||
|
|
||||||
$weekdays = strtr(strtolower($weekdays), array(
|
|
||||||
'sun' => 0,
|
|
||||||
'mon' => 1,
|
|
||||||
'tue' => 2,
|
|
||||||
'wed' => 3,
|
|
||||||
'thu' => 4,
|
|
||||||
'fri' => 5,
|
|
||||||
'sat' => 6,
|
|
||||||
));
|
|
||||||
|
|
||||||
$this->_period = array(
|
|
||||||
'minutes' => $this->_parse_crontab_field($minutes, 0, 59),
|
|
||||||
'hours' => $this->_parse_crontab_field($hours, 0, 23),
|
|
||||||
'monthdays' => $this->_parse_crontab_field($monthdays, 1, 31),
|
|
||||||
'months' => $this->_parse_crontab_field($months, 1, 12),
|
|
||||||
'weekdays' => $this->_parse_crontab_field($weekdays, 0, 7)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ensure Sunday is zero
|
|
||||||
if (end($this->_period['weekdays']) === 7)
|
|
||||||
{
|
|
||||||
array_pop($this->_period['weekdays']);
|
|
||||||
|
|
||||||
if (reset($this->_period['weekdays']) !== 0)
|
|
||||||
{
|
|
||||||
array_unshift($this->_period['weekdays'], 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$from = getdate($from);
|
|
||||||
|
|
||||||
if ( ! in_array($from['mon'], $this->_period['months']))
|
|
||||||
return $this->_next_crontab_month($from);
|
|
||||||
|
|
||||||
if (count($this->_period['weekdays']) === 7)
|
|
||||||
{
|
|
||||||
// Day of Week is unrestricted, defer to Day of Month
|
|
||||||
if ( ! in_array($from['mday'], $this->_period['monthdays']))
|
|
||||||
return $this->_next_crontab_monthday($from);
|
|
||||||
}
|
|
||||||
elseif (count($this->_period['monthdays']) === 31)
|
|
||||||
{
|
|
||||||
// Day of Month is unrestricted, use Day of Week
|
|
||||||
if ( ! in_array($from['wday'], $this->_period['weekdays']))
|
|
||||||
return $this->_next_crontab_weekday($from);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Both Day of Week and Day of Month are restricted
|
|
||||||
if ( ! in_array($from['mday'], $this->_period['monthdays']) AND ! in_array($from['wday'], $this->_period['weekdays']))
|
|
||||||
return $this->_next_crontab_day($from);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! in_array($from['hours'], $this->_period['hours']))
|
|
||||||
return $this->_next_crontab_hour($from);
|
|
||||||
|
|
||||||
return $this->_next_crontab_minute($from);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the first timestamp in the next day of this period when both
|
|
||||||
* Day of Week and Day of Month are restricted
|
|
||||||
*
|
|
||||||
* @uses _next_crontab_month()
|
|
||||||
*
|
|
||||||
* @param array Date array from getdate()
|
|
||||||
* @return integer Timestamp of next restricted Day
|
|
||||||
*/
|
|
||||||
protected function _next_crontab_day(array $from)
|
|
||||||
{
|
|
||||||
// Calculate effective Day of Month for next Day of Week
|
|
||||||
|
|
||||||
if ($from['wday'] >= end($this->_period['weekdays']))
|
|
||||||
{
|
|
||||||
$next = reset($this->_period['weekdays']) + 7;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach ($this->_period['weekdays'] as $next)
|
|
||||||
{
|
|
||||||
if ($from['wday'] < $next)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$monthday = $from['mday'] + $next - $from['wday'];
|
|
||||||
|
|
||||||
if ($monthday <= (int) date('t', mktime(0, 0, 0, $from['mon'], 1, $from['year'])))
|
|
||||||
{
|
|
||||||
// Next Day of Week is in this Month
|
|
||||||
|
|
||||||
if ($from['mday'] >= end($this->_period['monthdays']))
|
|
||||||
{
|
|
||||||
// No next Day of Month, use next Day of Week
|
|
||||||
$from['mday'] = $monthday;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Calculate next Day of Month
|
|
||||||
foreach ($this->_period['monthdays'] as $next)
|
|
||||||
{
|
|
||||||
if ($from['mday'] < $next)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use earliest day
|
|
||||||
$from['mday'] = min($monthday, $next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ($from['mday'] >= end($this->_period['monthdays']))
|
|
||||||
{
|
|
||||||
// No next Day of Month, use next Month
|
|
||||||
return $this->_next_crontab_month($from);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate next Day of Month
|
|
||||||
foreach ($this->_period['monthdays'] as $next)
|
|
||||||
{
|
|
||||||
if ($from['mday'] < $next)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use next Day of Month
|
|
||||||
$from['mday'] = $next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use first Hour and first Minute
|
|
||||||
return mktime(reset($this->_period['hours']), reset($this->_period['minutes']), 0, $from['mon'], $from['mday'], $from['year']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the first timestamp in the next hour of this period
|
|
||||||
*
|
|
||||||
* @uses _next_crontab_day()
|
|
||||||
* @uses _next_crontab_monthday()
|
|
||||||
* @uses _next_crontab_weekday()
|
|
||||||
*
|
|
||||||
* @param array Date array from getdate()
|
|
||||||
* @return integer Timestamp of next Hour
|
|
||||||
*/
|
|
||||||
protected function _next_crontab_hour(array $from)
|
|
||||||
{
|
|
||||||
if ($from['hours'] >= end($this->_period['hours']))
|
|
||||||
{
|
|
||||||
// No next Hour
|
|
||||||
|
|
||||||
if (count($this->_period['weekdays']) === 7)
|
|
||||||
{
|
|
||||||
// Day of Week is unrestricted, defer to Day of Month
|
|
||||||
return $this->_next_crontab_monthday($from);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($this->_period['monthdays']) === 31)
|
|
||||||
{
|
|
||||||
// Day of Month is unrestricted, use Day of Week
|
|
||||||
return $this->_next_crontab_weekday($from);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both Day of Week and Day of Month are restricted
|
|
||||||
return $this->_next_crontab_day($from);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate next Hour
|
|
||||||
foreach ($this->_period['hours'] as $next)
|
|
||||||
{
|
|
||||||
if ($from['hours'] < $next)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use next Hour and first Minute
|
|
||||||
return mktime($next, reset($this->_period['minutes']), 0, $from['mon'], $from['mday'], $from['year']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the timestamp of the next minute in this period
|
|
||||||
*
|
|
||||||
* @uses _next_crontab_hour()
|
|
||||||
*
|
|
||||||
* @param array Date array from getdate()
|
|
||||||
* @return integer Timestamp of next Minute
|
|
||||||
*/
|
|
||||||
protected function _next_crontab_minute(array $from)
|
|
||||||
{
|
|
||||||
if ($from['minutes'] >= end($this->_period['minutes']))
|
|
||||||
{
|
|
||||||
// No next Minute, use next Hour
|
|
||||||
return $this->_next_crontab_hour($from);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate next Minute
|
|
||||||
foreach ($this->_period['minutes'] as $next)
|
|
||||||
{
|
|
||||||
if ($from['minutes'] < $next)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use next Minute
|
|
||||||
return mktime($from['hours'], $next, 0, $from['mon'], $from['mday'], $from['year']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the first timestamp in the next month of this period
|
|
||||||
*
|
|
||||||
* @param array Date array from getdate()
|
|
||||||
* @return integer Timestamp of next Month
|
|
||||||
*/
|
|
||||||
protected function _next_crontab_month(array $from)
|
|
||||||
{
|
|
||||||
if ($from['mon'] >= end($this->_period['months']))
|
|
||||||
{
|
|
||||||
// No next Month, increment Year and use first Month
|
|
||||||
++$from['year'];
|
|
||||||
$from['mon'] = reset($this->_period['months']);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Calculate next Month
|
|
||||||
foreach ($this->_period['months'] as $next)
|
|
||||||
{
|
|
||||||
if ($from['mon'] < $next)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use next Month
|
|
||||||
$from['mon'] = $next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($this->_period['weekdays']) === 7)
|
|
||||||
{
|
|
||||||
// Day of Week is unrestricted, use first Day of Month
|
|
||||||
$from['mday'] = reset($this->_period['monthdays']);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Calculate Day of Month for the first Day of Week
|
|
||||||
$indices = array_flip($this->_period['weekdays']);
|
|
||||||
|
|
||||||
$monthday = 1;
|
|
||||||
$weekday = (int) date('w', mktime(0, 0, 0, $from['mon'], 1, $from['year']));
|
|
||||||
|
|
||||||
while ( ! isset($indices[$weekday % 7]) AND $monthday < 7)
|
|
||||||
{
|
|
||||||
++$monthday;
|
|
||||||
++$weekday;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($this->_period['monthdays']) === 31)
|
|
||||||
{
|
|
||||||
// Day of Month is unrestricted, use first Day of Week
|
|
||||||
$from['mday'] = $monthday;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Both Day of Month and Day of Week are restricted, use earliest one
|
|
||||||
$from['mday'] = min($monthday, reset($this->_period['monthdays']));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use first Hour and first Minute
|
|
||||||
return mktime(reset($this->_period['hours']), reset($this->_period['minutes']), 0, $from['mon'], $from['mday'], $from['year']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the first timestamp in the next day of this period when only
|
|
||||||
* Day of Month is restricted
|
|
||||||
*
|
|
||||||
* @uses _next_crontab_month()
|
|
||||||
*
|
|
||||||
* @param array Date array from getdate()
|
|
||||||
* @return integer Timestamp of next Day of Month
|
|
||||||
*/
|
|
||||||
protected function _next_crontab_monthday(array $from)
|
|
||||||
{
|
|
||||||
if ($from['mday'] >= end($this->_period['monthdays']))
|
|
||||||
{
|
|
||||||
// No next Day of Month, use next Month
|
|
||||||
return $this->_next_crontab_month($from);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate next Day of Month
|
|
||||||
foreach ($this->_period['monthdays'] as $next)
|
|
||||||
{
|
|
||||||
if ($from['mday'] < $next)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use next Day of Month, first Hour, and first Minute
|
|
||||||
return mktime(reset($this->_period['hours']), reset($this->_period['minutes']), 0, $from['mon'], $next, $from['year']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the first timestamp in the next day of this period when only
|
|
||||||
* Day of Week is restricted
|
|
||||||
*
|
|
||||||
* @uses _next_crontab_month()
|
|
||||||
*
|
|
||||||
* @param array Date array from getdate()
|
|
||||||
* @return integer Timestamp of next Day of Week
|
|
||||||
*/
|
|
||||||
protected function _next_crontab_weekday(array $from)
|
|
||||||
{
|
|
||||||
// Calculate effective Day of Month for next Day of Week
|
|
||||||
|
|
||||||
if ($from['wday'] >= end($this->_period['weekdays']))
|
|
||||||
{
|
|
||||||
$next = reset($this->_period['weekdays']) + 7;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach ($this->_period['weekdays'] as $next)
|
|
||||||
{
|
|
||||||
if ($from['wday'] < $next)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$monthday = $from['mday'] + $next - $from['wday'];
|
|
||||||
|
|
||||||
if ($monthday > (int) date('t', mktime(0, 0, 0, $from['mon'], 1, $from['year'])))
|
|
||||||
{
|
|
||||||
// Next Day of Week is not in this Month, use next Month
|
|
||||||
return $this->_next_crontab_month($from);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use next Day of Week, first Hour, and first Minute
|
|
||||||
return mktime(reset($this->_period['hours']), reset($this->_period['minutes']), 0, $from['mon'], $monthday, $from['year']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a sorted array of all the values indicated in a Crontab field
|
|
||||||
* @link http://linux.die.net/man/5/crontab
|
|
||||||
*
|
|
||||||
* @param string Crontab field
|
|
||||||
* @param integer Minimum value for this field
|
|
||||||
* @param integer Maximum value for this field
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function _parse_crontab_field($value, $min, $max)
|
|
||||||
{
|
|
||||||
$result = array();
|
|
||||||
|
|
||||||
foreach (explode(',', $value) as $value)
|
|
||||||
{
|
|
||||||
if ($slash = strrpos($value, '/'))
|
|
||||||
{
|
|
||||||
$step = (int) substr($value, $slash + 1);
|
|
||||||
$value = substr($value, 0, $slash);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($value === '*')
|
|
||||||
{
|
|
||||||
$result = array_merge($result, range($min, $max, $slash ? $step : 1));
|
|
||||||
}
|
|
||||||
elseif ($dash = strpos($value, '-'))
|
|
||||||
{
|
|
||||||
$result = array_merge($result, range(max($min, (int) substr($value, 0, $dash)), min($max, (int) substr($value, $dash + 1)), $slash ? $step : 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$value = (int) $value;
|
|
||||||
|
|
||||||
if ($min <= $value AND $value <= $max)
|
|
||||||
{
|
|
||||||
$result[] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort($result);
|
|
||||||
|
|
||||||
return array_unique($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
<?php defined('SYSPATH') OR die('No direct access allowed.');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Cron
|
|
||||||
*
|
|
||||||
* @author Chris Bandy
|
|
||||||
* @copyright (c) 2010 Chris Bandy
|
|
||||||
* @license http://www.opensource.org/licenses/isc-license.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
return array
|
|
||||||
(
|
|
||||||
// Path to a writable directory and lock file
|
|
||||||
'lock' => Kohana::$cache_dir.DIRECTORY_SEPARATOR.'cron.lck',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cron does not run EXACTLY when tasks are scheduled.
|
|
||||||
* A task can be executed up to this many seconds AFTER its scheduled time.
|
|
||||||
*
|
|
||||||
* For example, Cron is run at 10:48 and a task was scheduled to execute at
|
|
||||||
* 10:45, 180 seconds ago. If window is greater than 180, the task will be
|
|
||||||
* executed.
|
|
||||||
*
|
|
||||||
* This value should always be larger than the time it takes to run all
|
|
||||||
* your tasks.
|
|
||||||
*/
|
|
||||||
'window' => 300,
|
|
||||||
);
|
|
@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Cron
|
|
||||||
*
|
|
||||||
* @author Chris Bandy
|
|
||||||
* @copyright (c) 2010 Chris Bandy
|
|
||||||
* @license http://www.opensource.org/licenses/isc-license.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Path to Kohana's index.php
|
|
||||||
$system = dirname(dirname(dirname(__FILE__))).DIRECTORY_SEPARATOR.'index.php';
|
|
||||||
|
|
||||||
if (file_exists($system))
|
|
||||||
{
|
|
||||||
defined('SUPPRESS_REQUEST') or define('SUPPRESS_REQUEST', TRUE);
|
|
||||||
|
|
||||||
include $system;
|
|
||||||
|
|
||||||
// If Cron has been run in APPPATH/bootstrap.php, this second call is harmless
|
|
||||||
Cron::run();
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package Cron
|
|
||||||
* @group kohana
|
|
||||||
* @group kohana.cron
|
|
||||||
*
|
|
||||||
* @author Chris Bandy
|
|
||||||
* @copyright (c) 2010 Chris Bandy
|
|
||||||
* @license http://www.opensource.org/licenses/isc-license.txt
|
|
||||||
*/
|
|
||||||
class Kohana_Cron_Test extends PHPUnit_Framework_TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
* @dataProvider provider_next
|
|
||||||
*
|
|
||||||
* @param string Period
|
|
||||||
* @param integer Timestamp from which to calculate
|
|
||||||
* @param integer Next timestamp in period
|
|
||||||
*/
|
|
||||||
public function test_next($period, $from, $expected_result)
|
|
||||||
{
|
|
||||||
$cron = new Cron($period, NULL);
|
|
||||||
$result = $cron->next($from);
|
|
||||||
|
|
||||||
$this->assertSame($expected_result, $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provider_next()
|
|
||||||
{
|
|
||||||
return array
|
|
||||||
(
|
|
||||||
array('@annually', mktime(8, 45, 0, 11, 19, 2009), mktime(0, 0, 0, 1, 1, 2010)),
|
|
||||||
array('@monthly', mktime(8, 45, 0, 11, 19, 2009), mktime(0, 0, 0, 12, 1, 2009)),
|
|
||||||
array('@weekly', mktime(8, 45, 0, 11, 19, 2009), mktime(0, 0, 0, 11, 22, 2009)),
|
|
||||||
array('@daily', mktime(8, 45, 0, 11, 19, 2009), mktime(0, 0, 0, 11, 20, 2009)),
|
|
||||||
array('@hourly', mktime(8, 45, 0, 11, 19, 2009), mktime(9, 0, 0, 11, 19, 2009)),
|
|
||||||
|
|
||||||
array('* * * * *', mktime(8, 45, 0, 11, 19, 2009), mktime(8, 46, 0, 11, 19, 2009)),
|
|
||||||
|
|
||||||
array(
|
|
||||||
'* * * * 0', // Sundays
|
|
||||||
mktime(0, 0, 0, 11, 30, 2009), // Monday, Nov 30, 2009
|
|
||||||
mktime(0, 0, 0, 12, 6, 2009) // Sunday, Dec 6, 2009
|
|
||||||
),
|
|
||||||
|
|
||||||
array(
|
|
||||||
'* * 15 * 6', // 15th and Saturdays
|
|
||||||
mktime(0, 0, 0, 11, 29, 2009), // Sunday, Nov 29, 2009
|
|
||||||
mktime(0, 0, 0, 12, 5, 2009) // Saturday, Dec 5, 2009
|
|
||||||
),
|
|
||||||
|
|
||||||
array(
|
|
||||||
'* * * * 1,5', // Mondays and Fridays
|
|
||||||
mktime(0, 0, 0, 11, 24, 2009), // Tuesday, Nov 24, 2009
|
|
||||||
mktime(0, 0, 0, 11, 27, 2009) // Friday, Nov 27, 2009
|
|
||||||
),
|
|
||||||
|
|
||||||
array(
|
|
||||||
'* * 15 * 6-7', // 15th, Saturdays, and Sundays
|
|
||||||
mktime(0, 0, 0, 11, 23, 2009), // Monday, Nov 23, 2009
|
|
||||||
mktime(0, 0, 0, 11, 28, 2009) // Saturday, Nov 28, 2009
|
|
||||||
),
|
|
||||||
|
|
||||||
array(
|
|
||||||
'* * 15,30 * 2', // 15th, 30th, and Tuesdays
|
|
||||||
mktime(0, 0, 0, 11, 29, 2009), // Sunday, Nov 29, 2009
|
|
||||||
mktime(0, 0, 0, 11, 30, 2009) // Monday, Nov 30, 2009
|
|
||||||
),
|
|
||||||
|
|
||||||
array(
|
|
||||||
'0 0 * * 4', // Midnight on Thursdays
|
|
||||||
mktime(1, 0, 0, 11, 19, 2009), // 01:00 Thursday, Nov 19, 2009
|
|
||||||
mktime(0, 0, 0, 11, 26, 2009) // 00:00 Thursday, Nov 26, 2009
|
|
||||||
),
|
|
||||||
|
|
||||||
array(
|
|
||||||
'0 0 */2 * 4', // Midnight on odd days and Thursdays
|
|
||||||
mktime(1, 0, 0, 11, 19, 2009), // 01:00 Thursday, Nov 19, 2009
|
|
||||||
mktime(0, 0, 0, 11, 21, 2009) // 00:00 Saturday, Nov 21, 2009
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
37
modules/database/.travis.yml
Normal file
37
modules/database/.travis.yml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
sudo: false
|
||||||
|
|
||||||
|
language: php
|
||||||
|
|
||||||
|
# Only build the main develop/master branches - feature branches will be covered by PRs
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- /^[0-9\.]+\/(develop|master)$/
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- vendor
|
||||||
|
- $HOME/.composer/cache
|
||||||
|
|
||||||
|
php:
|
||||||
|
- 5.3
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
- 7.0
|
||||||
|
- hhvm
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- php: 5.3
|
||||||
|
env: 'COMPOSER_PHPUNIT="lowest"'
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- composer install --prefer-dist
|
||||||
|
- if [ "$COMPOSER_PHPUNIT" = "lowest" ]; then composer update --prefer-lowest --with-dependencies phpunit/phpunit; fi;
|
||||||
|
- vendor/bin/koharness
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cd /tmp/koharness && ./vendor/bin/phpunit --bootstrap=modules/unittest/bootstrap.php modules/unittest/tests.php
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
6
modules/database/README.md
Normal file
6
modules/database/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Kohana - database access module
|
||||||
|
|
||||||
|
| ver | Stable | Develop |
|
||||||
|
|-------|--------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| 3.3.x | [![Build Status - 3.3/master](https://travis-ci.org/kohana/database.svg?branch=3.3%2Fmaster)](https://travis-ci.org/kohana/database) | [![Build Status - 3.3/develop](https://travis-ci.org/kohana/database.svg?branch=3.3%2Fdevelop)](https://travis-ci.org/kohana/database) |
|
||||||
|
| 3.4.x | [![Build Status - 3.4/master](https://travis-ci.org/kohana/database.svg?branch=3.4%2Fmaster)](https://travis-ci.org/kohana/database) | [![Build Status - 3.4/develop](https://travis-ci.org/kohana/database.svg?branch=3.4%2Fdevelop)](https://travis-ci.org/kohana/database) |
|
3
modules/database/classes/Database/MySQLi.php
Normal file
3
modules/database/classes/Database/MySQLi.php
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||||
|
|
||||||
|
class Database_MySQLi extends Kohana_Database_MySQLi {}
|
3
modules/database/classes/Database/MySQLi/Result.php
Normal file
3
modules/database/classes/Database/MySQLi/Result.php
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||||
|
|
||||||
|
class Database_MySQLi_Result extends Kohana_Database_MySQLi_Result {}
|
@ -9,7 +9,7 @@
|
|||||||
* @copyright (c) 2012 Kohana Team
|
* @copyright (c) 2012 Kohana Team
|
||||||
* @license http://kohanaframework.org/license
|
* @license http://kohanaframework.org/license
|
||||||
*/
|
*/
|
||||||
class Kohana_Config_Database extends Kohana_Config_Database_Writer
|
class Kohana_Config_Database extends Config_Database_Writer
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,15 @@
|
|||||||
/**
|
/**
|
||||||
* Database writer for the config system
|
* Database writer for the config system
|
||||||
*
|
*
|
||||||
|
* Schema for configuration table:
|
||||||
|
*
|
||||||
|
* CREATE TABLE IF NOT EXISTS `config` (
|
||||||
|
* `group_name` varchar(128) NOT NULL,
|
||||||
|
* `config_key` varchar(128) NOT NULL,
|
||||||
|
* `config_value` text,
|
||||||
|
* PRIMARY KEY (`group_name`,`config_key`)
|
||||||
|
* ) ENGINE=InnoDB;
|
||||||
|
*
|
||||||
* @package Kohana
|
* @package Kohana
|
||||||
* @category Configuration
|
* @category Configuration
|
||||||
* @author Kohana Team
|
* @author Kohana Team
|
||||||
|
@ -51,6 +51,9 @@ class Kohana_Database_MySQL_Result extends Database_Result {
|
|||||||
// Increment internal row for optimization assuming rows are fetched in order
|
// Increment internal row for optimization assuming rows are fetched in order
|
||||||
$this->_internal_row++;
|
$this->_internal_row++;
|
||||||
|
|
||||||
|
// FIXME mysql_fetch_object has been deprecated as of php 5.5!
|
||||||
|
// Please use mysqli_fetch_object or PDOStatement::fetch(PDO::FETCH_OBJ) instead.
|
||||||
|
|
||||||
if ($this->_as_object === TRUE)
|
if ($this->_as_object === TRUE)
|
||||||
{
|
{
|
||||||
// Return an stdClass
|
// Return an stdClass
|
||||||
@ -58,8 +61,32 @@ class Kohana_Database_MySQL_Result extends Database_Result {
|
|||||||
}
|
}
|
||||||
elseif (is_string($this->_as_object))
|
elseif (is_string($this->_as_object))
|
||||||
{
|
{
|
||||||
// Return an object of given class name
|
/* The second and third argument for mysql_fetch_object are optional, but do
|
||||||
return mysql_fetch_object($this->_result, $this->_as_object, $this->_object_params);
|
* not have default values defined. Passing _object_params with a non-array value results
|
||||||
|
* in undefined behavior that varies by PHP version. For example, if NULL is supplied on
|
||||||
|
* PHP 5.3, the resulting behavior is identical to calling with array(), which results in the
|
||||||
|
* classes __construct function being called with no arguments. This is only an issue when
|
||||||
|
* the _as_object class does not have an explicit __construct method resulting in the
|
||||||
|
* cryptic error "Class %s does not have a constructor hence you cannot use ctor_params."
|
||||||
|
* In contrast, the same function call on PHP 5.5 will 'functionally' interpret
|
||||||
|
* _object_params == NULL as an omission of the third argument, resulting in the original
|
||||||
|
* intended functionally.
|
||||||
|
*
|
||||||
|
* Because the backing code for the mysql_fetch_object has not changed between 5.3 and 5.5,
|
||||||
|
* I suspect this discrepancy is due to the way the classes are instantiated on a boarder
|
||||||
|
* level. Additionally, mysql_fetch_object has been deprecated in 5.5 and should probably be
|
||||||
|
* replaced by mysqli_fetch_object or PDOStatement::fetch(PDO::FETCH_OBJ) in Kohana 3.4.
|
||||||
|
*/
|
||||||
|
if ($this->_object_params !== NULL)
|
||||||
|
{
|
||||||
|
// Return an object of given class name with constructor params
|
||||||
|
return mysql_fetch_object($this->_result, $this->_as_object, $this->_object_params);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Return an object of given class name without constructor params
|
||||||
|
return mysql_fetch_object($this->_result, $this->_as_object);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
422
modules/database/classes/Kohana/Database/MySQLi.php
Normal file
422
modules/database/classes/Kohana/Database/MySQLi.php
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||||
|
/**
|
||||||
|
* MySQLi database connection.
|
||||||
|
*
|
||||||
|
* @package Kohana/Database
|
||||||
|
* @category Drivers
|
||||||
|
* @author Kohana Team
|
||||||
|
* @copyright (c) 2008-2009 Kohana Team
|
||||||
|
* @license http://kohanaphp.com/license
|
||||||
|
*/
|
||||||
|
class Kohana_Database_MySQLi extends Database {
|
||||||
|
|
||||||
|
// Database in use by each connection
|
||||||
|
protected static $_current_databases = array();
|
||||||
|
|
||||||
|
// Use SET NAMES to set the character set
|
||||||
|
protected static $_set_names;
|
||||||
|
|
||||||
|
// Identifier for this connection within the PHP driver
|
||||||
|
protected $_connection_id;
|
||||||
|
|
||||||
|
// MySQL uses a backtick for identifiers
|
||||||
|
protected $_identifier = '`';
|
||||||
|
|
||||||
|
public function connect()
|
||||||
|
{
|
||||||
|
if ($this->_connection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Database_MySQLi::$_set_names === NULL)
|
||||||
|
{
|
||||||
|
// Determine if we can use mysqli_set_charset(), which is only
|
||||||
|
// available on PHP 5.2.3+ when compiled against MySQL 5.0+
|
||||||
|
Database_MySQLi::$_set_names = ! function_exists('mysqli_set_charset');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the connection parameters, adding required variabels
|
||||||
|
extract($this->_config['connection'] + array(
|
||||||
|
'database' => '',
|
||||||
|
'hostname' => '',
|
||||||
|
'username' => '',
|
||||||
|
'password' => '',
|
||||||
|
'socket' => '',
|
||||||
|
'port' => 3306,
|
||||||
|
'ssl' => NULL,
|
||||||
|
));
|
||||||
|
|
||||||
|
// Prevent this information from showing up in traces
|
||||||
|
unset($this->_config['connection']['username'], $this->_config['connection']['password']);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(is_array($ssl))
|
||||||
|
{
|
||||||
|
$this->_connection = mysqli_init();
|
||||||
|
$this->_connection->ssl_set(
|
||||||
|
Arr::get($ssl, 'client_key_path'),
|
||||||
|
Arr::get($ssl, 'client_cert_path'),
|
||||||
|
Arr::get($ssl, 'ca_cert_path'),
|
||||||
|
Arr::get($ssl, 'ca_dir_path'),
|
||||||
|
Arr::get($ssl, 'cipher')
|
||||||
|
);
|
||||||
|
$this->_connection->real_connect($hostname, $username, $password, $database, $port, $socket, MYSQLI_CLIENT_SSL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->_connection = new mysqli($hostname, $username, $password, $database, $port, $socket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception $e)
|
||||||
|
{
|
||||||
|
// No connection exists
|
||||||
|
$this->_connection = NULL;
|
||||||
|
|
||||||
|
throw new Database_Exception(':error', array(':error' => $e->getMessage()), $e->getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
// \xFF is a better delimiter, but the PHP driver uses underscore
|
||||||
|
$this->_connection_id = sha1($hostname.'_'.$username.'_'.$password);
|
||||||
|
|
||||||
|
if ( ! empty($this->_config['charset']))
|
||||||
|
{
|
||||||
|
// Set the character set
|
||||||
|
$this->set_charset($this->_config['charset']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty($this->_config['connection']['variables']))
|
||||||
|
{
|
||||||
|
// Set session variables
|
||||||
|
$variables = array();
|
||||||
|
|
||||||
|
foreach ($this->_config['connection']['variables'] as $var => $val)
|
||||||
|
{
|
||||||
|
$variables[] = 'SESSION '.$var.' = '.$this->quote($val);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_connection->query('SET '.implode(', ', $variables));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function disconnect()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Database is assumed disconnected
|
||||||
|
$status = TRUE;
|
||||||
|
|
||||||
|
if (is_resource($this->_connection))
|
||||||
|
{
|
||||||
|
if ($status = $this->_connection->close())
|
||||||
|
{
|
||||||
|
// Clear the connection
|
||||||
|
$this->_connection = NULL;
|
||||||
|
|
||||||
|
// Clear the instance
|
||||||
|
parent::disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception $e)
|
||||||
|
{
|
||||||
|
// Database is probably not disconnected
|
||||||
|
$status = ! is_resource($this->_connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set_charset($charset)
|
||||||
|
{
|
||||||
|
// Make sure the database is connected
|
||||||
|
$this->_connection or $this->connect();
|
||||||
|
|
||||||
|
if (Database_MySQLi::$_set_names === TRUE)
|
||||||
|
{
|
||||||
|
// PHP is compiled against MySQL 4.x
|
||||||
|
$status = (bool) $this->_connection->query('SET NAMES '.$this->quote($charset));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// PHP is compiled against MySQL 5.x
|
||||||
|
$status = $this->_connection->set_charset($charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status === FALSE)
|
||||||
|
{
|
||||||
|
throw new Database_Exception(':error', array(':error' => $this->_connection->error), $this->_connection->errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function query($type, $sql, $as_object = FALSE, array $params = NULL)
|
||||||
|
{
|
||||||
|
// Make sure the database is connected
|
||||||
|
$this->_connection or $this->connect();
|
||||||
|
|
||||||
|
if (Kohana::$profiling)
|
||||||
|
{
|
||||||
|
// Benchmark this query for the current instance
|
||||||
|
$benchmark = Profiler::start("Database ({$this->_instance})", $sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the query
|
||||||
|
if (($result = $this->_connection->query($sql)) === FALSE)
|
||||||
|
{
|
||||||
|
if (isset($benchmark))
|
||||||
|
{
|
||||||
|
// This benchmark is worthless
|
||||||
|
Profiler::delete($benchmark);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Database_Exception(':error [ :query ]', array(
|
||||||
|
':error' => $this->_connection->error,
|
||||||
|
':query' => $sql
|
||||||
|
), $this->_connection->errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($benchmark))
|
||||||
|
{
|
||||||
|
Profiler::stop($benchmark);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the last query
|
||||||
|
$this->last_query = $sql;
|
||||||
|
|
||||||
|
if ($type === Database::SELECT)
|
||||||
|
{
|
||||||
|
// Return an iterator of results
|
||||||
|
return new Database_MySQLi_Result($result, $sql, $as_object, $params);
|
||||||
|
}
|
||||||
|
elseif ($type === Database::INSERT)
|
||||||
|
{
|
||||||
|
// Return a list of insert id and rows created
|
||||||
|
return array(
|
||||||
|
$this->_connection->insert_id,
|
||||||
|
$this->_connection->affected_rows,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Return the number of rows affected
|
||||||
|
return $this->_connection->affected_rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function datatype($type)
|
||||||
|
{
|
||||||
|
static $types = array
|
||||||
|
(
|
||||||
|
'blob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '65535'),
|
||||||
|
'bool' => array('type' => 'bool'),
|
||||||
|
'bigint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '18446744073709551615'),
|
||||||
|
'datetime' => array('type' => 'string'),
|
||||||
|
'decimal unsigned' => array('type' => 'float', 'exact' => TRUE, 'min' => '0'),
|
||||||
|
'double' => array('type' => 'float'),
|
||||||
|
'double precision unsigned' => array('type' => 'float', 'min' => '0'),
|
||||||
|
'double unsigned' => array('type' => 'float', 'min' => '0'),
|
||||||
|
'enum' => array('type' => 'string'),
|
||||||
|
'fixed' => array('type' => 'float', 'exact' => TRUE),
|
||||||
|
'fixed unsigned' => array('type' => 'float', 'exact' => TRUE, 'min' => '0'),
|
||||||
|
'float unsigned' => array('type' => 'float', 'min' => '0'),
|
||||||
|
'geometry' => array('type' => 'string', 'binary' => TRUE),
|
||||||
|
'int unsigned' => array('type' => 'int', 'min' => '0', 'max' => '4294967295'),
|
||||||
|
'integer unsigned' => array('type' => 'int', 'min' => '0', 'max' => '4294967295'),
|
||||||
|
'longblob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '4294967295'),
|
||||||
|
'longtext' => array('type' => 'string', 'character_maximum_length' => '4294967295'),
|
||||||
|
'mediumblob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '16777215'),
|
||||||
|
'mediumint' => array('type' => 'int', 'min' => '-8388608', 'max' => '8388607'),
|
||||||
|
'mediumint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '16777215'),
|
||||||
|
'mediumtext' => array('type' => 'string', 'character_maximum_length' => '16777215'),
|
||||||
|
'national varchar' => array('type' => 'string'),
|
||||||
|
'numeric unsigned' => array('type' => 'float', 'exact' => TRUE, 'min' => '0'),
|
||||||
|
'nvarchar' => array('type' => 'string'),
|
||||||
|
'point' => array('type' => 'string', 'binary' => TRUE),
|
||||||
|
'real unsigned' => array('type' => 'float', 'min' => '0'),
|
||||||
|
'set' => array('type' => 'string'),
|
||||||
|
'smallint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '65535'),
|
||||||
|
'text' => array('type' => 'string', 'character_maximum_length' => '65535'),
|
||||||
|
'tinyblob' => array('type' => 'string', 'binary' => TRUE, 'character_maximum_length' => '255'),
|
||||||
|
'tinyint' => array('type' => 'int', 'min' => '-128', 'max' => '127'),
|
||||||
|
'tinyint unsigned' => array('type' => 'int', 'min' => '0', 'max' => '255'),
|
||||||
|
'tinytext' => array('type' => 'string', 'character_maximum_length' => '255'),
|
||||||
|
'year' => array('type' => 'string'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$type = str_replace(' zerofill', '', $type);
|
||||||
|
|
||||||
|
if (isset($types[$type]))
|
||||||
|
return $types[$type];
|
||||||
|
|
||||||
|
return parent::datatype($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a SQL transaction
|
||||||
|
*
|
||||||
|
* @link http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
|
||||||
|
*
|
||||||
|
* @param string $mode Isolation level
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function begin($mode = NULL)
|
||||||
|
{
|
||||||
|
// Make sure the database is connected
|
||||||
|
$this->_connection or $this->connect();
|
||||||
|
|
||||||
|
if ($mode AND ! $this->_connection->query("SET TRANSACTION ISOLATION LEVEL $mode"))
|
||||||
|
{
|
||||||
|
throw new Database_Exception(':error', array(
|
||||||
|
':error' => $this->_connection->error
|
||||||
|
), $this->_connection->errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bool) $this->_connection->query('START TRANSACTION');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commit a SQL transaction
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function commit()
|
||||||
|
{
|
||||||
|
// Make sure the database is connected
|
||||||
|
$this->_connection or $this->connect();
|
||||||
|
|
||||||
|
return (bool) $this->_connection->query('COMMIT');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rollback a SQL transaction
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function rollback()
|
||||||
|
{
|
||||||
|
// Make sure the database is connected
|
||||||
|
$this->_connection or $this->connect();
|
||||||
|
|
||||||
|
return (bool) $this->_connection->query('ROLLBACK');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function list_tables($like = NULL)
|
||||||
|
{
|
||||||
|
if (is_string($like))
|
||||||
|
{
|
||||||
|
// Search for table names
|
||||||
|
$result = $this->query(Database::SELECT, 'SHOW TABLES LIKE '.$this->quote($like), FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Find all table names
|
||||||
|
$result = $this->query(Database::SELECT, 'SHOW TABLES', FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tables = array();
|
||||||
|
foreach ($result as $row)
|
||||||
|
{
|
||||||
|
$tables[] = reset($row);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function list_columns($table, $like = NULL, $add_prefix = TRUE)
|
||||||
|
{
|
||||||
|
// Quote the table name
|
||||||
|
$table = ($add_prefix === TRUE) ? $this->quote_table($table) : $table;
|
||||||
|
|
||||||
|
if (is_string($like))
|
||||||
|
{
|
||||||
|
// Search for column names
|
||||||
|
$result = $this->query(Database::SELECT, 'SHOW FULL COLUMNS FROM '.$table.' LIKE '.$this->quote($like), FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Find all column names
|
||||||
|
$result = $this->query(Database::SELECT, 'SHOW FULL COLUMNS FROM '.$table, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = 0;
|
||||||
|
$columns = array();
|
||||||
|
foreach ($result as $row)
|
||||||
|
{
|
||||||
|
list($type, $length) = $this->_parse_type($row['Type']);
|
||||||
|
|
||||||
|
$column = $this->datatype($type);
|
||||||
|
|
||||||
|
$column['column_name'] = $row['Field'];
|
||||||
|
$column['column_default'] = $row['Default'];
|
||||||
|
$column['data_type'] = $type;
|
||||||
|
$column['is_nullable'] = ($row['Null'] == 'YES');
|
||||||
|
$column['ordinal_position'] = ++$count;
|
||||||
|
|
||||||
|
switch ($column['type'])
|
||||||
|
{
|
||||||
|
case 'float':
|
||||||
|
if (isset($length))
|
||||||
|
{
|
||||||
|
list($column['numeric_precision'], $column['numeric_scale']) = explode(',', $length);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'int':
|
||||||
|
if (isset($length))
|
||||||
|
{
|
||||||
|
// MySQL attribute
|
||||||
|
$column['display'] = $length;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
switch ($column['data_type'])
|
||||||
|
{
|
||||||
|
case 'binary':
|
||||||
|
case 'varbinary':
|
||||||
|
$column['character_maximum_length'] = $length;
|
||||||
|
break;
|
||||||
|
case 'char':
|
||||||
|
case 'varchar':
|
||||||
|
$column['character_maximum_length'] = $length;
|
||||||
|
case 'text':
|
||||||
|
case 'tinytext':
|
||||||
|
case 'mediumtext':
|
||||||
|
case 'longtext':
|
||||||
|
$column['collation_name'] = $row['Collation'];
|
||||||
|
break;
|
||||||
|
case 'enum':
|
||||||
|
case 'set':
|
||||||
|
$column['collation_name'] = $row['Collation'];
|
||||||
|
$column['options'] = explode('\',\'', substr($length, 1, -1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MySQL attributes
|
||||||
|
$column['comment'] = $row['Comment'];
|
||||||
|
$column['extra'] = $row['Extra'];
|
||||||
|
$column['key'] = $row['Key'];
|
||||||
|
$column['privileges'] = $row['Privileges'];
|
||||||
|
|
||||||
|
$columns[$row['Field']] = $column;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function escape($value)
|
||||||
|
{
|
||||||
|
// Make sure the database is connected
|
||||||
|
$this->_connection or $this->connect();
|
||||||
|
|
||||||
|
if (($value = $this->_connection->real_escape_string( (string) $value)) === FALSE)
|
||||||
|
{
|
||||||
|
throw new Database_Exception(':error', array(
|
||||||
|
':error' => $this->_connection->error,
|
||||||
|
), $this->_connection->errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SQL standard is to use single-quotes for all values
|
||||||
|
return "'$value'";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End Database_MySQLi
|
71
modules/database/classes/Kohana/Database/MySQLi/Result.php
Normal file
71
modules/database/classes/Kohana/Database/MySQLi/Result.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||||
|
/**
|
||||||
|
* MySQLi database result. See [Results](/database/results) for usage and examples.
|
||||||
|
*
|
||||||
|
* @package Kohana/Database
|
||||||
|
* @category Query/Result
|
||||||
|
* @author Kohana Team
|
||||||
|
* @copyright (c) 2008-2009 Kohana Team
|
||||||
|
* @license http://kohanaphp.com/license
|
||||||
|
*/
|
||||||
|
class Kohana_Database_MySQLi_Result extends Database_Result {
|
||||||
|
|
||||||
|
protected $_internal_row = 0;
|
||||||
|
|
||||||
|
public function __construct($result, $sql, $as_object = FALSE, array $params = NULL)
|
||||||
|
{
|
||||||
|
parent::__construct($result, $sql, $as_object, $params);
|
||||||
|
|
||||||
|
// Find the number of rows in the result
|
||||||
|
$this->_total_rows = $result->num_rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
if (is_resource($this->_result))
|
||||||
|
{
|
||||||
|
$this->_result->free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function seek($offset)
|
||||||
|
{
|
||||||
|
if ($this->offsetExists($offset) AND $this->_result->data_seek($offset))
|
||||||
|
{
|
||||||
|
// Set the current row to the offset
|
||||||
|
$this->_current_row = $this->_internal_row = $offset;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function current()
|
||||||
|
{
|
||||||
|
if ($this->_current_row !== $this->_internal_row AND ! $this->seek($this->_current_row))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Increment internal row for optimization assuming rows are fetched in order
|
||||||
|
$this->_internal_row++;
|
||||||
|
|
||||||
|
if ($this->_as_object === TRUE)
|
||||||
|
{
|
||||||
|
// Return an stdClass
|
||||||
|
return $this->_result->fetch_object();
|
||||||
|
}
|
||||||
|
elseif (is_string($this->_as_object))
|
||||||
|
{
|
||||||
|
// Return an object of given class name
|
||||||
|
return $this->_result->fetch_object($this->_as_object, (array) $this->_object_params);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Return an array of the row
|
||||||
|
return $this->_result->fetch_assoc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End Database_MySQLi_Result_Select
|
@ -60,6 +60,12 @@ class Kohana_Database_PDO extends Database {
|
|||||||
array(':error' => $e->getMessage()),
|
array(':error' => $e->getMessage()),
|
||||||
$e->getCode());
|
$e->getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! empty($this->_config['charset']))
|
||||||
|
{
|
||||||
|
// Set the character set
|
||||||
|
$this->set_charset($this->_config['charset']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,7 +80,7 @@ abstract class Kohana_Database_Query_Builder extends Database_Query {
|
|||||||
// Convert "val = NULL" to "val IS NULL"
|
// Convert "val = NULL" to "val IS NULL"
|
||||||
$op = 'IS';
|
$op = 'IS';
|
||||||
}
|
}
|
||||||
elseif ($op === '!=')
|
elseif ($op === '!=' OR $op === '<>')
|
||||||
{
|
{
|
||||||
// Convert "val != NULL" to "valu IS NOT NULL"
|
// Convert "val != NULL" to "valu IS NOT NULL"
|
||||||
$op = 'IS NOT';
|
$op = 'IS NOT';
|
||||||
|
@ -31,7 +31,7 @@ class Kohana_Database_Query_Builder_Insert extends Database_Query_Builder {
|
|||||||
if ($table)
|
if ($table)
|
||||||
{
|
{
|
||||||
// Set the inital table name
|
// Set the inital table name
|
||||||
$this->_table = $table;
|
$this->table($table);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($columns)
|
if ($columns)
|
||||||
@ -47,11 +47,14 @@ class Kohana_Database_Query_Builder_Insert extends Database_Query_Builder {
|
|||||||
/**
|
/**
|
||||||
* Sets the table to insert into.
|
* Sets the table to insert into.
|
||||||
*
|
*
|
||||||
* @param mixed $table table name or array($table, $alias) or object
|
* @param string $table table name
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function table($table)
|
public function table($table)
|
||||||
{
|
{
|
||||||
|
if ( ! is_string($table))
|
||||||
|
throw new Kohana_Exception('INSERT INTO syntax does not allow table aliasing');
|
||||||
|
|
||||||
$this->_table = $table;
|
$this->_table = $table;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
@ -87,7 +90,10 @@ class Kohana_Database_Query_Builder_Insert extends Database_Query_Builder {
|
|||||||
// Get all of the passed values
|
// Get all of the passed values
|
||||||
$values = func_get_args();
|
$values = func_get_args();
|
||||||
|
|
||||||
$this->_values = array_merge($this->_values, $values);
|
foreach ($values as $value)
|
||||||
|
{
|
||||||
|
$this->_values[] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -127,21 +127,8 @@ class Kohana_Database_Query_Builder_Join extends Database_Query_Builder {
|
|||||||
$op = ' '.strtoupper($op);
|
$op = ' '.strtoupper($op);
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case C2 is prefixed with table
|
|
||||||
$c2table = FALSE;
|
|
||||||
$parts = explode('.', $c2);
|
|
||||||
|
|
||||||
// If there are parts, we'll check that first one is the table name.
|
|
||||||
if (count($parts) == 2)
|
|
||||||
{
|
|
||||||
if ($db->list_columns($parts[0],$parts[1]))
|
|
||||||
{
|
|
||||||
$c2table = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quote each of the columns used for the condition
|
// Quote each of the columns used for the condition
|
||||||
$conditions[] = $db->quote_column($c1).$op.' '.($c2table ? $db->quote_column($c2) : $db->quote($c2));
|
$conditions[] = $db->quote_column($c1).$op.' '.$db->quote_column($c2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Concat the conditions "... AND ..."
|
// Concat the conditions "... AND ..."
|
||||||
|
@ -309,7 +309,7 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
|
|||||||
*/
|
*/
|
||||||
public function offset($number)
|
public function offset($number)
|
||||||
{
|
{
|
||||||
$this->_offset = $number;
|
$this->_offset = ($number === NULL) ? NULL : (int) $number;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -404,13 +404,14 @@ class Kohana_Database_Query_Builder_Select extends Database_Query_Builder_Where
|
|||||||
|
|
||||||
if ( ! empty($this->_union))
|
if ( ! empty($this->_union))
|
||||||
{
|
{
|
||||||
|
$query = '('.$query.')';
|
||||||
foreach ($this->_union as $u) {
|
foreach ($this->_union as $u) {
|
||||||
$query .= ' UNION ';
|
$query .= ' UNION ';
|
||||||
if ($u['all'] === TRUE)
|
if ($u['all'] === TRUE)
|
||||||
{
|
{
|
||||||
$query .= 'ALL ';
|
$query .= 'ALL ';
|
||||||
}
|
}
|
||||||
$query .= $u['select']->compile($db);
|
$query .= '('.$u['select']->compile($db).')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ abstract class Kohana_Database_Query_Builder_Where extends Database_Query_Builde
|
|||||||
*/
|
*/
|
||||||
public function limit($number)
|
public function limit($number)
|
||||||
{
|
{
|
||||||
$this->_limit = $number;
|
$this->_limit = ($number === NULL) ? NULL : (int) $number;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -204,6 +204,9 @@ class Kohana_Session_Database extends Session {
|
|||||||
// Execute the query
|
// Execute the query
|
||||||
$query->execute($this->_db);
|
$query->execute($this->_db);
|
||||||
|
|
||||||
|
// Delete the old session id
|
||||||
|
$this->_update_id = NULL;
|
||||||
|
|
||||||
// Delete the cookie
|
// Delete the cookie
|
||||||
Cookie::delete($this->_name);
|
Cookie::delete($this->_name);
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,13 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"composer/installers": "~1.0",
|
"composer/installers": "~1.0",
|
||||||
"kohana/core": ">=3.3",
|
"kohana/core": ">=3.3",
|
||||||
"php": ">=5.3.3"
|
"php": ">=5.3.6"
|
||||||
},
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"kohana/core": "3.3.*@dev",
|
||||||
|
"kohana/unittest": "3.3.*@dev",
|
||||||
|
"kohana/koharness": "*@dev"
|
||||||
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-mysql": "*",
|
"ext-mysql": "*",
|
||||||
"ext-pdo": "*"
|
"ext-pdo": "*"
|
||||||
@ -32,6 +37,9 @@
|
|||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-3.3/develop": "3.3.x-dev",
|
"dev-3.3/develop": "3.3.x-dev",
|
||||||
"dev-3.4/develop": "3.4.x-dev"
|
"dev-3.4/develop": "3.4.x-dev"
|
||||||
}
|
},
|
||||||
|
"installer-paths": {
|
||||||
|
"vendor/{$vendor}/{$name}": ["type:kohana-module"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,4 +53,38 @@ return array
|
|||||||
'charset' => 'utf8',
|
'charset' => 'utf8',
|
||||||
'caching' => FALSE,
|
'caching' => FALSE,
|
||||||
),
|
),
|
||||||
|
/**
|
||||||
|
* MySQLi driver config information
|
||||||
|
*
|
||||||
|
* The following options are available for MySQLi:
|
||||||
|
*
|
||||||
|
* string hostname server hostname, or socket
|
||||||
|
* string database database name
|
||||||
|
* string username database username
|
||||||
|
* string password database password
|
||||||
|
* boolean persistent use persistent connections?
|
||||||
|
* array ssl ssl parameters as "key => value" pairs.
|
||||||
|
* Available keys: client_key_path, client_cert_path, ca_cert_path, ca_dir_path, cipher
|
||||||
|
* array variables system variables as "key => value" pairs
|
||||||
|
*
|
||||||
|
* Ports and sockets may be appended to the hostname.
|
||||||
|
*
|
||||||
|
* MySQLi driver config example:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// 'alternate_mysqli' => array
|
||||||
|
// (
|
||||||
|
// 'type' => 'MySQLi',
|
||||||
|
// 'connection' => array(
|
||||||
|
// 'hostname' => 'localhost',
|
||||||
|
// 'database' => 'kohana',
|
||||||
|
// 'username' => FALSE,
|
||||||
|
// 'password' => FALSE,
|
||||||
|
// 'persistent' => FALSE,
|
||||||
|
// 'ssl' => NULL,
|
||||||
|
// ),
|
||||||
|
// 'table_prefix' => '',
|
||||||
|
// 'charset' => 'utf8',
|
||||||
|
// 'caching' => FALSE,
|
||||||
|
// ),
|
||||||
);
|
);
|
||||||
|
@ -11,13 +11,14 @@ The database configuration file contains an array of configuration groups. The s
|
|||||||
'charset' => string CHARACTER_SET,
|
'charset' => string CHARACTER_SET,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
Understanding each of these settings is important.
|
Understanding each of these settings is important.
|
||||||
|
|
||||||
INSTANCE_NAME
|
INSTANCE_NAME
|
||||||
: Connections can be named anything you want, but you should always have at least one connection called "default".
|
: Connections can be named anything you want, but you should always have at least one connection called "default".
|
||||||
|
|
||||||
DATABASE_TYPE
|
DATABASE_TYPE
|
||||||
: One of the installed database drivers. Kohana comes with "mysql" and "pdo" drivers. Drivers must extend the Database class.
|
: One of the installed database drivers. Kohana comes with "MySQL", "MySQLi", and "PDO" drivers. Drivers must extend the Database class. This parameter is case sensitive. Note the mysql php extension used by the MySQL driver is deprecated as of PHP 5.5 and you should look to use an alternative driver.
|
||||||
|
|
||||||
CONNECTION_ARRAY
|
CONNECTION_ARRAY
|
||||||
: Specific driver options for connecting to your database. (Driver options are explained [below](#connection-settings).)
|
: Specific driver options for connecting to your database. (Driver options are explained [below](#connection-settings).)
|
||||||
@ -49,7 +50,7 @@ The example file below shows 2 MySQL connections, one local and one remote.
|
|||||||
(
|
(
|
||||||
'default' => array
|
'default' => array
|
||||||
(
|
(
|
||||||
'type' => 'mysql',
|
'type' => 'MySQL',
|
||||||
'connection' => array(
|
'connection' => array(
|
||||||
'hostname' => 'localhost',
|
'hostname' => 'localhost',
|
||||||
'username' => 'dbuser',
|
'username' => 'dbuser',
|
||||||
@ -61,7 +62,7 @@ The example file below shows 2 MySQL connections, one local and one remote.
|
|||||||
'charset' => 'utf8',
|
'charset' => 'utf8',
|
||||||
),
|
),
|
||||||
'remote' => array(
|
'remote' => array(
|
||||||
'type' => 'mysql',
|
'type' => 'MySQL',
|
||||||
'connection' => array(
|
'connection' => array(
|
||||||
'hostname' => '55.55.55.55',
|
'hostname' => '55.55.55.55',
|
||||||
'username' => 'remote_user',
|
'username' => 'remote_user',
|
||||||
@ -74,6 +75,8 @@ The example file below shows 2 MySQL connections, one local and one remote.
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
[!!] Note that the 'type' parameter is case sensitive (eg 'MySQL', 'PDO').
|
||||||
|
|
||||||
## Connections and Instances
|
## Connections and Instances
|
||||||
|
|
||||||
Each configuration group is referred to as a database instance. Each instance can be accessed by calling [Database::instance]. If you don't provide a parameter, the default instance is used.
|
Each configuration group is referred to as a database instance. Each instance can be accessed by calling [Database::instance]. If you don't provide a parameter, the default instance is used.
|
||||||
@ -114,6 +117,24 @@ Type | Option | Description | Default value
|
|||||||
`boolean` | persistent | Persistent connections | `FALSE`
|
`boolean` | persistent | Persistent connections | `FALSE`
|
||||||
`string` | database | Database name | `kohana`
|
`string` | database | Database name | `kohana`
|
||||||
|
|
||||||
|
### MySQLi
|
||||||
|
|
||||||
|
A [MySQL database](http://php.net/manual/en/book.mysqli.php) can accept the following options in the `connection` array:
|
||||||
|
|
||||||
|
Type | Option | Description | Default value
|
||||||
|
----------|------------|----------------------------| -------------------------
|
||||||
|
`string` | hostname | Hostname of the database | `localhost`
|
||||||
|
`integer` | port | Port number | `NULL`
|
||||||
|
`string` | socket | UNIX socket | `NULL`
|
||||||
|
`string` | username | Database username | `NULL`
|
||||||
|
`string` | password | Database password | `NULL`
|
||||||
|
`boolean` | persistent | Persistent connections | `FALSE`
|
||||||
|
`string` | database | Database name | `kohana`
|
||||||
|
`array` | ssl | SSL parameters | `NULL`
|
||||||
|
|
||||||
|
SSL parameters should be specified as `key` => `value` pairs.
|
||||||
|
Available keys: client_key_path, client_cert_path, ca_cert_path, ca_dir_path, cipher
|
||||||
|
|
||||||
### PDO
|
### PDO
|
||||||
|
|
||||||
A [PDO database](http://php.net/manual/en/book.pdo.php) can accept these options in the `connection` array:
|
A [PDO database](http://php.net/manual/en/book.pdo.php) can accept these options in the `connection` array:
|
||||||
|
@ -25,7 +25,7 @@ In this example, we loop through an array of whitelisted input fields and for ea
|
|||||||
|
|
||||||
//copy the query & execute it
|
//copy the query & execute it
|
||||||
$pagination_query = clone $query;
|
$pagination_query = clone $query;
|
||||||
$count = $pagination_query->select(DB::expr('COUNT(*)) AS mycount')->execute()->get('mycount');
|
$count = $pagination_query->select(DB::expr('COUNT(*) AS mycount'))->execute()->get('mycount');
|
||||||
|
|
||||||
//pass the total item count to Pagination
|
//pass the total item count to Pagination
|
||||||
$config = Kohana::$config->load('pagination');
|
$config = Kohana::$config->load('pagination');
|
||||||
|
@ -76,7 +76,7 @@ This query would generate the following SQL:
|
|||||||
|
|
||||||
Often you will want the results in a particular order and rather than sorting the results, it's better to have the results returned to you in the correct order. You can do this by using the order_by() method. It takes the column name and an optional direction string as the parameters. Multiple `order_by()` methods can be used to add additional sorting capability.
|
Often you will want the results in a particular order and rather than sorting the results, it's better to have the results returned to you in the correct order. You can do this by using the order_by() method. It takes the column name and an optional direction string as the parameters. Multiple `order_by()` methods can be used to add additional sorting capability.
|
||||||
|
|
||||||
$query = DB::select()->from(`posts`)->order_by(`published`, `DESC`);
|
$query = DB::select()->from('posts')->order_by('published', 'DESC');
|
||||||
|
|
||||||
This query would generate the following SQL:
|
This query would generate the following SQL:
|
||||||
|
|
||||||
|
8
modules/database/koharness.php
Normal file
8
modules/database/koharness.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
// Configuration for koharness - builds a standalone skeleton Kohana app for running unit tests
|
||||||
|
return array(
|
||||||
|
'modules' => array(
|
||||||
|
'database' => __DIR__,
|
||||||
|
'unittest' => __DIR__ . '/vendor/kohana/unittest'
|
||||||
|
),
|
||||||
|
);
|
37
modules/image/.travis.yml
Normal file
37
modules/image/.travis.yml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
sudo: false
|
||||||
|
|
||||||
|
language: php
|
||||||
|
|
||||||
|
# Only build the main develop/master branches - feature branches will be covered by PRs
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- /^[0-9\.]+\/(develop|master)$/
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- vendor
|
||||||
|
- $HOME/.composer/cache
|
||||||
|
|
||||||
|
php:
|
||||||
|
- 5.3
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
- 7.0
|
||||||
|
- hhvm
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- php: 5.3
|
||||||
|
env: 'COMPOSER_PHPUNIT="lowest"'
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- composer install --prefer-dist
|
||||||
|
- if [ "$COMPOSER_PHPUNIT" = "lowest" ]; then composer update --prefer-lowest --with-dependencies phpunit/phpunit; fi;
|
||||||
|
- vendor/bin/koharness
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cd /tmp/koharness && ./vendor/bin/phpunit --bootstrap=modules/unittest/bootstrap.php modules/unittest/tests.php
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
@ -0,0 +1,6 @@
|
|||||||
|
# Kohana - image processing module
|
||||||
|
|
||||||
|
| ver | Stable | Develop |
|
||||||
|
|-------|--------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| 3.3.x | [![Build Status - 3.3/master](https://travis-ci.org/kohana/image.svg?branch=3.3%2Fmaster)](https://travis-ci.org/kohana/image) | [![Build Status - 3.3/develop](https://travis-ci.org/kohana/image.svg?branch=3.3%2Fdevelop)](https://travis-ci.org/kohana/image) |
|
||||||
|
| 3.4.x | [![Build Status - 3.4/master](https://travis-ci.org/kohana/image.svg?branch=3.4%2Fmaster)](https://travis-ci.org/kohana/image) | [![Build Status - 3.4/develop](https://travis-ci.org/kohana/image.svg?branch=3.4%2Fdevelop)](https://travis-ci.org/kohana/image) |
|
@ -23,6 +23,7 @@ abstract class Kohana_Image {
|
|||||||
const VERTICAL = 0x12;
|
const VERTICAL = 0x12;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated - provide an image.default_driver value in your configuration instead
|
||||||
* @var string default driver: GD, ImageMagick, etc
|
* @var string default driver: GD, ImageMagick, etc
|
||||||
*/
|
*/
|
||||||
public static $default_driver = 'GD';
|
public static $default_driver = 'GD';
|
||||||
@ -44,8 +45,9 @@ abstract class Kohana_Image {
|
|||||||
{
|
{
|
||||||
if ($driver === NULL)
|
if ($driver === NULL)
|
||||||
{
|
{
|
||||||
// Use the default driver
|
// Use the driver from configuration file or default one
|
||||||
$driver = Image::$default_driver;
|
$configured_driver = Kohana::$config->load('image.default_driver');
|
||||||
|
$driver = ($configured_driver) ? $configured_driver : Image::$default_driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the class name
|
// Set the class name
|
||||||
|
@ -611,6 +611,7 @@ class Kohana_Image_GD extends Image {
|
|||||||
switch (strtolower($extension))
|
switch (strtolower($extension))
|
||||||
{
|
{
|
||||||
case 'jpg':
|
case 'jpg':
|
||||||
|
case 'jpe':
|
||||||
case 'jpeg':
|
case 'jpeg':
|
||||||
// Save a JPG file
|
// Save a JPG file
|
||||||
$save = 'imagejpeg';
|
$save = 'imagejpeg';
|
||||||
|
@ -314,6 +314,7 @@ class Kohana_Image_Imagick extends Image {
|
|||||||
switch ($format)
|
switch ($format)
|
||||||
{
|
{
|
||||||
case 'jpg':
|
case 'jpg':
|
||||||
|
case 'jpe':
|
||||||
case 'jpeg':
|
case 'jpeg':
|
||||||
$type = IMAGETYPE_JPEG;
|
$type = IMAGETYPE_JPEG;
|
||||||
break;
|
break;
|
||||||
|
@ -24,6 +24,11 @@
|
|||||||
"kohana/core": ">=3.3",
|
"kohana/core": ">=3.3",
|
||||||
"php": ">=5.3.3"
|
"php": ">=5.3.3"
|
||||||
},
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"kohana/core": "3.3.*@dev",
|
||||||
|
"kohana/unittest": "3.3.*@dev",
|
||||||
|
"kohana/koharness": "*@dev"
|
||||||
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-gd": "*"
|
"ext-gd": "*"
|
||||||
},
|
},
|
||||||
@ -31,6 +36,9 @@
|
|||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-3.3/develop": "3.3.x-dev",
|
"dev-3.3/develop": "3.3.x-dev",
|
||||||
"dev-3.4/develop": "3.4.x-dev"
|
"dev-3.4/develop": "3.4.x-dev"
|
||||||
}
|
},
|
||||||
|
"installer-paths": {
|
||||||
|
"vendor/{$vendor}/{$name}": ["type:kohana-module"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
modules/image/config/image.php
Normal file
8
modules/image/config/image.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php defined('SYSPATH') OR die('No direct script access.');
|
||||||
|
|
||||||
|
return array(
|
||||||
|
// Provide the default driver to use - eg a value of Imagick will use Image_Imagick as the driver class
|
||||||
|
// If you set a value for this config key, then the Image::$default_driver static variable that was used
|
||||||
|
// to configure earlier versions will be ignored.
|
||||||
|
'default_driver' => NULL,
|
||||||
|
);
|
@ -4,7 +4,24 @@ Kohana 3.x provides a simple yet powerful image manipulation module. The [Image]
|
|||||||
|
|
||||||
## Drivers
|
## Drivers
|
||||||
|
|
||||||
[Image] module ships with [Image_GD] driver which requires `GD` extension enabled in your PHP installation. This is the default driver. Additional drivers can be created by extending the [Image] class.
|
[Image] module ships with [Image_GD] driver which requires `GD` extension enabled in your PHP installation, and
|
||||||
|
[Image_Imagick] driver which requires the `imagick` PHP extension. Additional drivers can be created by extending
|
||||||
|
the [Image] class.
|
||||||
|
|
||||||
|
The [Image_GD] driver is the default. You can change this by providing an `image.default_driver` configuration option
|
||||||
|
- for example:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
// application/config/image.php
|
||||||
|
<?php
|
||||||
|
return array(
|
||||||
|
'default_driver' => 'Imagick'
|
||||||
|
);
|
||||||
|
~~~
|
||||||
|
|
||||||
|
[!!] Older versions of Kohana allowed you to configure the driver with the `Image::$default_driver` static variable in
|
||||||
|
the bootstrap, an extension class, or elsewhere. That variable is now deprecated and will be ignored if you set a
|
||||||
|
config value.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
|
8
modules/image/koharness.php
Normal file
8
modules/image/koharness.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
// Configuration for koharness - builds a standalone skeleton Kohana app for running unit tests
|
||||||
|
return array(
|
||||||
|
'modules' => array(
|
||||||
|
'image' => __DIR__,
|
||||||
|
'unittest' => __DIR__ . '/vendor/kohana/unittest'
|
||||||
|
),
|
||||||
|
);
|
@ -1,39 +0,0 @@
|
|||||||
Email Module For Kohana 3.0
|
|
||||||
=================================
|
|
||||||
|
|
||||||
This is a direct port of the email helper from Kohana 2.3.3 source code.
|
|
||||||
|
|
||||||
It has been updated to work with SwiftMailer 4 and includes the libs dir from the 4.0.4 distribution.
|
|
||||||
|
|
||||||
Usage should be exactly as with old helper.
|
|
||||||
|
|
||||||
Methods defined:
|
|
||||||
|
|
||||||
### Email::connect($config = NULL)
|
|
||||||
|
|
||||||
Creates SwiftMailer object. $config is an array of configuration values and defaults to using the config file 'email'.
|
|
||||||
|
|
||||||
Note: PopBeforeSmtp is not supported in this release as I didn't know what was required to set it up.
|
|
||||||
It IS supported in Swiftmailer through the Swift_Plugins_PopBeforeSmtpPlugin plugin class. This can be used manually if required.
|
|
||||||
If anyone can modify and test the connect() methd with this functionality I'll add it but I can't find documentation about how it used to work (i.e. is expected to work) so I have left it out for now.
|
|
||||||
|
|
||||||
### Email::send($to, $from, $subject, $message, $html = false)
|
|
||||||
|
|
||||||
$to can be any of the following:
|
|
||||||
|
|
||||||
* a single string email address e.g. "test@example.com"
|
|
||||||
* an array specifying an email address and a name e.g. array('test@example.com', 'John Doe')
|
|
||||||
* an array of recipients in either above format, keyed by type e.g. array('to' => 'test@example.com', 'cc' => array('test2@example.com', 'Jane Doe'), 'bcc' => 'another@example.com')
|
|
||||||
|
|
||||||
$from can be either a string email or array of email and name as above
|
|
||||||
|
|
||||||
More complex email (multipart, attachments, batch mailing etc.) must be done using the native Swift_Mailer classes. The Swift Mailer autoloader is included by connect() so you can use and class in the Swift library without worrying about including files.
|
|
||||||
|
|
||||||
The Swift_Mailer object setup by connect is returned by it so if you need to access it manually use:
|
|
||||||
|
|
||||||
$mailer = Email::connect();
|
|
||||||
|
|
||||||
// Create complex Swift_Message object stored in $message
|
|
||||||
|
|
||||||
$mailer->send($message);
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
|||||||
<?php defined('SYSPATH') OR die('No direct access allowed.');
|
|
||||||
|
|
||||||
abstract class Email extends Kohana_Email { }
|
|
@ -1,145 +0,0 @@
|
|||||||
<?php defined('SYSPATH') OR die('No direct access allowed.');
|
|
||||||
/**
|
|
||||||
* Email module
|
|
||||||
*
|
|
||||||
* Ported from Kohana 2.2.3 Core to Kohana 3.0 module
|
|
||||||
*
|
|
||||||
* Updated to use Swiftmailer 4.0.4
|
|
||||||
*
|
|
||||||
* @package Core
|
|
||||||
* @author Kohana Team
|
|
||||||
* @copyright (c) 2007-2008 Kohana Team
|
|
||||||
* @license http://kohanaphp.com/license.html
|
|
||||||
*/
|
|
||||||
abstract class Kohana_Email {
|
|
||||||
|
|
||||||
// SwiftMailer instance
|
|
||||||
protected static $mail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a SwiftMailer instance.
|
|
||||||
*
|
|
||||||
* @param string DSN connection string
|
|
||||||
* @return object Swift object
|
|
||||||
*/
|
|
||||||
public static function connect($config = NULL)
|
|
||||||
{
|
|
||||||
if ( ! class_exists('Swift_Mailer', FALSE))
|
|
||||||
{
|
|
||||||
// Load SwiftMailer
|
|
||||||
require Kohana::find_file('vendor', 'swift/swift_required');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load default configuration
|
|
||||||
($config === NULL) and $config = Kohana::$config->load('email');
|
|
||||||
|
|
||||||
switch ($config['driver'])
|
|
||||||
{
|
|
||||||
case 'smtp':
|
|
||||||
// Set port
|
|
||||||
$port = empty($config['options']['port']) ? 25 : (int) $config['options']['port'];
|
|
||||||
|
|
||||||
// Create SMTP Transport
|
|
||||||
$transport = Swift_SmtpTransport::newInstance($config['options']['hostname'], $port);
|
|
||||||
|
|
||||||
if ( ! empty($config['options']['encryption']))
|
|
||||||
{
|
|
||||||
// Set encryption
|
|
||||||
$transport->setEncryption($config['options']['encryption']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do authentication, if part of the DSN
|
|
||||||
empty($config['options']['username']) or $transport->setUsername($config['options']['username']);
|
|
||||||
empty($config['options']['password']) or $transport->setPassword($config['options']['password']);
|
|
||||||
|
|
||||||
// Set the timeout to 5 seconds
|
|
||||||
$transport->setTimeout(empty($config['options']['timeout']) ? 5 : (int) $config['options']['timeout']);
|
|
||||||
break;
|
|
||||||
case 'sendmail':
|
|
||||||
// Create a sendmail connection
|
|
||||||
$transport = Swift_SendmailTransport::newInstance(empty($config['options']) ? "/usr/sbin/sendmail -bs" : $config['options']);
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Use the native connection
|
|
||||||
$transport = Swift_MailTransport::newInstance($config['options']);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the SwiftMailer instance
|
|
||||||
return Email::$mail = Swift_Mailer::newInstance($transport);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an email message.
|
|
||||||
*
|
|
||||||
* @param string|array recipient email (and name), or an array of To, Cc, Bcc names
|
|
||||||
* @param string|array sender email (and name)
|
|
||||||
* @param string message subject
|
|
||||||
* @param string message body
|
|
||||||
* @param boolean send email as HTML
|
|
||||||
* @return integer number of emails sent
|
|
||||||
*/
|
|
||||||
public static function send($to, $from, $subject, $message, $html = FALSE)
|
|
||||||
{
|
|
||||||
// Connect to SwiftMailer
|
|
||||||
(Email::$mail === NULL) and email::connect();
|
|
||||||
|
|
||||||
// Determine the message type
|
|
||||||
$html = ($html === TRUE) ? 'text/html' : 'text/plain';
|
|
||||||
|
|
||||||
// Create the message
|
|
||||||
$message = Swift_Message::newInstance($subject, $message, $html, 'utf-8');
|
|
||||||
|
|
||||||
if (is_string($to))
|
|
||||||
{
|
|
||||||
// Single recipient
|
|
||||||
$message->setTo($to);
|
|
||||||
}
|
|
||||||
elseif (is_array($to))
|
|
||||||
{
|
|
||||||
if (isset($to[0]) AND isset($to[1]))
|
|
||||||
{
|
|
||||||
// Create To: address set
|
|
||||||
$to = array('to' => $to);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($to as $method => $set)
|
|
||||||
{
|
|
||||||
if ( ! in_array($method, array('to', 'cc', 'bcc')))
|
|
||||||
{
|
|
||||||
// Use To: by default
|
|
||||||
$method = 'to';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create method name
|
|
||||||
$method = 'add'.ucfirst($method);
|
|
||||||
|
|
||||||
if (is_array($set))
|
|
||||||
{
|
|
||||||
// Add a recipient with name
|
|
||||||
$message->$method($set[0], $set[1]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Add a recipient without name
|
|
||||||
$message->$method($set);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_string($from))
|
|
||||||
{
|
|
||||||
// From without a name
|
|
||||||
$message->setFrom($from);
|
|
||||||
}
|
|
||||||
elseif (is_array($from))
|
|
||||||
{
|
|
||||||
// From with a name
|
|
||||||
$message->setFrom($from[0], $from[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Email::$mail->send($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // End email
|
|
@ -1,29 +0,0 @@
|
|||||||
<?php defined('SYSPATH') OR die('No direct access allowed.');
|
|
||||||
return array(
|
|
||||||
/**
|
|
||||||
* SwiftMailer driver, used with the email module.
|
|
||||||
*
|
|
||||||
* Valid drivers are: native, sendmail, smtp
|
|
||||||
*/
|
|
||||||
'driver' => 'native',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To use secure connections with SMTP, set "port" to 465 instead of 25.
|
|
||||||
* To enable TLS, set "encryption" to "tls".
|
|
||||||
*
|
|
||||||
* Note for SMTP, 'auth' key no longer exists as it did in 2.3.x helper
|
|
||||||
* Simply specifying a username and password is enough for all normal auth methods
|
|
||||||
* as they are autodeteccted in Swiftmailer 4
|
|
||||||
*
|
|
||||||
* PopB4Smtp is not supported in this module as I had no way to test it but
|
|
||||||
* SwiftMailer 4 does have a PopBeforeSMTP plugin so it shouldn't be hard to implement
|
|
||||||
*
|
|
||||||
* Encryption can be one of 'ssl' or 'tls' (both require non-default PHP extensions
|
|
||||||
*
|
|
||||||
* Driver options:
|
|
||||||
* @param null native: no options
|
|
||||||
* @param string sendmail: executable path, with -bs or equivalent attached
|
|
||||||
* @param array smtp: hostname, (username), (password), (port), (encryption)
|
|
||||||
*/
|
|
||||||
'options' => NULL
|
|
||||||
);
|
|
61
modules/khemail/vendor/swift/CHANGES
vendored
61
modules/khemail/vendor/swift/CHANGES
vendored
@ -1,61 +0,0 @@
|
|||||||
Changelog for Swift Mailer, since Version 4.x
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
09 March 2009: 4.0.0
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
* Complete rewrite of Version 3.x with lots of breaking changes at the interface
|
|
||||||
level, but for the best in the long run.
|
|
||||||
* Changed Connections to Transports
|
|
||||||
* Made sending more robust (less error prone)
|
|
||||||
* Simplified Swift_Message interface (removed need for separate RecipientList)
|
|
||||||
* Improved Plugin API (better event management)
|
|
||||||
* Changed all MIME generated content to be full RFC 2822 (and friends) compliant
|
|
||||||
|
|
||||||
11 March 2009: 4.0.1
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
* Fixed regression with cache clearing logic in setBody(), setEncoder() and
|
|
||||||
setCharset()
|
|
||||||
|
|
||||||
13 March 2009: 4.0.2
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
* Added addTo(), addCc() etc methods.
|
|
||||||
* Allowed setTo(), setCc() etc to accept a $name parameters.
|
|
||||||
* Patched a bug in MailTransport where failed recipients were not being merged.
|
|
||||||
* Added Swift::VERSION constant
|
|
||||||
* Allowed custom autoloaders to be used
|
|
||||||
|
|
||||||
20 March 2009: 4.0.3
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
* Fixed Bug where base64 encoded content could exceed 76 chars per line
|
|
||||||
* Allowed Decorator plugin to accept a custom Replacements object
|
|
||||||
|
|
||||||
12 August 2009: 4.0.4
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
* Bugfixes for operating under safe mode and using the MailTransport
|
|
||||||
* Compatibility for PHP 5.3
|
|
||||||
* Optimizations for addTo(), addCc() etc operations
|
|
||||||
* Bugfix for double-escaping issue in batch sending
|
|
||||||
|
|
||||||
27 September 2009: 4.0.5
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
* Fixed a warning (#78)
|
|
||||||
* Clarified license and updated the file headers accordingly
|
|
||||||
* Added __toString() methods where toString() methods already exists
|
|
||||||
* Removed constants (SWIFT_LIB_DIRECTORY, SWIFT_MAP_DIRECTORY, SWIFT_CLASS_DIRECTORY)
|
|
||||||
* Simplified autoloading
|
|
||||||
* Added a setAuthMode() method to AuthHandler (#54)
|
|
||||||
|
|
||||||
20 January 2010: 4.0.6
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
* added a PEAR package and a script to generate PEAR packages
|
|
||||||
* fixed Swift_Transport_TransportException for SMTP connection not thrown (#109)
|
|
||||||
* fixed Message-IDs are not updated properly (#118)
|
|
||||||
|
|
||||||
-- End of Changes --
|
|
165
modules/khemail/vendor/swift/LICENSE
vendored
165
modules/khemail/vendor/swift/LICENSE
vendored
@ -1,165 +0,0 @@
|
|||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
4. Combined Works.
|
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
|
|
||||||
d) Do one of the following:
|
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
30
modules/khemail/vendor/swift/README
vendored
30
modules/khemail/vendor/swift/README
vendored
@ -1,30 +0,0 @@
|
|||||||
Swift Mailer, by Chris Corbyn
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
Swift Mailer is a component based mailing solution for PHP 5.
|
|
||||||
It is released under the LGPL license.
|
|
||||||
|
|
||||||
Homepage: http://swiftmailer.org
|
|
||||||
Documentation: http://swiftmailer.org/docs
|
|
||||||
Mailing List: http://groups.google.com/group/swiftmailer
|
|
||||||
Bugs: http://swiftmailer.lighthouseapp.com/
|
|
||||||
Repository: http://github.com/swiftmailer/swiftmailer
|
|
||||||
|
|
||||||
Swift Mailer is highly object-oriented by design and lends itself
|
|
||||||
to use in complex web application with a great deal of flexibility.
|
|
||||||
|
|
||||||
For full details on usage, see the documentation.
|
|
||||||
|
|
||||||
IMPORTANT: Users upgrading from version 3.x or earlier absolutely
|
|
||||||
MUST read the documentation. In short, the API is considerably
|
|
||||||
different so your old code won't "just work".
|
|
||||||
|
|
||||||
If you'd like to make a donation, we are working on a system where
|
|
||||||
donations are taken on a per-feature-request basis via the website
|
|
||||||
with target amounts for each feature. In the meantime however you
|
|
||||||
may donate directly to the author via PayPal:
|
|
||||||
|
|
||||||
PayPal: chris@w3style.co.uk
|
|
||||||
|
|
||||||
Donations are certainly voluntary, but seriously, you donors are
|
|
||||||
complete legends and drive this project! :)
|
|
1
modules/khemail/vendor/swift/VERSION
vendored
1
modules/khemail/vendor/swift/VERSION
vendored
@ -1 +0,0 @@
|
|||||||
Swift-4.0.6
|
|
57
modules/khemail/vendor/swift/classes/Swift.php
vendored
57
modules/khemail/vendor/swift/classes/Swift.php
vendored
@ -1,57 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* General utility class in Swift Mailer, not to be instantiated.
|
|
||||||
*
|
|
||||||
* @package Swift
|
|
||||||
*
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
abstract class Swift
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Swift Mailer Version number generated during dist release process */
|
|
||||||
const VERSION = '4.0.6';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal autoloader for spl_autoload_register().
|
|
||||||
*
|
|
||||||
* @param string $class
|
|
||||||
*/
|
|
||||||
public static function autoload($class)
|
|
||||||
{
|
|
||||||
//Don't interfere with other autoloaders
|
|
||||||
if (0 !== strpos($class, 'Swift'))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$path = dirname(__FILE__).'/'.str_replace('_', '/', $class).'.php';
|
|
||||||
|
|
||||||
if (!file_exists($path))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once $path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure autoloading using Swift Mailer.
|
|
||||||
*
|
|
||||||
* This is designed to play nicely with other autoloaders.
|
|
||||||
*/
|
|
||||||
public static function registerAutoload()
|
|
||||||
{
|
|
||||||
spl_autoload_register(array('Swift', 'autoload'));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/Mime/Attachment.php';
|
|
||||||
//@require 'Swift/ByteStream/FileByteStream.php';
|
|
||||||
//@require 'Swift/DependencyContainer.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attachment class for attaching files to a {@link Swift_Mime_Message}.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Mime
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_Attachment extends Swift_Mime_Attachment
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new Attachment.
|
|
||||||
* Details may be optionally provided to the constructor.
|
|
||||||
* @param string|Swift_OutputByteStream $data
|
|
||||||
* @param string $filename
|
|
||||||
* @param string $contentType
|
|
||||||
*/
|
|
||||||
public function __construct($data = null, $filename = null,
|
|
||||||
$contentType = null)
|
|
||||||
{
|
|
||||||
call_user_func_array(
|
|
||||||
array($this, 'Swift_Mime_Attachment::__construct'),
|
|
||||||
Swift_DependencyContainer::getInstance()
|
|
||||||
->createDependenciesFor('mime.attachment')
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->setBody($data);
|
|
||||||
$this->setFilename($filename);
|
|
||||||
if ($contentType)
|
|
||||||
{
|
|
||||||
$this->setContentType($contentType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new Attachment.
|
|
||||||
* @param string|Swift_OutputByteStream $data
|
|
||||||
* @param string $filename
|
|
||||||
* @param string $contentType
|
|
||||||
* @return Swift_Mime_Attachment
|
|
||||||
*/
|
|
||||||
public static function newInstance($data = null, $filename = null,
|
|
||||||
$contentType = null)
|
|
||||||
{
|
|
||||||
return new self($data, $filename, $contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new Attachment from a filesystem path.
|
|
||||||
* @param string $path
|
|
||||||
* @param string $contentType optional
|
|
||||||
* @return Swift_Mime_Attachment
|
|
||||||
*/
|
|
||||||
public static function fromPath($path, $contentType = null)
|
|
||||||
{
|
|
||||||
return self::newInstance()->setFile(
|
|
||||||
new Swift_ByteStream_FileByteStream($path),
|
|
||||||
$contentType
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,178 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/InputByteStream.php';
|
|
||||||
//@require 'Swift/Filterable.php';
|
|
||||||
//@require 'Swift/StreamFilter.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides the base functionality for an InputStream supporting filters.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage ByteStream
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
abstract class Swift_ByteStream_AbstractFilterableInputStream
|
|
||||||
implements Swift_InputByteStream, Swift_Filterable
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Write sequence */
|
|
||||||
private $_sequence = 0;
|
|
||||||
|
|
||||||
/** StreamFilters */
|
|
||||||
private $_filters = array();
|
|
||||||
|
|
||||||
/** A buffer for writing */
|
|
||||||
private $_writeBuffer = '';
|
|
||||||
|
|
||||||
/** Bound streams */
|
|
||||||
private $_mirrors = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Commit the given bytes to the storage medium immediately.
|
|
||||||
* @param string $bytes
|
|
||||||
* @access protected
|
|
||||||
*/
|
|
||||||
abstract protected function _commit($bytes);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush any buffers/content with immediate effect.
|
|
||||||
* @access protected
|
|
||||||
*/
|
|
||||||
abstract protected function _flush();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a StreamFilter to this InputByteStream.
|
|
||||||
* @param Swift_StreamFilter $filter
|
|
||||||
* @param string $key
|
|
||||||
*/
|
|
||||||
public function addFilter(Swift_StreamFilter $filter, $key)
|
|
||||||
{
|
|
||||||
$this->_filters[$key] = $filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove an already present StreamFilter based on its $key.
|
|
||||||
* @param string $key
|
|
||||||
*/
|
|
||||||
public function removeFilter($key)
|
|
||||||
{
|
|
||||||
unset($this->_filters[$key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes $bytes to the end of the stream.
|
|
||||||
* @param string $bytes
|
|
||||||
* @throws Swift_IoException
|
|
||||||
*/
|
|
||||||
public function write($bytes)
|
|
||||||
{
|
|
||||||
$this->_writeBuffer .= $bytes;
|
|
||||||
foreach ($this->_filters as $filter)
|
|
||||||
{
|
|
||||||
if ($filter->shouldBuffer($this->_writeBuffer))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->_doWrite($this->_writeBuffer);
|
|
||||||
return ++$this->_sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For any bytes that are currently buffered inside the stream, force them
|
|
||||||
* off the buffer.
|
|
||||||
*
|
|
||||||
* @throws Swift_IoException
|
|
||||||
*/
|
|
||||||
public function commit()
|
|
||||||
{
|
|
||||||
$this->_doWrite($this->_writeBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attach $is to this stream.
|
|
||||||
* The stream acts as an observer, receiving all data that is written.
|
|
||||||
* All {@link write()} and {@link flushBuffers()} operations will be mirrored.
|
|
||||||
*
|
|
||||||
* @param Swift_InputByteStream $is
|
|
||||||
*/
|
|
||||||
public function bind(Swift_InputByteStream $is)
|
|
||||||
{
|
|
||||||
$this->_mirrors[] = $is;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove an already bound stream.
|
|
||||||
* If $is is not bound, no errors will be raised.
|
|
||||||
* If the stream currently has any buffered data it will be written to $is
|
|
||||||
* before unbinding occurs.
|
|
||||||
*
|
|
||||||
* @param Swift_InputByteStream $is
|
|
||||||
*/
|
|
||||||
public function unbind(Swift_InputByteStream $is)
|
|
||||||
{
|
|
||||||
foreach ($this->_mirrors as $k => $stream)
|
|
||||||
{
|
|
||||||
if ($is === $stream)
|
|
||||||
{
|
|
||||||
if ($this->_writeBuffer !== '')
|
|
||||||
{
|
|
||||||
$stream->write($this->_filter($this->_writeBuffer));
|
|
||||||
}
|
|
||||||
unset($this->_mirrors[$k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush the contents of the stream (empty it) and set the internal pointer
|
|
||||||
* to the beginning.
|
|
||||||
* @throws Swift_IoException
|
|
||||||
*/
|
|
||||||
public function flushBuffers()
|
|
||||||
{
|
|
||||||
if ($this->_writeBuffer !== '')
|
|
||||||
{
|
|
||||||
$this->_doWrite($this->_writeBuffer);
|
|
||||||
}
|
|
||||||
$this->_flush();
|
|
||||||
|
|
||||||
foreach ($this->_mirrors as $stream)
|
|
||||||
{
|
|
||||||
$stream->flushBuffers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Private methods
|
|
||||||
|
|
||||||
/** Run $bytes through all filters */
|
|
||||||
private function _filter($bytes)
|
|
||||||
{
|
|
||||||
foreach ($this->_filters as $filter)
|
|
||||||
{
|
|
||||||
$bytes = $filter->filter($bytes);
|
|
||||||
}
|
|
||||||
return $bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Just write the bytes to the stream */
|
|
||||||
private function _doWrite($bytes)
|
|
||||||
{
|
|
||||||
$this->_commit($this->_filter($bytes));
|
|
||||||
|
|
||||||
foreach ($this->_mirrors as $stream)
|
|
||||||
{
|
|
||||||
$stream->write($bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_writeBuffer = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,190 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/InputByteStream.php';
|
|
||||||
//@require 'Swift/OutputByteStream.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows reading and writing of bytes to and from an array.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage ByteStream
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_ByteStream_ArrayByteStream
|
|
||||||
implements Swift_InputByteStream, Swift_OutputByteStream
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The internal stack of bytes.
|
|
||||||
* @var string[]
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
private $_array = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The size of the stack
|
|
||||||
* @var int
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
private $_arraySize = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The internal pointer offset.
|
|
||||||
* @var int
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
private $_offset = 0;
|
|
||||||
|
|
||||||
/** Bound streams */
|
|
||||||
private $_mirrors = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new ArrayByteStream.
|
|
||||||
* If $stack is given the stream will be populated with the bytes it contains.
|
|
||||||
* @param mixed $stack of bytes in string or array form, optional
|
|
||||||
*/
|
|
||||||
public function __construct($stack = null)
|
|
||||||
{
|
|
||||||
if (is_array($stack))
|
|
||||||
{
|
|
||||||
$this->_array = $stack;
|
|
||||||
$this->_arraySize = count($stack);
|
|
||||||
}
|
|
||||||
elseif (is_string($stack))
|
|
||||||
{
|
|
||||||
$this->write($stack);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->_array = array();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads $length bytes from the stream into a string and moves the pointer
|
|
||||||
* through the stream by $length. If less bytes exist than are requested the
|
|
||||||
* remaining bytes are given instead. If no bytes are remaining at all, boolean
|
|
||||||
* false is returned.
|
|
||||||
* @param int $length
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function read($length)
|
|
||||||
{
|
|
||||||
if ($this->_offset == $this->_arraySize)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't use array slice
|
|
||||||
$end = $length + $this->_offset;
|
|
||||||
$end = $this->_arraySize<$end
|
|
||||||
?$this->_arraySize
|
|
||||||
:$end;
|
|
||||||
$ret = '';
|
|
||||||
for (; $this->_offset < $end; ++$this->_offset)
|
|
||||||
{
|
|
||||||
$ret .= $this->_array[$this->_offset];
|
|
||||||
}
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes $bytes to the end of the stream.
|
|
||||||
* @param string $bytes
|
|
||||||
*/
|
|
||||||
public function write($bytes)
|
|
||||||
{
|
|
||||||
$to_add = str_split($bytes);
|
|
||||||
foreach ($to_add as $value)
|
|
||||||
{
|
|
||||||
$this->_array[] = $value;
|
|
||||||
}
|
|
||||||
$this->_arraySize = count($this->_array);
|
|
||||||
|
|
||||||
foreach ($this->_mirrors as $stream)
|
|
||||||
{
|
|
||||||
$stream->write($bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not used.
|
|
||||||
*/
|
|
||||||
public function commit()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attach $is to this stream.
|
|
||||||
* The stream acts as an observer, receiving all data that is written.
|
|
||||||
* All {@link write()} and {@link flushBuffers()} operations will be mirrored.
|
|
||||||
*
|
|
||||||
* @param Swift_InputByteStream $is
|
|
||||||
*/
|
|
||||||
public function bind(Swift_InputByteStream $is)
|
|
||||||
{
|
|
||||||
$this->_mirrors[] = $is;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove an already bound stream.
|
|
||||||
* If $is is not bound, no errors will be raised.
|
|
||||||
* If the stream currently has any buffered data it will be written to $is
|
|
||||||
* before unbinding occurs.
|
|
||||||
*
|
|
||||||
* @param Swift_InputByteStream $is
|
|
||||||
*/
|
|
||||||
public function unbind(Swift_InputByteStream $is)
|
|
||||||
{
|
|
||||||
foreach ($this->_mirrors as $k => $stream)
|
|
||||||
{
|
|
||||||
if ($is === $stream)
|
|
||||||
{
|
|
||||||
unset($this->_mirrors[$k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move the internal read pointer to $byteOffset in the stream.
|
|
||||||
* @param int $byteOffset
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function setReadPointer($byteOffset)
|
|
||||||
{
|
|
||||||
if ($byteOffset > $this->_arraySize)
|
|
||||||
{
|
|
||||||
$byteOffset = $this->_arraySize;
|
|
||||||
}
|
|
||||||
elseif ($byteOffset < 0)
|
|
||||||
{
|
|
||||||
$byteOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_offset = $byteOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush the contents of the stream (empty it) and set the internal pointer
|
|
||||||
* to the beginning.
|
|
||||||
*/
|
|
||||||
public function flushBuffers()
|
|
||||||
{
|
|
||||||
$this->_offset = 0;
|
|
||||||
$this->_array = array();
|
|
||||||
$this->_arraySize = 0;
|
|
||||||
|
|
||||||
foreach ($this->_mirrors as $stream)
|
|
||||||
{
|
|
||||||
$stream->flushBuffers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,177 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/ByteStream/AbstractFilterableInputStream.php';
|
|
||||||
//@require 'Swift/InputByteStream.php';
|
|
||||||
//@require 'Swift/FileStream.php';
|
|
||||||
//@require 'Swift/IoException.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows reading and writing of bytes to and from a file.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage ByteStream
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_ByteStream_FileByteStream
|
|
||||||
extends Swift_ByteStream_AbstractFilterableInputStream
|
|
||||||
implements Swift_FileStream
|
|
||||||
{
|
|
||||||
|
|
||||||
/** The internal pointer offset */
|
|
||||||
private $_offset = 0;
|
|
||||||
|
|
||||||
/** The path to the file */
|
|
||||||
private $_path;
|
|
||||||
|
|
||||||
/** The mode this file is opened in for writing */
|
|
||||||
private $_mode;
|
|
||||||
|
|
||||||
/** A lazy-loaded resource handle for reading the file */
|
|
||||||
private $_reader;
|
|
||||||
|
|
||||||
/** A lazy-loaded resource handle for writing the file */
|
|
||||||
private $_writer;
|
|
||||||
|
|
||||||
/** If magic_quotes_runtime is on, this will be true */
|
|
||||||
private $_quotes = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new FileByteStream for $path.
|
|
||||||
* @param string $path
|
|
||||||
* @param string $writable if true
|
|
||||||
*/
|
|
||||||
public function __construct($path, $writable = false)
|
|
||||||
{
|
|
||||||
$this->_path = $path;
|
|
||||||
$this->_mode = $writable ? 'w+b' : 'rb';
|
|
||||||
$this->_quotes = get_magic_quotes_runtime();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the complete path to the file.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getPath()
|
|
||||||
{
|
|
||||||
return $this->_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads $length bytes from the stream into a string and moves the pointer
|
|
||||||
* through the stream by $length. If less bytes exist than are requested the
|
|
||||||
* remaining bytes are given instead. If no bytes are remaining at all, boolean
|
|
||||||
* false is returned.
|
|
||||||
* @param int $length
|
|
||||||
* @return string
|
|
||||||
* @throws Swift_IoException
|
|
||||||
*/
|
|
||||||
public function read($length)
|
|
||||||
{
|
|
||||||
$fp = $this->_getReadHandle();
|
|
||||||
if (!feof($fp))
|
|
||||||
{
|
|
||||||
if ($this->_quotes)
|
|
||||||
{
|
|
||||||
set_magic_quotes_runtime(0);
|
|
||||||
}
|
|
||||||
$bytes = fread($fp, $length);
|
|
||||||
if ($this->_quotes)
|
|
||||||
{
|
|
||||||
set_magic_quotes_runtime(1);
|
|
||||||
}
|
|
||||||
$this->_offset = ftell($fp);
|
|
||||||
return $bytes;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move the internal read pointer to $byteOffset in the stream.
|
|
||||||
* @param int $byteOffset
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function setReadPointer($byteOffset)
|
|
||||||
{
|
|
||||||
if (isset($this->_reader))
|
|
||||||
{
|
|
||||||
fseek($this->_reader, $byteOffset, SEEK_SET);
|
|
||||||
}
|
|
||||||
$this->_offset = $byteOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Private methods
|
|
||||||
|
|
||||||
/** Just write the bytes to the file */
|
|
||||||
protected function _commit($bytes)
|
|
||||||
{
|
|
||||||
fwrite($this->_getWriteHandle(), $bytes);
|
|
||||||
$this->_resetReadHandle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Not used */
|
|
||||||
protected function _flush()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the resource for reading */
|
|
||||||
private function _getReadHandle()
|
|
||||||
{
|
|
||||||
if (!isset($this->_reader))
|
|
||||||
{
|
|
||||||
if (!$this->_reader = fopen($this->_path, 'rb'))
|
|
||||||
{
|
|
||||||
throw new Swift_IoException(
|
|
||||||
'Unable to open file for reading [' . $this->_path . ']'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
fseek($this->_reader, $this->_offset, SEEK_SET);
|
|
||||||
}
|
|
||||||
return $this->_reader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the resource for writing */
|
|
||||||
private function _getWriteHandle()
|
|
||||||
{
|
|
||||||
if (!isset($this->_writer))
|
|
||||||
{
|
|
||||||
if (!$this->_writer = fopen($this->_path, $this->_mode))
|
|
||||||
{
|
|
||||||
throw new Swift_IoException(
|
|
||||||
'Unable to open file for writing [' . $this->_path . ']'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $this->_writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Force a reload of the resource for writing */
|
|
||||||
private function _resetWriteHandle()
|
|
||||||
{
|
|
||||||
if (isset($this->_writer))
|
|
||||||
{
|
|
||||||
fclose($this->_writer);
|
|
||||||
$this->_writer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Force a reload of the resource for reading */
|
|
||||||
private function _resetReadHandle()
|
|
||||||
{
|
|
||||||
if (isset($this->_reader))
|
|
||||||
{
|
|
||||||
fclose($this->_reader);
|
|
||||||
$this->_reader = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Analyzes characters for a specific character set.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Encoder
|
|
||||||
* @author Chris Corbyn
|
|
||||||
* @author Xavier De Cock <xdecock@gmail.com>
|
|
||||||
*/
|
|
||||||
interface Swift_CharacterReader
|
|
||||||
{
|
|
||||||
const MAP_TYPE_INVALID = 0x01;
|
|
||||||
const MAP_TYPE_FIXED_LEN = 0x02;
|
|
||||||
const MAP_TYPE_POSITIONS = 0x03;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the complete charactermap
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
* @param int $startOffset
|
|
||||||
* @param array $currentMap
|
|
||||||
* @param mixed $ignoredChars
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns mapType
|
|
||||||
* @int mapType
|
|
||||||
*/
|
|
||||||
public function getMapType();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an integer which specifies how many more bytes to read.
|
|
||||||
* A positive integer indicates the number of more bytes to fetch before invoking
|
|
||||||
* this method again.
|
|
||||||
* A value of zero means this is already a valid character.
|
|
||||||
* A value of -1 means this cannot possibly be a valid character.
|
|
||||||
* @param int[] $bytes
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function validateByteSequence($bytes, $size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of bytes which should be read to start each character.
|
|
||||||
* For fixed width character sets this should be the number of
|
|
||||||
* octets-per-character. For multibyte character sets this will probably be 1.
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getInitialByteSize();
|
|
||||||
|
|
||||||
}
|
|
@ -1,96 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/CharacterReader.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides fixed-width byte sizes for reading fixed-width character sets.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Encoder
|
|
||||||
* @author Chris Corbyn
|
|
||||||
* @author Xavier De Cock <xdecock@gmail.com>
|
|
||||||
*/
|
|
||||||
class Swift_CharacterReader_GenericFixedWidthReader
|
|
||||||
implements Swift_CharacterReader
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of bytes in a single character.
|
|
||||||
* @var int
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
private $_width;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new GenericFixedWidthReader using $width bytes per character.
|
|
||||||
* @param int $width
|
|
||||||
*/
|
|
||||||
public function __construct($width)
|
|
||||||
{
|
|
||||||
$this->_width = $width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the complete charactermap
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
* @param int $startOffset
|
|
||||||
* @param array $currentMap
|
|
||||||
* @param mixed $ignoredChars
|
|
||||||
* @return $int
|
|
||||||
*/
|
|
||||||
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
|
|
||||||
{
|
|
||||||
$strlen = strlen($string);
|
|
||||||
// % and / are CPU intensive, so, maybe find a better way
|
|
||||||
$ignored = $strlen%$this->_width;
|
|
||||||
$ignoredChars = substr($string, - $ignored);
|
|
||||||
$currentMap = $this->_width;
|
|
||||||
return ($strlen - $ignored)/$this->_width;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns mapType
|
|
||||||
* @int mapType
|
|
||||||
*/
|
|
||||||
public function getMapType()
|
|
||||||
{
|
|
||||||
return self::MAP_TYPE_FIXED_LEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an integer which specifies how many more bytes to read.
|
|
||||||
* A positive integer indicates the number of more bytes to fetch before invoking
|
|
||||||
* this method again.
|
|
||||||
* A value of zero means this is already a valid character.
|
|
||||||
* A value of -1 means this cannot possibly be a valid character.
|
|
||||||
* @param string $bytes
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function validateByteSequence($bytes, $size)
|
|
||||||
{
|
|
||||||
$needed = $this->_width - $size;
|
|
||||||
return ($needed > -1)
|
|
||||||
? $needed
|
|
||||||
: -1
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of bytes which should be read to start each character.
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getInitialByteSize()
|
|
||||||
{
|
|
||||||
return $this->_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/CharacterReader.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Analyzes US-ASCII characters.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Encoder
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_CharacterReader_UsAsciiReader
|
|
||||||
implements Swift_CharacterReader
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns the complete charactermap
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
* @param int $startOffset
|
|
||||||
* @param string $ignoredChars
|
|
||||||
*/
|
|
||||||
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
|
|
||||||
{
|
|
||||||
$strlen=strlen($string);
|
|
||||||
$ignoredChars='';
|
|
||||||
for( $i = 0; $i < $strlen; ++$i)
|
|
||||||
{
|
|
||||||
if ($string[$i]>"\x07F")
|
|
||||||
{ // Invalid char
|
|
||||||
$currentMap[$i+$startOffset]=$string[$i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $strlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns mapType
|
|
||||||
* @int mapType
|
|
||||||
*/
|
|
||||||
public function getMapType()
|
|
||||||
{
|
|
||||||
return self::MAP_TYPE_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an integer which specifies how many more bytes to read.
|
|
||||||
* A positive integer indicates the number of more bytes to fetch before invoking
|
|
||||||
* this method again.
|
|
||||||
* A value of zero means this is already a valid character.
|
|
||||||
* A value of -1 means this cannot possibly be a valid character.
|
|
||||||
* @param string $bytes
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function validateByteSequence($bytes, $size)
|
|
||||||
{
|
|
||||||
$byte = reset($bytes);
|
|
||||||
if (1 == count($bytes) && $byte >= 0x00 && $byte <= 0x7F)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of bytes which should be read to start each character.
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getInitialByteSize()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,183 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/CharacterReader.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Analyzes UTF-8 characters.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Encoder
|
|
||||||
* @author Chris Corbyn
|
|
||||||
* @author Xavier De Cock <xdecock@gmail.com>
|
|
||||||
*/
|
|
||||||
class Swift_CharacterReader_Utf8Reader
|
|
||||||
implements Swift_CharacterReader
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Pre-computed for optimization */
|
|
||||||
private static $length_map=array(
|
|
||||||
//N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,
|
|
||||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //0x0N
|
|
||||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //0x1N
|
|
||||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //0x2N
|
|
||||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //0x3N
|
|
||||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //0x4N
|
|
||||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //0x5N
|
|
||||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //0x6N
|
|
||||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, //0x7N
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //0x8N
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //0x9N
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //0xAN
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //0xBN
|
|
||||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, //0xCN
|
|
||||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, //0xDN
|
|
||||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, //0xEN
|
|
||||||
4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0 //0xFN
|
|
||||||
);
|
|
||||||
private static $s_length_map=array(
|
|
||||||
"\x00"=>1, "\x01"=>1, "\x02"=>1, "\x03"=>1, "\x04"=>1, "\x05"=>1, "\x06"=>1, "\x07"=>1,
|
|
||||||
"\x08"=>1, "\x09"=>1, "\x0a"=>1, "\x0b"=>1, "\x0c"=>1, "\x0d"=>1, "\x0e"=>1, "\x0f"=>1,
|
|
||||||
"\x10"=>1, "\x11"=>1, "\x12"=>1, "\x13"=>1, "\x14"=>1, "\x15"=>1, "\x16"=>1, "\x17"=>1,
|
|
||||||
"\x18"=>1, "\x19"=>1, "\x1a"=>1, "\x1b"=>1, "\x1c"=>1, "\x1d"=>1, "\x1e"=>1, "\x1f"=>1,
|
|
||||||
"\x20"=>1, "\x21"=>1, "\x22"=>1, "\x23"=>1, "\x24"=>1, "\x25"=>1, "\x26"=>1, "\x27"=>1,
|
|
||||||
"\x28"=>1, "\x29"=>1, "\x2a"=>1, "\x2b"=>1, "\x2c"=>1, "\x2d"=>1, "\x2e"=>1, "\x2f"=>1,
|
|
||||||
"\x30"=>1, "\x31"=>1, "\x32"=>1, "\x33"=>1, "\x34"=>1, "\x35"=>1, "\x36"=>1, "\x37"=>1,
|
|
||||||
"\x38"=>1, "\x39"=>1, "\x3a"=>1, "\x3b"=>1, "\x3c"=>1, "\x3d"=>1, "\x3e"=>1, "\x3f"=>1,
|
|
||||||
"\x40"=>1, "\x41"=>1, "\x42"=>1, "\x43"=>1, "\x44"=>1, "\x45"=>1, "\x46"=>1, "\x47"=>1,
|
|
||||||
"\x48"=>1, "\x49"=>1, "\x4a"=>1, "\x4b"=>1, "\x4c"=>1, "\x4d"=>1, "\x4e"=>1, "\x4f"=>1,
|
|
||||||
"\x50"=>1, "\x51"=>1, "\x52"=>1, "\x53"=>1, "\x54"=>1, "\x55"=>1, "\x56"=>1, "\x57"=>1,
|
|
||||||
"\x58"=>1, "\x59"=>1, "\x5a"=>1, "\x5b"=>1, "\x5c"=>1, "\x5d"=>1, "\x5e"=>1, "\x5f"=>1,
|
|
||||||
"\x60"=>1, "\x61"=>1, "\x62"=>1, "\x63"=>1, "\x64"=>1, "\x65"=>1, "\x66"=>1, "\x67"=>1,
|
|
||||||
"\x68"=>1, "\x69"=>1, "\x6a"=>1, "\x6b"=>1, "\x6c"=>1, "\x6d"=>1, "\x6e"=>1, "\x6f"=>1,
|
|
||||||
"\x70"=>1, "\x71"=>1, "\x72"=>1, "\x73"=>1, "\x74"=>1, "\x75"=>1, "\x76"=>1, "\x77"=>1,
|
|
||||||
"\x78"=>1, "\x79"=>1, "\x7a"=>1, "\x7b"=>1, "\x7c"=>1, "\x7d"=>1, "\x7e"=>1, "\x7f"=>1,
|
|
||||||
"\x80"=>0, "\x81"=>0, "\x82"=>0, "\x83"=>0, "\x84"=>0, "\x85"=>0, "\x86"=>0, "\x87"=>0,
|
|
||||||
"\x88"=>0, "\x89"=>0, "\x8a"=>0, "\x8b"=>0, "\x8c"=>0, "\x8d"=>0, "\x8e"=>0, "\x8f"=>0,
|
|
||||||
"\x90"=>0, "\x91"=>0, "\x92"=>0, "\x93"=>0, "\x94"=>0, "\x95"=>0, "\x96"=>0, "\x97"=>0,
|
|
||||||
"\x98"=>0, "\x99"=>0, "\x9a"=>0, "\x9b"=>0, "\x9c"=>0, "\x9d"=>0, "\x9e"=>0, "\x9f"=>0,
|
|
||||||
"\xa0"=>0, "\xa1"=>0, "\xa2"=>0, "\xa3"=>0, "\xa4"=>0, "\xa5"=>0, "\xa6"=>0, "\xa7"=>0,
|
|
||||||
"\xa8"=>0, "\xa9"=>0, "\xaa"=>0, "\xab"=>0, "\xac"=>0, "\xad"=>0, "\xae"=>0, "\xaf"=>0,
|
|
||||||
"\xb0"=>0, "\xb1"=>0, "\xb2"=>0, "\xb3"=>0, "\xb4"=>0, "\xb5"=>0, "\xb6"=>0, "\xb7"=>0,
|
|
||||||
"\xb8"=>0, "\xb9"=>0, "\xba"=>0, "\xbb"=>0, "\xbc"=>0, "\xbd"=>0, "\xbe"=>0, "\xbf"=>0,
|
|
||||||
"\xc0"=>2, "\xc1"=>2, "\xc2"=>2, "\xc3"=>2, "\xc4"=>2, "\xc5"=>2, "\xc6"=>2, "\xc7"=>2,
|
|
||||||
"\xc8"=>2, "\xc9"=>2, "\xca"=>2, "\xcb"=>2, "\xcc"=>2, "\xcd"=>2, "\xce"=>2, "\xcf"=>2,
|
|
||||||
"\xd0"=>2, "\xd1"=>2, "\xd2"=>2, "\xd3"=>2, "\xd4"=>2, "\xd5"=>2, "\xd6"=>2, "\xd7"=>2,
|
|
||||||
"\xd8"=>2, "\xd9"=>2, "\xda"=>2, "\xdb"=>2, "\xdc"=>2, "\xdd"=>2, "\xde"=>2, "\xdf"=>2,
|
|
||||||
"\xe0"=>3, "\xe1"=>3, "\xe2"=>3, "\xe3"=>3, "\xe4"=>3, "\xe5"=>3, "\xe6"=>3, "\xe7"=>3,
|
|
||||||
"\xe8"=>3, "\xe9"=>3, "\xea"=>3, "\xeb"=>3, "\xec"=>3, "\xed"=>3, "\xee"=>3, "\xef"=>3,
|
|
||||||
"\xf0"=>4, "\xf1"=>4, "\xf2"=>4, "\xf3"=>4, "\xf4"=>4, "\xf5"=>4, "\xf6"=>4, "\xf7"=>4,
|
|
||||||
"\xf8"=>5, "\xf9"=>5, "\xfa"=>5, "\xfb"=>5, "\xfc"=>6, "\xfd"=>6, "\xfe"=>0, "\xff"=>0,
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the complete charactermap
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
* @param int $startOffset
|
|
||||||
* @param array $currentMap
|
|
||||||
* @param mixed $ignoredChars
|
|
||||||
*/
|
|
||||||
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
|
|
||||||
{
|
|
||||||
if (!isset($currentMap['i']) || !isset($currentMap['p']))
|
|
||||||
{
|
|
||||||
$currentMap['p'] = $currentMap['i'] = array();
|
|
||||||
}
|
|
||||||
$strlen=strlen($string);
|
|
||||||
$charPos=count($currentMap['p']);
|
|
||||||
$foundChars=0;
|
|
||||||
$invalid=false;
|
|
||||||
for ($i=0; $i<$strlen; ++$i)
|
|
||||||
{
|
|
||||||
$char=$string[$i];
|
|
||||||
$size=self::$s_length_map[$char];
|
|
||||||
if ($size==0)
|
|
||||||
{
|
|
||||||
/* char is invalid, we must wait for a resync */
|
|
||||||
$invalid=true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ($invalid==true)
|
|
||||||
{
|
|
||||||
/* We mark the chars as invalid and start a new char */
|
|
||||||
$currentMap['p'][$charPos+$foundChars]=$startOffset+$i;
|
|
||||||
$currentMap['i'][$charPos+$foundChars]=true;
|
|
||||||
++$foundChars;
|
|
||||||
$invalid=false;
|
|
||||||
}
|
|
||||||
if (($i+$size) > $strlen){
|
|
||||||
$ignoredChars=substr($string, $i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for ($j=1; $j<$size; ++$j)
|
|
||||||
{
|
|
||||||
$char=$string[$i+$j];
|
|
||||||
if ($char>"\x7F" && $char<"\xC0")
|
|
||||||
{
|
|
||||||
// Valid - continue parsing
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* char is invalid, we must wait for a resync */
|
|
||||||
$invalid=true;
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Ok we got a complete char here */
|
|
||||||
$lastChar=$currentMap['p'][$charPos+$foundChars]=$startOffset+$i+$size;
|
|
||||||
$i+=$j-1;
|
|
||||||
++$foundChars;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $foundChars;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns mapType
|
|
||||||
* @int mapType
|
|
||||||
*/
|
|
||||||
public function getMapType()
|
|
||||||
{
|
|
||||||
return self::MAP_TYPE_POSITIONS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an integer which specifies how many more bytes to read.
|
|
||||||
* A positive integer indicates the number of more bytes to fetch before invoking
|
|
||||||
* this method again.
|
|
||||||
* A value of zero means this is already a valid character.
|
|
||||||
* A value of -1 means this cannot possibly be a valid character.
|
|
||||||
* @param string $bytes
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function validateByteSequence($bytes, $size)
|
|
||||||
{
|
|
||||||
if ($size<1){
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
$needed = self::$length_map[$bytes[0]] - $size;
|
|
||||||
return ($needed > -1)
|
|
||||||
? $needed
|
|
||||||
: -1
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of bytes which should be read to start each character.
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function getInitialByteSize()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/CharacterReader.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A factory for creating CharacterReaders.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Encoder
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
interface Swift_CharacterReaderFactory
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a CharacterReader suitable for the charset applied.
|
|
||||||
* @param string $charset
|
|
||||||
* @return Swift_CharacterReader
|
|
||||||
*/
|
|
||||||
public function getReaderFor($charset);
|
|
||||||
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/CharacterReaderFactory.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Standard factory for creating CharacterReaders.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Encoder
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_CharacterReaderFactory_SimpleCharacterReaderFactory
|
|
||||||
implements Swift_CharacterReaderFactory
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A map of charset patterns to their implementation classes.
|
|
||||||
* @var array
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
private $_map = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factories which have already been loaded.
|
|
||||||
* @var Swift_CharacterReaderFactory[]
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
private $_loaded = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new CharacterReaderFactory.
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$prefix = 'Swift_CharacterReader_';
|
|
||||||
|
|
||||||
$singleByte = array(
|
|
||||||
'class' => $prefix . 'GenericFixedWidthReader',
|
|
||||||
'constructor' => array(1)
|
|
||||||
);
|
|
||||||
|
|
||||||
$doubleByte = array(
|
|
||||||
'class' => $prefix . 'GenericFixedWidthReader',
|
|
||||||
'constructor' => array(2)
|
|
||||||
);
|
|
||||||
|
|
||||||
$fourBytes = array(
|
|
||||||
'class' => $prefix . 'GenericFixedWidthReader',
|
|
||||||
'constructor' => array(4)
|
|
||||||
);
|
|
||||||
|
|
||||||
//Utf-8
|
|
||||||
$this->_map['utf-?8'] = array(
|
|
||||||
'class' => $prefix . 'Utf8Reader',
|
|
||||||
'constructor' => array()
|
|
||||||
);
|
|
||||||
|
|
||||||
//7-8 bit charsets
|
|
||||||
$this->_map['(us-)?ascii'] = $singleByte;
|
|
||||||
$this->_map['(iso|iec)-?8859-?[0-9]+'] = $singleByte;
|
|
||||||
$this->_map['windows-?125[0-9]'] = $singleByte;
|
|
||||||
$this->_map['cp-?[0-9]+'] = $singleByte;
|
|
||||||
$this->_map['ansi'] = $singleByte;
|
|
||||||
$this->_map['macintosh'] = $singleByte;
|
|
||||||
$this->_map['koi-?7'] = $singleByte;
|
|
||||||
$this->_map['koi-?8-?.+'] = $singleByte;
|
|
||||||
$this->_map['mik'] = $singleByte;
|
|
||||||
$this->_map['(cork|t1)'] = $singleByte;
|
|
||||||
$this->_map['v?iscii'] = $singleByte;
|
|
||||||
|
|
||||||
//16 bits
|
|
||||||
$this->_map['(ucs-?2|utf-?16)'] = $doubleByte;
|
|
||||||
|
|
||||||
//32 bits
|
|
||||||
$this->_map['(ucs-?4|utf-?32)'] = $fourBytes;
|
|
||||||
|
|
||||||
//Fallback
|
|
||||||
$this->_map['.*'] = $singleByte;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a CharacterReader suitable for the charset applied.
|
|
||||||
* @param string $charset
|
|
||||||
* @return Swift_CharacterReader
|
|
||||||
*/
|
|
||||||
public function getReaderFor($charset)
|
|
||||||
{
|
|
||||||
$charset = trim(strtolower($charset));
|
|
||||||
foreach ($this->_map as $pattern => $spec)
|
|
||||||
{
|
|
||||||
$re = '/^' . $pattern . '$/D';
|
|
||||||
if (preg_match($re, $charset))
|
|
||||||
{
|
|
||||||
if (!array_key_exists($pattern, $this->_loaded))
|
|
||||||
{
|
|
||||||
$reflector = new ReflectionClass($spec['class']);
|
|
||||||
if ($reflector->getConstructor())
|
|
||||||
{
|
|
||||||
$reader = $reflector->newInstanceArgs($spec['constructor']);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$reader = $reflector->newInstance();
|
|
||||||
}
|
|
||||||
$this->_loaded[$pattern] = $reader;
|
|
||||||
}
|
|
||||||
return $this->_loaded[$pattern];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once dirname(__FILE__) . '/OutputByteStream.php';
|
|
||||||
require_once dirname(__FILE__) . '/CharacterReaderFactory.php';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An abstract means of reading and writing data in terms of characters as opposed
|
|
||||||
* to bytes.
|
|
||||||
* Classes implementing this interface may use a subsystem which requires less
|
|
||||||
* memory than working with large strings of data.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage CharacterStream
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
interface Swift_CharacterStream
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the character set used in this CharacterStream.
|
|
||||||
* @param string $charset
|
|
||||||
*/
|
|
||||||
public function setCharacterSet($charset);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the CharacterReaderFactory for multi charset support.
|
|
||||||
* @param Swift_CharacterReaderFactory $factory
|
|
||||||
*/
|
|
||||||
public function setCharacterReaderFactory(
|
|
||||||
Swift_CharacterReaderFactory $factory);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overwrite this character stream using the byte sequence in the byte stream.
|
|
||||||
* @param Swift_OutputByteStream $os output stream to read from
|
|
||||||
*/
|
|
||||||
public function importByteStream(Swift_OutputByteStream $os);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import a string a bytes into this CharacterStream, overwriting any existing
|
|
||||||
* data in the stream.
|
|
||||||
* @param string $string
|
|
||||||
*/
|
|
||||||
public function importString($string);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read $length characters from the stream and move the internal pointer
|
|
||||||
* $length further into the stream.
|
|
||||||
* @param int $length
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function read($length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read $length characters from the stream and return a 1-dimensional array
|
|
||||||
* containing there octet values.
|
|
||||||
* @param int $length
|
|
||||||
* @return int[]
|
|
||||||
*/
|
|
||||||
public function readBytes($length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write $chars to the end of the stream.
|
|
||||||
* @param string $chars
|
|
||||||
*/
|
|
||||||
public function write($chars);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move the internal pointer to $charOffset in the stream.
|
|
||||||
* @param int $charOffset
|
|
||||||
*/
|
|
||||||
public function setPointer($charOffset);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Empty the stream and reset the internal pointer.
|
|
||||||
*/
|
|
||||||
public function flushContents();
|
|
||||||
|
|
||||||
}
|
|
@ -1,319 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/CharacterStream.php';
|
|
||||||
//@require 'Swift/OutputByteStream.php';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A CharacterStream implementation which stores characters in an internal array.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage CharacterStream
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_CharacterStream_ArrayCharacterStream
|
|
||||||
implements Swift_CharacterStream
|
|
||||||
{
|
|
||||||
|
|
||||||
/** A map of byte values and their respective characters */
|
|
||||||
private static $_charMap;
|
|
||||||
|
|
||||||
/** A map of characters and their derivative byte values */
|
|
||||||
private static $_byteMap;
|
|
||||||
|
|
||||||
/** The char reader (lazy-loaded) for the current charset */
|
|
||||||
private $_charReader;
|
|
||||||
|
|
||||||
/** A factory for creatiing CharacterReader instances */
|
|
||||||
private $_charReaderFactory;
|
|
||||||
|
|
||||||
/** The character set this stream is using */
|
|
||||||
private $_charset;
|
|
||||||
|
|
||||||
/** Array of characters */
|
|
||||||
private $_array = array();
|
|
||||||
|
|
||||||
/** Size of the array of character */
|
|
||||||
private $_array_size = array();
|
|
||||||
|
|
||||||
/** The current character offset in the stream */
|
|
||||||
private $_offset = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new CharacterStream with the given $chars, if set.
|
|
||||||
* @param Swift_CharacterReaderFactory $factory for loading validators
|
|
||||||
* @param string $charset used in the stream
|
|
||||||
*/
|
|
||||||
public function __construct(Swift_CharacterReaderFactory $factory,
|
|
||||||
$charset)
|
|
||||||
{
|
|
||||||
self::_initializeMaps();
|
|
||||||
$this->setCharacterReaderFactory($factory);
|
|
||||||
$this->setCharacterSet($charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the character set used in this CharacterStream.
|
|
||||||
* @param string $charset
|
|
||||||
*/
|
|
||||||
public function setCharacterSet($charset)
|
|
||||||
{
|
|
||||||
$this->_charset = $charset;
|
|
||||||
$this->_charReader = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the CharacterReaderFactory for multi charset support.
|
|
||||||
* @param Swift_CharacterReaderFactory $factory
|
|
||||||
*/
|
|
||||||
public function setCharacterReaderFactory(
|
|
||||||
Swift_CharacterReaderFactory $factory)
|
|
||||||
{
|
|
||||||
$this->_charReaderFactory = $factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overwrite this character stream using the byte sequence in the byte stream.
|
|
||||||
* @param Swift_OutputByteStream $os output stream to read from
|
|
||||||
*/
|
|
||||||
public function importByteStream(Swift_OutputByteStream $os)
|
|
||||||
{
|
|
||||||
if (!isset($this->_charReader))
|
|
||||||
{
|
|
||||||
$this->_charReader = $this->_charReaderFactory
|
|
||||||
->getReaderFor($this->_charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
$startLength = $this->_charReader->getInitialByteSize();
|
|
||||||
while (false !== $bytes = $os->read($startLength))
|
|
||||||
{
|
|
||||||
$c = array();
|
|
||||||
for ($i = 0, $len = strlen($bytes); $i < $len; ++$i)
|
|
||||||
{
|
|
||||||
$c[] = self::$_byteMap[$bytes[$i]];
|
|
||||||
}
|
|
||||||
$size = count($c);
|
|
||||||
$need = $this->_charReader
|
|
||||||
->validateByteSequence($c, $size);
|
|
||||||
if ($need > 0 &&
|
|
||||||
false !== $bytes = $os->read($need))
|
|
||||||
{
|
|
||||||
for ($i = 0, $len = strlen($bytes); $i < $len; ++$i)
|
|
||||||
{
|
|
||||||
$c[] = self::$_byteMap[$bytes[$i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->_array[] = $c;
|
|
||||||
++$this->_array_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import a string a bytes into this CharacterStream, overwriting any existing
|
|
||||||
* data in the stream.
|
|
||||||
* @param string $string
|
|
||||||
*/
|
|
||||||
public function importString($string)
|
|
||||||
{
|
|
||||||
$this->flushContents();
|
|
||||||
$this->write($string);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read $length characters from the stream and move the internal pointer
|
|
||||||
* $length further into the stream.
|
|
||||||
* @param int $length
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function read($length)
|
|
||||||
{
|
|
||||||
if ($this->_offset == $this->_array_size)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't use array slice
|
|
||||||
$arrays = array();
|
|
||||||
$end = $length + $this->_offset;
|
|
||||||
for ($i = $this->_offset; $i < $end; ++$i)
|
|
||||||
{
|
|
||||||
if (!isset($this->_array[$i]))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$arrays[] = $this->_array[$i];
|
|
||||||
}
|
|
||||||
$this->_offset += $i - $this->_offset; // Limit function calls
|
|
||||||
$chars = false;
|
|
||||||
foreach ($arrays as $array)
|
|
||||||
{
|
|
||||||
$chars .= implode('', array_map('chr', $array));
|
|
||||||
}
|
|
||||||
return $chars;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read $length characters from the stream and return a 1-dimensional array
|
|
||||||
* containing there octet values.
|
|
||||||
* @param int $length
|
|
||||||
* @return int[]
|
|
||||||
*/
|
|
||||||
public function readBytes($length)
|
|
||||||
{
|
|
||||||
if ($this->_offset == $this->_array_size)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$arrays = array();
|
|
||||||
$end = $length + $this->_offset;
|
|
||||||
for ($i = $this->_offset; $i < $end; ++$i)
|
|
||||||
{
|
|
||||||
if (!isset($this->_array[$i]))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$arrays[] = $this->_array[$i];
|
|
||||||
}
|
|
||||||
$this->_offset += ($i - $this->_offset); // Limit function calls
|
|
||||||
return call_user_func_array('array_merge', $arrays);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write $chars to the end of the stream.
|
|
||||||
* @param string $chars
|
|
||||||
*/
|
|
||||||
public function write($chars)
|
|
||||||
{
|
|
||||||
if (!isset($this->_charReader))
|
|
||||||
{
|
|
||||||
$this->_charReader = $this->_charReaderFactory->getReaderFor(
|
|
||||||
$this->_charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
$startLength = $this->_charReader->getInitialByteSize();
|
|
||||||
|
|
||||||
$fp = fopen('php://memory', 'w+b');
|
|
||||||
fwrite($fp, $chars);
|
|
||||||
unset($chars);
|
|
||||||
fseek($fp, 0, SEEK_SET);
|
|
||||||
|
|
||||||
$buffer = array(0);
|
|
||||||
$buf_pos = 1;
|
|
||||||
$buf_len = 1;
|
|
||||||
$has_datas = true;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
$bytes = array();
|
|
||||||
// Buffer Filing
|
|
||||||
if ($buf_len - $buf_pos < $startLength)
|
|
||||||
{
|
|
||||||
$buf = array_splice($buffer, $buf_pos);
|
|
||||||
$new = $this->_reloadBuffer($fp, 100);
|
|
||||||
if ($new)
|
|
||||||
{
|
|
||||||
$buffer = array_merge($buf, $new);
|
|
||||||
$buf_len = count($buffer);
|
|
||||||
$buf_pos = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$has_datas = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($buf_len - $buf_pos > 0)
|
|
||||||
{
|
|
||||||
$size = 0;
|
|
||||||
for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i)
|
|
||||||
{
|
|
||||||
++$size;
|
|
||||||
$bytes[] = $buffer[$buf_pos++];
|
|
||||||
}
|
|
||||||
$need = $this->_charReader->validateByteSequence(
|
|
||||||
$bytes, $size);
|
|
||||||
if ($need > 0)
|
|
||||||
{
|
|
||||||
if ($buf_len - $buf_pos < $need)
|
|
||||||
{
|
|
||||||
$new = $this->_reloadBuffer($fp, $need);
|
|
||||||
|
|
||||||
if ($new)
|
|
||||||
{
|
|
||||||
$buffer = array_merge($buffer, $new);
|
|
||||||
$buf_len = count($buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i)
|
|
||||||
{
|
|
||||||
$bytes[] = $buffer[$buf_pos++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->_array[] = $bytes;
|
|
||||||
++$this->_array_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while ($has_datas);
|
|
||||||
|
|
||||||
fclose($fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move the internal pointer to $charOffset in the stream.
|
|
||||||
* @param int $charOffset
|
|
||||||
*/
|
|
||||||
public function setPointer($charOffset)
|
|
||||||
{
|
|
||||||
if ($charOffset > $this->_array_size)
|
|
||||||
{
|
|
||||||
$charOffset = $this->_array_size;
|
|
||||||
}
|
|
||||||
elseif ($charOffset < 0)
|
|
||||||
{
|
|
||||||
$charOffset = 0;
|
|
||||||
}
|
|
||||||
$this->_offset = $charOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Empty the stream and reset the internal pointer.
|
|
||||||
*/
|
|
||||||
public function flushContents()
|
|
||||||
{
|
|
||||||
$this->_offset = 0;
|
|
||||||
$this->_array = array();
|
|
||||||
$this->_array_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function _reloadBuffer($fp, $len)
|
|
||||||
{
|
|
||||||
if (!feof($fp) && ($bytes = fread($fp, $len)) !== false)
|
|
||||||
{
|
|
||||||
$buf = array();
|
|
||||||
for ($i = 0, $len = strlen($bytes); $i < $len; ++$i)
|
|
||||||
{
|
|
||||||
$buf[] = self::$_byteMap[$bytes[$i]];
|
|
||||||
}
|
|
||||||
return $buf;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function _initializeMaps()
|
|
||||||
{
|
|
||||||
if (!isset(self::$_charMap))
|
|
||||||
{
|
|
||||||
self::$_charMap = array();
|
|
||||||
for ($byte = 0; $byte < 256; ++$byte)
|
|
||||||
{
|
|
||||||
self::$_charMap[$byte] = chr($byte);
|
|
||||||
}
|
|
||||||
self::$_byteMap = array_flip(self::$_charMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,300 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
CharacterStream implementation using an array in Swift Mailer.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/CharacterStream.php';
|
|
||||||
//@require 'Swift/OutputByteStream.php';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A CharacterStream implementation which stores characters in an internal array.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage CharacterStream
|
|
||||||
* @author Xavier De Cock <xdecock@gmail.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
Class Swift_CharacterStream_NgCharacterStream
|
|
||||||
implements Swift_CharacterStream
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The char reader (lazy-loaded) for the current charset.
|
|
||||||
* @var Swift_CharacterReader
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
private $_charReader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A factory for creatiing CharacterReader instances.
|
|
||||||
* @var Swift_CharacterReaderFactory
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
private $_charReaderFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The character set this stream is using.
|
|
||||||
* @var string
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
private $_charset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The datas stored as is
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $_datas = "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of bytes in the stream
|
|
||||||
*
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
private $_datasSize = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map
|
|
||||||
*
|
|
||||||
* @var mixed
|
|
||||||
*/
|
|
||||||
private $_map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map Type
|
|
||||||
*
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
private $_mapType = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of characters in the stream
|
|
||||||
*
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
private $_charCount = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Position in the stream
|
|
||||||
*
|
|
||||||
* @var unknown_type
|
|
||||||
*/
|
|
||||||
private $_currentPos = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The constructor
|
|
||||||
*
|
|
||||||
* @param Swift_CharacterReaderFactory $factory
|
|
||||||
* @param unknown_type $charset
|
|
||||||
*/
|
|
||||||
public function __construct(Swift_CharacterReaderFactory $factory,
|
|
||||||
$charset)
|
|
||||||
{
|
|
||||||
$this->setCharacterReaderFactory($factory);
|
|
||||||
$this->setCharacterSet($charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -- Changing parameters of the stream -- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the character set used in this CharacterStream.
|
|
||||||
* @param string $charset
|
|
||||||
*/
|
|
||||||
public function setCharacterSet($charset)
|
|
||||||
{
|
|
||||||
$this->_charset = $charset;
|
|
||||||
$this->_charReader = null;
|
|
||||||
$this->_mapType = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the CharacterReaderFactory for multi charset support.
|
|
||||||
* @param Swift_CharacterReaderFactory $factory
|
|
||||||
*/
|
|
||||||
public function setCharacterReaderFactory(
|
|
||||||
Swift_CharacterReaderFactory $factory)
|
|
||||||
{
|
|
||||||
$this->_charReaderFactory = $factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Swift_CharacterStream::flushContents()
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function flushContents()
|
|
||||||
{
|
|
||||||
$this->_datas = null;
|
|
||||||
$this->_map = null;
|
|
||||||
$this->_charCount = 0;
|
|
||||||
$this->_currentPos = 0;
|
|
||||||
$this->_datasSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Swift_CharacterStream::importByteStream()
|
|
||||||
*
|
|
||||||
* @param Swift_OutputByteStream $os
|
|
||||||
*/
|
|
||||||
public function importByteStream(Swift_OutputByteStream $os)
|
|
||||||
{
|
|
||||||
$this->flushContents();
|
|
||||||
$blocks=512;
|
|
||||||
$os->setReadPointer(0);
|
|
||||||
while(false!==($read = $os->read($blocks)))
|
|
||||||
$this->write($read);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Swift_CharacterStream::importString()
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
*/
|
|
||||||
public function importString($string)
|
|
||||||
{
|
|
||||||
$this->flushContents();
|
|
||||||
$this->write($string);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Swift_CharacterStream::read()
|
|
||||||
*
|
|
||||||
* @param int $length
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function read($length)
|
|
||||||
{
|
|
||||||
if ($this->_currentPos>=$this->_charCount)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$ret=false;
|
|
||||||
$length = ($this->_currentPos+$length > $this->_charCount)
|
|
||||||
? $this->_charCount - $this->_currentPos
|
|
||||||
: $length;
|
|
||||||
switch ($this->_mapType)
|
|
||||||
{
|
|
||||||
case Swift_CharacterReader::MAP_TYPE_FIXED_LEN:
|
|
||||||
$len = $length*$this->_map;
|
|
||||||
$ret = substr($this->_datas,
|
|
||||||
$this->_currentPos * $this->_map,
|
|
||||||
$len);
|
|
||||||
$this->_currentPos += $length;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Swift_CharacterReader::MAP_TYPE_INVALID:
|
|
||||||
$end = $this->_currentPos + $length;
|
|
||||||
$end = $end > $this->_charCount
|
|
||||||
?$this->_charCount
|
|
||||||
:$end;
|
|
||||||
$ret = '';
|
|
||||||
for (; $this->_currentPos < $length; ++$this->_currentPos)
|
|
||||||
{
|
|
||||||
if (isset ($this->_map[$this->_currentPos]))
|
|
||||||
{
|
|
||||||
$ret .= '?';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$ret .= $this->_datas[$this->_currentPos];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Swift_CharacterReader::MAP_TYPE_POSITIONS:
|
|
||||||
$end = $this->_currentPos + $length;
|
|
||||||
$end = $end > $this->_charCount
|
|
||||||
?$this->_charCount
|
|
||||||
:$end;
|
|
||||||
$ret = '';
|
|
||||||
$start = 0;
|
|
||||||
if ($this->_currentPos>0)
|
|
||||||
{
|
|
||||||
$start = $this->_map['p'][$this->_currentPos-1];
|
|
||||||
}
|
|
||||||
$to = $start;
|
|
||||||
for (; $this->_currentPos < $end; ++$this->_currentPos)
|
|
||||||
{
|
|
||||||
if (isset($this->_map['i'][$this->_currentPos])) {
|
|
||||||
$ret .= substr($this->_datas, $start, $to - $start).'?';
|
|
||||||
$start = $this->_map['p'][$this->_currentPos];
|
|
||||||
} else {
|
|
||||||
$to = $this->_map['p'][$this->_currentPos];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$ret .= substr($this->_datas, $start, $to - $start);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Swift_CharacterStream::readBytes()
|
|
||||||
*
|
|
||||||
* @param int $length
|
|
||||||
* @return int[]
|
|
||||||
*/
|
|
||||||
public function readBytes($length)
|
|
||||||
{
|
|
||||||
$read=$this->read($length);
|
|
||||||
if ($read!==false)
|
|
||||||
{
|
|
||||||
$ret = array_map('ord', str_split($read, 1));
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Swift_CharacterStream::setPointer()
|
|
||||||
*
|
|
||||||
* @param int $charOffset
|
|
||||||
*/
|
|
||||||
public function setPointer($charOffset)
|
|
||||||
{
|
|
||||||
if ($this->_charCount<$charOffset){
|
|
||||||
$charOffset=$this->_charCount;
|
|
||||||
}
|
|
||||||
$this->_currentPos = $charOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see Swift_CharacterStream::write()
|
|
||||||
*
|
|
||||||
* @param string $chars
|
|
||||||
*/
|
|
||||||
public function write($chars)
|
|
||||||
{
|
|
||||||
if (!isset($this->_charReader))
|
|
||||||
{
|
|
||||||
$this->_charReader = $this->_charReaderFactory->getReaderFor(
|
|
||||||
$this->_charset);
|
|
||||||
$this->_map = array();
|
|
||||||
$this->_mapType = $this->_charReader->getMapType();
|
|
||||||
}
|
|
||||||
$ignored='';
|
|
||||||
$this->_datas .= $chars;
|
|
||||||
$this->_charCount += $this->_charReader->getCharPositions(substr($this->_datas, $this->_datasSize), $this->_datasSize, $this->_map, $ignored);
|
|
||||||
if ($ignored!==false) {
|
|
||||||
$this->_datasSize=strlen($this->_datas)-strlen($ignored);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->_datasSize=strlen($this->_datas);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,349 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/DependencyException.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dependency Injection container.
|
|
||||||
* @package Swift
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_DependencyContainer
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Constant for literal value types */
|
|
||||||
const TYPE_VALUE = 0x0001;
|
|
||||||
|
|
||||||
/** Constant for new instance types */
|
|
||||||
const TYPE_INSTANCE = 0x0010;
|
|
||||||
|
|
||||||
/** Constant for shared instance types */
|
|
||||||
const TYPE_SHARED = 0x0100;
|
|
||||||
|
|
||||||
/** Constant for aliases */
|
|
||||||
const TYPE_ALIAS = 0x1000;
|
|
||||||
|
|
||||||
/** Singleton instance */
|
|
||||||
private static $_instance = null;
|
|
||||||
|
|
||||||
/** The data container */
|
|
||||||
private $_store = array();
|
|
||||||
|
|
||||||
/** The current endpoint in the data container */
|
|
||||||
private $_endPoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor should not be used.
|
|
||||||
* Use {@link getInstance()} instead.
|
|
||||||
*/
|
|
||||||
public function __construct() { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a singleton of the DependencyContainer.
|
|
||||||
* @return Swift_DependencyContainer
|
|
||||||
*/
|
|
||||||
public static function getInstance()
|
|
||||||
{
|
|
||||||
if (!isset(self::$_instance))
|
|
||||||
{
|
|
||||||
self::$_instance = new self();
|
|
||||||
}
|
|
||||||
return self::$_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List the names of all items stored in the Container.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function listItems()
|
|
||||||
{
|
|
||||||
return array_keys($this->_store);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if an item is registered in this container with the given name.
|
|
||||||
* @param string $itemName
|
|
||||||
* @return boolean
|
|
||||||
* @see register()
|
|
||||||
*/
|
|
||||||
public function has($itemName)
|
|
||||||
{
|
|
||||||
return array_key_exists($itemName, $this->_store)
|
|
||||||
&& isset($this->_store[$itemName]['lookupType']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lookup the item with the given $itemName.
|
|
||||||
* @param string $itemName
|
|
||||||
* @return mixed
|
|
||||||
* @throws Swift_DependencyException If the dependency is not found
|
|
||||||
* @see register()
|
|
||||||
*/
|
|
||||||
public function lookup($itemName)
|
|
||||||
{
|
|
||||||
if (!$this->has($itemName))
|
|
||||||
{
|
|
||||||
throw new Swift_DependencyException(
|
|
||||||
'Cannot lookup dependency "' . $itemName . '" since it is not registered.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($this->_store[$itemName]['lookupType'])
|
|
||||||
{
|
|
||||||
case self::TYPE_ALIAS:
|
|
||||||
return $this->_createAlias($itemName);
|
|
||||||
case self::TYPE_VALUE:
|
|
||||||
return $this->_getValue($itemName);
|
|
||||||
case self::TYPE_INSTANCE:
|
|
||||||
return $this->_createNewInstance($itemName);
|
|
||||||
case self::TYPE_SHARED:
|
|
||||||
return $this->_createSharedInstance($itemName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an array of arguments passed to the constructor of $itemName.
|
|
||||||
* @param string $itemName
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function createDependenciesFor($itemName)
|
|
||||||
{
|
|
||||||
$args = array();
|
|
||||||
if (isset($this->_store[$itemName]['args']))
|
|
||||||
{
|
|
||||||
$args = $this->_resolveArgs($this->_store[$itemName]['args']);
|
|
||||||
}
|
|
||||||
return $args;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a new dependency with $itemName.
|
|
||||||
* This method returns the current DependencyContainer instance because it
|
|
||||||
* requires the use of the fluid interface to set the specific details for the
|
|
||||||
* dependency.
|
|
||||||
*
|
|
||||||
* @param string $itemName
|
|
||||||
* @return Swift_DependencyContainer
|
|
||||||
* @see asNewInstanceOf(), asSharedInstanceOf(), asValue()
|
|
||||||
*/
|
|
||||||
public function register($itemName)
|
|
||||||
{
|
|
||||||
$this->_store[$itemName] = array();
|
|
||||||
$this->_endPoint =& $this->_store[$itemName];
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the previously registered item as a literal value.
|
|
||||||
* {@link register()} must be called before this will work.
|
|
||||||
*
|
|
||||||
* @param mixed $value
|
|
||||||
* @return Swift_DependencyContainer
|
|
||||||
*/
|
|
||||||
public function asValue($value)
|
|
||||||
{
|
|
||||||
$endPoint =& $this->_getEndPoint();
|
|
||||||
$endPoint['lookupType'] = self::TYPE_VALUE;
|
|
||||||
$endPoint['value'] = $value;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the previously registered item as an alias of another item.
|
|
||||||
* @param string $lookup
|
|
||||||
* @return Swift_DependencyContainer
|
|
||||||
*/
|
|
||||||
public function asAliasOf($lookup)
|
|
||||||
{
|
|
||||||
$endPoint =& $this->_getEndPoint();
|
|
||||||
$endPoint['lookupType'] = self::TYPE_ALIAS;
|
|
||||||
$endPoint['ref'] = $lookup;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the previously registered item as a new instance of $className.
|
|
||||||
* {@link register()} must be called before this will work.
|
|
||||||
* Any arguments can be set with {@link withDependencies()},
|
|
||||||
* {@link addConstructorValue()} or {@link addConstructorLookup()}.
|
|
||||||
*
|
|
||||||
* @param string $className
|
|
||||||
* @return Swift_DependencyContainer
|
|
||||||
* @see withDependencies(), addConstructorValue(), addConstructorLookup()
|
|
||||||
*/
|
|
||||||
public function asNewInstanceOf($className)
|
|
||||||
{
|
|
||||||
$endPoint =& $this->_getEndPoint();
|
|
||||||
$endPoint['lookupType'] = self::TYPE_INSTANCE;
|
|
||||||
$endPoint['className'] = $className;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the previously registered item as a shared instance of $className.
|
|
||||||
* {@link register()} must be called before this will work.
|
|
||||||
* @param string $className
|
|
||||||
* @return Swift_DependencyContainer
|
|
||||||
*/
|
|
||||||
public function asSharedInstanceOf($className)
|
|
||||||
{
|
|
||||||
$endPoint =& $this->_getEndPoint();
|
|
||||||
$endPoint['lookupType'] = self::TYPE_SHARED;
|
|
||||||
$endPoint['className'] = $className;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify a list of injected dependencies for the previously registered item.
|
|
||||||
* This method takes an array of lookup names.
|
|
||||||
*
|
|
||||||
* @param array $lookups
|
|
||||||
* @return Swift_DependencyContainer
|
|
||||||
* @see addConstructorValue(), addConstructorLookup()
|
|
||||||
*/
|
|
||||||
public function withDependencies(array $lookups)
|
|
||||||
{
|
|
||||||
$endPoint =& $this->_getEndPoint();
|
|
||||||
$endPoint['args'] = array();
|
|
||||||
foreach ($lookups as $lookup)
|
|
||||||
{
|
|
||||||
$this->addConstructorLookup($lookup);
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify a literal (non looked up) value for the constructor of the
|
|
||||||
* previously registered item.
|
|
||||||
*
|
|
||||||
* @param mixed $value
|
|
||||||
* @return Swift_DependencyContainer
|
|
||||||
* @see withDependencies(), addConstructorLookup()
|
|
||||||
*/
|
|
||||||
public function addConstructorValue($value)
|
|
||||||
{
|
|
||||||
$endPoint =& $this->_getEndPoint();
|
|
||||||
if (!isset($endPoint['args']))
|
|
||||||
{
|
|
||||||
$endPoint['args'] = array();
|
|
||||||
}
|
|
||||||
$endPoint['args'][] = array('type' => 'value', 'item' => $value);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify a dependency lookup for the constructor of the previously
|
|
||||||
* registered item.
|
|
||||||
*
|
|
||||||
* @param string $lookup
|
|
||||||
* @return Swift_DependencyContainer
|
|
||||||
* @see withDependencies(), addConstructorValue()
|
|
||||||
*/
|
|
||||||
public function addConstructorLookup($lookup)
|
|
||||||
{
|
|
||||||
$endPoint =& $this->_getEndPoint();
|
|
||||||
if (!isset($this->_endPoint['args']))
|
|
||||||
{
|
|
||||||
$endPoint['args'] = array();
|
|
||||||
}
|
|
||||||
$endPoint['args'][] = array('type' => 'lookup', 'item' => $lookup);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Private methods
|
|
||||||
|
|
||||||
/** Get the literal value with $itemName */
|
|
||||||
private function _getValue($itemName)
|
|
||||||
{
|
|
||||||
return $this->_store[$itemName]['value'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Resolve an alias to another item */
|
|
||||||
private function _createAlias($itemName)
|
|
||||||
{
|
|
||||||
return $this->lookup($this->_store[$itemName]['ref']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a fresh instance of $itemName */
|
|
||||||
private function _createNewInstance($itemName)
|
|
||||||
{
|
|
||||||
$reflector = new ReflectionClass($this->_store[$itemName]['className']);
|
|
||||||
if ($reflector->getConstructor())
|
|
||||||
{
|
|
||||||
return $reflector->newInstanceArgs(
|
|
||||||
$this->createDependenciesFor($itemName)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return $reflector->newInstance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create and register a shared instance of $itemName */
|
|
||||||
private function _createSharedInstance($itemName)
|
|
||||||
{
|
|
||||||
if (!isset($this->_store[$itemName]['instance']))
|
|
||||||
{
|
|
||||||
$this->_store[$itemName]['instance'] = $this->_createNewInstance($itemName);
|
|
||||||
}
|
|
||||||
return $this->_store[$itemName]['instance'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the current endpoint in the store */
|
|
||||||
private function &_getEndPoint()
|
|
||||||
{
|
|
||||||
if (!isset($this->_endPoint))
|
|
||||||
{
|
|
||||||
throw new BadMethodCallException(
|
|
||||||
'Component must first be registered by calling register()'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return $this->_endPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get an argument list with dependencies resolved */
|
|
||||||
private function _resolveArgs(array $args)
|
|
||||||
{
|
|
||||||
$resolved = array();
|
|
||||||
foreach ($args as $argDefinition)
|
|
||||||
{
|
|
||||||
switch ($argDefinition['type'])
|
|
||||||
{
|
|
||||||
case 'lookup':
|
|
||||||
$resolved[] = $this->_lookupRecursive($argDefinition['item']);
|
|
||||||
break;
|
|
||||||
case 'value':
|
|
||||||
$resolved[] = $argDefinition['item'];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $resolved;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Resolve a single dependency with an collections */
|
|
||||||
private function _lookupRecursive($item)
|
|
||||||
{
|
|
||||||
if (is_array($item))
|
|
||||||
{
|
|
||||||
$collection = array();
|
|
||||||
foreach ($item as $k => $v)
|
|
||||||
{
|
|
||||||
$collection[$k] = $this->_lookupRecursive($v);
|
|
||||||
}
|
|
||||||
return $collection;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return $this->lookup($item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/SwiftException.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DependencyException thrown when a requested dependeny is missing.
|
|
||||||
* @package Swift
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_DependencyException extends Swift_SwiftException
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new DependencyException with $message.
|
|
||||||
* @param string $message
|
|
||||||
*/
|
|
||||||
public function __construct($message)
|
|
||||||
{
|
|
||||||
parent::__construct($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/Mime/Attachment.php';
|
|
||||||
//@require 'Swift/DependencyContainer.php';
|
|
||||||
//@require 'Swift/ByteStream/FileByteStream.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An embedded file, in a multipart message.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Mime
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_EmbeddedFile extends Swift_Mime_EmbeddedFile
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new EmbeddedFile.
|
|
||||||
* Details may be optionally provided to the constructor.
|
|
||||||
* @param string|Swift_OutputByteStream $data
|
|
||||||
* @param string $filename
|
|
||||||
* @param string $contentType
|
|
||||||
*/
|
|
||||||
public function __construct($data = null, $filename = null,
|
|
||||||
$contentType = null)
|
|
||||||
{
|
|
||||||
call_user_func_array(
|
|
||||||
array($this, 'Swift_Mime_EmbeddedFile::__construct'),
|
|
||||||
Swift_DependencyContainer::getInstance()
|
|
||||||
->createDependenciesFor('mime.embeddedfile')
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->setBody($data);
|
|
||||||
$this->setFilename($filename);
|
|
||||||
if ($contentType)
|
|
||||||
{
|
|
||||||
$this->setContentType($contentType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new EmbeddedFile.
|
|
||||||
* @param string|Swift_OutputByteStream $data
|
|
||||||
* @param string $filename
|
|
||||||
* @param string $contentType
|
|
||||||
* @return Swift_Mime_EmbeddedFile
|
|
||||||
*/
|
|
||||||
public static function newInstance($data = null, $filename = null,
|
|
||||||
$contentType = null)
|
|
||||||
{
|
|
||||||
return new self($data, $filename, $contentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new EmbeddedFile from a filesystem path.
|
|
||||||
* @param string $path
|
|
||||||
* @return Swift_Mime_EmbeddedFile
|
|
||||||
*/
|
|
||||||
public static function fromPath($path)
|
|
||||||
{
|
|
||||||
return self::newInstance()->setFile(
|
|
||||||
new Swift_ByteStream_FileByteStream($path)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/Mime/CharsetObserver.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for all Encoder schemes.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Encoder
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
interface Swift_Encoder extends Swift_Mime_CharsetObserver
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode a given string to produce an encoded string.
|
|
||||||
* @param string $string
|
|
||||||
* @param int $firstLineOffset if first line needs to be shorter
|
|
||||||
* @param int $maxLineLength - 0 indicates the default length for this encoding
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function encodeString($string, $firstLineOffset = 0,
|
|
||||||
$maxLineLength = 0);
|
|
||||||
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/Encoder.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles Base 64 Encoding in Swift Mailer.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Encoder
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_Encoder_Base64Encoder implements Swift_Encoder
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes an unencoded string and produces a Base64 encoded string from it.
|
|
||||||
* Base64 encoded strings have a maximum line length of 76 characters.
|
|
||||||
* If the first line needs to be shorter, indicate the difference with
|
|
||||||
* $firstLineOffset.
|
|
||||||
* @param string $string to encode
|
|
||||||
* @param int $firstLineOffset
|
|
||||||
* @param int $maxLineLength, optional, 0 indicates the default of 76 bytes
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function encodeString($string, $firstLineOffset = 0,
|
|
||||||
$maxLineLength = 0)
|
|
||||||
{
|
|
||||||
if (0 >= $maxLineLength || 76 < $maxLineLength)
|
|
||||||
{
|
|
||||||
$maxLineLength = 76;
|
|
||||||
}
|
|
||||||
|
|
||||||
$encodedString = base64_encode($string);
|
|
||||||
$firstLine = '';
|
|
||||||
|
|
||||||
if (0 != $firstLineOffset)
|
|
||||||
{
|
|
||||||
$firstLine = substr(
|
|
||||||
$encodedString, 0, $maxLineLength - $firstLineOffset
|
|
||||||
) . "\r\n";
|
|
||||||
$encodedString = substr(
|
|
||||||
$encodedString, $maxLineLength - $firstLineOffset
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $firstLine . trim(chunk_split($encodedString, $maxLineLength, "\r\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does nothing.
|
|
||||||
*/
|
|
||||||
public function charsetChanged($charset)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,263 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/Encoder.php';
|
|
||||||
//@require 'Swift/CharacterStream.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles Quoted Printable (QP) Encoding in Swift Mailer.
|
|
||||||
* Possibly the most accurate RFC 2045 QP implementation found in PHP.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Encoder
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_Encoder_QpEncoder implements Swift_Encoder
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The CharacterStream used for reading characters (as opposed to bytes).
|
|
||||||
* @var Swift_CharacterStream
|
|
||||||
* @access protected
|
|
||||||
*/
|
|
||||||
protected $_charStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A filter used if input should be canonicalized.
|
|
||||||
* @var Swift_StreamFilter
|
|
||||||
* @access protected
|
|
||||||
*/
|
|
||||||
protected $_filter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pre-computed QP for HUGE optmization.
|
|
||||||
* @var string[]
|
|
||||||
* @access protected
|
|
||||||
*/
|
|
||||||
protected static $_qpMap = array(
|
|
||||||
0 => '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04',
|
|
||||||
5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09',
|
|
||||||
10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E',
|
|
||||||
15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13',
|
|
||||||
20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18',
|
|
||||||
25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D',
|
|
||||||
30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22',
|
|
||||||
35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27',
|
|
||||||
40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C',
|
|
||||||
45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31',
|
|
||||||
50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36',
|
|
||||||
55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B',
|
|
||||||
60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40',
|
|
||||||
65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45',
|
|
||||||
70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A',
|
|
||||||
75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F',
|
|
||||||
80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54',
|
|
||||||
85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59',
|
|
||||||
90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E',
|
|
||||||
95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63',
|
|
||||||
100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68',
|
|
||||||
105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D',
|
|
||||||
110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72',
|
|
||||||
115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77',
|
|
||||||
120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C',
|
|
||||||
125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81',
|
|
||||||
130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86',
|
|
||||||
135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B',
|
|
||||||
140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90',
|
|
||||||
145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95',
|
|
||||||
150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A',
|
|
||||||
155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F',
|
|
||||||
160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4',
|
|
||||||
165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9',
|
|
||||||
170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE',
|
|
||||||
175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3',
|
|
||||||
180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8',
|
|
||||||
185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD',
|
|
||||||
190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2',
|
|
||||||
195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7',
|
|
||||||
200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC',
|
|
||||||
205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1',
|
|
||||||
210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6',
|
|
||||||
215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB',
|
|
||||||
220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0',
|
|
||||||
225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5',
|
|
||||||
230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA',
|
|
||||||
235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF',
|
|
||||||
240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4',
|
|
||||||
245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9',
|
|
||||||
250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE',
|
|
||||||
255 => '=FF'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A map of non-encoded ascii characters.
|
|
||||||
* @var string[]
|
|
||||||
* @access protected
|
|
||||||
*/
|
|
||||||
protected static $_safeMap = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new QpEncoder for the given CharacterStream.
|
|
||||||
* @param Swift_CharacterStream $charStream to use for reading characters
|
|
||||||
* @param Swift_StreamFilter $filter if input should be canonicalized
|
|
||||||
*/
|
|
||||||
public function __construct(Swift_CharacterStream $charStream,
|
|
||||||
Swift_StreamFilter $filter = null)
|
|
||||||
{
|
|
||||||
$this->_charStream = $charStream;
|
|
||||||
if (empty(self::$_safeMap))
|
|
||||||
{
|
|
||||||
foreach (array_merge(
|
|
||||||
array(0x09, 0x20), range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte)
|
|
||||||
{
|
|
||||||
self::$_safeMap[$byte] = chr($byte);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->_filter = $filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes an unencoded string and produces a QP encoded string from it.
|
|
||||||
* QP encoded strings have a maximum line length of 76 characters.
|
|
||||||
* If the first line needs to be shorter, indicate the difference with
|
|
||||||
* $firstLineOffset.
|
|
||||||
* @param string $string to encode
|
|
||||||
* @param int $firstLineOffset, optional
|
|
||||||
* @param int $maxLineLength, optional, 0 indicates the default of 76 chars
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function encodeString($string, $firstLineOffset = 0,
|
|
||||||
$maxLineLength = 0)
|
|
||||||
{
|
|
||||||
if ($maxLineLength > 76 || $maxLineLength <= 0)
|
|
||||||
{
|
|
||||||
$maxLineLength = 76;
|
|
||||||
}
|
|
||||||
|
|
||||||
$thisLineLength = $maxLineLength - $firstLineOffset;
|
|
||||||
|
|
||||||
$lines = array();
|
|
||||||
$lNo = 0;
|
|
||||||
$lines[$lNo] = '';
|
|
||||||
$currentLine =& $lines[$lNo++];
|
|
||||||
$size=$lineLen=0;
|
|
||||||
|
|
||||||
$this->_charStream->flushContents();
|
|
||||||
$this->_charStream->importString($string);
|
|
||||||
|
|
||||||
//Fetching more than 4 chars at one is slower, as is fetching fewer bytes
|
|
||||||
// Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6
|
|
||||||
// bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes
|
|
||||||
while (false !== $bytes = $this->_nextSequence())
|
|
||||||
{
|
|
||||||
//If we're filtering the input
|
|
||||||
if (isset($this->_filter))
|
|
||||||
{
|
|
||||||
//If we can't filter because we need more bytes
|
|
||||||
while ($this->_filter->shouldBuffer($bytes))
|
|
||||||
{
|
|
||||||
//Then collect bytes into the buffer
|
|
||||||
if (false === $moreBytes = $this->_nextSequence(1))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($moreBytes as $b)
|
|
||||||
{
|
|
||||||
$bytes[] = $b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//And filter them
|
|
||||||
$bytes = $this->_filter->filter($bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
$enc = $this->_encodeByteSequence($bytes, $size);
|
|
||||||
if ($currentLine && $lineLen+$size >= $thisLineLength)
|
|
||||||
{
|
|
||||||
$lines[$lNo] = '';
|
|
||||||
$currentLine =& $lines[$lNo++];
|
|
||||||
$thisLineLength = $maxLineLength;
|
|
||||||
$lineLen=0;
|
|
||||||
}
|
|
||||||
$lineLen+=$size;
|
|
||||||
$currentLine .= $enc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->_standardize(implode("=\r\n", $lines));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the charset used.
|
|
||||||
* @param string $charset
|
|
||||||
*/
|
|
||||||
public function charsetChanged($charset)
|
|
||||||
{
|
|
||||||
$this->_charStream->setCharacterSet($charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Protected methods
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encode the given byte array into a verbatim QP form.
|
|
||||||
* @param int[] $bytes
|
|
||||||
* @return string
|
|
||||||
* @access protected
|
|
||||||
*/
|
|
||||||
protected function _encodeByteSequence(array $bytes, &$size)
|
|
||||||
{
|
|
||||||
$ret = '';
|
|
||||||
$size=0;
|
|
||||||
foreach ($bytes as $b)
|
|
||||||
{
|
|
||||||
if (isset(self::$_safeMap[$b]))
|
|
||||||
{
|
|
||||||
$ret .= self::$_safeMap[$b];
|
|
||||||
++$size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$ret .= self::$_qpMap[$b];
|
|
||||||
$size+=3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the next sequence of bytes to read from the char stream.
|
|
||||||
* @param int $size number of bytes to read
|
|
||||||
* @return int[]
|
|
||||||
* @access protected
|
|
||||||
*/
|
|
||||||
protected function _nextSequence($size = 4)
|
|
||||||
{
|
|
||||||
return $this->_charStream->readBytes($size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make sure CRLF is correct and HT/SPACE are in valid places.
|
|
||||||
* @param string $string
|
|
||||||
* @return string
|
|
||||||
* @access protected
|
|
||||||
*/
|
|
||||||
protected function _standardize($string)
|
|
||||||
{
|
|
||||||
$string = str_replace(array("\t=0D=0A", " =0D=0A", "=0D=0A"),
|
|
||||||
array("=09\r\n", "=20\r\n", "\r\n"), $string
|
|
||||||
);
|
|
||||||
switch ($end = ord(substr($string, -1)))
|
|
||||||
{
|
|
||||||
case 0x09:
|
|
||||||
case 0x20:
|
|
||||||
$string = substr_replace($string, self::$_qpMap[$end], -1);
|
|
||||||
}
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of SwiftMailer.
|
|
||||||
* (c) 2004-2009 Chris Corbyn
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
//@require 'Swift/Encoder.php';
|
|
||||||
//@require 'Swift/CharacterStream.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles RFC 2231 specified Encoding in Swift Mailer.
|
|
||||||
* @package Swift
|
|
||||||
* @subpackage Encoder
|
|
||||||
* @author Chris Corbyn
|
|
||||||
*/
|
|
||||||
class Swift_Encoder_Rfc2231Encoder implements Swift_Encoder
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A character stream to use when reading a string as characters instead of bytes.
|
|
||||||
* @var Swift_CharacterStream
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
private $_charStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Rfc2231Encoder using the given character stream instance.
|
|
||||||
* @param Swift_CharacterStream
|
|
||||||
*/
|
|
||||||
public function __construct(Swift_CharacterStream $charStream)
|
|
||||||
{
|
|
||||||
$this->_charStream = $charStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes an unencoded string and produces a string encoded according to
|
|
||||||
* RFC 2231 from it.
|
|
||||||
* @param string $string to encode
|
|
||||||
* @param int $firstLineOffset
|
|
||||||
* @param int $maxLineLength, optional, 0 indicates the default of 75 bytes
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function encodeString($string, $firstLineOffset = 0,
|
|
||||||
$maxLineLength = 0)
|
|
||||||
{
|
|
||||||
$lines = array(); $lineCount = 0;
|
|
||||||
$lines[] = '';
|
|
||||||
$currentLine =& $lines[$lineCount++];
|
|
||||||
|
|
||||||
if (0 >= $maxLineLength)
|
|
||||||
{
|
|
||||||
$maxLineLength = 75;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_charStream->flushContents();
|
|
||||||
$this->_charStream->importString($string);
|
|
||||||
|
|
||||||
$thisLineLength = $maxLineLength - $firstLineOffset;
|
|
||||||
|
|
||||||
while (false !== $char = $this->_charStream->read(4))
|
|
||||||
{
|
|
||||||
$encodedChar = rawurlencode($char);
|
|
||||||
if (0 != strlen($currentLine)
|
|
||||||
&& strlen($currentLine . $encodedChar) > $thisLineLength)
|
|
||||||
{
|
|
||||||
$lines[] = '';
|
|
||||||
$currentLine =& $lines[$lineCount++];
|
|
||||||
$thisLineLength = $maxLineLength;
|
|
||||||
}
|
|
||||||
$currentLine .= $encodedChar;
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode("\r\n", $lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the charset used.
|
|
||||||
* @param string $charset
|
|
||||||
*/
|
|
||||||
public function charsetChanged($charset)
|
|
||||||
{
|
|
||||||
$this->_charStream->setCharacterSet($charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user