diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..0c3c885b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +# rAthena FluxCP EditorConfig file +# EditorConfig is awesome: https://EditorConfig.org + +root = true + +[*] +insert_final_newline = true +trim_trailing_whitespace = true + +[*.php] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 4 + +[*.json] +indent_style = space +indent_size = 2 + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..133f4f8a --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +# rAthena environment configuration file +APP_ENV="production" +APP_ADDRESS="localhost" +APP_BASE_URI="/" + +INSTALLER_PASSWORD="CHANGEME" +DEFAULT_LANGUAGE="en-us" diff --git a/.gitignore b/.gitignore index c8ecfd74..eff66bdf 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,19 @@ # Caches /data/tmp/*.php /data/tmp/*.cache +/data/tmp/emblems + +# Non-Default Themes +/themes/* +!/themes/default +!/themes/bootstrap +!/themes/installer + +# Composer's vendor directory +/vendor/ + +# Intellij IDEA/phpStorm +/.idea/ + +# .env +.env diff --git a/README.md b/README.md index 67c132b3..e619facb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -FluxCP -====== +# FluxCP + [![Total alerts](https://img.shields.io/lgtm/alerts/g/rathena/FluxCP.svg?logo=lgtm&logoWidth=18&color=orange)](https://lgtm.com/projects/g/rathena/FluxCP/alerts/) [![Open Issues](https://img.shields.io/github/issues/rathena/FluxCP.svg?logo=github&logoWidth=18&color=yellow)](https://lgtm.com/projects/g/rathena/FluxCP/alerts/) [![Open PRs](https://img.shields.io/github/issues-pr/rathena/FluxCP.svg?logo=github&logoWidth=18&color=blue)](https://lgtm.com/projects/g/rathena/FluxCP/alerts/) @@ -7,10 +7,10 @@ FluxCP Flux Control Panel (FluxCP) for rAthena servers. -Requirements ---------- -* PHP 5.2 -* PDO and PDO-MYSQL extensions for PHP5 (including PHP_MYSQL support) +## Requirements +* Composer dependency manager +* PHP 7.0 or later +* PDO and PDO-MYSQL extensions for PHP * MySQL 5 * Optional: GD2 (for guild emblems and registration CAPTCHA) * Optional: Tidy (for cleaner HTML output) @@ -18,47 +18,43 @@ Requirements * Optional: [Item images](http://rathena.org/board/files/file/2509-item-images/) -What's New? ---------- +## What's New? * The description files are kept upto-date with each new commit from rAthena. * Pre-integrated themes: - - default - - Bootstrap + * default + * Bootstrap * Built-In: - - News and Pages CMS with integrated TinyMCE - - Service Desk (ITIL Incident Management style support ticket system) - - Additional Logs - - More Ranking Lists - - Discord Integration - - Google ReCaptcha - - Remote AtCommand functionality + * News and Pages CMS with integrated TinyMCE + * Service Desk (ITIL Incident Management style support ticket system) + * Additional Logs + * More Ranking Lists + * Discord Integration + * Google ReCaptcha + * Remote AtCommand functionality -How To ... ? ---------- +## How To ... ? We have a small doc library that covers: * Basic User Documentation - - Installation - - [Themes](https://github.com/rathena/FluxCP/blob/master/doc/user_theme.md) - - [Languages](https://github.com/rathena/FluxCP/blob/master/doc/user_lang.md) - - Installing Addons - - Updating FluxCP + * [Installation](https://github.com/rathena/FluxCP/blob/master/doc/installing.md) + * [Themes](https://github.com/rathena/FluxCP/blob/master/doc/user_theme.md) + * [Languages](https://github.com/rathena/FluxCP/blob/master/doc/user_lang.md) + * Installing Addons + * Updating FluxCP * Developer Documentation - - Creating an Addon - - Providing Addon updates - - Creating a custom Theme - + * Creating an Addon + * Providing Addon updates + * Creating a custom Theme + * [Migrating your addon to FluxCP 2.0](https://github.com/rathena/FluxCP/blob/master/doc/migrating.md) -Join the Discussion ---------- +## Join the Discussion We have a discord server separate from rAthena just for FluxCP stuff! The channels there can be used to obtain help, discuss testing, view anonymous feedback log, Github commits, etc. https://discord.gg/0XP9qqhUV9GLSfCh -Extra Credits ---------- +## Extra Credits Original FluxCP created by Paradox924X and Byteflux with additional contributions from Xantara. Some works from other users have been integrated into this project. diff --git a/addons/helloworld/modules/helloworld/index.php b/addons/helloworld/modules/helloworld/index.php index 191fa59a..02e34205 100644 --- a/addons/helloworld/modules/helloworld/index.php +++ b/addons/helloworld/modules/helloworld/index.php @@ -1,4 +1,7 @@ +

diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..f086c2b1 --- /dev/null +++ b/composer.json @@ -0,0 +1,26 @@ +{ + "name": "rathena/fluxcp", + "description": "rAthena MMORPG server control panel", + "type": "project", + "license": "LGPL-3.0-only", + "minimum-stability": "stable", + "require": { + "php": ">=7.0", + "ext-pdo": "*", + "ext-pdo_mysql": "*", + "ext-gd": "*", + "phpmailer/phpmailer": "^5.2.27", + "vlucas/phpdotenv": "^3.3" + }, + "autoload": { + "psr-4": { + "rAthena\\FluxCp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "require-dev": { + "filp/whoops": "^2.3" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..6511c75c --- /dev/null +++ b/composer.lock @@ -0,0 +1,471 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "6a0033b2bb4f4800f7ca9338d7785d37", + "packages": [ + { + "name": "phpmailer/phpmailer", + "version": "v5.2.28", + "source": { + "type": "git", + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "acba50393dd03da69a50226c139722af8b153b11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/acba50393dd03da69a50226c139722af8b153b11", + "reference": "acba50393dd03da69a50226c139722af8b153b11", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": ">=5.0.0" + }, + "require-dev": { + "doctrine/annotations": "1.2.*", + "jms/serializer": "0.16.*", + "phpdocumentor/phpdocumentor": "2.*", + "phpunit/phpunit": "4.8.*", + "symfony/debug": "2.8.*", + "symfony/filesystem": "2.8.*", + "symfony/translation": "2.8.*", + "symfony/yaml": "2.8.*", + "zendframework/zend-cache": "2.5.1", + "zendframework/zend-config": "2.5.1", + "zendframework/zend-eventmanager": "2.5.1", + "zendframework/zend-filter": "2.5.1", + "zendframework/zend-i18n": "2.5.1", + "zendframework/zend-json": "2.5.1", + "zendframework/zend-math": "2.5.1", + "zendframework/zend-serializer": "2.5.*", + "zendframework/zend-servicemanager": "2.5.*", + "zendframework/zend-stdlib": "2.5.1" + }, + "suggest": { + "league/oauth2-google": "Needed for Google XOAUTH2 authentication" + }, + "type": "library", + "autoload": { + "classmap": [ + "class.phpmailer.php", + "class.phpmaileroauth.php", + "class.phpmaileroauthgoogle.php", + "class.smtp.php", + "class.pop3.php", + "extras/EasyPeasyICS.php", + "extras/ntlm_sasl_client.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v5.2.28" + }, + "funding": [ + { + "url": "https://marcus.bointon.com/donations/", + "type": "custom" + }, + { + "url": "https://github.com/Synchro", + "type": "github" + }, + { + "url": "https://www.patreon.com/marcusbointon", + "type": "patreon" + } + ], + "time": "2020-03-19T14:29:37+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.8.1", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", + "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.8.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2021-12-04T23:24:31+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.24.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "30885182c981ab175d4d034db0f6f469898070ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-10-20T20:35:02+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v3.6.10", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "5b547cdb25825f10251370f57ba5d9d924e6f68e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/5b547cdb25825f10251370f57ba5d9d924e6f68e", + "reference": "5b547cdb25825f10251370f57ba5d9d924e6f68e", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0", + "phpoption/phpoption": "^1.5.2", + "symfony/polyfill-ctype": "^1.17" + }, + "require-dev": { + "ext-filter": "*", + "ext-pcre": "*", + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.21" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator.", + "ext-pcre": "Required to use most of the library." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v3.6.10" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2021-12-12T23:02:06+00:00" + } + ], + "packages-dev": [ + { + "name": "filp/whoops", + "version": "2.14.5", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", + "reference": "a63e5e8f26ebbebf8ed3c5c691637325512eb0dc", + "shasum": "" + }, + "require": { + "php": "^5.5.9 || ^7.0 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^0.9 || ^1.0", + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.14.5" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2022-01-07T12:00:00+00:00" + }, + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.0", + "ext-pdo": "*", + "ext-pdo_mysql": "*", + "ext-gd": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/config/access.php b/config/access.php index 5d8fa23d..e19f3d15 100644 --- a/config/access.php +++ b/config/access.php @@ -98,9 +98,6 @@ 'item' => array( 'index' => AccountLevel::ANYONE, 'view' => AccountLevel::ANYONE, - 'add' => AccountLevel::ADMIN, - 'edit' => AccountLevel::ADMIN, - 'copy' => AccountLevel::ADMIN, 'iteminfo' => AccountLevel::ADMIN ), 'monster' => array( @@ -137,7 +134,7 @@ 'changemail' => AccountLevel::ADMIN, 'ban' => AccountLevel::ADMIN, 'ipban' => AccountLevel::ADMIN, - 'txnview' => AccountLevel::ADMIN + 'txnview' => AccountLevel::ADMIN ), 'ipban' => array( 'index' => AccountLevel::ADMIN, @@ -201,7 +198,7 @@ 'vending' => array( 'index' => AccountLevel::ANYONE, 'viewshop' => AccountLevel::ANYONE, - ), + ), 'webcommands' => array( 'index' => AccountLevel::ADMIN, ), @@ -253,7 +250,7 @@ 'SeeAccountID' => AccountLevel::LOWGM, // Minimum group level required to see Account ID on account view and character view pages. 'SeeUnknownItems' => AccountLevel::LOWGM, // Minimum group level required to see unidentified items as identified. 'AvoidSexChangeCost' => AccountLevel::LOWGM, // Avoid paying cost (if any) for sex changes. - + 'EditHigherPower' => AccountLevel::NOONE, 'BanHigherPower' => AccountLevel::NOONE ) diff --git a/config/application.php b/config/application.php index 5daed0b8..3959f142 100644 --- a/config/application.php +++ b/config/application.php @@ -1,15 +1,19 @@ 'localhost', // This value is the hostname:port under which Flux runs. (e.g., example.com or example.com:80) - 'BaseURI' => 'fluxcp', // The base URI is the base web root on which your application lies. - 'InstallerPassword' => 'secretpassword', // Installer/updater password. + 'ServerAddress' => env('APP_ADDRESS', 'localhost'), // This value is the hostname:port under which Flux runs. (e.g., example.com or example.com:80) + 'BaseURI' => env('APP_BASE_URI', 'fluxcp'), // The base URI is the base web root on which your application lies. + 'InstallerPassword' => env('INSTALLER_PASSWORD', 'secretpassword'), // Installer/updater password. 'RequireOwnership' => true, // Require the executing user to be owner of the FLUX_ROOT/data/ directory tree? (Better for security) // WARNING: This will be mostly IGNORED on non-POSIX-compliant OSes (e.g. Windows). 'DefaultLoginGroup' => null, 'DefaultCharMapServer' => null, - 'DefaultLanguage' => 'en_us', // Specify the default control panel language (see FLUX_ROOT/lang/ directory for available languages.) + 'DefaultLanguage' => env('DEFAULT_LANGUAGE', 'en_us'), // Specify the default control panel language (see FLUX_ROOT/lang/ directory for available languages.) 'SiteTitle' => 'Flux Control Panel', // This value is only used if the theme decides to use it. 'ThemeName' => array('default', 'bootstrap'), // Names of the themes you would like list for use in the footer. Themes are in FLUX_ROOT/themes. 'ScriptTimeLimit' => 0, // Script execution time limit. Specifies (in seconds) how long a page should run before timing out. (0 means forever) @@ -18,8 +22,10 @@ 'ItemImageNameFormat' => '%d.png', // The filename format for item images (defaults to {itemid}.png). 'MonsterImageNameFormat' => '%d.gif', // The filename format for monster images (defaults to {monsterid}.gif). 'JobImageNameFormat' => '%d.gif', // The filename format for job images (defaults to {jobid}.gif). + 'DivinePrideIntegration' => true, // Download monsters and items images from https://www.divine-pride.net if it's not exist. 'ForceEmptyEmblem' => false, // Forcefully display empty guild emblems, helpful when you don't have GD2 installed. 'EmblemCacheInterval' => 12, // Hourly interval to re-cache guild emblems (set to 0 to disable emblem cache). + 'EmblemUseWebservice' => true, // Load emblems from WebService? 'SessionCookieExpire' => 48, // Duration in hours. 'AdminMenuGroupLevel' => AccountLevel::LOWGM, // The starting group ID for which module actions are moved into the admin menu for display. 'DateDefaultTimezone' => 'UTC', // The default timezone, consult the PHP manual for valid timezones: http://php.net/timezones (null for defaut system TZ) @@ -85,7 +91,7 @@ 'ReCaptchaTheme' => 'light', // ReCaptcha theme to use (Value: dark or light) (see: https://developers.google.com/recaptcha/docs/display#render_param) 'DisplaySinglePages' => true, // Whether or not to display paging for single page results. 'ForwardYears' => 15, // (Visual) The number of years to display ahead of the current year in date inputs. - 'BackwardYears' => 30, // (Visual) The number of years to display behind the current year in date inputs. + 'BackwardYears' => 60, // (Visual) The number of years to display behind the current year in date inputs. 'ColumnSortAscending' => ' ▲', // (Visual) Text displayed for ascending sorted column names. 'ColumnSortDescending' => ' ▼', // (Visual) Text displayed for descending sorted column names. 'CreditExchangeRate' => 1.0, // The rate at which credits are exchanged for dollars. @@ -95,7 +101,7 @@ 'MoneyThousandsSymbol' => ',', // (Visual) Thousandths place separator (a period in European currencies). 'MoneyDecimalSymbol' => '.', // (Visual) Decimal separator (a comma in European currencies). 'AcceptDonations' => true, // Whether or not to accept donations. - 'PayPalIpnUrl' => 'www.sandbox.paypal.com',// The URL for PayPal's IPN responses (www.paypal.com for live and www.sandbox.paypal.com for testing) + 'PayPalIpnUrl' => 'www.paypal.com', // The ipnpb.paypal.com and ipnpb.sandbox.paypal.com endpoints only accept HTTPS connections. If you currently use www.paypal.com, you should move to ipnpb.paypal.com when you update your code to use HTTPS. 'PayPalBusinessEmail' => 'admin@localhost', // Enter the e-mail under which you have registered your business account. 'PayPalReceiverEmails' => array( // These are the receiver e-mail addresses who are allowed to receive payment. //'admin2@localhost', // -- This array may be empty if you only use one e-mail @@ -155,7 +161,7 @@ 'BlacksmithRankingLimit' => 20, // 'HomunRankingLimit' => 20, // 'MVPRankingLimit' => 20, // - + 'RankingHideGroupLevel' => AccountLevel::LOWGM, // 'InfoHideZenyGroupLevel' => AccountLevel::LOWGM, // Minimum group level of account to hide zeny from in server information page. @@ -196,8 +202,8 @@ 'AdminMenuNewStyle' => true, // Use new-style admin menu; Applies to 'default' theme. 'EnablePeakDisplay' => true, // Display Peak User count on Server Status page. - - + + // News Options 'CMSNewsOnHomepage' => true, // Display News on Home Page instead of "You've Just Installed FluxCP" message? 'CMSNewsType' => 1, // Type = source of news feed: @@ -219,10 +225,12 @@ // Discord Webhooks 'DiscordUseWebhook' => false, 'DiscordWebhookURL' => 'enter_webhook_url_from_discord_here', - 'DiscordSendOnRegister' => true, - 'DiscordSendOnNewTicket' => true, - 'DiscordSendOnWebCommand' => true, - 'DiscordSendOnMarketing' => true, + 'DiscordSendOnRegister' => true, // Sends a channel message when someone registers + 'DiscordSendOnNewTicket' => true, // Sends a channel message when someone submits a new ticket to the Service Desk + 'DiscordSendOnWebCommand' => true, // Sends a channel message when someone uses the Web Command feature in FluxCP + 'DiscordSendOnMarketing' => true, // Sends a channel message when someone uses the Send Email feature in FluxCP + + 'TinyMCEKey' => 'no-key', // Register for a key at https://www.tiny.cloud/my-account/dashboard/ // These are the main menu items that should be displayed by themes. // They route to modules and actions. Whether they are displayed or @@ -290,7 +298,7 @@ //'Economy' => array('module' => 'economy') ) ), - + // Sub-menu items that are displayed for any action belonging to a // particular module. The format it simple. 'SubMenuItems' => array( @@ -375,7 +383,6 @@ ), 'item' => array( 'index' => 'List Items', - 'add' => 'Add Item', 'iteminfo' => 'Add Item Info', ), 'pages' => array( @@ -400,7 +407,7 @@ 'index' => 'Buyers', ), ), - + 'AllowMD5PasswordSearch' => false, 'ReallyAllowMD5PasswordSearch' => false, // Are you POSITIVELY sure? @@ -436,9 +443,9 @@ // Shouldn't touch this either. 'ItemTypes' => include('itemtypes.php'), - // Special Item Types with their corresponding names (For Weapons & Ammo by default). + // Item SubTypes with their corresponding names. // Shouldn't touch this either. - 'ItemTypes2' => include('itemtypes2.php'), + 'ItemSubTypes' => include('itemsubtypes.php'), // Common Equip Location Combinations with their corresponding names. // Shouldn't touch this unless you've added custom combinations. @@ -471,6 +478,7 @@ // rA monster modes mapping. 'MonsterModes' => include('monstermode.php'), + 'MonsterAI' => include('monster_ai.php'), // Item shop categories. 'ShopCategories' => include('shopcategories.php'), @@ -487,6 +495,15 @@ // Castle names. 'CastleNames' => include('castlenames.php'), + // Trade restrictions. + 'TradeRestriction' => include('trade_restrictions.php'), + + // Item flags. + 'ItemFlags' => include('itemsflags.php'), + + // Item random options. + 'RandomOptions' => include('item_randoptions.php'), + // DON'T TOUCH. THIS IS FOR DEVELOPERS. 'FluxTables' => array( 'CreditsTable' => 'cp_credits', diff --git a/config/castlenames.php b/config/castlenames.php index af00e113..5833f1d0 100644 --- a/config/castlenames.php +++ b/config/castlenames.php @@ -36,7 +36,17 @@ 30 => 'Cyr', 31 => 'Horn', 32 => 'Gefn', - 33 => 'Bandis' + 33 => 'Bandis', + 34 => 'Leilah', + 35 => 'Pavianne', + 36 => 'Jasmine', + 37 => 'Roxie', + 38 => 'Curly Sue', + 39 => 'Gaebolg', + 40 => 'Richard', + 41 => 'Wigner', + 42 => 'Heine', + 43 => 'Nerious' // kRO Names /** * 0 => 'Noisyubantian', @@ -74,5 +84,4 @@ *32 => 'Gefn', *33 => 'Bandis' */ -) -?> +); diff --git a/config/elements.php b/config/elements.php index c7b08ac6..13832289 100644 --- a/config/elements.php +++ b/config/elements.php @@ -1,15 +1,14 @@ 'Neutral', - 1 => 'Water', - 2 => 'Earth', - 3 => 'Fire', - 4 => 'Wind', - 5 => 'Poison', - 6 => 'Holy', - 7 => 'Dark', - 8 => 'Ghost', - 9 => 'Undead' + 'Neutral' => 'Neutral', + 'Water' => 'Water', + 'Earth' => 'Earth', + 'Fire' => 'Fire', + 'Wind' => 'Wind', + 'Poison' => 'Poison', + 'Holy' => 'Holy', + 'Dark' => 'Dark', + 'Ghost' => 'Ghost', + 'Undead' => 'Undead' ); -?> diff --git a/config/equip_jobs.php b/config/equip_jobs.php index 1f34bd15..e3c810ee 100644 --- a/config/equip_jobs.php +++ b/config/equip_jobs.php @@ -1,36 +1,37 @@ 'Novice', - pow(2, 1) => 'Swordman', - pow(2, 2) => 'Mage', - pow(2, 3) => 'Archer', - pow(2, 4) => 'Acolyte', - pow(2, 5) => 'Merchant', - pow(2, 6) => 'Thief', - pow(2, 7) => 'Knight', - pow(2, 8) => 'Priest', - pow(2, 9) => 'Wizard', - pow(2, 10) => 'Blacksmith', - pow(2, 11) => 'Hunter', - pow(2, 12) => 'Assassin', - pow(2, 13) => 'Unused', - pow(2, 14) => 'Crusader', - pow(2, 15) => 'Monk', - pow(2, 16) => 'Sage', - pow(2, 17) => 'Rogue', - pow(2, 18) => 'Alchemist', - pow(2, 19) => 'Bard/Dancer', - pow(2, 20) => 'Unused', - pow(2, 21) => 'Taekwon', - pow(2, 22) => 'Star Gladiator', - pow(2, 23) => 'Soul Linker', - pow(2, 24) => 'Gunslinger', - pow(2, 25) => 'Ninja', - pow(2, 26) => 'Gangsi', - pow(2, 27) => 'Death Knight', - pow(2, 28) => 'Dark Collector', - pow(2, 29) => 'Kagerou/Oboro', - pow(2, 30) => 'Rebellion', - pow(2, 31) => 'Summoner', -) -?> + 0 => // Default job list + array( + 'job_all' => 'All jobs', + 'job_novice' => 'Novice', + 'job_supernovice' => 'Super novice', + 'job_swordman' => 'Swordman', + 'job_mage' => 'Mage', + 'job_archer' => 'Archer', + 'job_merchant' => 'Merchant', + 'job_thief' => 'Thief', + 'job_knight' => 'Knight', + 'job_priest' => 'Priest', + 'job_wizard' => 'Wizard', + 'job_blacksmith' => 'Blacksmith', + 'job_hunter' => 'Hunter', + 'job_assassin' => 'Assassin', + 'job_crusader' => 'Crusader', + 'job_monk' => 'Monk', + 'job_sage' => 'Sage', + 'job_rogue' => 'Rogue', + 'job_alchemist' => 'Alchemist', + 'job_barddancer' => 'Bard / Dancer', + 'job_taekwon' => 'Taekwon', + 'job_stargladiator' => 'Star Gladiator', + 'job_soullinker' => 'Soul Linker', + 'job_gunslinger' => 'Gunslinger', + 'job_ninja' => 'Ninja', + ), + 1 => // Renewal job list + array( + 'job_kagerouoboro' => 'Kagerou / Oboro', + 'job_rebellion' => 'Rebellion', + 'job_summoner' => 'Summoner' + ) +); diff --git a/config/equip_location_combinations.php b/config/equip_location_combinations.php index 5269132e..a8599ed3 100644 --- a/config/equip_location_combinations.php +++ b/config/equip_location_combinations.php @@ -1,33 +1,15 @@ 'None', - 65536 => 'Shadow Armor', - 131072 => 'Shadow Weapon', - 262144 => 'Shadow Shield', - 524288 => 'Shadow Shoes', - 1048576 => 'Shadow Accessory Right (Earring)', - 2097152 => 'Shadow Accessory Left (Pendant)', - 4096 => 'Costume Low Headgear', - 2048 => 'Costume Mid Headgear', - 1024 => 'Costume Top Headgear', - 7168 => 'Costume Low/Mid/Top Headgear', - 3072 => 'Costume Mid/Top Headgear', - 6144 => 'Costume Low/Mid Headgear', - 256 => 'Upper Headgear', - 512 => 'Middle Headgear', - 1 => 'Lower Headgear', - 769 => 'Upper/Mid/Lower Headgear', - 768 => 'Upper/Mid Headgear', - //257 => 'Upper/Lower Headgear', - 513 => 'Mid/Lower Headgear', - 16 => 'Armor', - 2 => 'Weapon', - 32 => 'Shield', - 34 => 'Two-Handed', - 50 => 'Armor/Hands', - 4 => 'Garment', - 64 => 'Footgear', - 136 => 'Accessories', - 32768 => 'Arrow/Ammo' -) -?> + 'location_left_hand/location_right_hand' => 'Two-Handed', + 'location_head_low/location_head_mid/location_head_top' => 'Upper/Mid/Lower Headgear', + 'location_head_mid/location_head_top' => 'Upper/Mid Headgear', + 'location_head_top/location_head_low' => 'Upper/Lower Headgear', + 'location_head_low/location_head_mid' => 'Mid/Lower Headgear', + 'location_head_low/location_head_top' => 'Upper/Lower Headgear', + 'location_costume_head_mid/location_costume_head_top' => 'Costume Upper/Mid Headgear', + 'location_costume_head_low/location_costume_head_top' => 'Costume Upper/Lower Headgear', + 'location_costume_head_low/location_costume_head_mid' => 'Costume Mid/Lower Headgear', + 'location_costume_head_low/location_costume_head_mid/location_costume_head_top' => 'Costume Upper/Mid/Lower Headgear', + 'location_left_accessory/location_right_accessory' => 'Accessory Left/Right', + 'location_armor/location_garment/location_head_low/location_head_mid/location_head_top/location_left_accessory/location_left_hand/location_right_accessory/location_right_hand/location_shoes' => 'All equip', +); diff --git a/config/equip_locations.php b/config/equip_locations.php index d31e5755..a8599ed3 100644 --- a/config/equip_locations.php +++ b/config/equip_locations.php @@ -1,25 +1,15 @@ 'Lower Headgear', - 2 => 'Main Hand', - 4 => 'Garment', - 8 => 'Accessory Right', - 16 => 'Armor', - 32 => 'Off Hand', - 64 => 'Footgear', - 128 => 'Accessory Left', - 256 => 'Upper Headgear', - 512 => 'Middle Headgear', - 1024 => 'Costume Top Headgear', - 2048 => 'Costume Mid Headgear', - 4096 => 'Costume Low Headgear', - 8192 => 'Costume Garment', - 32768 => 'Ammo', - 65536 => 'Shadow Armor', - 131072 => 'Shadow Weapon', - 262144 => 'Shadow Shield', - 524288 => 'Shadow Shoes', - 1048576 => 'Shadow Accessory Right (Earring)', - 2097152 => 'Shadow Accessory Left (Pendant)', -) -?> + 'location_left_hand/location_right_hand' => 'Two-Handed', + 'location_head_low/location_head_mid/location_head_top' => 'Upper/Mid/Lower Headgear', + 'location_head_mid/location_head_top' => 'Upper/Mid Headgear', + 'location_head_top/location_head_low' => 'Upper/Lower Headgear', + 'location_head_low/location_head_mid' => 'Mid/Lower Headgear', + 'location_head_low/location_head_top' => 'Upper/Lower Headgear', + 'location_costume_head_mid/location_costume_head_top' => 'Costume Upper/Mid Headgear', + 'location_costume_head_low/location_costume_head_top' => 'Costume Upper/Lower Headgear', + 'location_costume_head_low/location_costume_head_mid' => 'Costume Mid/Lower Headgear', + 'location_costume_head_low/location_costume_head_mid/location_costume_head_top' => 'Costume Upper/Mid/Lower Headgear', + 'location_left_accessory/location_right_accessory' => 'Accessory Left/Right', + 'location_armor/location_garment/location_head_low/location_head_mid/location_head_top/location_left_accessory/location_left_hand/location_right_accessory/location_right_hand/location_shoes' => 'All equip', +); diff --git a/config/equip_upper.php b/config/equip_upper.php index 6795ee20..3cc06f90 100644 --- a/config/equip_upper.php +++ b/config/equip_upper.php @@ -1,10 +1,16 @@ 'Normal', - 2 => 'Upper', - 4 => 'Baby', - 8 => 'Third', - 16 => 'Third Upper', - 32 => 'Third Baby' -) -?> + 0 => // Default class list + array( + 'class_all' => 'All classes', + 'class_normal' => 'Normal', + 'class_upper' => 'Upper', + 'class_baby' => 'Baby' + ), + 1 => // Renewal class list + array( + 'class_third' => 'Third', + 'class_third_upper' => 'Third Upper', + 'class_third_baby' => 'Third Baby' + ) +); diff --git a/config/item_randoptions.php b/config/item_randoptions.php new file mode 100644 index 00000000..46aa56dc --- /dev/null +++ b/config/item_randoptions.php @@ -0,0 +1,223 @@ + 'MaxHP +%s', + 2 => 'MaxSP +%s', + 3 => 'STR +%s', + 4 => 'AGI +%s', + 5 => 'VIT +%s', + 6 => 'INT +%s', + 7 => 'DEX +%s', + 8 => 'LUK +%s', + 9 => 'MaxHP +%s%%', + 10 => 'MaxSP +%s%%', + 11 => 'HP regen +%s%%', + 12 => 'SP regen +%s%%', + 13 => 'ATK +%s%%', + 14 => 'MATK +%s%%', + 15 => 'ASPD +%s', + 16 => 'Delay after attack -%s%%', + 17 => 'ATK +%s', + 18 => 'HIT +%s', + 19 => 'MATK +%s', + 20 => 'DEF +%s', + 21 => 'MDEF +%s', + 22 => 'FLEE +%s', + 23 => 'Perfect dodge +%s', + 24 => 'CRIT +%s', + 25 => 'Neutral elemental resistance +%s%%', + 26 => 'Water elemental resistance +%s%%', + 27 => 'Earth elemental resistance +%s%%', + 28 => 'Fire elemental resistance +%s%%', + 29 => 'Wind elemental resistance +%s%%', + 30 => 'Poison elemental resistance +%s%%', + 31 => 'Holy elemental resistance +%s%%', + 32 => 'Shadow elemental resistance +%s%%', + 33 => 'Ghost elemental resistance +%s%%', + 34 => 'Undead elemental resistance +%s%%', + 35 => 'All elementals resistance +%s%%', + 36 => 'Neutral monster resistance +%s%%', + 37 => 'ATK +%s%% against Neutral monster', + 38 => 'Water monster resistance +%s%%', + 39 => 'ATK +%s%% against Water monster', + 40 => 'Earth monster resistance +%s%%', + 41 => 'ATK +%s%% against Earth monster', + 42 => 'Fire monster resistance +%s%%', + 43 => 'ATK +%s%% against Fire monster', + 44 => 'Wind monster resistance +%s%%', + 45 => 'ATK +%s%% against Wind monster', + 46 => 'Poison monster resistance +%s%%', + 47 => 'ATK +%s%% against Poison monster', + 48 => 'Holy monster resistance +%s%%', + 49 => 'ATK +%s%% against Holy monster', + 50 => 'Shadow monster resistance +%s%%', + 51 => 'ATK +%s%% against Shadow monster', + 52 => 'Ghost monster resistance +%s%%', + 53 => 'ATK +%s%% against Ghost monster', + 54 => 'Undead monster resistance +%s%%', + 55 => 'ATK +%s%% against Undead monster', + 56 => 'Neutral monster magic resistance +%s%%', + 57 => 'MATK +%s%% against Neutral monster', + 58 => 'Water monster magic resistance +%s%%', + 59 => 'MATK +%s%% against Water monster', + 60 => 'Earth monster magic resistance +%s%%', + 61 => 'MATK +%s%% against Earth monster', + 62 => 'Fire monster magic resistance +%s%%', + 63 => 'MATK +%s%% against Fire monster', + 64 => 'Wind monster magic resistance +%s%%', + 65 => 'MATK +%s%% against Wind monster', + 66 => 'Poison monster magic resistance +%s%%', + 67 => 'MATK +%s%% against Poison monster', + 68 => 'Holy monster magic resistance +%s%%', + 69 => 'MATK +%s%% against Holy monster', + 70 => 'Shadow monster magic resistance +%s%%', + 71 => 'MATK +%s%% against Shadow monster', + 72 => 'Ghost monster magic resistance +%s%%', + 73 => 'MATK +%s%% against Ghost monster', + 74 => 'Undead monster magic resistance +%s%%', + 75 => 'MATK +%s%% against Undead monster', + 76 => 'Armor element: Neutral', + 77 => 'Armor element: Water', + 78 => 'Armor element: Earth', + 79 => 'Armor element: Fire', + 80 => 'Armor element: Wind', + 81 => 'Armor element: Poison', + 82 => 'Armor element: Holy', + 83 => 'Armor element: Shadow', + 84 => 'Armor element: Ghost', + 85 => 'Armor element: Undead', + //86 => '', + 87 => 'Formless monster resistance +%s%%', + 88 => 'Undead monster resistance +%s%%', + 89 => 'Brute monster resistance +%s%%', + 90 => 'Plant monster resistance +%s%%', + 91 => 'Insect monster resistance +%s%%', + 92 => 'Fish monster resistance +%s%%', + 93 => 'Demon monster resistance +%s%%', + 94 => 'Demihuman monster resistance +%s%%', + 95 => 'Angel monster resistance +%s%%', + 96 => 'Dragon monster resistance +%s%%', + 97 => 'ATK +%s%% against Formless monster', + 98 => 'ATK +%s%% against Undead monster', + 99 => 'ATK +%s%% against Brute monster', + 100 => 'ATK +%s%% against Plant monster', + 101 => 'ATK +%s%% against Insect monster', + 102 => 'ATK +%s%% against Fish monster', + 103 => 'ATK +%s%% against Demon monster', + 104 => 'ATK +%s%% against Demihuman monster', + 105 => 'ATK +%s%% against Angel monster', + 106 => 'ATK +%s%% against Dragon monster', + 107 => 'MATK +%s%% against Formless monster', + 108 => 'MATK +%s%% against Undead monster', + 109 => 'MATK +%s%% against Brute monster', + 110 => 'MATK +%s%% against Plant monster', + 111 => 'MATK +%s%% against Insect monster', + 112 => 'MATK +%s%% against Fish monster', + 113 => 'MATK +%s%% against Devil monster', + 114 => 'MATK +%s%% against Demihuman monster', + 115 => 'MATK +%s%% against Angel monster', + 116 => 'MATK +%s%% against Dragon monster', + 117 => 'CRIT +%s against Formless monster', + 118 => 'CRIT +%s against Undead monster', + 119 => 'CRIT +%s against Brute monster', + 120 => 'CRIT +%s against Plant monster', + 121 => 'CRIT +%s against Insect monster', + 122 => 'CRIT +%s against Fish monster', + 123 => 'CRIT +%s against Demon monster', + 124 => 'CRIT +%s against Demihuman monster', + 125 => 'CRIT +%s against Angel monster', + 126 => 'CRIT +%s against Dragon monster', + 127 => 'Pierces %s%% DEF of Formless monster', + 128 => 'Pierces %s%% DEF of Undead monster', + 129 => 'Pierces %s%% DEF of Brute monster', + 130 => 'Pierces %s%% DEF of Plant monster', + 131 => 'Pierces %s%% DEF of Insect monster', + 132 => 'Pierces %s%% DEF of Fish monster', + 133 => 'Pierces %s%% DEF of Demon monster', + 134 => 'Pierces %s%% DEF of Demihuman monster', + 135 => 'Pierces %s%% DEF of Angel monster', + 136 => 'Pierces %s%% DEF of Dragon monster', + 137 => 'Pierces %s%% MDEF of Formless monster', + 138 => 'Pierces %s%% MDEF of Undead monster', + 139 => 'Pierces %s%% MDEF of Brute monster', + 140 => 'Pierces %s%% MDEF of Plant monster', + 141 => 'Pierces %s%% MDEF of Insect monster', + 142 => 'Pierces %s%% MDEF of Fish monster', + 143 => 'Pierces %s%% MDEF of Demon monster', + 144 => 'Pierces %s%% MDEF of Demihuman monster', + 145 => 'Pierces %s%% MDEF of Angel monster', + 146 => 'Pierces %s%% MDEF of Dragon monster', + 147 => 'ATK +%s%% against Normal monster', + 148 => 'ATK +%s%% against Boss monster', + 149 => 'Normal monster resistance +%s%%', + 150 => 'Boss monster resistance +%s%%', + 151 => 'MATK +%s%% against Normal monster', + 152 => 'MATK +%s%% against Boss monster', + 153 => 'Pierces %s%% DEF of Normal monster', + 154 => 'Pierces %s%% DEF of Boss monster', + 155 => 'Pierces %s%% MDEF of Normal monster', + 156 => 'Pierces %s%% MDEF of Boss monster', + 157 => 'ATK +%s%% against Small size monster', + 158 => 'ATK +%s%% against Medium size monster', + 159 => 'ATK +%s%% against Large size monster', + 160 => 'Small monster resistance +%s%%', + 161 => 'Medium monster resistance +%s%%', + 162 => 'Large monster resistance +%s%%', + 163 => 'Nullify weapon\'s damage size penalty', + 164 => 'Critical attack +%s%%', + 165 => 'Critical damage -%s%%', + 166 => 'Long range physical attack +%s%%', + 167 => 'Long range physical damage -%s%%', + 168 => 'Healing skills +%s%%', + 169 => 'Restoration gained from Healing skills +%s%%', + 170 => 'Variable cast time -%s%%', + 171 => 'After cast delay -%s%%', + 172 => 'Reduces SP cost by %s%%', + //173 => '', + //174 => '', + 175 => 'Weapon element: Neutral', + 176 => 'Weapon element: Water', + 177 => 'Weapon element: Earth', + 178 => 'Weapon element: Fire', + 179 => 'Weapon element: Wind', + 180 => 'Weapon element: Poison', + 181 => 'Weapon element: Holy', + 182 => 'Weapon element: Shadow', + 183 => 'Weapon element: Ghost', + 184 => 'Weapon element: Undead', + 185 => 'Indestructible in battle', + 186 => 'Indestructible in battle', + 187 => 'MATK against Small size monster +%s%%', + 188 => 'MATK against Medium size monster +%s%%', + 189 => 'MATK against Large size monster +%s%%', + 190 => 'Small monster magic resistance +%s%%', + 191 => 'Medium monster magic resistance +%s%%', + 192 => 'Large monster magic resistance +%s%%', + 193 => 'Elemental attacks resistance +%s%%', + 194 => 'Formless monster resistance +%s%%', + 195 => 'Undead monster resistance +%s%%', + 196 => 'Brute monster resistance +%s%%', + 197 => 'Plant monster resistance +%s%%', + 198 => 'Insect monster resistance +%s%%', + 199 => 'Fish monster resistance +%s%%', + 200 => 'Demon monster resistance +%s%%', + 201 => 'Demihuman monster resistance +%s%%', + 202 => 'Angel monster resistance +%s%%', + 203 => 'Dragon monster resistance +%s%%', + 204 => 'Long range physical attack +%s%%', + 205 => 'Long range physical damage -%s%%', + 206 => 'Demi-Human players resistance + %s%%', + 207 => 'Doram players resistance +%s%%', + 208 => 'ATK against Demi-Human players +%s%%', + 209 => 'ATK against Doram players +%s%%', + 210 => 'MATK against Demi-Human players +%s%%', + 211 => 'MATK against Doram players +%s%%', + 212 => 'Critical +%s for Demi-Human players', + 213 => 'Critical +%s for Doram players', + 214 => 'Pierces %s%% DEF of Demi-Human players', + 215 => 'Pierces %s%% DEF of Doram players', + 216 => 'Pierces %s%% MDEF of Demi-Human players', + 217 => 'Pierces %s%% MDEF of Doram players', + 218 => 'Recieved reflected damage -%s%%', + 219 => 'Melee physical damage +%s%%', + 220 => 'Melee physical damage -%s%%', +]; diff --git a/config/itemflags.php b/config/itemflags.php new file mode 100644 index 00000000..f9da1751 --- /dev/null +++ b/config/itemflags.php @@ -0,0 +1,10 @@ + 'Item is available to Buying Stores', + 'flag_deadbranch' => 'Item is a Dead Branch type', + 'flag_container' => 'Item is part of a Container', + 'flag_uniqueid' => 'Item is a unique stack', + 'flag_bindonequip' => 'Item is bound to the character upon equipping', + 'flag_dropannounce' => 'Item has a special announcement to self on drop', + 'flag_noconsume' => 'Item is consumed on use', +); diff --git a/config/itemsubtypes.php b/config/itemsubtypes.php new file mode 100644 index 00000000..50c634a2 --- /dev/null +++ b/config/itemsubtypes.php @@ -0,0 +1,42 @@ + array( + '1haxe' => 'One-Handed Axe', + '1hspear' => 'One-Handed Spear', + '1hsword' => 'One-Handed Sword', + '2haxe' => 'Two-Handed Axe', + '2hspear' => 'Two-Handed Spear', + '2hstaff' => 'Two-Handed Staff', + '2hsword' => 'Two-Handed Sword', + 'book' => 'Book', + 'bow' => 'Bow', + 'dagger' => 'Dagger', + 'gatling' => 'Gatling Gun', + 'grenade' => 'Grenade Launcher', + 'huuma' => 'Fuuma Shuriken', + 'katar' => 'Katar', + 'knuckle' => 'Knuckle', + 'mace' => 'Mace', + 'musical' => 'Musical Instrument', + 'revolver' => 'Revolver', + 'rifle' => 'Rifle', + 'shotgun' => 'Shotgun', + 'staff' => 'Staff', + 'whip' => 'Whip' + ), + 'ammo' => array( + 'arrow' => 'Arrow', + 'bullet' => 'Bullet', + 'dagger' => 'Throwing Dagger', + 'cannonball' => 'Cannonball', + 'grenade' => 'Grenade', + 'kunai' => 'Kunai', + 'shell' => 'Shell', + 'shuriken' => 'Shuriken', + 'throwweapon' => 'Throwable Item (Sling Item)' + ), + 'card' => array( + 'normal' => 'Card', + 'enchant' => 'Enchant' + ) +); diff --git a/config/itemtypes.php b/config/itemtypes.php index a84a8e92..aaf7a485 100644 --- a/config/itemtypes.php +++ b/config/itemtypes.php @@ -1,18 +1,15 @@ 'Healing', - //1 => 'Unknown', - 2 => 'Usable', - 3 => 'Etc', - 4 => 'Armor', - 5 => 'Weapon', - 6 => 'Card', - 7 => 'Pet Egg', - 8 => 'Pet Armor', - //9 => 'Unknown2', - 10 => 'Ammo', - 11 => 'Delay Consume', - 12 => 'Shadow Equipment', - 18 => 'Cash Shop Reward' -) -?> + 'ammo' => 'Ammo', + 'armor' => 'Armor', + 'card' => 'Card', + 'cash' => 'Cash Shop Reward', + 'delayconsume' => 'Delay Consume', + 'etc' => 'Etc', + 'healing' => 'Healing', + 'petarmor' => 'Pet Armor', + 'petegg' => 'Pet Egg', + 'shadowgear' => 'Shadow Equipment', + 'usable' => 'Usable', + 'weapon' => 'Weapon' +); diff --git a/config/itemtypes2.php b/config/itemtypes2.php deleted file mode 100644 index 3e77770d..00000000 --- a/config/itemtypes2.php +++ /dev/null @@ -1,48 +0,0 @@ - array( // Weapons - 0 => 'Bare Fist', - 1 => 'Dagger', - 2 => 'One-Handed Sword', - 3 => 'Two-Handed Sword', - 4 => 'One-Handed Spear', - 5 => 'Two-Handed Spear', - 6 => 'One-Handed Axe', - 7 => 'Two-Handed Axe', - 8 => 'Mace', - //9 => 'Unused', - 10 => 'Staff', - 11 => 'Bow', - 12 => 'Knuckle', - 13 => 'Musical Instrument', - 14 => 'Whip', - 15 => 'Book', - 16 => 'Katar', - 17 => 'Revolver', - 18 => 'Rifle', - 19 => 'Gatling Gun', - 20 => 'Shotgun', - 21 => 'Grenade Launcher', - 22 => 'Fuuma Shuriken', - 23 => 'Two-handed staves', - //24 => '', - 25 => 'Dual-wield Daggers', - 26 => 'Dual-wield Swords', - 27 => 'Dual-wield Axes', - 28 => 'Dagger + Sword', - 29 => 'Dagger + Axe', - 30 => 'Sword + Axe' - ), - 10 => array( // Ammo - 1 => 'Arrow', - 2 => 'Throwing Dagger', - 3 => 'Bullet', - 4 => 'Shell', - 5 => 'Grenade', - 6 => 'Shuriken', - 7 => 'Kunai', - 8 => 'Cannonballs', - 9 => 'Throwable Item (Sling Item)' - ) -) -?> diff --git a/config/jobs.php b/config/jobs.php index ff92604a..1f51e381 100644 --- a/config/jobs.php +++ b/config/jobs.php @@ -77,7 +77,7 @@ 4043 => 'Baby Dancer', //4044 => 'Baby Crusader (Mounted)', 4045 => 'Super Baby', - + 4046 => 'Taekwon', 4047 => 'Star Gladiator', //4048 => 'Star Gladiator (Flying)', @@ -136,18 +136,18 @@ 4106 => 'Baby Sura', 4107 => 'Baby Genetic', 4108 => 'Baby Shadow Chaser', - + //4109 => 'Baby Rune Knight (Mounted)', //4110 => 'Baby Royal Guard (Mounted)', //4111 => 'Baby Ranger (Mounted)', //4112 => 'Baby Mechanic (Magic Gear)', - + 4190 => 'Expanded Super Novice', 4191 => 'Expanded Super Baby', - + 4211 => 'Kagerou', 4212 => 'Oboro', - + 4215 => 'Rebellion', 4218 => 'Summoner', @@ -161,5 +161,23 @@ 4228 => 'Baby Gunslinger', 4229 => 'Baby Rebellion', //4238 => 'Baby Star Gladiator (Union)', -) -?> + + 4239 => 'Star Emperor', + 4240 => 'Soul Reaper', + 4241 => 'Baby Star Emperor', + 4242 => 'Baby Soul Reaper', + + 4252 => 'Dragon Knight', + 4253 => 'Meister', + 4254 => 'Shadow Cross', + 4255 => 'Arch Mage', + 4256 => 'Cardinal', + 4257 => 'WindHawk', + 4258 => 'Imperial Guard', + 4259 => 'Biolo', + 4260 => 'Abyss Chaser', + 4261 => 'Elemental Master', + 4262 => 'Inquisitor', + 4263 => 'Troubadour', + 4264 => 'Trouvere', +); diff --git a/config/jobs_alchemist.php b/config/jobs_alchemist.php index fd82db4e..e535912c 100644 --- a/config/jobs_alchemist.php +++ b/config/jobs_alchemist.php @@ -5,6 +5,6 @@ 4041 => 'Baby Alchemist', 4071 => 'Genetic', 4078 => 'Genetic+', - 4107 => 'Baby Genetic' -) -?> + 4107 => 'Baby Genetic', + 4259 => 'Biolo', +); diff --git a/config/jobs_blacksmith.php b/config/jobs_blacksmith.php index 524a5c0d..e6ebced4 100644 --- a/config/jobs_blacksmith.php +++ b/config/jobs_blacksmith.php @@ -5,6 +5,6 @@ 4033 => 'Baby Blacksmith', 4058 => 'Mechanic', 4064 => 'Mechanic+', - 4100 => 'Baby Mechanic' -) -?> + 4100 => 'Baby Mechanic', + 4253 => 'Meister', +); diff --git a/config/jobs_gender_linked.php b/config/jobs_gender_linked.php index d7c968c8..3103c15d 100644 --- a/config/jobs_gender_linked.php +++ b/config/jobs_gender_linked.php @@ -11,6 +11,11 @@ 4075 => 'Minstrel+', 4076 => 'Wanderer+', 4104 => 'Baby Minstrel', - 4105 => 'Baby Wanderer' -) -?> + 4105 => 'Baby Wanderer', + 4211 => 'Kagerou', + 4212 => 'Oboro', + 4223 => 'Baby Kagerou', + 4224 => 'Baby Oboro', + 4263 => 'Troubadour', + 4264 => 'Trouvere', +); diff --git a/config/monster_ai.php b/config/monster_ai.php new file mode 100644 index 00000000..94245fb8 --- /dev/null +++ b/config/monster_ai.php @@ -0,0 +1,30 @@ + array('mode_canattack', 'mode_canmove'), + '02' => array('mode_canattack', 'mode_looter', 'mode_canmove'), + '03' => array('mode_changetargetmelee', 'mode_canattack', 'mode_assist', 'mode_canmove'), + '04' => array('mode_changetargetchase', 'mode_changetargetmelee', 'mode_angry', 'mode_canattack', 'mode_aggressive', 'mode_canmove'), + '05' => array('mode_changetargetchase', 'mode_canattack', 'mode_aggressive', 'mode_canmove'), + '06' => array(), + '07' => array('mode_changetargetmelee', 'mode_canattack', 'mode_assist', 'mode_looter', 'mode_canmove'), + '08' => array('mode_targetweak', 'mode_changetargetchase', 'mode_changetargetmelee', 'mode_canattack', 'mode_aggressive', 'mode_canmove'), + '09' => array('mode_changetargetchase', 'mode_changetargetmelee', 'mode_canattack', 'mode_castsensoridle', 'mode_aggressive', 'mode_canmove'), + '10' => array('mode_canattack', 'mode_aggressive'), + '11' => array('mode_canattack', 'mode_aggressive'), + '12' => array('mode_changetargetchase', 'mode_canattack', 'mode_aggressive', 'mode_canmove'), + '13' => array('mode_changetargetchase', 'mode_changetargetmelee', 'mode_canattack', 'mode_assist', 'mode_aggressive', 'mode_canmove'), + //14 => array(), + //15 => array(), + //16 => array(), + '17' => array('mode_canattack', 'mode_castsensoridle', 'mode_canmove'), + //18 => array(), + '19' => array('mode_changetargetchase', 'mode_changetargetmelee', 'mode_canattack', 'mode_castsensoridle', 'mode_aggressive', 'mode_canmove'), + '20' => array('mode_changetargetchase', 'mode_changetargetmelee', 'mode_castsensorchase', 'mode_canattack', 'mode_castsensoridle', 'mode_aggressive', 'mode_canmove'), + '21' => array('mode_changetargetchase', 'mode_changetargetmelee', 'mode_changechase', 'mode_castsensorchase', 'mode_canattack', 'mode_castsensoridle', 'mode_aggressive', 'mode_canmove'), + //22 => array(), + //23 => array(), + '24' => array('mode_canattack', 'mode_norandomwalk', 'mode_canmove'), + '25' => array('mode_canmove'), + '26' => array('mode_randomtarget', 'mode_changetargetchase', 'mode_changetargetmelee', 'mode_changechase', 'mode_castsensorchase', 'mode_canattack', 'mode_castsensoridle', 'mode_aggressive', 'mode_canmove'), + '27' => array('mode_randomtarget', 'mode_canattack', 'mode_aggressive'), +); diff --git a/config/monstermode.php b/config/monstermode.php index 0c2126b3..5bb58ff8 100644 --- a/config/monstermode.php +++ b/config/monstermode.php @@ -1,32 +1,28 @@ 'Can Move', - 2 => 'Looter', - 4 => 'Aggressive', - 8 => 'Assist', - 16 => 'Cast Sensor Idle', - 32 => 'Boss', - 64 => 'Plant', - 128 => 'Can Attack', - 256 => 'Detector', - 512 => 'Cast Sensor Chase', - 1024 => 'Change Chase', - 2048 => 'Angry', - 4096 => 'Change Target Melee', - 8192 => 'Change Target Chase', - 16384 => 'Target Weak', - 32768 => 'Random Target', - 65536 => 'Ignore Melee', - 131072 => 'Ignore Magic', - 262144 => 'Ignore Ranged', - 524288 => 'MVP', - 1048576 => 'Ignore Misc', - 2097152 => 'Knockback Immune', - 4194304 => 'Teleport Block', - 8388608 => 'Unknown', - 16777216 => 'Fixed Item Drop', - 33554432 => 'Detector', - 67108864 => 'Status Immune', - 134217728 => 'Skill Immune', -) -?> + 'mode_aggressive' => 'Aggressive', + 'mode_angry' => 'Angry', + 'mode_assist' => 'Assist', + 'mode_canattack' => 'Can Attack', + 'mode_canmove' => 'Can Move', + 'mode_castsensorchase' => 'Cast Sensor Chase', + 'mode_castsensoridle' => 'Cast Sensor Idle', + 'mode_changechase' => 'Change Chase', + 'mode_changetargetchase' => 'Change Target Chase', + 'mode_changetargetmelee' => 'Change Target Melee', + 'mode_detector' => 'Detector', + 'mode_fixeditemdrop' => 'Fixed Item Drop', + 'mode_ignoremagic' => 'Ignore Magic', + 'mode_ignoremelee' => 'Ignore Melee', + 'mode_ignoremisc' => 'Ignore Misc', + 'mode_ignoreranged' => 'Ignore Ranged', + 'mode_knockbackimmune' => 'Knockback Immune', + 'mode_looter' => 'Looter', + 'mode_mvp' => 'MVP', + 'mode_norandomwalk' => 'Plant', + 'mode_randomtarget' => 'Random Target', + 'mode_skillimmune' => 'Skill Immune', + 'mode_statusimmune' => 'Status Immune', + 'mode_targetweak' => 'Target Weak', + 'mode_teleportblock' => 'Teleport Block', +); diff --git a/config/races.php b/config/races.php index 59fdbf4f..6efcab79 100644 --- a/config/races.php +++ b/config/races.php @@ -1,16 +1,14 @@ 'Formless', - 1 => 'Undead', - 2 => 'Brute', - 3 => 'Plant', - 4 => 'Insect', - 5 => 'Fish', - 6 => 'Demon', - 7 => 'Demi-Human', - 8 => 'Angel', - 9 => 'Dragon', - 10 => 'Human' -) -?> + 'Formless' => 'Formless', + 'Undead' => 'Undead', + 'Brute' => 'Brute', + 'Plant' => 'Plant', + 'Insect' => 'Insect', + 'Fish' => 'Fish', + 'Demon' => 'Demon', + 'Demihuman' => 'Demi-Human', + 'Angel' => 'Angel', + 'Dragon' => 'Dragon' +); diff --git a/config/sizes.php b/config/sizes.php index 96de6938..f4099ffd 100644 --- a/config/sizes.php +++ b/config/sizes.php @@ -1,8 +1,7 @@ 'Small', - 1 => 'Medium', - 2 => 'Large' -) -?> + 'Small' => 'Small', + 'Medium' => 'Medium', + 'Large' => 'Large' +); diff --git a/config/trade_restrictions.php b/config/trade_restrictions.php new file mode 100644 index 00000000..37fe531d --- /dev/null +++ b/config/trade_restrictions.php @@ -0,0 +1,12 @@ + 'Can\'t be dropped', + 'trade_notrade' => 'Can\'t be traded with player', + 'trade_tradepartner' => 'Can\'t be traded with partner', + 'trade_nosell' => 'Can\'t be sold to NPC', + 'trade_nocart' => 'Can\'t be put in Cart', + 'trade_nostorage' => 'Can\'t be put in Storage', + 'trade_noguildstorage' => 'Can\'t be put in Guild Storage', + 'trade_nomail' => 'Can\'t be attached in Mail', + 'trade_noauction' => 'Can\'t be auctioned' +); diff --git a/data/paypal/button.php b/data/paypal/button.php index 23457b9e..e29b5500 100644 --- a/data/paypal/button.php +++ b/data/paypal/button.php @@ -1,4 +1,7 @@ 'English', 'YesLabel' => 'Yes', @@ -51,11 +54,12 @@ 'ItemIdentifyLabel' => 'Identified', 'ItemRefineLabel' => 'Refine', 'ItemBrokenLabel' => 'Broken', - 'ItemCard0Label' => 'Card 0', - 'ItemCard1Label' => 'Card 1', - 'ItemCard2Label' => 'Card 2', - 'ItemCard3Label' => 'Card 3', - + 'ItemCard0Label' => 'Slot 1', + 'ItemCard1Label' => 'Slot 2', + 'ItemCard2Label' => 'Slot 3', + 'ItemCard3Label' => 'Slot 4', + 'ItemRandOptionsLabel' => 'Random options', + //SIDEBAR //FluxCP Menu Items //Categories @@ -101,7 +105,7 @@ 'MobDatabaseLabel' => 'Mob Database', 'JoinUsInFacebookLabel' => 'Join us on Facebook!', 'RateUsOnRMSLabel' => 'Rate us on RMS!', - + // Module: account // - account/changemail 'EmailChangeTitle' => 'Change E-mail', @@ -365,7 +369,7 @@ 'XferLogCharNameLabel' => 'To Character', 'XferLogNotReceived' => 'You have not received any credit transfers.', 'XferLogNotSent' => 'You have not sent any credit transfers.', - + // Module: character // - character/changeslot // - character/index @@ -395,20 +399,20 @@ 'DivorceText3' => 'Wedding rings will also be deleted.', 'DivorceButton' => 'Yes, do it please.', 'DivorceSuccessful' => '%s has been divorced!', - + // Module: cplog // - cplog/index.php // - cplog/login.php // - cplog/paypal.php // - cplog/resetpass.php // - cplog/txnview.php - + // Module: donate // - donate/complete // - donate/history // - donate/index // - donate/trusted - + // Module: errors // - errors/missing_action 'MissingActionTitle' => 'Missing Action', @@ -424,12 +428,12 @@ 'MissingViewActLabel' => 'Action:', 'MissingViewReqLabel' => 'Request URI:', 'MissingViewLocLabel' => 'File system location:', - + // Module: guild // - guild/export // - guild/index // - guild/view - + // Module: history // - history/cplogin 'HistoryCpLoginTitle' => 'Control Panel Logins', @@ -473,7 +477,7 @@ 'HistoryPassResetResetDate' => 'Reset Date', 'HistoryPassResetResetIp' => 'Reset IP', 'HistoryNoPassResets' => 'No password reset attempts found.', - + // Module: ipban // - ipban/add 'IpbanAddTitle' => 'Add IP Ban', @@ -524,20 +528,20 @@ 'IpbanEnterUnbanReason' => 'Please enter a reason for lifting the IP ban(s).', 'IpbanUnbanned' => 'Lifted selected IP ban(s)!', 'IpbanUnbanFailed' => 'Failed to lift %d of the specified IP unban(s)!', - + // Module: item // - item/add // - item/copy // - item/edit // - item/index // - item/view - + // Module: itemshop // - itemshop/add // - itemshop/delete // - itemshop/edit // - itemshop/imagedel - + // Module: logdata // - logdata/chat // - logdata/cashpoints @@ -572,10 +576,10 @@ 'PickLogItemLabel' => 'Item Name', 'PickLogAmountLabel' => 'Amount', 'PickLogRefineLabel' => 'Refine', - 'PickLogCard0Label' => 'Card 0', - 'PickLogCard1Label' => 'Card 1', - 'PickLogCard2Label' => 'Card 2', - 'PickLogCard3Label' => 'Card 3', + 'PickLogCard0Label' => 'Slot 1', + 'PickLogCard1Label' => 'Slot 2', + 'PickLogCard2Label' => 'Slot 3', + 'PickLogCard3Label' => 'Slot 4', 'PickLogMapLabel' => 'Map', // - logdata/branch 'BranchLogTitle' => 'List Branch Log', @@ -636,7 +640,7 @@ 'ZenyLogMapLabel' => 'Map', // - logdata/feeding 'FeedingLogTitle' => 'Feeding Log', - + // Module: mail // - mail/index 'MailerTitle' => 'Form Mailer', @@ -652,7 +656,7 @@ 'MailerSubjectLabel' => 'Subject', 'MailerBodyLabel' => 'Body', 'MailerSelectTemplateLabel' => 'Select Template', - + // Module: main // - main/index 'MainPageHeading' => 'Flux Control Panel', @@ -668,11 +672,11 @@ 'PageNotFoundInfo' => 'The page you have requested was not found on our server. Please check the address and make sure it is correct, and try again.', // - main/preprocess 'DisallowedDuringWoE' => 'The page you have requested is not accessible during WoE.', - + // Module: monster // - monster/index // - monster/view - + // Module: purchase // - purchase/add // - purchase/cart @@ -681,12 +685,12 @@ // - purchase/index // - purchase/pending // - purchase/remove - + // Module: ranking // - ranking/character // - ranking/guild // - ranking/zeny - + // Module: server // - server/info 'ServerInfoTitle' => 'Server Information', @@ -709,20 +713,20 @@ 'ServerStatusMapLabel' => 'Map Server', 'ServerStatusOnlineLabel' => 'Players Online', 'ServerStatusPeakLabel' => 'Player Peak', - + // Module: service // - service/tos 'TermsTitle' => 'Terms of Service', 'TermsHeading' => 'Terms of Service', 'TermsInfo' => 'Please read before creating an account!', 'TermsInfo2' => "FOR CONTROL PANEL ADMINISTRATOR: You may add your server's ToS in this view file directly. The location of the view file is: %s", - + // Module: unauthorized // - unauthorized/index 'UnauthorizedTitle' => 'Unauthorized', 'UnauthorizedHeading' => 'Unauthorized', 'UnauthorizedInfo' => 'You are unauthorized to view this page. Redirecting…', - + // Module: woe // - woe/index 'WoeTitle' => 'WoE Hours', @@ -732,10 +736,10 @@ 'WoeServerLabel' => 'Servers', 'WoeTimesLabel' => 'War of Emperium Times', 'WoeNotScheduledInfo' => 'There are no scheduled WoE hours.', - + // Module: contactform 'CFTitleSubmit' => 'Contact Us', - + // Module: News and Pages 'CMSNewsHeader' => 'Announcements', 'CMSPageHeader' => 'Content Management System', @@ -748,7 +752,7 @@ 'CMSNewsAdded' => 'News added to system', 'CMSPagesAdded' => 'Your new page has been added', 'CMSNewsUpdated' => 'News updated', - 'CMSPageUpdated' => 'Your page has been updated', + 'CMSPageUpdated' => 'Your page has been updated', 'CMSNewsAddTitle' => 'Add a news item', 'CMSPageAddTitle' => 'Add a new page', 'CMSNewsEditTitle' => 'Edit news', @@ -778,17 +782,17 @@ 'CMSOptionalLabel' => '(Optional)', 'CMSRequiredLabel' => '(Required)', 'CMSCreateLabel' => 'Add News', - + // Module: vending 'TLHeaderTasks' => 'Tasks', - 'TLHeaderOwner' => 'Owner', - 'TLHeaderPriority' => 'Priority', - 'TLHeaderStatus' => 'Status', + 'TLHeaderOwner' => 'Owner', + 'TLHeaderPriority' => 'Priority', + 'TLHeaderStatus' => 'Status', 'TLHeaderCreated' => 'Created', 'TLHeaderModified' => 'Modified', 'TLHeaderResources' => 'Additional Resources', 'TLHeaderBody' => 'Body', - + // Module: servicedesk 'SDHeader' => 'Service Desk', 'SDCreateNew' => 'Create a new ticket', @@ -800,18 +804,18 @@ 'SDNoInactiveTickets' => 'You have no in-active tickets at the moment.', 'SDNoClosedTickets' => 'There are no Closed tickets in the database.', 'SDNoCats' => 'There are no categories within the database.', - 'SDHuh' => 'You should not be here o.O', + 'SDHuh' => 'You should not be here o.O', 'SDPointerChatLog' => 'We recommend pasting to pastebin.com then putting the link in here.', 'SDPointerScreenShot' => 'Provide image links as evidence', 'SDPointerVideoLink' => 'We recommend uploading to youtube then putting the link in here.', - 'SDHeaderID' => 'Ticket #', - 'SDHeaderSubject' => 'Subject', + 'SDHeaderID' => 'Ticket #', + 'SDHeaderSubject' => 'Subject', 'SDHeaderCategory' => 'Category', - 'SDHeaderStatus' => 'Current Status', + 'SDHeaderStatus' => 'Current Status', 'SDHeaderLastAuthor' => 'Last Author', - 'SDHeaderTimestamp' => 'Created', - 'SDHeaderAccount' => 'Account', - 'SDHeaderTeam' => 'Team', + 'SDHeaderTimestamp' => 'Created', + 'SDHeaderAccount' => 'Account', + 'SDHeaderTeam' => 'Team', 'SDH3ActiveTickets' => 'Active Tickets', 'SDH3InActiveTickets' => 'In-Active Tickets', 'SDH3ClosedTickets' => 'Closed Tickets', diff --git a/lang/es_es.php b/lang/es_es.php index f219dd88..b36738c7 100755 --- a/lang/es_es.php +++ b/lang/es_es.php @@ -13,7 +13,9 @@ // Example: storage -> almacén ? No! That'd require scripts to be translated for that! // Example: ban -> expulsión -> bloqueo ? Yes! No scripts to be translated and it's widely understood! // ip ban -> IP con acceso prohibido ? - + +use rAthena\FluxCp\Flux; + return array( // Generic/Misc. 'Language' => 'Spanish', @@ -66,10 +68,10 @@ 'ItemIdentifyLabel' => 'Identificado', 'ItemRefineLabel' => 'Refinado', 'ItemBrokenLabel' => 'Roto', - 'ItemCard0Label' => 'Carta 0', - 'ItemCard1Label' => 'Carta 1', - 'ItemCard2Label' => 'Carta 2', - 'ItemCard3Label' => 'Carta 3', + 'ItemCard0Label' => 'Carta 1', + 'ItemCard1Label' => 'Carta 2', + 'ItemCard2Label' => 'Carta 3', + 'ItemCard3Label' => 'Carta 4', //SIDEBAR //FluxCP Menu Items @@ -579,10 +581,10 @@ 'PickLogItemLabel' => 'Nombre de Objeto', 'PickLogAmountLabel' => 'Cantidad', 'PickLogRefineLabel' => 'Refinado', - 'PickLogCard0Label' => 'Carta 0', - 'PickLogCard1Label' => 'Carta 1', - 'PickLogCard2Label' => 'Carta 2', - 'PickLogCard3Label' => 'Carta 3', + 'PickLogCard0Label' => 'Carta 1', + 'PickLogCard1Label' => 'Carta 2', + 'PickLogCard2Label' => 'Carta 3', + 'PickLogCard3Label' => 'Carta 4', 'PickLogMapLabel' => 'Mapa', // - logdata/zeny 'ZenyLogTitle' => 'Lista de Transacciones de Zeny', diff --git a/lang/id_id.php b/lang/id_id.php index 95b2966c..2b68ccba 100644 --- a/lang/id_id.php +++ b/lang/id_id.php @@ -6,6 +6,8 @@ // Oleh: // Cydh, nanakiwurtz, +use rAthena\FluxCp\Flux; + return array( // Generic/Misc. 'Language' => 'Indonesian', @@ -58,10 +60,10 @@ 'ItemIdentifyLabel' => 'Teridentifikasi', 'ItemRefineLabel' => 'Tempa', 'ItemBrokenLabel' => 'Rusak', - 'ItemCard0Label' => 'Kartu 0', - 'ItemCard1Label' => 'Kartu 1', - 'ItemCard2Label' => 'Kartu 2', - 'ItemCard3Label' => 'Kartu 3', + 'ItemCard0Label' => 'Kartu 1', + 'ItemCard1Label' => 'Kartu 2', + 'ItemCard2Label' => 'Kartu 3', + 'ItemCard3Label' => 'Kartu 4', //SIDEBAR //FluxCP Menu Items @@ -578,10 +580,10 @@ 'PickLogItemLabel' => 'Nama Barang', 'PickLogAmountLabel' => 'Jumlah', 'PickLogRefineLabel' => 'Tempa', - 'PickLogCard0Label' => 'Kartu 0', - 'PickLogCard1Label' => 'Kartu 1', - 'PickLogCard2Label' => 'Kartu 2', - 'PickLogCard3Label' => 'Kartu 3', + 'PickLogCard0Label' => 'Kartu 1', + 'PickLogCard1Label' => 'Kartu 2', + 'PickLogCard2Label' => 'Kartu 3', + 'PickLogCard3Label' => 'Kartu 4', 'PickLogMapLabel' => 'Map', // - logdata/branch 'BranchLogTitle' => 'Daftar Branch', diff --git a/lang/pt_br.php b/lang/pt_br.php index fea759b7..3d71def3 100644 --- a/lang/pt_br.php +++ b/lang/pt_br.php @@ -1,4 +1,7 @@ 'Portuguese', @@ -51,10 +54,10 @@ 'ItemIdentifyLabel' => 'Identificado', 'ItemRefineLabel' => 'Refinado', 'ItemBrokenLabel' => 'Quebrado', - 'ItemCard0Label' => 'Carta 0', - 'ItemCard1Label' => 'Carta 1', - 'ItemCard2Label' => 'Carta 2', - 'ItemCard3Label' => 'Carta 3', + 'ItemCard0Label' => 'Carta 1', + 'ItemCard1Label' => 'Carta 2', + 'ItemCard2Label' => 'Carta 3', + 'ItemCard3Label' => 'Carta 4', // Security 'SecuritySessionInvalid' => 'Desculpe, a sessão expirou, tente novamente.', diff --git a/lib/Flux/CashShop.php b/lib/Flux/CashShop.php deleted file mode 100644 index 4396adf5..00000000 --- a/lib/Flux/CashShop.php +++ /dev/null @@ -1,102 +0,0 @@ -server = $server; - } - - /** - * Add an item to the cash shop. - */ - public function add($tab, $itemID, $price) { - $db = $this->server->charMapDatabase; - $sql = "INSERT INTO $db.`item_cash_db` (tab, item_id, price) VALUES (?, ?, ?)"; - $sth = $this->server->connection->getStatement($sql); - $res = $sth->execute(array($tab, $itemID, $price)); - - if ($res) { - return true; - } else { - return false; - } - } - - /** - * Modify item info in the shop. - */ - public function edit($shopItemID, $tab = null, $price = null) { - $tabQ = ''; - $priceQ = ''; - $bind = array(); - - if (!is_null($tab)) { - $tabQ = "tab = ? "; - $bind[] = (int)$tab; - } - - if (!is_null($price)) { - if ($tabQ) { - $priceQ = ", price = ? "; - } else { - $priceQ = "price = ? "; - } - $bind[] = (int)$price; - } - - if (empty($bind)) { return false; } - - $db = $this->server->charMapDatabase; - $sql = "UPDATE $db.`item_cash_db` SET $tabQ $priceQ WHERE item_id = ?"; - $sth = $this->server->connection->getStatement($sql); - - $bind[] = $shopItemID; - return $sth->execute($bind); - } - - /** - * - */ - public function delete($ItemID) { - $db = $this->server->charMapDatabase; - $sql = "DELETE FROM $db.`item_cash_db` WHERE item_id = ?"; - $sth = $this->server->connection->getStatement($sql); - - return $sth->execute(array($ItemID)); - } - - /** - * - */ - public function getItem($shopItemID) { - $db = $this->server->charMapDatabase; - - if($this->server->isRenewal) { - $fromTables = array("$db.item_db_re", "$db.item_db2_re"); - } else { - $fromTables = array("$db.item_db", "$db.item_db2"); - } - - $temp = new Flux_TemporaryTable($this->server->connection, "$db.items", $fromTables); - $shop = 'item_cash_db'; - $col = "$shop.item_id AS shop_item_id, $shop.tab AS shop_item_tab, $shop.price AS shop_item_price, "; - $col .= "items.name_japanese AS shop_item_name"; - $sql = "SELECT $col FROM $db.$shop LEFT OUTER JOIN $db.items ON items.id = $shop.item_id WHERE $shop.item_id = ?"; - $sth = $this->server->connection->getStatement($sql); - - if ($sth->execute(array($shopItemID))) { - return $sth->fetch(); - } else { - return false; - } - } - -} -?> diff --git a/lib/Flux/CharServer.php b/lib/Flux/CharServer.php deleted file mode 100644 index f30eac85..00000000 --- a/lib/Flux/CharServer.php +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/lib/Flux/Connection/Statement.php b/lib/Flux/Connection/Statement.php deleted file mode 100644 index 3a3332f1..00000000 --- a/lib/Flux/Connection/Statement.php +++ /dev/null @@ -1,38 +0,0 @@ -stmt = $stmt; - - if (!self::$errorLog) { - self::$errorLog = new Flux_LogFile(FLUX_DATA_DIR.'/logs/mysql/errors/'.date('Ymd').'.log', 'a'); - } - } - - public function execute(array $inputParameters = array()) - { - $res = $this->stmt->execute($inputParameters); - Flux::$numberOfQueries++; - if ((int)$this->stmt->errorCode()) { - $info = $this->stmt->errorInfo(); - self::$errorLog->puts('[SQLSTATE=%s] Err %s: %s', $info[0], $info[1], $info[2]); - if (Flux::config('DebugMode')) { - $message = sprintf('MySQL error (SQLSTATE: %s, ERROR: %s): %s', $info[0], $info[1], $info[2]); - throw new Flux_Error($message); - } - } - return $res; - } - - public function __call($method, $args) - { - return call_user_func_array(array($this->stmt, $method), $args); - } -} -?> diff --git a/lib/Flux/Connection/index.html b/lib/Flux/Connection/index.html deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/Flux/Installer/CharMapServer.php b/lib/Flux/Installer/CharMapServer.php deleted file mode 100644 index 86e81aa1..00000000 --- a/lib/Flux/Installer/CharMapServer.php +++ /dev/null @@ -1,33 +0,0 @@ -mainServer = $mainServer; - $this->athena = $athena; - $this->schemas = Flux_Installer_Schema::getSchemas($mainServer, $this); - } -} -?> diff --git a/lib/Flux/Installer/index.html b/lib/Flux/Installer/index.html deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/Flux/ItemExistsError.php b/lib/Flux/ItemExistsError.php deleted file mode 100644 index 9e5be5b3..00000000 --- a/lib/Flux/ItemExistsError.php +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/lib/Flux/ItemShop.php b/lib/Flux/ItemShop.php deleted file mode 100644 index 422a354e..00000000 --- a/lib/Flux/ItemShop.php +++ /dev/null @@ -1,250 +0,0 @@ -server = $server; - } - - /** - * Add an item to the shop. - */ - public function add($itemID, $categoryID, $cost, $quantity, $info, $useExisting = 0) - { - $db = $this->server->charMapDatabase; - $table = Flux::config('FluxTables.ItemShopTable'); - $sql = "INSERT INTO $db.$table (nameid, category, quantity, cost, info, use_existing, create_date) VALUES (?, ?, ?, ?, ?, ?, NOW())"; - $sth = $this->server->connection->getStatement($sql); - $res = $sth->execute(array($itemID, $categoryID, $quantity, $cost, $info, $useExisting)); - $sth2 = $this->server->connection->getStatement('SELECT LAST_INSERT_ID() AS insID'); - $res2 = $sth2->execute(); - - if ($res && $res2 && ($insertID=$sth2->fetch()->insID)) { - return $insertID; - } - else { - return false; - } - } - - /** - * Modify item info in the shop. - */ - public function edit($shopItemID, $categoryID = null, $cost = null, $quantity = null, $info = null, $useExisting = null) - { - $catQ = ''; - $crdQ = ''; - $qtyQ = ''; - $infQ = ''; - $imgQ = ''; - $bind = array(); - - if (!is_null($categoryID)) { - $catQ = "category = ? "; - $bind[] = (int)$categoryID; - } - - if (!is_null($cost)) { - if ($catQ) { - $crdQ = ", cost = ? "; - } - else { - $crdQ = "cost = ? "; - } - - $bind[] = (int)$cost; - } - - if (!is_null($quantity)) { - if ($crdQ) { - $qtyQ = ', quantity = ? '; - } - else { - $qtyQ = "quantity = ? "; - } - - $bind[] = (int)$quantity; - } - - if (!is_null($info)) { - if ($qtyQ) { - $infQ = ', info = ? '; - } - else { - $infQ = "info = ? "; - } - - $bind[] = trim($info); - } - - if (!is_null($useExisting)) { - if ($infQ) { - $imgQ = ', use_existing = ? '; - } - else { - $imgQ = "use_existing = ? "; - } - - $bind[] = (int)$useExisting; - } - - if (empty($bind)) { - return false; - } - - $db = $this->server->charMapDatabase; - $table = Flux::config('FluxTables.ItemShopTable'); - $sql = "UPDATE $db.$table SET $catQ $crdQ $qtyQ $infQ $imgQ WHERE id = ?"; - $sth = $this->server->connection->getStatement($sql); - - $bind[] = $shopItemID; - return $sth->execute($bind); - } - - /** - * - */ - public function delete($shopItemID) - { - $db = $this->server->charMapDatabase; - $table = Flux::config('FluxTables.ItemShopTable'); - $sql = "DELETE FROM $db.$table WHERE id = ?"; - $sth = $this->server->connection->getStatement($sql); - - return $sth->execute(array($shopItemID)); - } - - /** - * - */ - public function buy(Flux_DataObject $account, $shopItemID) - { - - } - - /** - * - */ - public function getItem($shopItemID) - { - $db = $this->server->charMapDatabase; - - if($this->server->isRenewal) { - $fromTables = array("$db.item_db_re", "$db.item_db2_re"); - } else { - $fromTables = array("$db.item_db", "$db.item_db2"); - } - - $temp = new Flux_TemporaryTable($this->server->connection, "$db.items", $fromTables); - $shop = Flux::config('FluxTables.ItemShopTable'); - $col = "$shop.id AS shop_item_id, $shop.category AS shop_item_category, $shop.cost AS shop_item_cost, $shop.quantity AS shop_item_qty, $shop.use_existing AS shop_item_use_existing, "; - $col .= "$shop.nameid AS shop_item_nameid, $shop.info AS shop_item_info, items.name_japanese AS shop_item_name"; - $sql = "SELECT $col FROM $db.$shop LEFT OUTER JOIN $db.items ON items.id = $shop.nameid WHERE $shop.id = ?"; - $sth = $this->server->connection->getStatement($sql); - - if ($sth->execute(array($shopItemID))) { - return $sth->fetch(); - } - else { - return false; - } - } - - /** - * - */ - public function getItems($paginator, $categoryID = null) - { - $sqlpartial = ""; - $bind = array(); - $db = $this->server->charMapDatabase; - - if($this->server->isRenewal) { - $fromTables = array("$db.item_db_re", "$db.item_db2_re"); - } else { - $fromTables = array("$db.item_db", "$db.item_db2"); - } - - $temp = new Flux_TemporaryTable($this->server->connection, "$db.items", $fromTables); - $shop = Flux::config('FluxTables.ItemShopTable'); - $col = "$shop.id AS shop_item_id, $shop.cost AS shop_item_cost, $shop.quantity AS shop_item_qty, $shop.use_existing AS shop_item_use_existing, "; - $col .= "$shop.nameid AS shop_item_nameid, $shop.info AS shop_item_info, items.name_japanese AS shop_item_name"; - if (!is_null($categoryID)) { - $sqlpartial = " WHERE $shop.category = ?"; - $bind[] = $categoryID; - } - $sql = $paginator->getSQL("SELECT $col FROM $db.$shop LEFT OUTER JOIN $db.items ON items.id = $shop.nameid $sqlpartial"); - $sth = $this->server->connection->getStatement($sql); - - if ($sth->execute($bind)) { - return $sth->fetchAll(); - } - else { - return false; - } - } - - /** - * - */ - public function deleteShopItemImage($shopItemID) - { - $serverName = $this->server->loginAthenaGroup->serverName; - $athenaServerName = $this->server->serverName; - $dir = FLUX_DATA_DIR."/itemshop/$serverName/$athenaServerName"; - $files = glob("$dir/$shopItemID.*"); - - foreach ($files as $file) { - unlink($file); - } - - return true; - } - - /** - * - */ - public function uploadShopItemImage($shopItemID, Flux_Config $file) - { - if ($file->get('error')) { - return false; - } - - $validexts = array_map('strtolower', Flux::config('ShopImageExtensions')->toArray()); - $extension = strtolower(pathinfo($file->get('name'), PATHINFO_EXTENSION)); - - if (!in_array($extension, $validexts)) { - return false; - } - - $serverName = $this->server->loginAthenaGroup->serverName; - $athenaServerName = $this->server->serverName; - $dir = FLUX_DATA_DIR."/itemshop/$serverName/$athenaServerName"; - - if (!is_dir(FLUX_DATA_DIR."/itemshop/$serverName")) { - mkdir(FLUX_DATA_DIR."/itemshop/$serverName"); - } - - if (!is_dir($dir)) { - mkdir($dir); - } - - $this->deleteShopItemImage($shopItemID); - - if (move_uploaded_file($file->get('tmp_name'), "$dir/$shopItemID.$extension")) { - return true; - } - else { - return false; - } - } -} -?> diff --git a/lib/Flux/ItemShop/index.html b/lib/Flux/ItemShop/index.html deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/Flux/LoginError.php b/lib/Flux/LoginError.php deleted file mode 100644 index 807a1f90..00000000 --- a/lib/Flux/LoginError.php +++ /dev/null @@ -1,14 +0,0 @@ - diff --git a/lib/Flux/MapServer.php b/lib/Flux/MapServer.php deleted file mode 100644 index 6190b99f..00000000 --- a/lib/Flux/MapServer.php +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/lib/Flux/PermissionError.php b/lib/Flux/PermissionError.php deleted file mode 100644 index a59e050f..00000000 --- a/lib/Flux/PermissionError.php +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/lib/Flux/RegisterError.php b/lib/Flux/RegisterError.php deleted file mode 100644 index dcf05974..00000000 --- a/lib/Flux/RegisterError.php +++ /dev/null @@ -1,27 +0,0 @@ - diff --git a/lib/Flux/index.html b/lib/Flux/index.html deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/functions/getReposVersion.php b/lib/functions/getReposVersion.php deleted file mode 100644 index 0f5acc5c..00000000 --- a/lib/functions/getReposVersion.php +++ /dev/null @@ -1,85 +0,0 @@ - $rev) { - $rev = $curr; - } - } - } - - fclose($fp); - } - } - - return $rev; -} - -?> diff --git a/lib/functions/imagecreatefrombmpstring.php b/lib/functions/imagecreatefrombmpstring.php deleted file mode 100644 index cc26cd8d..00000000 --- a/lib/functions/imagecreatefrombmpstring.php +++ /dev/null @@ -1,93 +0,0 @@ - - */ -function imagecreatefrombmpstring($im) { - $header = unpack("vtype/Vsize/v2reserved/Voffset", substr($im, 0, 14)); - $info = unpack("Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vimportant", substr($im, 14, 40)); - extract($info); - extract($header); - if($type != 0x4D42) - return false; - $palette_size = $offset - 54; - $imres=imagecreatetruecolor($width, $height); - imagealphablending($imres, false); - imagesavealpha($imres, true); - $pal=array(); - if($palette_size) { - $palette = substr($im, 54, $palette_size); - $j = 0; $n = 0; - while($j < $palette_size) { - $b = ord($palette{$j++}); - $g = ord($palette{$j++}); - $r = ord($palette{$j++}); - $a = ord($palette{$j++}); - if ( ($r & 0xf8 == 0xf8) && ($g == 0) && ($b & 0xf8 == 0xf8)) - $a = 127; // alpha = 255 on 0xFF00FF - $pal[$n++] = imagecolorallocatealpha($imres, $r, $g, $b, $a); - } - } - $scan_line_size = (($bits * $width) + 7) >> 3; - $scan_line_align = ($scan_line_size & 0x03) ? 4 - ($scan_line_size & 0x03): 0; - for($i = 0, $l = $height - 1; $i < $height; $i++, $l--) { - $scan_line = substr($im, $offset + (($scan_line_size + $scan_line_align) * $l), $scan_line_size); - if($bits == 24) { - $j = 0; $n = 0; - while($j < $scan_line_size) { - $b = ord($scan_line{$j++}); - $g = ord($scan_line{$j++}); - $r = ord($scan_line{$j++}); - $a = 0; - if ( ($r & 0xf8 == 0xf8) && ($g == 0) && ($b & 0xf8 == 0xf8)) - $a = 127; // alpha = 255 on 0xFF00FF - $col=imagecolorallocatealpha($imres, $r, $g, $b, $a); - imagesetpixel($imres, $n++, $i, $col); - } - } - else if($bits == 8) { - $j = 0; - while($j < $scan_line_size) { - $col = $pal[ord($scan_line{$j++})]; - imagesetpixel($imres, $j-1, $i, $col); - } - } - else if($bits == 4) { - $j = 0; $n = 0; - while($j < $scan_line_size) { - $byte = ord($scan_line{$j++}); - $p1 = $byte >> 4; - $p2 = $byte & 0x0F; - imagesetpixel($imres, $n++, $i, $pal[$p1]); - imagesetpixel($imres, $n++, $i, $pal[$p2]); - } - } - else if($bits == 1) { - $j = 0; $n = 0; - while($j < $scan_line_size) { - $byte = ord($scan_line{$j++}); - $p1 = (int) (($byte & 0x80) != 0); - $p2 = (int) (($byte & 0x40) != 0); - $p3 = (int) (($byte & 0x20) != 0); - $p4 = (int) (($byte & 0x10) != 0); - $p5 = (int) (($byte & 0x08) != 0); - $p6 = (int) (($byte & 0x04) != 0); - $p7 = (int) (($byte & 0x02) != 0); - $p8 = (int) (($byte & 0x01) != 0); - imagesetpixel($imres, $n++, $i, $pal[$p1]); - imagesetpixel($imres, $n++, $i, $pal[$p2]); - imagesetpixel($imres, $n++, $i, $pal[$p3]); - imagesetpixel($imres, $n++, $i, $pal[$p4]); - imagesetpixel($imres, $n++, $i, $pal[$p5]); - imagesetpixel($imres, $n++, $i, $pal[$p6]); - imagesetpixel($imres, $n++, $i, $pal[$p7]); - imagesetpixel($imres, $n++, $i, $pal[$p8]); - } - } - } - return $imres; -} - -?> diff --git a/lib/functions/index.html b/lib/functions/index.html deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/index.html b/lib/index.html deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/phpmailer/LICENSE b/lib/phpmailer/LICENSE deleted file mode 100644 index 8e0763d1..00000000 --- a/lib/phpmailer/LICENSE +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. 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 not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the 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 -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/lib/phpmailer/PHPMailerAutoload.php b/lib/phpmailer/PHPMailerAutoload.php deleted file mode 100644 index eaa2e303..00000000 --- a/lib/phpmailer/PHPMailerAutoload.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @author Jim Jagielski (jimjag) - * @author Andy Prevost (codeworxtech) - * @author Brent R. Matzelle (original founder) - * @copyright 2012 - 2014 Marcus Bointon - * @copyright 2010 - 2012 Jim Jagielski - * @copyright 2004 - 2009 Andy Prevost - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - * @note This program is distributed in the hope that it will be useful - WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - */ - -/** - * PHPMailer SPL autoloader. - * @param string $classname The name of the class to load - */ -function PHPMailerAutoload($classname) -{ - //Can't use __DIR__ as it's only in PHP 5.3+ - $filename = dirname(__FILE__).DIRECTORY_SEPARATOR.'class.'.strtolower($classname).'.php'; - if (is_readable($filename)) { - require $filename; - } -} - -if (version_compare(PHP_VERSION, '5.1.2', '>=')) { - //SPL autoloading was introduced in PHP 5.1.2 - if (version_compare(PHP_VERSION, '5.3.0', '>=')) { - spl_autoload_register('PHPMailerAutoload', true, true); - } else { - spl_autoload_register('PHPMailerAutoload'); - } -} else { - /** - * Fall back to traditional autoload for old PHP versions - * @param string $classname The name of the class to load - */ - function __autoload($classname) - { - PHPMailerAutoload($classname); - } -} diff --git a/lib/phpmailer/VERSION b/lib/phpmailer/VERSION deleted file mode 100644 index f0fb1a22..00000000 --- a/lib/phpmailer/VERSION +++ /dev/null @@ -1 +0,0 @@ -5.2.26 diff --git a/lib/phpmailer/class.phpmailer.php b/lib/phpmailer/class.phpmailer.php deleted file mode 100644 index 99f9092c..00000000 --- a/lib/phpmailer/class.phpmailer.php +++ /dev/null @@ -1,4044 +0,0 @@ - - * @author Jim Jagielski (jimjag) - * @author Andy Prevost (codeworxtech) - * @author Brent R. Matzelle (original founder) - * @copyright 2012 - 2014 Marcus Bointon - * @copyright 2010 - 2012 Jim Jagielski - * @copyright 2004 - 2009 Andy Prevost - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - * @note This program is distributed in the hope that it will be useful - WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - */ - -/** - * PHPMailer - PHP email creation and transport class. - * @package PHPMailer - * @author Marcus Bointon (Synchro/coolbru) - * @author Jim Jagielski (jimjag) - * @author Andy Prevost (codeworxtech) - * @author Brent R. Matzelle (original founder) - */ -class PHPMailer -{ - /** - * The PHPMailer Version number. - * @var string - */ - public $Version = '5.2.26'; - - /** - * Email priority. - * Options: null (default), 1 = High, 3 = Normal, 5 = low. - * When null, the header is not set at all. - * @var integer - */ - public $Priority = null; - - /** - * The character set of the message. - * @var string - */ - public $CharSet = 'iso-8859-1'; - - /** - * The MIME Content-type of the message. - * @var string - */ - public $ContentType = 'text/plain'; - - /** - * The message encoding. - * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable". - * @var string - */ - public $Encoding = '8bit'; - - /** - * Holds the most recent mailer error message. - * @var string - */ - public $ErrorInfo = ''; - - /** - * The From email address for the message. - * @var string - */ - public $From = 'root@localhost'; - - /** - * The From name of the message. - * @var string - */ - public $FromName = 'Root User'; - - /** - * The Sender email (Return-Path) of the message. - * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode. - * @var string - */ - public $Sender = ''; - - /** - * The Return-Path of the message. - * If empty, it will be set to either From or Sender. - * @var string - * @deprecated Email senders should never set a return-path header; - * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything. - * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference - */ - public $ReturnPath = ''; - - /** - * The Subject of the message. - * @var string - */ - public $Subject = ''; - - /** - * An HTML or plain text message body. - * If HTML then call isHTML(true). - * @var string - */ - public $Body = ''; - - /** - * The plain-text message body. - * This body can be read by mail clients that do not have HTML email - * capability such as mutt & Eudora. - * Clients that can read HTML will view the normal Body. - * @var string - */ - public $AltBody = ''; - - /** - * An iCal message part body. - * Only supported in simple alt or alt_inline message types - * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator - * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/ - * @link http://kigkonsult.se/iCalcreator/ - * @var string - */ - public $Ical = ''; - - /** - * The complete compiled MIME message body. - * @access protected - * @var string - */ - protected $MIMEBody = ''; - - /** - * The complete compiled MIME message headers. - * @var string - * @access protected - */ - protected $MIMEHeader = ''; - - /** - * Extra headers that createHeader() doesn't fold in. - * @var string - * @access protected - */ - protected $mailHeader = ''; - - /** - * Word-wrap the message body to this number of chars. - * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance. - * @var integer - */ - public $WordWrap = 0; - - /** - * Which method to use to send mail. - * Options: "mail", "sendmail", or "smtp". - * @var string - */ - public $Mailer = 'mail'; - - /** - * The path to the sendmail program. - * @var string - */ - public $Sendmail = '/usr/sbin/sendmail'; - - /** - * Whether mail() uses a fully sendmail-compatible MTA. - * One which supports sendmail's "-oi -f" options. - * @var boolean - */ - public $UseSendmailOptions = true; - - /** - * Path to PHPMailer plugins. - * Useful if the SMTP class is not in the PHP include path. - * @var string - * @deprecated Should not be needed now there is an autoloader. - */ - public $PluginDir = ''; - - /** - * The email address that a reading confirmation should be sent to, also known as read receipt. - * @var string - */ - public $ConfirmReadingTo = ''; - - /** - * The hostname to use in the Message-ID header and as default HELO string. - * If empty, PHPMailer attempts to find one with, in order, - * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value - * 'localhost.localdomain'. - * @var string - */ - public $Hostname = ''; - - /** - * An ID to be used in the Message-ID header. - * If empty, a unique id will be generated. - * You can set your own, but it must be in the format "", - * as defined in RFC5322 section 3.6.4 or it will be ignored. - * @see https://tools.ietf.org/html/rfc5322#section-3.6.4 - * @var string - */ - public $MessageID = ''; - - /** - * The message Date to be used in the Date header. - * If empty, the current date will be added. - * @var string - */ - public $MessageDate = ''; - - /** - * SMTP hosts. - * Either a single hostname or multiple semicolon-delimited hostnames. - * You can also specify a different port - * for each host by using this format: [hostname:port] - * (e.g. "smtp1.example.com:25;smtp2.example.com"). - * You can also specify encryption type, for example: - * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465"). - * Hosts will be tried in order. - * @var string - */ - public $Host = 'localhost'; - - /** - * The default SMTP server port. - * @var integer - * @TODO Why is this needed when the SMTP class takes care of it? - */ - public $Port = 25; - - /** - * The SMTP HELO of the message. - * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find - * one with the same method described above for $Hostname. - * @var string - * @see PHPMailer::$Hostname - */ - public $Helo = ''; - - /** - * What kind of encryption to use on the SMTP connection. - * Options: '', 'ssl' or 'tls' - * @var string - */ - public $SMTPSecure = ''; - - /** - * Whether to enable TLS encryption automatically if a server supports it, - * even if `SMTPSecure` is not set to 'tls'. - * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid. - * @var boolean - */ - public $SMTPAutoTLS = true; - - /** - * Whether to use SMTP authentication. - * Uses the Username and Password properties. - * @var boolean - * @see PHPMailer::$Username - * @see PHPMailer::$Password - */ - public $SMTPAuth = false; - - /** - * Options array passed to stream_context_create when connecting via SMTP. - * @var array - */ - public $SMTPOptions = array(); - - /** - * SMTP username. - * @var string - */ - public $Username = ''; - - /** - * SMTP password. - * @var string - */ - public $Password = ''; - - /** - * SMTP auth type. - * Options are CRAM-MD5, LOGIN, PLAIN, NTLM, XOAUTH2, attempted in that order if not specified - * @var string - */ - public $AuthType = ''; - - /** - * SMTP realm. - * Used for NTLM auth - * @var string - */ - public $Realm = ''; - - /** - * SMTP workstation. - * Used for NTLM auth - * @var string - */ - public $Workstation = ''; - - /** - * The SMTP server timeout in seconds. - * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 - * @var integer - */ - public $Timeout = 300; - - /** - * SMTP class debug output mode. - * Debug output level. - * Options: - * * `0` No output - * * `1` Commands - * * `2` Data and commands - * * `3` As 2 plus connection status - * * `4` Low-level data output - * @var integer - * @see SMTP::$do_debug - */ - public $SMTPDebug = 0; - - /** - * How to handle debug output. - * Options: - * * `echo` Output plain-text as-is, appropriate for CLI - * * `html` Output escaped, line breaks converted to `
`, appropriate for browser output - * * `error_log` Output to error log as configured in php.ini - * - * Alternatively, you can provide a callable expecting two params: a message string and the debug level: - * - * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; - * - * @var string|callable - * @see SMTP::$Debugoutput - */ - public $Debugoutput = 'echo'; - - /** - * Whether to keep SMTP connection open after each message. - * If this is set to true then to close the connection - * requires an explicit call to smtpClose(). - * @var boolean - */ - public $SMTPKeepAlive = false; - - /** - * Whether to split multiple to addresses into multiple messages - * or send them all in one message. - * Only supported in `mail` and `sendmail` transports, not in SMTP. - * @var boolean - */ - public $SingleTo = false; - - /** - * Storage for addresses when SingleTo is enabled. - * @var array - * @TODO This should really not be public - */ - public $SingleToArray = array(); - - /** - * Whether to generate VERP addresses on send. - * Only applicable when sending via SMTP. - * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path - * @link http://www.postfix.org/VERP_README.html Postfix VERP info - * @var boolean - */ - public $do_verp = false; - - /** - * Whether to allow sending messages with an empty body. - * @var boolean - */ - public $AllowEmpty = false; - - /** - * The default line ending. - * @note The default remains "\n". We force CRLF where we know - * it must be used via self::CRLF. - * @var string - */ - public $LE = "\n"; - - /** - * DKIM selector. - * @var string - */ - public $DKIM_selector = ''; - - /** - * DKIM Identity. - * Usually the email address used as the source of the email. - * @var string - */ - public $DKIM_identity = ''; - - /** - * DKIM passphrase. - * Used if your key is encrypted. - * @var string - */ - public $DKIM_passphrase = ''; - - /** - * DKIM signing domain name. - * @example 'example.com' - * @var string - */ - public $DKIM_domain = ''; - - /** - * DKIM private key file path. - * @var string - */ - public $DKIM_private = ''; - - /** - * DKIM private key string. - * If set, takes precedence over `$DKIM_private`. - * @var string - */ - public $DKIM_private_string = ''; - - /** - * Callback Action function name. - * - * The function that handles the result of the send email action. - * It is called out by send() for each email sent. - * - * Value can be any php callable: http://www.php.net/is_callable - * - * Parameters: - * boolean $result result of the send action - * array $to email addresses of the recipients - * array $cc cc email addresses - * array $bcc bcc email addresses - * string $subject the subject - * string $body the email body - * string $from email address of sender - * @var string - */ - public $action_function = ''; - - /** - * What to put in the X-Mailer header. - * Options: An empty string for PHPMailer default, whitespace for none, or a string to use - * @var string - */ - public $XMailer = ''; - - /** - * Which validator to use by default when validating email addresses. - * May be a callable to inject your own validator, but there are several built-in validators. - * @see PHPMailer::validateAddress() - * @var string|callable - * @static - */ - public static $validator = 'auto'; - - /** - * An instance of the SMTP sender class. - * @var SMTP - * @access protected - */ - protected $smtp = null; - - /** - * The array of 'to' names and addresses. - * @var array - * @access protected - */ - protected $to = array(); - - /** - * The array of 'cc' names and addresses. - * @var array - * @access protected - */ - protected $cc = array(); - - /** - * The array of 'bcc' names and addresses. - * @var array - * @access protected - */ - protected $bcc = array(); - - /** - * The array of reply-to names and addresses. - * @var array - * @access protected - */ - protected $ReplyTo = array(); - - /** - * An array of all kinds of addresses. - * Includes all of $to, $cc, $bcc - * @var array - * @access protected - * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc - */ - protected $all_recipients = array(); - - /** - * An array of names and addresses queued for validation. - * In send(), valid and non duplicate entries are moved to $all_recipients - * and one of $to, $cc, or $bcc. - * This array is used only for addresses with IDN. - * @var array - * @access protected - * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc - * @see PHPMailer::$all_recipients - */ - protected $RecipientsQueue = array(); - - /** - * An array of reply-to names and addresses queued for validation. - * In send(), valid and non duplicate entries are moved to $ReplyTo. - * This array is used only for addresses with IDN. - * @var array - * @access protected - * @see PHPMailer::$ReplyTo - */ - protected $ReplyToQueue = array(); - - /** - * The array of attachments. - * @var array - * @access protected - */ - protected $attachment = array(); - - /** - * The array of custom headers. - * @var array - * @access protected - */ - protected $CustomHeader = array(); - - /** - * The most recent Message-ID (including angular brackets). - * @var string - * @access protected - */ - protected $lastMessageID = ''; - - /** - * The message's MIME type. - * @var string - * @access protected - */ - protected $message_type = ''; - - /** - * The array of MIME boundary strings. - * @var array - * @access protected - */ - protected $boundary = array(); - - /** - * The array of available languages. - * @var array - * @access protected - */ - protected $language = array(); - - /** - * The number of errors encountered. - * @var integer - * @access protected - */ - protected $error_count = 0; - - /** - * The S/MIME certificate file path. - * @var string - * @access protected - */ - protected $sign_cert_file = ''; - - /** - * The S/MIME key file path. - * @var string - * @access protected - */ - protected $sign_key_file = ''; - - /** - * The optional S/MIME extra certificates ("CA Chain") file path. - * @var string - * @access protected - */ - protected $sign_extracerts_file = ''; - - /** - * The S/MIME password for the key. - * Used only if the key is encrypted. - * @var string - * @access protected - */ - protected $sign_key_pass = ''; - - /** - * Whether to throw exceptions for errors. - * @var boolean - * @access protected - */ - protected $exceptions = false; - - /** - * Unique ID used for message ID and boundaries. - * @var string - * @access protected - */ - protected $uniqueid = ''; - - /** - * Error severity: message only, continue processing. - */ - const STOP_MESSAGE = 0; - - /** - * Error severity: message, likely ok to continue processing. - */ - const STOP_CONTINUE = 1; - - /** - * Error severity: message, plus full stop, critical error reached. - */ - const STOP_CRITICAL = 2; - - /** - * SMTP RFC standard line ending. - */ - const CRLF = "\r\n"; - - /** - * The maximum line length allowed by RFC 2822 section 2.1.1 - * @var integer - */ - const MAX_LINE_LENGTH = 998; - - /** - * Constructor. - * @param boolean $exceptions Should we throw external exceptions? - */ - public function __construct($exceptions = null) - { - if ($exceptions !== null) { - $this->exceptions = (boolean)$exceptions; - } - //Pick an appropriate debug output format automatically - $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html'); - } - - /** - * Destructor. - */ - public function __destruct() - { - //Close any open SMTP connection nicely - $this->smtpClose(); - } - - /** - * Call mail() in a safe_mode-aware fashion. - * Also, unless sendmail_path points to sendmail (or something that - * claims to be sendmail), don't pass params (not a perfect fix, - * but it will do) - * @param string $to To - * @param string $subject Subject - * @param string $body Message Body - * @param string $header Additional Header(s) - * @param string $params Params - * @access private - * @return boolean - */ - private function mailPassthru($to, $subject, $body, $header, $params) - { - //Check overloading of mail function to avoid double-encoding - if (ini_get('mbstring.func_overload') & 1) { - $subject = $this->secureHeader($subject); - } else { - $subject = $this->encodeHeader($this->secureHeader($subject)); - } - - //Can't use additional_parameters in safe_mode, calling mail() with null params breaks - //@link http://php.net/manual/en/function.mail.php - if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) { - $result = @mail($to, $subject, $body, $header); - } else { - $result = @mail($to, $subject, $body, $header, $params); - } - return $result; - } - /** - * Output debugging info via user-defined method. - * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug). - * @see PHPMailer::$Debugoutput - * @see PHPMailer::$SMTPDebug - * @param string $str - */ - protected function edebug($str) - { - if ($this->SMTPDebug <= 0) { - return; - } - //Avoid clash with built-in function names - if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) { - call_user_func($this->Debugoutput, $str, $this->SMTPDebug); - return; - } - switch ($this->Debugoutput) { - case 'error_log': - //Don't output, just log - error_log($str); - break; - case 'html': - //Cleans up output a bit for a better looking, HTML-safe output - echo htmlentities( - preg_replace('/[\r\n]+/', '', $str), - ENT_QUOTES, - 'UTF-8' - ) - . "
\n"; - break; - case 'echo': - default: - //Normalize line breaks - $str = preg_replace('/\r\n?/ms', "\n", $str); - echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( - "\n", - "\n \t ", - trim($str) - ) . "\n"; - } - } - - /** - * Sets message type to HTML or plain. - * @param boolean $isHtml True for HTML mode. - * @return void - */ - public function isHTML($isHtml = true) - { - if ($isHtml) { - $this->ContentType = 'text/html'; - } else { - $this->ContentType = 'text/plain'; - } - } - - /** - * Send messages using SMTP. - * @return void - */ - public function isSMTP() - { - $this->Mailer = 'smtp'; - } - - /** - * Send messages using PHP's mail() function. - * @return void - */ - public function isMail() - { - $this->Mailer = 'mail'; - } - - /** - * Send messages using $Sendmail. - * @return void - */ - public function isSendmail() - { - $ini_sendmail_path = ini_get('sendmail_path'); - - if (!stristr($ini_sendmail_path, 'sendmail')) { - $this->Sendmail = '/usr/sbin/sendmail'; - } else { - $this->Sendmail = $ini_sendmail_path; - } - $this->Mailer = 'sendmail'; - } - - /** - * Send messages using qmail. - * @return void - */ - public function isQmail() - { - $ini_sendmail_path = ini_get('sendmail_path'); - - if (!stristr($ini_sendmail_path, 'qmail')) { - $this->Sendmail = '/var/qmail/bin/qmail-inject'; - } else { - $this->Sendmail = $ini_sendmail_path; - } - $this->Mailer = 'qmail'; - } - - /** - * Add a "To" address. - * @param string $address The email address to send to - * @param string $name - * @return boolean true on success, false if address already used or invalid in some way - */ - public function addAddress($address, $name = '') - { - return $this->addOrEnqueueAnAddress('to', $address, $name); - } - - /** - * Add a "CC" address. - * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer. - * @param string $address The email address to send to - * @param string $name - * @return boolean true on success, false if address already used or invalid in some way - */ - public function addCC($address, $name = '') - { - return $this->addOrEnqueueAnAddress('cc', $address, $name); - } - - /** - * Add a "BCC" address. - * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer. - * @param string $address The email address to send to - * @param string $name - * @return boolean true on success, false if address already used or invalid in some way - */ - public function addBCC($address, $name = '') - { - return $this->addOrEnqueueAnAddress('bcc', $address, $name); - } - - /** - * Add a "Reply-To" address. - * @param string $address The email address to reply to - * @param string $name - * @return boolean true on success, false if address already used or invalid in some way - */ - public function addReplyTo($address, $name = '') - { - return $this->addOrEnqueueAnAddress('Reply-To', $address, $name); - } - - /** - * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer - * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still - * be modified after calling this function), addition of such addresses is delayed until send(). - * Addresses that have been added already return false, but do not throw exceptions. - * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo' - * @param string $address The email address to send, resp. to reply to - * @param string $name - * @throws phpmailerException - * @return boolean true on success, false if address already used or invalid in some way - * @access protected - */ - protected function addOrEnqueueAnAddress($kind, $address, $name) - { - $address = trim($address); - $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim - if (($pos = strrpos($address, '@')) === false) { - // At-sign is misssing. - $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; - $this->setError($error_message); - $this->edebug($error_message); - if ($this->exceptions) { - throw new phpmailerException($error_message); - } - return false; - } - $params = array($kind, $address, $name); - // Enqueue addresses with IDN until we know the PHPMailer::$CharSet. - if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) { - if ($kind != 'Reply-To') { - if (!array_key_exists($address, $this->RecipientsQueue)) { - $this->RecipientsQueue[$address] = $params; - return true; - } - } else { - if (!array_key_exists($address, $this->ReplyToQueue)) { - $this->ReplyToQueue[$address] = $params; - return true; - } - } - return false; - } - // Immediately add standard addresses without IDN. - return call_user_func_array(array($this, 'addAnAddress'), $params); - } - - /** - * Add an address to one of the recipient arrays or to the ReplyTo array. - * Addresses that have been added already return false, but do not throw exceptions. - * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo' - * @param string $address The email address to send, resp. to reply to - * @param string $name - * @throws phpmailerException - * @return boolean true on success, false if address already used or invalid in some way - * @access protected - */ - protected function addAnAddress($kind, $address, $name = '') - { - if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) { - $error_message = $this->lang('Invalid recipient kind: ') . $kind; - $this->setError($error_message); - $this->edebug($error_message); - if ($this->exceptions) { - throw new phpmailerException($error_message); - } - return false; - } - if (!$this->validateAddress($address)) { - $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; - $this->setError($error_message); - $this->edebug($error_message); - if ($this->exceptions) { - throw new phpmailerException($error_message); - } - return false; - } - if ($kind != 'Reply-To') { - if (!array_key_exists(strtolower($address), $this->all_recipients)) { - array_push($this->$kind, array($address, $name)); - $this->all_recipients[strtolower($address)] = true; - return true; - } - } else { - if (!array_key_exists(strtolower($address), $this->ReplyTo)) { - $this->ReplyTo[strtolower($address)] = array($address, $name); - return true; - } - } - return false; - } - - /** - * Parse and validate a string containing one or more RFC822-style comma-separated email addresses - * of the form "display name
" into an array of name/address pairs. - * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available. - * Note that quotes in the name part are removed. - * @param string $addrstr The address list string - * @param bool $useimap Whether to use the IMAP extension to parse the list - * @return array - * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation - */ - public function parseAddresses($addrstr, $useimap = true) - { - $addresses = array(); - if ($useimap and function_exists('imap_rfc822_parse_adrlist')) { - //Use this built-in parser if it's available - $list = imap_rfc822_parse_adrlist($addrstr, ''); - foreach ($list as $address) { - if ($address->host != '.SYNTAX-ERROR.') { - if ($this->validateAddress($address->mailbox . '@' . $address->host)) { - $addresses[] = array( - 'name' => (property_exists($address, 'personal') ? $address->personal : ''), - 'address' => $address->mailbox . '@' . $address->host - ); - } - } - } - } else { - //Use this simpler parser - $list = explode(',', $addrstr); - foreach ($list as $address) { - $address = trim($address); - //Is there a separate name part? - if (strpos($address, '<') === false) { - //No separate name, just use the whole thing - if ($this->validateAddress($address)) { - $addresses[] = array( - 'name' => '', - 'address' => $address - ); - } - } else { - list($name, $email) = explode('<', $address); - $email = trim(str_replace('>', '', $email)); - if ($this->validateAddress($email)) { - $addresses[] = array( - 'name' => trim(str_replace(array('"', "'"), '', $name)), - 'address' => $email - ); - } - } - } - } - return $addresses; - } - - /** - * Set the From and FromName properties. - * @param string $address - * @param string $name - * @param boolean $auto Whether to also set the Sender address, defaults to true - * @throws phpmailerException - * @return boolean - */ - public function setFrom($address, $name = '', $auto = true) - { - $address = trim($address); - $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim - // Don't validate now addresses with IDN. Will be done in send(). - if (($pos = strrpos($address, '@')) === false or - (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and - !$this->validateAddress($address)) { - $error_message = $this->lang('invalid_address') . " (setFrom) $address"; - $this->setError($error_message); - $this->edebug($error_message); - if ($this->exceptions) { - throw new phpmailerException($error_message); - } - return false; - } - $this->From = $address; - $this->FromName = $name; - if ($auto) { - if (empty($this->Sender)) { - $this->Sender = $address; - } - } - return true; - } - - /** - * Return the Message-ID header of the last email. - * Technically this is the value from the last time the headers were created, - * but it's also the message ID of the last sent message except in - * pathological cases. - * @return string - */ - public function getLastMessageID() - { - return $this->lastMessageID; - } - - /** - * Check that a string looks like an email address. - * @param string $address The email address to check - * @param string|callable $patternselect A selector for the validation pattern to use : - * * `auto` Pick best pattern automatically; - * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14; - * * `pcre` Use old PCRE implementation; - * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; - * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. - * * `noregex` Don't use a regex: super fast, really dumb. - * Alternatively you may pass in a callable to inject your own validator, for example: - * PHPMailer::validateAddress('user@example.com', function($address) { - * return (strpos($address, '@') !== false); - * }); - * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. - * @return boolean - * @static - * @access public - */ - public static function validateAddress($address, $patternselect = null) - { - if (is_null($patternselect)) { - $patternselect = self::$validator; - } - if (is_callable($patternselect)) { - return call_user_func($patternselect, $address); - } - //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 - if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) { - return false; - } - if (!$patternselect or $patternselect == 'auto') { - //Check this constant first so it works when extension_loaded() is disabled by safe mode - //Constant was added in PHP 5.2.4 - if (defined('PCRE_VERSION')) { - //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2 - if (version_compare(PCRE_VERSION, '8.0.3') >= 0) { - $patternselect = 'pcre8'; - } else { - $patternselect = 'pcre'; - } - } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) { - //Fall back to older PCRE - $patternselect = 'pcre'; - } else { - //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension - if (version_compare(PHP_VERSION, '5.2.0') >= 0) { - $patternselect = 'php'; - } else { - $patternselect = 'noregex'; - } - } - } - switch ($patternselect) { - case 'pcre8': - /** - * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains. - * @link http://squiloople.com/2009/12/20/email-address-validation/ - * @copyright 2009-2010 Michael Rushton - * Feel free to use and redistribute this code. But please keep this copyright notice. - */ - return (boolean)preg_match( - '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' . - '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' . - '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' . - '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' . - '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' . - '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' . - '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' . - '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' . - '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', - $address - ); - case 'pcre': - //An older regex that doesn't need a recent PCRE - return (boolean)preg_match( - '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' . - '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' . - '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' . - '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' . - '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' . - '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' . - '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' . - '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' . - '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' . - '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD', - $address - ); - case 'html5': - /** - * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements. - * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email) - */ - return (boolean)preg_match( - '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' . - '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD', - $address - ); - case 'noregex': - //No PCRE! Do something _very_ approximate! - //Check the address is 3 chars or longer and contains an @ that's not the first or last char - return (strlen($address) >= 3 - and strpos($address, '@') >= 1 - and strpos($address, '@') != strlen($address) - 1); - case 'php': - default: - return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL); - } - } - - /** - * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the - * "intl" and "mbstring" PHP extensions. - * @return bool "true" if required functions for IDN support are present - */ - public function idnSupported() - { - // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2. - return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding'); - } - - /** - * Converts IDN in given email address to its ASCII form, also known as punycode, if possible. - * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet. - * This function silently returns unmodified address if: - * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form) - * - Conversion to punycode is impossible (e.g. required PHP functions are not available) - * or fails for any reason (e.g. domain has characters not allowed in an IDN) - * @see PHPMailer::$CharSet - * @param string $address The email address to convert - * @return string The encoded address in ASCII form - */ - public function punyencodeAddress($address) - { - // Verify we have required functions, CharSet, and at-sign. - if ($this->idnSupported() and - !empty($this->CharSet) and - ($pos = strrpos($address, '@')) !== false) { - $domain = substr($address, ++$pos); - // Verify CharSet string is a valid one, and domain properly encoded in this CharSet. - if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) { - $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet); - if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ? - idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) : - idn_to_ascii($domain)) !== false) { - return substr($address, 0, $pos) . $punycode; - } - } - } - return $address; - } - - /** - * Create a message and send it. - * Uses the sending method specified by $Mailer. - * @throws phpmailerException - * @return boolean false on error - See the ErrorInfo property for details of the error. - */ - public function send() - { - try { - if (!$this->preSend()) { - return false; - } - return $this->postSend(); - } catch (phpmailerException $exc) { - $this->mailHeader = ''; - $this->setError($exc->getMessage()); - if ($this->exceptions) { - throw $exc; - } - return false; - } - } - - /** - * Prepare a message for sending. - * @throws phpmailerException - * @return boolean - */ - public function preSend() - { - try { - $this->error_count = 0; // Reset errors - $this->mailHeader = ''; - - // Dequeue recipient and Reply-To addresses with IDN - foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) { - $params[1] = $this->punyencodeAddress($params[1]); - call_user_func_array(array($this, 'addAnAddress'), $params); - } - if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) { - throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL); - } - - // Validate From, Sender, and ConfirmReadingTo addresses - foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) { - $this->$address_kind = trim($this->$address_kind); - if (empty($this->$address_kind)) { - continue; - } - $this->$address_kind = $this->punyencodeAddress($this->$address_kind); - if (!$this->validateAddress($this->$address_kind)) { - $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind; - $this->setError($error_message); - $this->edebug($error_message); - if ($this->exceptions) { - throw new phpmailerException($error_message); - } - return false; - } - } - - // Set whether the message is multipart/alternative - if ($this->alternativeExists()) { - $this->ContentType = 'multipart/alternative'; - } - - $this->setMessageType(); - // Refuse to send an empty message unless we are specifically allowing it - if (!$this->AllowEmpty and empty($this->Body)) { - throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL); - } - - // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding) - $this->MIMEHeader = ''; - $this->MIMEBody = $this->createBody(); - // createBody may have added some headers, so retain them - $tempheaders = $this->MIMEHeader; - $this->MIMEHeader = $this->createHeader(); - $this->MIMEHeader .= $tempheaders; - - // To capture the complete message when using mail(), create - // an extra header list which createHeader() doesn't fold in - if ($this->Mailer == 'mail') { - if (count($this->to) > 0) { - $this->mailHeader .= $this->addrAppend('To', $this->to); - } else { - $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;'); - } - $this->mailHeader .= $this->headerLine( - 'Subject', - $this->encodeHeader($this->secureHeader(trim($this->Subject))) - ); - } - - // Sign with DKIM if enabled - if (!empty($this->DKIM_domain) - && !empty($this->DKIM_selector) - && (!empty($this->DKIM_private_string) - || (!empty($this->DKIM_private) && file_exists($this->DKIM_private)) - ) - ) { - $header_dkim = $this->DKIM_Add( - $this->MIMEHeader . $this->mailHeader, - $this->encodeHeader($this->secureHeader($this->Subject)), - $this->MIMEBody - ); - $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF . - str_replace("\r\n", "\n", $header_dkim) . self::CRLF; - } - return true; - } catch (phpmailerException $exc) { - $this->setError($exc->getMessage()); - if ($this->exceptions) { - throw $exc; - } - return false; - } - } - - /** - * Actually send a message. - * Send the email via the selected mechanism - * @throws phpmailerException - * @return boolean - */ - public function postSend() - { - try { - // Choose the mailer and send through it - switch ($this->Mailer) { - case 'sendmail': - case 'qmail': - return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody); - case 'smtp': - return $this->smtpSend($this->MIMEHeader, $this->MIMEBody); - case 'mail': - return $this->mailSend($this->MIMEHeader, $this->MIMEBody); - default: - $sendMethod = $this->Mailer.'Send'; - if (method_exists($this, $sendMethod)) { - return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody); - } - - return $this->mailSend($this->MIMEHeader, $this->MIMEBody); - } - } catch (phpmailerException $exc) { - $this->setError($exc->getMessage()); - $this->edebug($exc->getMessage()); - if ($this->exceptions) { - throw $exc; - } - } - return false; - } - - /** - * Send mail using the $Sendmail program. - * @param string $header The message headers - * @param string $body The message body - * @see PHPMailer::$Sendmail - * @throws phpmailerException - * @access protected - * @return boolean - */ - protected function sendmailSend($header, $body) - { - // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. - if (!empty($this->Sender) and self::isShellSafe($this->Sender)) { - if ($this->Mailer == 'qmail') { - $sendmailFmt = '%s -f%s'; - } else { - $sendmailFmt = '%s -oi -f%s -t'; - } - } else { - if ($this->Mailer == 'qmail') { - $sendmailFmt = '%s'; - } else { - $sendmailFmt = '%s -oi -t'; - } - } - - // TODO: If possible, this should be changed to escapeshellarg. Needs thorough testing. - $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender); - - if ($this->SingleTo) { - foreach ($this->SingleToArray as $toAddr) { - if (!@$mail = popen($sendmail, 'w')) { - throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); - } - fputs($mail, 'To: ' . $toAddr . "\n"); - fputs($mail, $header); - fputs($mail, $body); - $result = pclose($mail); - $this->doCallback( - ($result == 0), - array($toAddr), - $this->cc, - $this->bcc, - $this->Subject, - $body, - $this->From - ); - if ($result != 0) { - throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); - } - } - } else { - if (!@$mail = popen($sendmail, 'w')) { - throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); - } - fputs($mail, $header); - fputs($mail, $body); - $result = pclose($mail); - $this->doCallback( - ($result == 0), - $this->to, - $this->cc, - $this->bcc, - $this->Subject, - $body, - $this->From - ); - if ($result != 0) { - throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); - } - } - return true; - } - - /** - * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters. - * - * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows. - * @param string $string The string to be validated - * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report - * @access protected - * @return boolean - */ - protected static function isShellSafe($string) - { - // Future-proof - if (escapeshellcmd($string) !== $string - or !in_array(escapeshellarg($string), array("'$string'", "\"$string\"")) - ) { - return false; - } - - $length = strlen($string); - - for ($i = 0; $i < $length; $i++) { - $c = $string[$i]; - - // All other characters have a special meaning in at least one common shell, including = and +. - // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here. - // Note that this does permit non-Latin alphanumeric characters based on the current locale. - if (!ctype_alnum($c) && strpos('@_-.', $c) === false) { - return false; - } - } - - return true; - } - - /** - * Send mail using the PHP mail() function. - * @param string $header The message headers - * @param string $body The message body - * @link http://www.php.net/manual/en/book.mail.php - * @throws phpmailerException - * @access protected - * @return boolean - */ - protected function mailSend($header, $body) - { - $toArr = array(); - foreach ($this->to as $toaddr) { - $toArr[] = $this->addrFormat($toaddr); - } - $to = implode(', ', $toArr); - - $params = null; - //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver - if (!empty($this->Sender) and $this->validateAddress($this->Sender)) { - // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. - if (self::isShellSafe($this->Sender)) { - $params = sprintf('-f%s', $this->Sender); - } - } - if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) { - $old_from = ini_get('sendmail_from'); - ini_set('sendmail_from', $this->Sender); - } - $result = false; - if ($this->SingleTo and count($toArr) > 1) { - foreach ($toArr as $toAddr) { - $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params); - $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From); - } - } else { - $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params); - $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From); - } - if (isset($old_from)) { - ini_set('sendmail_from', $old_from); - } - if (!$result) { - throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL); - } - return true; - } - - /** - * Get an instance to use for SMTP operations. - * Override this function to load your own SMTP implementation - * @return SMTP - */ - public function getSMTPInstance() - { - if (!is_object($this->smtp)) { - $this->smtp = new SMTP; - } - return $this->smtp; - } - - /** - * Send mail via SMTP. - * Returns false if there is a bad MAIL FROM, RCPT, or DATA input. - * Uses the PHPMailerSMTP class by default. - * @see PHPMailer::getSMTPInstance() to use a different class. - * @param string $header The message headers - * @param string $body The message body - * @throws phpmailerException - * @uses SMTP - * @access protected - * @return boolean - */ - protected function smtpSend($header, $body) - { - $bad_rcpt = array(); - if (!$this->smtpConnect($this->SMTPOptions)) { - throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL); - } - if (!empty($this->Sender) and $this->validateAddress($this->Sender)) { - $smtp_from = $this->Sender; - } else { - $smtp_from = $this->From; - } - if (!$this->smtp->mail($smtp_from)) { - $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError())); - throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL); - } - - // Attempt to send to all recipients - foreach (array($this->to, $this->cc, $this->bcc) as $togroup) { - foreach ($togroup as $to) { - if (!$this->smtp->recipient($to[0])) { - $error = $this->smtp->getError(); - $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']); - $isSent = false; - } else { - $isSent = true; - } - $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From); - } - } - - // Only send the DATA command if we have viable recipients - if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) { - throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL); - } - if ($this->SMTPKeepAlive) { - $this->smtp->reset(); - } else { - $this->smtp->quit(); - $this->smtp->close(); - } - //Create error message for any bad addresses - if (count($bad_rcpt) > 0) { - $errstr = ''; - foreach ($bad_rcpt as $bad) { - $errstr .= $bad['to'] . ': ' . $bad['error']; - } - throw new phpmailerException( - $this->lang('recipients_failed') . $errstr, - self::STOP_CONTINUE - ); - } - return true; - } - - /** - * Initiate a connection to an SMTP server. - * Returns false if the operation failed. - * @param array $options An array of options compatible with stream_context_create() - * @uses SMTP - * @access public - * @throws phpmailerException - * @return boolean - */ - public function smtpConnect($options = null) - { - if (is_null($this->smtp)) { - $this->smtp = $this->getSMTPInstance(); - } - - //If no options are provided, use whatever is set in the instance - if (is_null($options)) { - $options = $this->SMTPOptions; - } - - // Already connected? - if ($this->smtp->connected()) { - return true; - } - - $this->smtp->setTimeout($this->Timeout); - $this->smtp->setDebugLevel($this->SMTPDebug); - $this->smtp->setDebugOutput($this->Debugoutput); - $this->smtp->setVerp($this->do_verp); - $hosts = explode(';', $this->Host); - $lastexception = null; - - foreach ($hosts as $hostentry) { - $hostinfo = array(); - if (!preg_match( - '/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*|\[[a-fA-F0-9:]+\]):?([0-9]*)$/', - trim($hostentry), - $hostinfo - )) { - // Not a valid host entry - $this->edebug('Ignoring invalid host: ' . $hostentry); - continue; - } - // $hostinfo[2]: optional ssl or tls prefix - // $hostinfo[3]: the hostname - // $hostinfo[4]: optional port number - // The host string prefix can temporarily override the current setting for SMTPSecure - // If it's not specified, the default value is used - $prefix = ''; - $secure = $this->SMTPSecure; - $tls = ($this->SMTPSecure == 'tls'); - if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) { - $prefix = 'ssl://'; - $tls = false; // Can't have SSL and TLS at the same time - $secure = 'ssl'; - } elseif ($hostinfo[2] == 'tls') { - $tls = true; - // tls doesn't use a prefix - $secure = 'tls'; - } - //Do we need the OpenSSL extension? - $sslext = defined('OPENSSL_ALGO_SHA1'); - if ('tls' === $secure or 'ssl' === $secure) { - //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled - if (!$sslext) { - throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL); - } - } - $host = $hostinfo[3]; - $port = $this->Port; - $tport = (integer)$hostinfo[4]; - if ($tport > 0 and $tport < 65536) { - $port = $tport; - } - if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) { - try { - if ($this->Helo) { - $hello = $this->Helo; - } else { - $hello = $this->serverHostname(); - } - $this->smtp->hello($hello); - //Automatically enable TLS encryption if: - // * it's not disabled - // * we have openssl extension - // * we are not already using SSL - // * the server offers STARTTLS - if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) { - $tls = true; - } - if ($tls) { - if (!$this->smtp->startTLS()) { - throw new phpmailerException($this->lang('connect_host')); - } - // We must resend EHLO after TLS negotiation - $this->smtp->hello($hello); - } - if ($this->SMTPAuth) { - if (!$this->smtp->authenticate( - $this->Username, - $this->Password, - $this->AuthType, - $this->Realm, - $this->Workstation - ) - ) { - throw new phpmailerException($this->lang('authenticate')); - } - } - return true; - } catch (phpmailerException $exc) { - $lastexception = $exc; - $this->edebug($exc->getMessage()); - // We must have connected, but then failed TLS or Auth, so close connection nicely - $this->smtp->quit(); - } - } - } - // If we get here, all connection attempts have failed, so close connection hard - $this->smtp->close(); - // As we've caught all exceptions, just report whatever the last one was - if ($this->exceptions and !is_null($lastexception)) { - throw $lastexception; - } - return false; - } - - /** - * Close the active SMTP session if one exists. - * @return void - */ - public function smtpClose() - { - if (is_a($this->smtp, 'SMTP')) { - if ($this->smtp->connected()) { - $this->smtp->quit(); - $this->smtp->close(); - } - } - } - - /** - * Set the language for error messages. - * Returns false if it cannot load the language file. - * The default language is English. - * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr") - * @param string $lang_path Path to the language file directory, with trailing separator (slash) - * @return boolean - * @access public - */ - public function setLanguage($langcode = 'en', $lang_path = '') - { - // Backwards compatibility for renamed language codes - $renamed_langcodes = array( - 'br' => 'pt_br', - 'cz' => 'cs', - 'dk' => 'da', - 'no' => 'nb', - 'se' => 'sv', - 'sr' => 'rs' - ); - - if (isset($renamed_langcodes[$langcode])) { - $langcode = $renamed_langcodes[$langcode]; - } - - // Define full set of translatable strings in English - $PHPMAILER_LANG = array( - 'authenticate' => 'SMTP Error: Could not authenticate.', - 'connect_host' => 'SMTP Error: Could not connect to SMTP host.', - 'data_not_accepted' => 'SMTP Error: data not accepted.', - 'empty_message' => 'Message body empty', - 'encoding' => 'Unknown encoding: ', - 'execute' => 'Could not execute: ', - 'file_access' => 'Could not access file: ', - 'file_open' => 'File Error: Could not open file: ', - 'from_failed' => 'The following From address failed: ', - 'instantiate' => 'Could not instantiate mail function.', - 'invalid_address' => 'Invalid address: ', - 'mailer_not_supported' => ' mailer is not supported.', - 'provide_address' => 'You must provide at least one recipient email address.', - 'recipients_failed' => 'SMTP Error: The following recipients failed: ', - 'signing' => 'Signing Error: ', - 'smtp_connect_failed' => 'SMTP connect() failed.', - 'smtp_error' => 'SMTP server error: ', - 'variable_set' => 'Cannot set or reset variable: ', - 'extension_missing' => 'Extension missing: ' - ); - if (empty($lang_path)) { - // Calculate an absolute path so it can work if CWD is not here - $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR; - } - //Validate $langcode - if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) { - $langcode = 'en'; - } - $foundlang = true; - $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php'; - // There is no English translation file - if ($langcode != 'en') { - // Make sure language file path is readable - if (!is_readable($lang_file)) { - $foundlang = false; - } else { - // Overwrite language-specific strings. - // This way we'll never have missing translation keys. - $foundlang = include $lang_file; - } - } - $this->language = $PHPMAILER_LANG; - return (boolean)$foundlang; // Returns false if language not found - } - - /** - * Get the array of strings for the current language. - * @return array - */ - public function getTranslations() - { - return $this->language; - } - - /** - * Create recipient headers. - * @access public - * @param string $type - * @param array $addr An array of recipient, - * where each recipient is a 2-element indexed array with element 0 containing an address - * and element 1 containing a name, like: - * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User')) - * @return string - */ - public function addrAppend($type, $addr) - { - $addresses = array(); - foreach ($addr as $address) { - $addresses[] = $this->addrFormat($address); - } - return $type . ': ' . implode(', ', $addresses) . $this->LE; - } - - /** - * Format an address for use in a message header. - * @access public - * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name - * like array('joe@example.com', 'Joe User') - * @return string - */ - public function addrFormat($addr) - { - if (empty($addr[1])) { // No name provided - return $this->secureHeader($addr[0]); - } else { - return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader( - $addr[0] - ) . '>'; - } - } - - /** - * Word-wrap message. - * For use with mailers that do not automatically perform wrapping - * and for quoted-printable encoded messages. - * Original written by philippe. - * @param string $message The message to wrap - * @param integer $length The line length to wrap to - * @param boolean $qp_mode Whether to run in Quoted-Printable mode - * @access public - * @return string - */ - public function wrapText($message, $length, $qp_mode = false) - { - if ($qp_mode) { - $soft_break = sprintf(' =%s', $this->LE); - } else { - $soft_break = $this->LE; - } - // If utf-8 encoding is used, we will need to make sure we don't - // split multibyte characters when we wrap - $is_utf8 = (strtolower($this->CharSet) == 'utf-8'); - $lelen = strlen($this->LE); - $crlflen = strlen(self::CRLF); - - $message = $this->fixEOL($message); - //Remove a trailing line break - if (substr($message, -$lelen) == $this->LE) { - $message = substr($message, 0, -$lelen); - } - - //Split message into lines - $lines = explode($this->LE, $message); - //Message will be rebuilt in here - $message = ''; - foreach ($lines as $line) { - $words = explode(' ', $line); - $buf = ''; - $firstword = true; - foreach ($words as $word) { - if ($qp_mode and (strlen($word) > $length)) { - $space_left = $length - strlen($buf) - $crlflen; - if (!$firstword) { - if ($space_left > 20) { - $len = $space_left; - if ($is_utf8) { - $len = $this->utf8CharBoundary($word, $len); - } elseif (substr($word, $len - 1, 1) == '=') { - $len--; - } elseif (substr($word, $len - 2, 1) == '=') { - $len -= 2; - } - $part = substr($word, 0, $len); - $word = substr($word, $len); - $buf .= ' ' . $part; - $message .= $buf . sprintf('=%s', self::CRLF); - } else { - $message .= $buf . $soft_break; - } - $buf = ''; - } - while (strlen($word) > 0) { - if ($length <= 0) { - break; - } - $len = $length; - if ($is_utf8) { - $len = $this->utf8CharBoundary($word, $len); - } elseif (substr($word, $len - 1, 1) == '=') { - $len--; - } elseif (substr($word, $len - 2, 1) == '=') { - $len -= 2; - } - $part = substr($word, 0, $len); - $word = substr($word, $len); - - if (strlen($word) > 0) { - $message .= $part . sprintf('=%s', self::CRLF); - } else { - $buf = $part; - } - } - } else { - $buf_o = $buf; - if (!$firstword) { - $buf .= ' '; - } - $buf .= $word; - - if (strlen($buf) > $length and $buf_o != '') { - $message .= $buf_o . $soft_break; - $buf = $word; - } - } - $firstword = false; - } - $message .= $buf . self::CRLF; - } - - return $message; - } - - /** - * Find the last character boundary prior to $maxLength in a utf-8 - * quoted-printable encoded string. - * Original written by Colin Brown. - * @access public - * @param string $encodedText utf-8 QP text - * @param integer $maxLength Find the last character boundary prior to this length - * @return integer - */ - public function utf8CharBoundary($encodedText, $maxLength) - { - $foundSplitPos = false; - $lookBack = 3; - while (!$foundSplitPos) { - $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); - $encodedCharPos = strpos($lastChunk, '='); - if (false !== $encodedCharPos) { - // Found start of encoded character byte within $lookBack block. - // Check the encoded byte value (the 2 chars after the '=') - $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); - $dec = hexdec($hex); - if ($dec < 128) { - // Single byte character. - // If the encoded char was found at pos 0, it will fit - // otherwise reduce maxLength to start of the encoded char - if ($encodedCharPos > 0) { - $maxLength = $maxLength - ($lookBack - $encodedCharPos); - } - $foundSplitPos = true; - } elseif ($dec >= 192) { - // First byte of a multi byte character - // Reduce maxLength to split at start of character - $maxLength = $maxLength - ($lookBack - $encodedCharPos); - $foundSplitPos = true; - } elseif ($dec < 192) { - // Middle byte of a multi byte character, look further back - $lookBack += 3; - } - } else { - // No encoded character found - $foundSplitPos = true; - } - } - return $maxLength; - } - - /** - * Apply word wrapping to the message body. - * Wraps the message body to the number of chars set in the WordWrap property. - * You should only do this to plain-text bodies as wrapping HTML tags may break them. - * This is called automatically by createBody(), so you don't need to call it yourself. - * @access public - * @return void - */ - public function setWordWrap() - { - if ($this->WordWrap < 1) { - return; - } - - switch ($this->message_type) { - case 'alt': - case 'alt_inline': - case 'alt_attach': - case 'alt_inline_attach': - $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap); - break; - default: - $this->Body = $this->wrapText($this->Body, $this->WordWrap); - break; - } - } - - /** - * Assemble message headers. - * @access public - * @return string The assembled headers - */ - public function createHeader() - { - $result = ''; - - $result .= $this->headerLine('Date', $this->MessageDate == '' ? self::rfcDate() : $this->MessageDate); - - // To be created automatically by mail() - if ($this->SingleTo) { - if ($this->Mailer != 'mail') { - foreach ($this->to as $toaddr) { - $this->SingleToArray[] = $this->addrFormat($toaddr); - } - } - } else { - if (count($this->to) > 0) { - if ($this->Mailer != 'mail') { - $result .= $this->addrAppend('To', $this->to); - } - } elseif (count($this->cc) == 0) { - $result .= $this->headerLine('To', 'undisclosed-recipients:;'); - } - } - - $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName))); - - // sendmail and mail() extract Cc from the header before sending - if (count($this->cc) > 0) { - $result .= $this->addrAppend('Cc', $this->cc); - } - - // sendmail and mail() extract Bcc from the header before sending - if (( - $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail' - ) - and count($this->bcc) > 0 - ) { - $result .= $this->addrAppend('Bcc', $this->bcc); - } - - if (count($this->ReplyTo) > 0) { - $result .= $this->addrAppend('Reply-To', $this->ReplyTo); - } - - // mail() sets the subject itself - if ($this->Mailer != 'mail') { - $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject))); - } - - // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4 - // https://tools.ietf.org/html/rfc5322#section-3.6.4 - if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) { - $this->lastMessageID = $this->MessageID; - } else { - $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname()); - } - $result .= $this->headerLine('Message-ID', $this->lastMessageID); - if (!is_null($this->Priority)) { - $result .= $this->headerLine('X-Priority', $this->Priority); - } - if ($this->XMailer == '') { - $result .= $this->headerLine( - 'X-Mailer', - 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)' - ); - } else { - $myXmailer = trim($this->XMailer); - if ($myXmailer) { - $result .= $this->headerLine('X-Mailer', $myXmailer); - } - } - - if ($this->ConfirmReadingTo != '') { - $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>'); - } - - // Add custom headers - foreach ($this->CustomHeader as $header) { - $result .= $this->headerLine( - trim($header[0]), - $this->encodeHeader(trim($header[1])) - ); - } - if (!$this->sign_key_file) { - $result .= $this->headerLine('MIME-Version', '1.0'); - $result .= $this->getMailMIME(); - } - - return $result; - } - - /** - * Get the message MIME type headers. - * @access public - * @return string - */ - public function getMailMIME() - { - $result = ''; - $ismultipart = true; - switch ($this->message_type) { - case 'inline': - $result .= $this->headerLine('Content-Type', 'multipart/related;'); - $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); - break; - case 'attach': - case 'inline_attach': - case 'alt_attach': - case 'alt_inline_attach': - $result .= $this->headerLine('Content-Type', 'multipart/mixed;'); - $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); - break; - case 'alt': - case 'alt_inline': - $result .= $this->headerLine('Content-Type', 'multipart/alternative;'); - $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); - break; - default: - // Catches case 'plain': and case '': - $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet); - $ismultipart = false; - break; - } - // RFC1341 part 5 says 7bit is assumed if not specified - if ($this->Encoding != '7bit') { - // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE - if ($ismultipart) { - if ($this->Encoding == '8bit') { - $result .= $this->headerLine('Content-Transfer-Encoding', '8bit'); - } - // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible - } else { - $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding); - } - } - - if ($this->Mailer != 'mail') { - $result .= $this->LE; - } - - return $result; - } - - /** - * Returns the whole MIME message. - * Includes complete headers and body. - * Only valid post preSend(). - * @see PHPMailer::preSend() - * @access public - * @return string - */ - public function getSentMIMEMessage() - { - return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody; - } - - /** - * Create unique ID - * @return string - */ - protected function generateId() { - return md5(uniqid(time())); - } - - /** - * Assemble the message body. - * Returns an empty string on failure. - * @access public - * @throws phpmailerException - * @return string The assembled message body - */ - public function createBody() - { - $body = ''; - //Create unique IDs and preset boundaries - $this->uniqueid = $this->generateId(); - $this->boundary[1] = 'b1_' . $this->uniqueid; - $this->boundary[2] = 'b2_' . $this->uniqueid; - $this->boundary[3] = 'b3_' . $this->uniqueid; - - if ($this->sign_key_file) { - $body .= $this->getMailMIME() . $this->LE; - } - - $this->setWordWrap(); - - $bodyEncoding = $this->Encoding; - $bodyCharSet = $this->CharSet; - //Can we do a 7-bit downgrade? - if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) { - $bodyEncoding = '7bit'; - //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit - $bodyCharSet = 'us-ascii'; - } - //If lines are too long, and we're not already using an encoding that will shorten them, - //change to quoted-printable transfer encoding for the body part only - if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) { - $bodyEncoding = 'quoted-printable'; - } - - $altBodyEncoding = $this->Encoding; - $altBodyCharSet = $this->CharSet; - //Can we do a 7-bit downgrade? - if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) { - $altBodyEncoding = '7bit'; - //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit - $altBodyCharSet = 'us-ascii'; - } - //If lines are too long, and we're not already using an encoding that will shorten them, - //change to quoted-printable transfer encoding for the alt body part only - if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) { - $altBodyEncoding = 'quoted-printable'; - } - //Use this as a preamble in all multipart message types - $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE; - switch ($this->message_type) { - case 'inline': - $body .= $mimepre; - $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); - $body .= $this->encodeString($this->Body, $bodyEncoding); - $body .= $this->LE . $this->LE; - $body .= $this->attachAll('inline', $this->boundary[1]); - break; - case 'attach': - $body .= $mimepre; - $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); - $body .= $this->encodeString($this->Body, $bodyEncoding); - $body .= $this->LE . $this->LE; - $body .= $this->attachAll('attachment', $this->boundary[1]); - break; - case 'inline_attach': - $body .= $mimepre; - $body .= $this->textLine('--' . $this->boundary[1]); - $body .= $this->headerLine('Content-Type', 'multipart/related;'); - $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); - $body .= $this->LE; - $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding); - $body .= $this->encodeString($this->Body, $bodyEncoding); - $body .= $this->LE . $this->LE; - $body .= $this->attachAll('inline', $this->boundary[2]); - $body .= $this->LE; - $body .= $this->attachAll('attachment', $this->boundary[1]); - break; - case 'alt': - $body .= $mimepre; - $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); - $body .= $this->encodeString($this->AltBody, $altBodyEncoding); - $body .= $this->LE . $this->LE; - $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding); - $body .= $this->encodeString($this->Body, $bodyEncoding); - $body .= $this->LE . $this->LE; - if (!empty($this->Ical)) { - $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', ''); - $body .= $this->encodeString($this->Ical, $this->Encoding); - $body .= $this->LE . $this->LE; - } - $body .= $this->endBoundary($this->boundary[1]); - break; - case 'alt_inline': - $body .= $mimepre; - $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); - $body .= $this->encodeString($this->AltBody, $altBodyEncoding); - $body .= $this->LE . $this->LE; - $body .= $this->textLine('--' . $this->boundary[1]); - $body .= $this->headerLine('Content-Type', 'multipart/related;'); - $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); - $body .= $this->LE; - $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); - $body .= $this->encodeString($this->Body, $bodyEncoding); - $body .= $this->LE . $this->LE; - $body .= $this->attachAll('inline', $this->boundary[2]); - $body .= $this->LE; - $body .= $this->endBoundary($this->boundary[1]); - break; - case 'alt_attach': - $body .= $mimepre; - $body .= $this->textLine('--' . $this->boundary[1]); - $body .= $this->headerLine('Content-Type', 'multipart/alternative;'); - $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); - $body .= $this->LE; - $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); - $body .= $this->encodeString($this->AltBody, $altBodyEncoding); - $body .= $this->LE . $this->LE; - $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); - $body .= $this->encodeString($this->Body, $bodyEncoding); - $body .= $this->LE . $this->LE; - $body .= $this->endBoundary($this->boundary[2]); - $body .= $this->LE; - $body .= $this->attachAll('attachment', $this->boundary[1]); - break; - case 'alt_inline_attach': - $body .= $mimepre; - $body .= $this->textLine('--' . $this->boundary[1]); - $body .= $this->headerLine('Content-Type', 'multipart/alternative;'); - $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); - $body .= $this->LE; - $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); - $body .= $this->encodeString($this->AltBody, $altBodyEncoding); - $body .= $this->LE . $this->LE; - $body .= $this->textLine('--' . $this->boundary[2]); - $body .= $this->headerLine('Content-Type', 'multipart/related;'); - $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"'); - $body .= $this->LE; - $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding); - $body .= $this->encodeString($this->Body, $bodyEncoding); - $body .= $this->LE . $this->LE; - $body .= $this->attachAll('inline', $this->boundary[3]); - $body .= $this->LE; - $body .= $this->endBoundary($this->boundary[2]); - $body .= $this->LE; - $body .= $this->attachAll('attachment', $this->boundary[1]); - break; - default: - // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types - //Reset the `Encoding` property in case we changed it for line length reasons - $this->Encoding = $bodyEncoding; - $body .= $this->encodeString($this->Body, $this->Encoding); - break; - } - - if ($this->isError()) { - $body = ''; - } elseif ($this->sign_key_file) { - try { - if (!defined('PKCS7_TEXT')) { - throw new phpmailerException($this->lang('extension_missing') . 'openssl'); - } - // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1 - $file = tempnam(sys_get_temp_dir(), 'mail'); - if (false === file_put_contents($file, $body)) { - throw new phpmailerException($this->lang('signing') . ' Could not write temp file'); - } - $signed = tempnam(sys_get_temp_dir(), 'signed'); - //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197 - if (empty($this->sign_extracerts_file)) { - $sign = @openssl_pkcs7_sign( - $file, - $signed, - 'file://' . realpath($this->sign_cert_file), - array('file://' . realpath($this->sign_key_file), $this->sign_key_pass), - null - ); - } else { - $sign = @openssl_pkcs7_sign( - $file, - $signed, - 'file://' . realpath($this->sign_cert_file), - array('file://' . realpath($this->sign_key_file), $this->sign_key_pass), - null, - PKCS7_DETACHED, - $this->sign_extracerts_file - ); - } - if ($sign) { - @unlink($file); - $body = file_get_contents($signed); - @unlink($signed); - //The message returned by openssl contains both headers and body, so need to split them up - $parts = explode("\n\n", $body, 2); - $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE; - $body = $parts[1]; - } else { - @unlink($file); - @unlink($signed); - throw new phpmailerException($this->lang('signing') . openssl_error_string()); - } - } catch (phpmailerException $exc) { - $body = ''; - if ($this->exceptions) { - throw $exc; - } - } - } - return $body; - } - - /** - * Return the start of a message boundary. - * @access protected - * @param string $boundary - * @param string $charSet - * @param string $contentType - * @param string $encoding - * @return string - */ - protected function getBoundary($boundary, $charSet, $contentType, $encoding) - { - $result = ''; - if ($charSet == '') { - $charSet = $this->CharSet; - } - if ($contentType == '') { - $contentType = $this->ContentType; - } - if ($encoding == '') { - $encoding = $this->Encoding; - } - $result .= $this->textLine('--' . $boundary); - $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet); - $result .= $this->LE; - // RFC1341 part 5 says 7bit is assumed if not specified - if ($encoding != '7bit') { - $result .= $this->headerLine('Content-Transfer-Encoding', $encoding); - } - $result .= $this->LE; - - return $result; - } - - /** - * Return the end of a message boundary. - * @access protected - * @param string $boundary - * @return string - */ - protected function endBoundary($boundary) - { - return $this->LE . '--' . $boundary . '--' . $this->LE; - } - - /** - * Set the message type. - * PHPMailer only supports some preset message types, not arbitrary MIME structures. - * @access protected - * @return void - */ - protected function setMessageType() - { - $type = array(); - if ($this->alternativeExists()) { - $type[] = 'alt'; - } - if ($this->inlineImageExists()) { - $type[] = 'inline'; - } - if ($this->attachmentExists()) { - $type[] = 'attach'; - } - $this->message_type = implode('_', $type); - if ($this->message_type == '') { - //The 'plain' message_type refers to the message having a single body element, not that it is plain-text - $this->message_type = 'plain'; - } - } - - /** - * Format a header line. - * @access public - * @param string $name - * @param string $value - * @return string - */ - public function headerLine($name, $value) - { - return $name . ': ' . $value . $this->LE; - } - - /** - * Return a formatted mail line. - * @access public - * @param string $value - * @return string - */ - public function textLine($value) - { - return $value . $this->LE; - } - - /** - * Add an attachment from a path on the filesystem. - * Never use a user-supplied path to a file! - * Returns false if the file could not be found or read. - * @param string $path Path to the attachment. - * @param string $name Overrides the attachment name. - * @param string $encoding File encoding (see $Encoding). - * @param string $type File extension (MIME) type. - * @param string $disposition Disposition to use - * @throws phpmailerException - * @return boolean - */ - public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment') - { - try { - if (!@is_file($path)) { - throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE); - } - - // If a MIME type is not specified, try to work it out from the file name - if ($type == '') { - $type = self::filenameToType($path); - } - - $filename = basename($path); - if ($name == '') { - $name = $filename; - } - - $this->attachment[] = array( - 0 => $path, - 1 => $filename, - 2 => $name, - 3 => $encoding, - 4 => $type, - 5 => false, // isStringAttachment - 6 => $disposition, - 7 => 0 - ); - - } catch (phpmailerException $exc) { - $this->setError($exc->getMessage()); - $this->edebug($exc->getMessage()); - if ($this->exceptions) { - throw $exc; - } - return false; - } - return true; - } - - /** - * Return the array of attachments. - * @return array - */ - public function getAttachments() - { - return $this->attachment; - } - - /** - * Attach all file, string, and binary attachments to the message. - * Returns an empty string on failure. - * @access protected - * @param string $disposition_type - * @param string $boundary - * @return string - */ - protected function attachAll($disposition_type, $boundary) - { - // Return text of body - $mime = array(); - $cidUniq = array(); - $incl = array(); - - // Add all attachments - foreach ($this->attachment as $attachment) { - // Check if it is a valid disposition_filter - if ($attachment[6] == $disposition_type) { - // Check for string attachment - $string = ''; - $path = ''; - $bString = $attachment[5]; - if ($bString) { - $string = $attachment[0]; - } else { - $path = $attachment[0]; - } - - $inclhash = md5(serialize($attachment)); - if (in_array($inclhash, $incl)) { - continue; - } - $incl[] = $inclhash; - $name = $attachment[2]; - $encoding = $attachment[3]; - $type = $attachment[4]; - $disposition = $attachment[6]; - $cid = $attachment[7]; - if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) { - continue; - } - $cidUniq[$cid] = true; - - $mime[] = sprintf('--%s%s', $boundary, $this->LE); - //Only include a filename property if we have one - if (!empty($name)) { - $mime[] = sprintf( - 'Content-Type: %s; name="%s"%s', - $type, - $this->encodeHeader($this->secureHeader($name)), - $this->LE - ); - } else { - $mime[] = sprintf( - 'Content-Type: %s%s', - $type, - $this->LE - ); - } - // RFC1341 part 5 says 7bit is assumed if not specified - if ($encoding != '7bit') { - $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE); - } - - if ($disposition == 'inline') { - $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE); - } - - // If a filename contains any of these chars, it should be quoted, - // but not otherwise: RFC2183 & RFC2045 5.1 - // Fixes a warning in IETF's msglint MIME checker - // Allow for bypassing the Content-Disposition header totally - if (!(empty($disposition))) { - $encoded_name = $this->encodeHeader($this->secureHeader($name)); - if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) { - $mime[] = sprintf( - 'Content-Disposition: %s; filename="%s"%s', - $disposition, - $encoded_name, - $this->LE . $this->LE - ); - } else { - if (!empty($encoded_name)) { - $mime[] = sprintf( - 'Content-Disposition: %s; filename=%s%s', - $disposition, - $encoded_name, - $this->LE . $this->LE - ); - } else { - $mime[] = sprintf( - 'Content-Disposition: %s%s', - $disposition, - $this->LE . $this->LE - ); - } - } - } else { - $mime[] = $this->LE; - } - - // Encode as string attachment - if ($bString) { - $mime[] = $this->encodeString($string, $encoding); - if ($this->isError()) { - return ''; - } - $mime[] = $this->LE . $this->LE; - } else { - $mime[] = $this->encodeFile($path, $encoding); - if ($this->isError()) { - return ''; - } - $mime[] = $this->LE . $this->LE; - } - } - } - - $mime[] = sprintf('--%s--%s', $boundary, $this->LE); - - return implode('', $mime); - } - - /** - * Encode a file attachment in requested format. - * Returns an empty string on failure. - * @param string $path The full path to the file - * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' - * @throws phpmailerException - * @access protected - * @return string - */ - protected function encodeFile($path, $encoding = 'base64') - { - try { - if (!is_readable($path)) { - throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE); - } - $magic_quotes = get_magic_quotes_runtime(); - if ($magic_quotes) { - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - set_magic_quotes_runtime(false); - } else { - //Doesn't exist in PHP 5.4, but we don't need to check because - //get_magic_quotes_runtime always returns false in 5.4+ - //so it will never get here - ini_set('magic_quotes_runtime', false); - } - } - $file_buffer = file_get_contents($path); - $file_buffer = $this->encodeString($file_buffer, $encoding); - if ($magic_quotes) { - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - set_magic_quotes_runtime($magic_quotes); - } else { - ini_set('magic_quotes_runtime', $magic_quotes); - } - } - return $file_buffer; - } catch (Exception $exc) { - $this->setError($exc->getMessage()); - return ''; - } - } - - /** - * Encode a string in requested format. - * Returns an empty string on failure. - * @param string $str The text to encode - * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' - * @access public - * @return string - */ - public function encodeString($str, $encoding = 'base64') - { - $encoded = ''; - switch (strtolower($encoding)) { - case 'base64': - $encoded = chunk_split(base64_encode($str), 76, $this->LE); - break; - case '7bit': - case '8bit': - $encoded = $this->fixEOL($str); - // Make sure it ends with a line break - if (substr($encoded, -(strlen($this->LE))) != $this->LE) { - $encoded .= $this->LE; - } - break; - case 'binary': - $encoded = $str; - break; - case 'quoted-printable': - $encoded = $this->encodeQP($str); - break; - default: - $this->setError($this->lang('encoding') . $encoding); - break; - } - return $encoded; - } - - /** - * Encode a header string optimally. - * Picks shortest of Q, B, quoted-printable or none. - * @access public - * @param string $str - * @param string $position - * @return string - */ - public function encodeHeader($str, $position = 'text') - { - $matchcount = 0; - switch (strtolower($position)) { - case 'phrase': - if (!preg_match('/[\200-\377]/', $str)) { - // Can't use addslashes as we don't know the value of magic_quotes_sybase - $encoded = addcslashes($str, "\0..\37\177\\\""); - if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { - return ($encoded); - } else { - return ("\"$encoded\""); - } - } - $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); - break; - /** @noinspection PhpMissingBreakStatementInspection */ - case 'comment': - $matchcount = preg_match_all('/[()"]/', $str, $matches); - // Intentional fall-through - case 'text': - default: - $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); - break; - } - - //There are no chars that need encoding - if ($matchcount == 0) { - return ($str); - } - - $maxlen = 75 - 7 - strlen($this->CharSet); - // Try to select the encoding which should produce the shortest output - if ($matchcount > strlen($str) / 3) { - // More than a third of the content will need encoding, so B encoding will be most efficient - $encoding = 'B'; - if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) { - // Use a custom function which correctly encodes and wraps long - // multibyte strings without breaking lines within a character - $encoded = $this->base64EncodeWrapMB($str, "\n"); - } else { - $encoded = base64_encode($str); - $maxlen -= $maxlen % 4; - $encoded = trim(chunk_split($encoded, $maxlen, "\n")); - } - } else { - $encoding = 'Q'; - $encoded = $this->encodeQ($str, $position); - $encoded = $this->wrapText($encoded, $maxlen, true); - $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded)); - } - - $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded); - $encoded = trim(str_replace("\n", $this->LE, $encoded)); - - return $encoded; - } - - /** - * Check if a string contains multi-byte characters. - * @access public - * @param string $str multi-byte text to wrap encode - * @return boolean - */ - public function hasMultiBytes($str) - { - if (function_exists('mb_strlen')) { - return (strlen($str) > mb_strlen($str, $this->CharSet)); - } else { // Assume no multibytes (we can't handle without mbstring functions anyway) - return false; - } - } - - /** - * Does a string contain any 8-bit chars (in any charset)? - * @param string $text - * @return boolean - */ - public function has8bitChars($text) - { - return (boolean)preg_match('/[\x80-\xFF]/', $text); - } - - /** - * Encode and wrap long multibyte strings for mail headers - * without breaking lines within a character. - * Adapted from a function by paravoid - * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283 - * @access public - * @param string $str multi-byte text to wrap encode - * @param string $linebreak string to use as linefeed/end-of-line - * @return string - */ - public function base64EncodeWrapMB($str, $linebreak = null) - { - $start = '=?' . $this->CharSet . '?B?'; - $end = '?='; - $encoded = ''; - if ($linebreak === null) { - $linebreak = $this->LE; - } - - $mb_length = mb_strlen($str, $this->CharSet); - // Each line must have length <= 75, including $start and $end - $length = 75 - strlen($start) - strlen($end); - // Average multi-byte ratio - $ratio = $mb_length / strlen($str); - // Base64 has a 4:3 ratio - $avgLength = floor($length * $ratio * .75); - - for ($i = 0; $i < $mb_length; $i += $offset) { - $lookBack = 0; - do { - $offset = $avgLength - $lookBack; - $chunk = mb_substr($str, $i, $offset, $this->CharSet); - $chunk = base64_encode($chunk); - $lookBack++; - } while (strlen($chunk) > $length); - $encoded .= $chunk . $linebreak; - } - - // Chomp the last linefeed - $encoded = substr($encoded, 0, -strlen($linebreak)); - return $encoded; - } - - /** - * Encode a string in quoted-printable format. - * According to RFC2045 section 6.7. - * @access public - * @param string $string The text to encode - * @param integer $line_max Number of chars allowed on a line before wrapping - * @return string - * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment - */ - public function encodeQP($string, $line_max = 76) - { - // Use native function if it's available (>= PHP5.3) - if (function_exists('quoted_printable_encode')) { - return quoted_printable_encode($string); - } - // Fall back to a pure PHP implementation - $string = str_replace( - array('%20', '%0D%0A.', '%0D%0A', '%'), - array(' ', "\r\n=2E", "\r\n", '='), - rawurlencode($string) - ); - return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string); - } - - /** - * Backward compatibility wrapper for an old QP encoding function that was removed. - * @see PHPMailer::encodeQP() - * @access public - * @param string $string - * @param integer $line_max - * @param boolean $space_conv - * @return string - * @deprecated Use encodeQP instead. - */ - public function encodeQPphp( - $string, - $line_max = 76, - /** @noinspection PhpUnusedParameterInspection */ $space_conv = false - ) { - return $this->encodeQP($string, $line_max); - } - - /** - * Encode a string using Q encoding. - * @link http://tools.ietf.org/html/rfc2047 - * @param string $str the text to encode - * @param string $position Where the text is going to be used, see the RFC for what that means - * @access public - * @return string - */ - public function encodeQ($str, $position = 'text') - { - // There should not be any EOL in the string - $pattern = ''; - $encoded = str_replace(array("\r", "\n"), '', $str); - switch (strtolower($position)) { - case 'phrase': - // RFC 2047 section 5.3 - $pattern = '^A-Za-z0-9!*+\/ -'; - break; - /** @noinspection PhpMissingBreakStatementInspection */ - case 'comment': - // RFC 2047 section 5.2 - $pattern = '\(\)"'; - // intentional fall-through - // for this reason we build the $pattern without including delimiters and [] - case 'text': - default: - // RFC 2047 section 5.1 - // Replace every high ascii, control, =, ? and _ characters - $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern; - break; - } - $matches = array(); - if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) { - // If the string contains an '=', make sure it's the first thing we replace - // so as to avoid double-encoding - $eqkey = array_search('=', $matches[0]); - if (false !== $eqkey) { - unset($matches[0][$eqkey]); - array_unshift($matches[0], '='); - } - foreach (array_unique($matches[0]) as $char) { - $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded); - } - } - // Replace every spaces to _ (more readable than =20) - return str_replace(' ', '_', $encoded); - } - - /** - * Add a string or binary attachment (non-filesystem). - * This method can be used to attach ascii or binary data, - * such as a BLOB record from a database. - * @param string $string String attachment data. - * @param string $filename Name of the attachment. - * @param string $encoding File encoding (see $Encoding). - * @param string $type File extension (MIME) type. - * @param string $disposition Disposition to use - * @return void - */ - public function addStringAttachment( - $string, - $filename, - $encoding = 'base64', - $type = '', - $disposition = 'attachment' - ) { - // If a MIME type is not specified, try to work it out from the file name - if ($type == '') { - $type = self::filenameToType($filename); - } - // Append to $attachment array - $this->attachment[] = array( - 0 => $string, - 1 => $filename, - 2 => basename($filename), - 3 => $encoding, - 4 => $type, - 5 => true, // isStringAttachment - 6 => $disposition, - 7 => 0 - ); - } - - /** - * Add an embedded (inline) attachment from a file. - * This can include images, sounds, and just about any other document type. - * These differ from 'regular' attachments in that they are intended to be - * displayed inline with the message, not just attached for download. - * This is used in HTML messages that embed the images - * the HTML refers to using the $cid value. - * Never use a user-supplied path to a file! - * @param string $path Path to the attachment. - * @param string $cid Content ID of the attachment; Use this to reference - * the content when using an embedded image in HTML. - * @param string $name Overrides the attachment name. - * @param string $encoding File encoding (see $Encoding). - * @param string $type File MIME type. - * @param string $disposition Disposition to use - * @return boolean True on successfully adding an attachment - */ - public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline') - { - if (!@is_file($path)) { - $this->setError($this->lang('file_access') . $path); - return false; - } - - // If a MIME type is not specified, try to work it out from the file name - if ($type == '') { - $type = self::filenameToType($path); - } - - $filename = basename($path); - if ($name == '') { - $name = $filename; - } - - // Append to $attachment array - $this->attachment[] = array( - 0 => $path, - 1 => $filename, - 2 => $name, - 3 => $encoding, - 4 => $type, - 5 => false, // isStringAttachment - 6 => $disposition, - 7 => $cid - ); - return true; - } - - /** - * Add an embedded stringified attachment. - * This can include images, sounds, and just about any other document type. - * Be sure to set the $type to an image type for images: - * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'. - * @param string $string The attachment binary data. - * @param string $cid Content ID of the attachment; Use this to reference - * the content when using an embedded image in HTML. - * @param string $name - * @param string $encoding File encoding (see $Encoding). - * @param string $type MIME type. - * @param string $disposition Disposition to use - * @return boolean True on successfully adding an attachment - */ - public function addStringEmbeddedImage( - $string, - $cid, - $name = '', - $encoding = 'base64', - $type = '', - $disposition = 'inline' - ) { - // If a MIME type is not specified, try to work it out from the name - if ($type == '' and !empty($name)) { - $type = self::filenameToType($name); - } - - // Append to $attachment array - $this->attachment[] = array( - 0 => $string, - 1 => $name, - 2 => $name, - 3 => $encoding, - 4 => $type, - 5 => true, // isStringAttachment - 6 => $disposition, - 7 => $cid - ); - return true; - } - - /** - * Check if an inline attachment is present. - * @access public - * @return boolean - */ - public function inlineImageExists() - { - foreach ($this->attachment as $attachment) { - if ($attachment[6] == 'inline') { - return true; - } - } - return false; - } - - /** - * Check if an attachment (non-inline) is present. - * @return boolean - */ - public function attachmentExists() - { - foreach ($this->attachment as $attachment) { - if ($attachment[6] == 'attachment') { - return true; - } - } - return false; - } - - /** - * Check if this message has an alternative body set. - * @return boolean - */ - public function alternativeExists() - { - return !empty($this->AltBody); - } - - /** - * Clear queued addresses of given kind. - * @access protected - * @param string $kind 'to', 'cc', or 'bcc' - * @return void - */ - public function clearQueuedAddresses($kind) - { - $RecipientsQueue = $this->RecipientsQueue; - foreach ($RecipientsQueue as $address => $params) { - if ($params[0] == $kind) { - unset($this->RecipientsQueue[$address]); - } - } - } - - /** - * Clear all To recipients. - * @return void - */ - public function clearAddresses() - { - foreach ($this->to as $to) { - unset($this->all_recipients[strtolower($to[0])]); - } - $this->to = array(); - $this->clearQueuedAddresses('to'); - } - - /** - * Clear all CC recipients. - * @return void - */ - public function clearCCs() - { - foreach ($this->cc as $cc) { - unset($this->all_recipients[strtolower($cc[0])]); - } - $this->cc = array(); - $this->clearQueuedAddresses('cc'); - } - - /** - * Clear all BCC recipients. - * @return void - */ - public function clearBCCs() - { - foreach ($this->bcc as $bcc) { - unset($this->all_recipients[strtolower($bcc[0])]); - } - $this->bcc = array(); - $this->clearQueuedAddresses('bcc'); - } - - /** - * Clear all ReplyTo recipients. - * @return void - */ - public function clearReplyTos() - { - $this->ReplyTo = array(); - $this->ReplyToQueue = array(); - } - - /** - * Clear all recipient types. - * @return void - */ - public function clearAllRecipients() - { - $this->to = array(); - $this->cc = array(); - $this->bcc = array(); - $this->all_recipients = array(); - $this->RecipientsQueue = array(); - } - - /** - * Clear all filesystem, string, and binary attachments. - * @return void - */ - public function clearAttachments() - { - $this->attachment = array(); - } - - /** - * Clear all custom headers. - * @return void - */ - public function clearCustomHeaders() - { - $this->CustomHeader = array(); - } - - /** - * Add an error message to the error container. - * @access protected - * @param string $msg - * @return void - */ - protected function setError($msg) - { - $this->error_count++; - if ($this->Mailer == 'smtp' and !is_null($this->smtp)) { - $lasterror = $this->smtp->getError(); - if (!empty($lasterror['error'])) { - $msg .= $this->lang('smtp_error') . $lasterror['error']; - if (!empty($lasterror['detail'])) { - $msg .= ' Detail: '. $lasterror['detail']; - } - if (!empty($lasterror['smtp_code'])) { - $msg .= ' SMTP code: ' . $lasterror['smtp_code']; - } - if (!empty($lasterror['smtp_code_ex'])) { - $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex']; - } - } - } - $this->ErrorInfo = $msg; - } - - /** - * Return an RFC 822 formatted date. - * @access public - * @return string - * @static - */ - public static function rfcDate() - { - // Set the time zone to whatever the default is to avoid 500 errors - // Will default to UTC if it's not set properly in php.ini - date_default_timezone_set(@date_default_timezone_get()); - return date('D, j M Y H:i:s O'); - } - - /** - * Get the server hostname. - * Returns 'localhost.localdomain' if unknown. - * @access protected - * @return string - */ - protected function serverHostname() - { - $result = 'localhost.localdomain'; - if (!empty($this->Hostname)) { - $result = $this->Hostname; - } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) { - $result = $_SERVER['SERVER_NAME']; - } elseif (function_exists('gethostname') && gethostname() !== false) { - $result = gethostname(); - } elseif (php_uname('n') !== false) { - $result = php_uname('n'); - } - return $result; - } - - /** - * Get an error message in the current language. - * @access protected - * @param string $key - * @return string - */ - protected function lang($key) - { - if (count($this->language) < 1) { - $this->setLanguage('en'); // set the default language - } - - if (array_key_exists($key, $this->language)) { - if ($key == 'smtp_connect_failed') { - //Include a link to troubleshooting docs on SMTP connection failure - //this is by far the biggest cause of support questions - //but it's usually not PHPMailer's fault. - return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting'; - } - return $this->language[$key]; - } else { - //Return the key as a fallback - return $key; - } - } - - /** - * Check if an error occurred. - * @access public - * @return boolean True if an error did occur. - */ - public function isError() - { - return ($this->error_count > 0); - } - - /** - * Ensure consistent line endings in a string. - * Changes every end of line from CRLF, CR or LF to $this->LE. - * @access public - * @param string $str String to fixEOL - * @return string - */ - public function fixEOL($str) - { - // Normalise to \n - $nstr = str_replace(array("\r\n", "\r"), "\n", $str); - // Now convert LE as needed - if ($this->LE !== "\n") { - $nstr = str_replace("\n", $this->LE, $nstr); - } - return $nstr; - } - - /** - * Add a custom header. - * $name value can be overloaded to contain - * both header name and value (name:value) - * @access public - * @param string $name Custom header name - * @param string $value Header value - * @return void - */ - public function addCustomHeader($name, $value = null) - { - if ($value === null) { - // Value passed in as name:value - $this->CustomHeader[] = explode(':', $name, 2); - } else { - $this->CustomHeader[] = array($name, $value); - } - } - - /** - * Returns all custom headers. - * @return array - */ - public function getCustomHeaders() - { - return $this->CustomHeader; - } - - /** - * Create a message body from an HTML string. - * Automatically inlines images and creates a plain-text version by converting the HTML, - * overwriting any existing values in Body and AltBody. - * Do not source $message content from user input! - * $basedir is prepended when handling relative URLs, e.g. and must not be empty - * will look for an image file in $basedir/images/a.png and convert it to inline. - * If you don't provide a $basedir, relative paths will be left untouched (and thus probably break in email) - * If you don't want to apply these transformations to your HTML, just set Body and AltBody directly. - * @access public - * @param string $message HTML message string - * @param string $basedir Absolute path to a base directory to prepend to relative paths to images - * @param boolean|callable $advanced Whether to use the internal HTML to text converter - * or your own custom converter @see PHPMailer::html2text() - * @return string $message The transformed message Body - */ - public function msgHTML($message, $basedir = '', $advanced = false) - { - preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images); - if (array_key_exists(2, $images)) { - if (strlen($basedir) > 1 && substr($basedir, -1) != '/') { - // Ensure $basedir has a trailing / - $basedir .= '/'; - } - foreach ($images[2] as $imgindex => $url) { - // Convert data URIs into embedded images - if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) { - $data = substr($url, strpos($url, ',')); - if ($match[2]) { - $data = base64_decode($data); - } else { - $data = rawurldecode($data); - } - $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2 - if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) { - $message = str_replace( - $images[0][$imgindex], - $images[1][$imgindex] . '="cid:' . $cid . '"', - $message - ); - } - continue; - } - if ( - // Only process relative URLs if a basedir is provided (i.e. no absolute local paths) - !empty($basedir) - // Ignore URLs containing parent dir traversal (..) - && (strpos($url, '..') === false) - // Do not change urls that are already inline images - && substr($url, 0, 4) !== 'cid:' - // Do not change absolute URLs, including anonymous protocol - && !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url) - ) { - $filename = basename($url); - $directory = dirname($url); - if ($directory == '.') { - $directory = ''; - } - $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2 - if (strlen($directory) > 1 && substr($directory, -1) != '/') { - $directory .= '/'; - } - if ($this->addEmbeddedImage( - $basedir . $directory . $filename, - $cid, - $filename, - 'base64', - self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION)) - ) - ) { - $message = preg_replace( - '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui', - $images[1][$imgindex] . '="cid:' . $cid . '"', - $message - ); - } - } - } - } - $this->isHTML(true); - // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better - $this->Body = $this->normalizeBreaks($message); - $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced)); - if (!$this->alternativeExists()) { - $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . - self::CRLF . self::CRLF; - } - return $this->Body; - } - - /** - * Convert an HTML string into plain text. - * This is used by msgHTML(). - * Note - older versions of this function used a bundled advanced converter - * which was been removed for license reasons in #232. - * Example usage: - * - * // Use default conversion - * $plain = $mail->html2text($html); - * // Use your own custom converter - * $plain = $mail->html2text($html, function($html) { - * $converter = new MyHtml2text($html); - * return $converter->get_text(); - * }); - * - * @param string $html The HTML text to convert - * @param boolean|callable $advanced Any boolean value to use the internal converter, - * or provide your own callable for custom conversion. - * @return string - */ - public function html2text($html, $advanced = false) - { - if (is_callable($advanced)) { - return call_user_func($advanced, $html); - } - return html_entity_decode( - trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))), - ENT_QUOTES, - $this->CharSet - ); - } - - /** - * Get the MIME type for a file extension. - * @param string $ext File extension - * @access public - * @return string MIME type of file. - * @static - */ - public static function _mime_types($ext = '') - { - $mimes = array( - 'xl' => 'application/excel', - 'js' => 'application/javascript', - 'hqx' => 'application/mac-binhex40', - 'cpt' => 'application/mac-compactpro', - 'bin' => 'application/macbinary', - 'doc' => 'application/msword', - 'word' => 'application/msword', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', - 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', - 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', - 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', - 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', - 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', - 'class' => 'application/octet-stream', - 'dll' => 'application/octet-stream', - 'dms' => 'application/octet-stream', - 'exe' => 'application/octet-stream', - 'lha' => 'application/octet-stream', - 'lzh' => 'application/octet-stream', - 'psd' => 'application/octet-stream', - 'sea' => 'application/octet-stream', - 'so' => 'application/octet-stream', - 'oda' => 'application/oda', - 'pdf' => 'application/pdf', - 'ai' => 'application/postscript', - 'eps' => 'application/postscript', - 'ps' => 'application/postscript', - 'smi' => 'application/smil', - 'smil' => 'application/smil', - 'mif' => 'application/vnd.mif', - 'xls' => 'application/vnd.ms-excel', - 'ppt' => 'application/vnd.ms-powerpoint', - 'wbxml' => 'application/vnd.wap.wbxml', - 'wmlc' => 'application/vnd.wap.wmlc', - 'dcr' => 'application/x-director', - 'dir' => 'application/x-director', - 'dxr' => 'application/x-director', - 'dvi' => 'application/x-dvi', - 'gtar' => 'application/x-gtar', - 'php3' => 'application/x-httpd-php', - 'php4' => 'application/x-httpd-php', - 'php' => 'application/x-httpd-php', - 'phtml' => 'application/x-httpd-php', - 'phps' => 'application/x-httpd-php-source', - 'swf' => 'application/x-shockwave-flash', - 'sit' => 'application/x-stuffit', - 'tar' => 'application/x-tar', - 'tgz' => 'application/x-tar', - 'xht' => 'application/xhtml+xml', - 'xhtml' => 'application/xhtml+xml', - 'zip' => 'application/zip', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mp2' => 'audio/mpeg', - 'mp3' => 'audio/mpeg', - 'mpga' => 'audio/mpeg', - 'aif' => 'audio/x-aiff', - 'aifc' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'ram' => 'audio/x-pn-realaudio', - 'rm' => 'audio/x-pn-realaudio', - 'rpm' => 'audio/x-pn-realaudio-plugin', - 'ra' => 'audio/x-realaudio', - 'wav' => 'audio/x-wav', - 'bmp' => 'image/bmp', - 'gif' => 'image/gif', - 'jpeg' => 'image/jpeg', - 'jpe' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'png' => 'image/png', - 'tiff' => 'image/tiff', - 'tif' => 'image/tiff', - 'eml' => 'message/rfc822', - 'css' => 'text/css', - 'html' => 'text/html', - 'htm' => 'text/html', - 'shtml' => 'text/html', - 'log' => 'text/plain', - 'text' => 'text/plain', - 'txt' => 'text/plain', - 'rtx' => 'text/richtext', - 'rtf' => 'text/rtf', - 'vcf' => 'text/vcard', - 'vcard' => 'text/vcard', - 'xml' => 'text/xml', - 'xsl' => 'text/xml', - 'mpeg' => 'video/mpeg', - 'mpe' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mov' => 'video/quicktime', - 'qt' => 'video/quicktime', - 'rv' => 'video/vnd.rn-realvideo', - 'avi' => 'video/x-msvideo', - 'movie' => 'video/x-sgi-movie' - ); - if (array_key_exists(strtolower($ext), $mimes)) { - return $mimes[strtolower($ext)]; - } - return 'application/octet-stream'; - } - - /** - * Map a file name to a MIME type. - * Defaults to 'application/octet-stream', i.e.. arbitrary binary data. - * @param string $filename A file name or full path, does not need to exist as a file - * @return string - * @static - */ - public static function filenameToType($filename) - { - // In case the path is a URL, strip any query string before getting extension - $qpos = strpos($filename, '?'); - if (false !== $qpos) { - $filename = substr($filename, 0, $qpos); - } - $pathinfo = self::mb_pathinfo($filename); - return self::_mime_types($pathinfo['extension']); - } - - /** - * Multi-byte-safe pathinfo replacement. - * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe. - * Works similarly to the one in PHP >= 5.2.0 - * @link http://www.php.net/manual/en/function.pathinfo.php#107461 - * @param string $path A filename or path, does not need to exist as a file - * @param integer|string $options Either a PATHINFO_* constant, - * or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2 - * @return string|array - * @static - */ - public static function mb_pathinfo($path, $options = null) - { - $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => ''); - $pathinfo = array(); - if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) { - if (array_key_exists(1, $pathinfo)) { - $ret['dirname'] = $pathinfo[1]; - } - if (array_key_exists(2, $pathinfo)) { - $ret['basename'] = $pathinfo[2]; - } - if (array_key_exists(5, $pathinfo)) { - $ret['extension'] = $pathinfo[5]; - } - if (array_key_exists(3, $pathinfo)) { - $ret['filename'] = $pathinfo[3]; - } - } - switch ($options) { - case PATHINFO_DIRNAME: - case 'dirname': - return $ret['dirname']; - case PATHINFO_BASENAME: - case 'basename': - return $ret['basename']; - case PATHINFO_EXTENSION: - case 'extension': - return $ret['extension']; - case PATHINFO_FILENAME: - case 'filename': - return $ret['filename']; - default: - return $ret; - } - } - - /** - * Set or reset instance properties. - * You should avoid this function - it's more verbose, less efficient, more error-prone and - * harder to debug than setting properties directly. - * Usage Example: - * `$mail->set('SMTPSecure', 'tls');` - * is the same as: - * `$mail->SMTPSecure = 'tls';` - * @access public - * @param string $name The property name to set - * @param mixed $value The value to set the property to - * @return boolean - * @TODO Should this not be using the __set() magic function? - */ - public function set($name, $value = '') - { - if (property_exists($this, $name)) { - $this->$name = $value; - return true; - } else { - $this->setError($this->lang('variable_set') . $name); - return false; - } - } - - /** - * Strip newlines to prevent header injection. - * @access public - * @param string $str - * @return string - */ - public function secureHeader($str) - { - return trim(str_replace(array("\r", "\n"), '', $str)); - } - - /** - * Normalize line breaks in a string. - * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format. - * Defaults to CRLF (for message bodies) and preserves consecutive breaks. - * @param string $text - * @param string $breaktype What kind of line break to use, defaults to CRLF - * @return string - * @access public - * @static - */ - public static function normalizeBreaks($text, $breaktype = "\r\n") - { - return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text); - } - - /** - * Set the public and private key files and password for S/MIME signing. - * @access public - * @param string $cert_filename - * @param string $key_filename - * @param string $key_pass Password for private key - * @param string $extracerts_filename Optional path to chain certificate - */ - public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '') - { - $this->sign_cert_file = $cert_filename; - $this->sign_key_file = $key_filename; - $this->sign_key_pass = $key_pass; - $this->sign_extracerts_file = $extracerts_filename; - } - - /** - * Quoted-Printable-encode a DKIM header. - * @access public - * @param string $txt - * @return string - */ - public function DKIM_QP($txt) - { - $line = ''; - for ($i = 0; $i < strlen($txt); $i++) { - $ord = ord($txt[$i]); - if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) { - $line .= $txt[$i]; - } else { - $line .= '=' . sprintf('%02X', $ord); - } - } - return $line; - } - - /** - * Generate a DKIM signature. - * @access public - * @param string $signHeader - * @throws phpmailerException - * @return string The DKIM signature value - */ - public function DKIM_Sign($signHeader) - { - if (!defined('PKCS7_TEXT')) { - if ($this->exceptions) { - throw new phpmailerException($this->lang('extension_missing') . 'openssl'); - } - return ''; - } - $privKeyStr = !empty($this->DKIM_private_string) ? $this->DKIM_private_string : file_get_contents($this->DKIM_private); - if ('' != $this->DKIM_passphrase) { - $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase); - } else { - $privKey = openssl_pkey_get_private($privKeyStr); - } - //Workaround for missing digest algorithms in old PHP & OpenSSL versions - //@link http://stackoverflow.com/a/11117338/333340 - if (version_compare(PHP_VERSION, '5.3.0') >= 0 and - in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) { - if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) { - openssl_pkey_free($privKey); - return base64_encode($signature); - } - } else { - $pinfo = openssl_pkey_get_details($privKey); - $hash = hash('sha256', $signHeader); - //'Magic' constant for SHA256 from RFC3447 - //@link https://tools.ietf.org/html/rfc3447#page-43 - $t = '3031300d060960864801650304020105000420' . $hash; - $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3); - $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t); - - if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) { - openssl_pkey_free($privKey); - return base64_encode($signature); - } - } - openssl_pkey_free($privKey); - return ''; - } - - /** - * Generate a DKIM canonicalization header. - * @access public - * @param string $signHeader Header - * @return string - */ - public function DKIM_HeaderC($signHeader) - { - $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader); - $lines = explode("\r\n", $signHeader); - foreach ($lines as $key => $line) { - list($heading, $value) = explode(':', $line, 2); - $heading = strtolower($heading); - $value = preg_replace('/\s{2,}/', ' ', $value); // Compress useless spaces - $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value - } - $signHeader = implode("\r\n", $lines); - return $signHeader; - } - - /** - * Generate a DKIM canonicalization body. - * @access public - * @param string $body Message Body - * @return string - */ - public function DKIM_BodyC($body) - { - if ($body == '') { - return "\r\n"; - } - // stabilize line endings - $body = str_replace("\r\n", "\n", $body); - $body = str_replace("\n", "\r\n", $body); - // END stabilize line endings - while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") { - $body = substr($body, 0, strlen($body) - 2); - } - return $body; - } - - /** - * Create the DKIM header and body in a new message header. - * @access public - * @param string $headers_line Header lines - * @param string $subject Subject - * @param string $body Body - * @return string - */ - public function DKIM_Add($headers_line, $subject, $body) - { - $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms - $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body - $DKIMquery = 'dns/txt'; // Query method - $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone) - $subject_header = "Subject: $subject"; - $headers = explode($this->LE, $headers_line); - $from_header = ''; - $to_header = ''; - $date_header = ''; - $current = ''; - foreach ($headers as $header) { - if (strpos($header, 'From:') === 0) { - $from_header = $header; - $current = 'from_header'; - } elseif (strpos($header, 'To:') === 0) { - $to_header = $header; - $current = 'to_header'; - } elseif (strpos($header, 'Date:') === 0) { - $date_header = $header; - $current = 'date_header'; - } else { - if (!empty($$current) && strpos($header, ' =?') === 0) { - $$current .= $header; - } else { - $current = ''; - } - } - } - $from = str_replace('|', '=7C', $this->DKIM_QP($from_header)); - $to = str_replace('|', '=7C', $this->DKIM_QP($to_header)); - $date = str_replace('|', '=7C', $this->DKIM_QP($date_header)); - $subject = str_replace( - '|', - '=7C', - $this->DKIM_QP($subject_header) - ); // Copied header fields (dkim-quoted-printable) - $body = $this->DKIM_BodyC($body); - $DKIMlen = strlen($body); // Length of body - $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body - if ('' == $this->DKIM_identity) { - $ident = ''; - } else { - $ident = ' i=' . $this->DKIM_identity . ';'; - } - $dkimhdrs = 'DKIM-Signature: v=1; a=' . - $DKIMsignatureType . '; q=' . - $DKIMquery . '; l=' . - $DKIMlen . '; s=' . - $this->DKIM_selector . - ";\r\n" . - "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" . - "\th=From:To:Date:Subject;\r\n" . - "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" . - "\tz=$from\r\n" . - "\t|$to\r\n" . - "\t|$date\r\n" . - "\t|$subject;\r\n" . - "\tbh=" . $DKIMb64 . ";\r\n" . - "\tb="; - $toSign = $this->DKIM_HeaderC( - $from_header . "\r\n" . - $to_header . "\r\n" . - $date_header . "\r\n" . - $subject_header . "\r\n" . - $dkimhdrs - ); - $signed = $this->DKIM_Sign($toSign); - return $dkimhdrs . $signed . "\r\n"; - } - - /** - * Detect if a string contains a line longer than the maximum line length allowed. - * @param string $str - * @return boolean - * @static - */ - public static function hasLineLongerThanMax($str) - { - //+2 to include CRLF line break for a 1000 total - return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str); - } - - /** - * Allows for public read access to 'to' property. - * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. - * @access public - * @return array - */ - public function getToAddresses() - { - return $this->to; - } - - /** - * Allows for public read access to 'cc' property. - * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. - * @access public - * @return array - */ - public function getCcAddresses() - { - return $this->cc; - } - - /** - * Allows for public read access to 'bcc' property. - * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. - * @access public - * @return array - */ - public function getBccAddresses() - { - return $this->bcc; - } - - /** - * Allows for public read access to 'ReplyTo' property. - * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. - * @access public - * @return array - */ - public function getReplyToAddresses() - { - return $this->ReplyTo; - } - - /** - * Allows for public read access to 'all_recipients' property. - * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. - * @access public - * @return array - */ - public function getAllRecipientAddresses() - { - return $this->all_recipients; - } - - /** - * Perform a callback. - * @param boolean $isSent - * @param array $to - * @param array $cc - * @param array $bcc - * @param string $subject - * @param string $body - * @param string $from - */ - protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from) - { - if (!empty($this->action_function) && is_callable($this->action_function)) { - $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from); - call_user_func_array($this->action_function, $params); - } - } -} - -/** - * PHPMailer exception handler - * @package PHPMailer - */ -class phpmailerException extends Exception -{ - /** - * Prettify error message output - * @return string - */ - public function errorMessage() - { - $errorMsg = '' . htmlspecialchars($this->getMessage()) . "
\n"; - return $errorMsg; - } -} diff --git a/lib/phpmailer/class.pop3.php b/lib/phpmailer/class.pop3.php deleted file mode 100644 index f833ac61..00000000 --- a/lib/phpmailer/class.pop3.php +++ /dev/null @@ -1,407 +0,0 @@ - - * @author Jim Jagielski (jimjag) - * @author Andy Prevost (codeworxtech) - * @author Brent R. Matzelle (original founder) - * @copyright 2012 - 2014 Marcus Bointon - * @copyright 2010 - 2012 Jim Jagielski - * @copyright 2004 - 2009 Andy Prevost - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - * @note This program is distributed in the hope that it will be useful - WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - */ - -/** - * PHPMailer POP-Before-SMTP Authentication Class. - * Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication. - * Does not support APOP. - * @package PHPMailer - * @author Richard Davey (original author) - * @author Marcus Bointon (Synchro/coolbru) - * @author Jim Jagielski (jimjag) - * @author Andy Prevost (codeworxtech) - */ -class POP3 -{ - /** - * The POP3 PHPMailer Version number. - * @var string - * @access public - */ - public $Version = '5.2.26'; - - /** - * Default POP3 port number. - * @var integer - * @access public - */ - public $POP3_PORT = 110; - - /** - * Default timeout in seconds. - * @var integer - * @access public - */ - public $POP3_TIMEOUT = 30; - - /** - * POP3 Carriage Return + Line Feed. - * @var string - * @access public - * @deprecated Use the constant instead - */ - public $CRLF = "\r\n"; - - /** - * Debug display level. - * Options: 0 = no, 1+ = yes - * @var integer - * @access public - */ - public $do_debug = 0; - - /** - * POP3 mail server hostname. - * @var string - * @access public - */ - public $host; - - /** - * POP3 port number. - * @var integer - * @access public - */ - public $port; - - /** - * POP3 Timeout Value in seconds. - * @var integer - * @access public - */ - public $tval; - - /** - * POP3 username - * @var string - * @access public - */ - public $username; - - /** - * POP3 password. - * @var string - * @access public - */ - public $password; - - /** - * Resource handle for the POP3 connection socket. - * @var resource - * @access protected - */ - protected $pop_conn; - - /** - * Are we connected? - * @var boolean - * @access protected - */ - protected $connected = false; - - /** - * Error container. - * @var array - * @access protected - */ - protected $errors = array(); - - /** - * Line break constant - */ - const CRLF = "\r\n"; - - /** - * Simple static wrapper for all-in-one POP before SMTP - * @param $host - * @param integer|boolean $port The port number to connect to - * @param integer|boolean $timeout The timeout value - * @param string $username - * @param string $password - * @param integer $debug_level - * @return boolean - */ - public static function popBeforeSmtp( - $host, - $port = false, - $timeout = false, - $username = '', - $password = '', - $debug_level = 0 - ) { - $pop = new POP3; - return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level); - } - - /** - * Authenticate with a POP3 server. - * A connect, login, disconnect sequence - * appropriate for POP-before SMTP authorisation. - * @access public - * @param string $host The hostname to connect to - * @param integer|boolean $port The port number to connect to - * @param integer|boolean $timeout The timeout value - * @param string $username - * @param string $password - * @param integer $debug_level - * @return boolean - */ - public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0) - { - $this->host = $host; - // If no port value provided, use default - if (false === $port) { - $this->port = $this->POP3_PORT; - } else { - $this->port = (integer)$port; - } - // If no timeout value provided, use default - if (false === $timeout) { - $this->tval = $this->POP3_TIMEOUT; - } else { - $this->tval = (integer)$timeout; - } - $this->do_debug = $debug_level; - $this->username = $username; - $this->password = $password; - // Reset the error log - $this->errors = array(); - // connect - $result = $this->connect($this->host, $this->port, $this->tval); - if ($result) { - $login_result = $this->login($this->username, $this->password); - if ($login_result) { - $this->disconnect(); - return true; - } - } - // We need to disconnect regardless of whether the login succeeded - $this->disconnect(); - return false; - } - - /** - * Connect to a POP3 server. - * @access public - * @param string $host - * @param integer|boolean $port - * @param integer $tval - * @return boolean - */ - public function connect($host, $port = false, $tval = 30) - { - // Are we already connected? - if ($this->connected) { - return true; - } - - //On Windows this will raise a PHP Warning error if the hostname doesn't exist. - //Rather than suppress it with @fsockopen, capture it cleanly instead - set_error_handler(array($this, 'catchWarning')); - - if (false === $port) { - $port = $this->POP3_PORT; - } - - // connect to the POP3 server - $this->pop_conn = fsockopen( - $host, // POP3 Host - $port, // Port # - $errno, // Error Number - $errstr, // Error Message - $tval - ); // Timeout (seconds) - // Restore the error handler - restore_error_handler(); - - // Did we connect? - if (false === $this->pop_conn) { - // It would appear not... - $this->setError(array( - 'error' => "Failed to connect to server $host on port $port", - 'errno' => $errno, - 'errstr' => $errstr - )); - return false; - } - - // Increase the stream time-out - stream_set_timeout($this->pop_conn, $tval, 0); - - // Get the POP3 server response - $pop3_response = $this->getResponse(); - // Check for the +OK - if ($this->checkResponse($pop3_response)) { - // The connection is established and the POP3 server is talking - $this->connected = true; - return true; - } - return false; - } - - /** - * Log in to the POP3 server. - * Does not support APOP (RFC 2828, 4949). - * @access public - * @param string $username - * @param string $password - * @return boolean - */ - public function login($username = '', $password = '') - { - if (!$this->connected) { - $this->setError('Not connected to POP3 server'); - } - if (empty($username)) { - $username = $this->username; - } - if (empty($password)) { - $password = $this->password; - } - - // Send the Username - $this->sendString("USER $username" . self::CRLF); - $pop3_response = $this->getResponse(); - if ($this->checkResponse($pop3_response)) { - // Send the Password - $this->sendString("PASS $password" . self::CRLF); - $pop3_response = $this->getResponse(); - if ($this->checkResponse($pop3_response)) { - return true; - } - } - return false; - } - - /** - * Disconnect from the POP3 server. - * @access public - */ - public function disconnect() - { - $this->sendString('QUIT'); - //The QUIT command may cause the daemon to exit, which will kill our connection - //So ignore errors here - try { - @fclose($this->pop_conn); - } catch (Exception $e) { - //Do nothing - }; - } - - /** - * Get a response from the POP3 server. - * $size is the maximum number of bytes to retrieve - * @param integer $size - * @return string - * @access protected - */ - protected function getResponse($size = 128) - { - $response = fgets($this->pop_conn, $size); - if ($this->do_debug >= 1) { - echo "Server -> Client: $response"; - } - return $response; - } - - /** - * Send raw data to the POP3 server. - * @param string $string - * @return integer - * @access protected - */ - protected function sendString($string) - { - if ($this->pop_conn) { - if ($this->do_debug >= 2) { //Show client messages when debug >= 2 - echo "Client -> Server: $string"; - } - return fwrite($this->pop_conn, $string, strlen($string)); - } - return 0; - } - - /** - * Checks the POP3 server response. - * Looks for for +OK or -ERR. - * @param string $string - * @return boolean - * @access protected - */ - protected function checkResponse($string) - { - if (substr($string, 0, 3) !== '+OK') { - $this->setError(array( - 'error' => "Server reported an error: $string", - 'errno' => 0, - 'errstr' => '' - )); - return false; - } else { - return true; - } - } - - /** - * Add an error to the internal error store. - * Also display debug output if it's enabled. - * @param $error - * @access protected - */ - protected function setError($error) - { - $this->errors[] = $error; - if ($this->do_debug >= 1) { - echo '
';
-            foreach ($this->errors as $error) {
-                print_r($error);
-            }
-            echo '
'; - } - } - - /** - * Get an array of error messages, if any. - * @return array - */ - public function getErrors() - { - return $this->errors; - } - - /** - * POP3 connection error handler. - * @param integer $errno - * @param string $errstr - * @param string $errfile - * @param integer $errline - * @access protected - */ - protected function catchWarning($errno, $errstr, $errfile, $errline) - { - $this->setError(array( - 'error' => "Connecting to the POP3 server raised a PHP warning: ", - 'errno' => $errno, - 'errstr' => $errstr, - 'errfile' => $errfile, - 'errline' => $errline - )); - } -} diff --git a/lib/phpmailer/class.smtp.php b/lib/phpmailer/class.smtp.php deleted file mode 100644 index be6ddce4..00000000 --- a/lib/phpmailer/class.smtp.php +++ /dev/null @@ -1,1276 +0,0 @@ - - * @author Jim Jagielski (jimjag) - * @author Andy Prevost (codeworxtech) - * @author Brent R. Matzelle (original founder) - * @copyright 2014 Marcus Bointon - * @copyright 2010 - 2012 Jim Jagielski - * @copyright 2004 - 2009 Andy Prevost - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - * @note This program is distributed in the hope that it will be useful - WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. - */ - -/** - * PHPMailer RFC821 SMTP email transport class. - * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server. - * @package PHPMailer - * @author Chris Ryan - * @author Marcus Bointon - */ -class SMTP -{ - /** - * The PHPMailer SMTP version number. - * @var string - */ - const VERSION = '5.2.26'; - - /** - * SMTP line break constant. - * @var string - */ - const CRLF = "\r\n"; - - /** - * The SMTP port to use if one is not specified. - * @var integer - */ - const DEFAULT_SMTP_PORT = 25; - - /** - * The maximum line length allowed by RFC 2822 section 2.1.1 - * @var integer - */ - const MAX_LINE_LENGTH = 998; - - /** - * Debug level for no output - */ - const DEBUG_OFF = 0; - - /** - * Debug level to show client -> server messages - */ - const DEBUG_CLIENT = 1; - - /** - * Debug level to show client -> server and server -> client messages - */ - const DEBUG_SERVER = 2; - - /** - * Debug level to show connection status, client -> server and server -> client messages - */ - const DEBUG_CONNECTION = 3; - - /** - * Debug level to show all messages - */ - const DEBUG_LOWLEVEL = 4; - - /** - * The PHPMailer SMTP Version number. - * @var string - * @deprecated Use the `VERSION` constant instead - * @see SMTP::VERSION - */ - public $Version = '5.2.26'; - - /** - * SMTP server port number. - * @var integer - * @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead - * @see SMTP::DEFAULT_SMTP_PORT - */ - public $SMTP_PORT = 25; - - /** - * SMTP reply line ending. - * @var string - * @deprecated Use the `CRLF` constant instead - * @see SMTP::CRLF - */ - public $CRLF = "\r\n"; - - /** - * Debug output level. - * Options: - * * self::DEBUG_OFF (`0`) No debug output, default - * * self::DEBUG_CLIENT (`1`) Client commands - * * self::DEBUG_SERVER (`2`) Client commands and server responses - * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status - * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages - * @var integer - */ - public $do_debug = self::DEBUG_OFF; - - /** - * How to handle debug output. - * Options: - * * `echo` Output plain-text as-is, appropriate for CLI - * * `html` Output escaped, line breaks converted to `
`, appropriate for browser output - * * `error_log` Output to error log as configured in php.ini - * - * Alternatively, you can provide a callable expecting two params: a message string and the debug level: - * - * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; - * - * @var string|callable - */ - public $Debugoutput = 'echo'; - - /** - * Whether to use VERP. - * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path - * @link http://www.postfix.org/VERP_README.html Info on VERP - * @var boolean - */ - public $do_verp = false; - - /** - * The timeout value for connection, in seconds. - * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 - * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure. - * @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2 - * @var integer - */ - public $Timeout = 300; - - /** - * How long to wait for commands to complete, in seconds. - * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 - * @var integer - */ - public $Timelimit = 300; - - /** - * @var array Patterns to extract an SMTP transaction id from reply to a DATA command. - * The first capture group in each regex will be used as the ID. - */ - protected $smtp_transaction_id_patterns = array( - 'exim' => '/[0-9]{3} OK id=(.*)/', - 'sendmail' => '/[0-9]{3} 2.0.0 (.*) Message/', - 'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/' - ); - - /** - * @var string The last transaction ID issued in response to a DATA command, - * if one was detected - */ - protected $last_smtp_transaction_id; - - /** - * The socket for the server connection. - * @var resource - */ - protected $smtp_conn; - - /** - * Error information, if any, for the last SMTP command. - * @var array - */ - protected $error = array( - 'error' => '', - 'detail' => '', - 'smtp_code' => '', - 'smtp_code_ex' => '' - ); - - /** - * The reply the server sent to us for HELO. - * If null, no HELO string has yet been received. - * @var string|null - */ - protected $helo_rply = null; - - /** - * The set of SMTP extensions sent in reply to EHLO command. - * Indexes of the array are extension names. - * Value at index 'HELO' or 'EHLO' (according to command that was sent) - * represents the server name. In case of HELO it is the only element of the array. - * Other values can be boolean TRUE or an array containing extension options. - * If null, no HELO/EHLO string has yet been received. - * @var array|null - */ - protected $server_caps = null; - - /** - * The most recent reply received from the server. - * @var string - */ - protected $last_reply = ''; - - /** - * Output debugging info via a user-selected method. - * @see SMTP::$Debugoutput - * @see SMTP::$do_debug - * @param string $str Debug string to output - * @param integer $level The debug level of this message; see DEBUG_* constants - * @return void - */ - protected function edebug($str, $level = 0) - { - if ($level > $this->do_debug) { - return; - } - //Avoid clash with built-in function names - if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) { - call_user_func($this->Debugoutput, $str, $level); - return; - } - switch ($this->Debugoutput) { - case 'error_log': - //Don't output, just log - error_log($str); - break; - case 'html': - //Cleans up output a bit for a better looking, HTML-safe output - echo gmdate('Y-m-d H:i:s') . ' ' . htmlentities( - preg_replace('/[\r\n]+/', '', $str), - ENT_QUOTES, - 'UTF-8' - ) . "
\n"; - break; - case 'echo': - default: - //Normalize line breaks - $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str); - echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( - "\n", - "\n \t ", - trim($str) - ) . "\n"; - } - } - - /** - * Connect to an SMTP server. - * @param string $host SMTP server IP or host name - * @param integer $port The port number to connect to - * @param integer $timeout How long to wait for the connection to open - * @param array $options An array of options for stream_context_create() - * @access public - * @return boolean - */ - public function connect($host, $port = null, $timeout = 30, $options = array()) - { - static $streamok; - //This is enabled by default since 5.0.0 but some providers disable it - //Check this once and cache the result - if (is_null($streamok)) { - $streamok = function_exists('stream_socket_client'); - } - // Clear errors to avoid confusion - $this->setError(''); - // Make sure we are __not__ connected - if ($this->connected()) { - // Already connected, generate error - $this->setError('Already connected to a server'); - return false; - } - if (empty($port)) { - $port = self::DEFAULT_SMTP_PORT; - } - // Connect to the SMTP server - $this->edebug( - "Connection: opening to $host:$port, timeout=$timeout, options=" . - var_export($options, true), - self::DEBUG_CONNECTION - ); - $errno = 0; - $errstr = ''; - if ($streamok) { - $socket_context = stream_context_create($options); - set_error_handler(array($this, 'errorHandler')); - $this->smtp_conn = stream_socket_client( - $host . ":" . $port, - $errno, - $errstr, - $timeout, - STREAM_CLIENT_CONNECT, - $socket_context - ); - restore_error_handler(); - } else { - //Fall back to fsockopen which should work in more places, but is missing some features - $this->edebug( - "Connection: stream_socket_client not available, falling back to fsockopen", - self::DEBUG_CONNECTION - ); - set_error_handler(array($this, 'errorHandler')); - $this->smtp_conn = fsockopen( - $host, - $port, - $errno, - $errstr, - $timeout - ); - restore_error_handler(); - } - // Verify we connected properly - if (!is_resource($this->smtp_conn)) { - $this->setError( - 'Failed to connect to server', - $errno, - $errstr - ); - $this->edebug( - 'SMTP ERROR: ' . $this->error['error'] - . ": $errstr ($errno)", - self::DEBUG_CLIENT - ); - return false; - } - $this->edebug('Connection: opened', self::DEBUG_CONNECTION); - // SMTP server can take longer to respond, give longer timeout for first read - // Windows does not have support for this timeout function - if (substr(PHP_OS, 0, 3) != 'WIN') { - $max = ini_get('max_execution_time'); - // Don't bother if unlimited - if ($max != 0 && $timeout > $max) { - @set_time_limit($timeout); - } - stream_set_timeout($this->smtp_conn, $timeout, 0); - } - // Get any announcement - $announce = $this->get_lines(); - $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER); - return true; - } - - /** - * Initiate a TLS (encrypted) session. - * @access public - * @return boolean - */ - public function startTLS() - { - if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { - return false; - } - - //Allow the best TLS version(s) we can - $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; - - //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT - //so add them back in manually if we can - if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { - $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; - $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; - } - - // Begin encrypted connection - set_error_handler(array($this, 'errorHandler')); - $crypto_ok = stream_socket_enable_crypto( - $this->smtp_conn, - true, - $crypto_method - ); - restore_error_handler(); - return $crypto_ok; - } - - /** - * Perform SMTP authentication. - * Must be run after hello(). - * @see hello() - * @param string $username The user name - * @param string $password The password - * @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5, XOAUTH2) - * @param string $realm The auth realm for NTLM - * @param string $workstation The auth workstation for NTLM - * @param null|OAuth $OAuth An optional OAuth instance (@see PHPMailerOAuth) - * @return bool True if successfully authenticated.* @access public - */ - public function authenticate( - $username, - $password, - $authtype = null, - $realm = '', - $workstation = '', - $OAuth = null - ) { - if (!$this->server_caps) { - $this->setError('Authentication is not allowed before HELO/EHLO'); - return false; - } - - if (array_key_exists('EHLO', $this->server_caps)) { - // SMTP extensions are available; try to find a proper authentication method - if (!array_key_exists('AUTH', $this->server_caps)) { - $this->setError('Authentication is not allowed at this stage'); - // 'at this stage' means that auth may be allowed after the stage changes - // e.g. after STARTTLS - return false; - } - - self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL); - self::edebug( - 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']), - self::DEBUG_LOWLEVEL - ); - - if (empty($authtype)) { - foreach (array('CRAM-MD5', 'LOGIN', 'PLAIN', 'NTLM', 'XOAUTH2') as $method) { - if (in_array($method, $this->server_caps['AUTH'])) { - $authtype = $method; - break; - } - } - if (empty($authtype)) { - $this->setError('No supported authentication methods found'); - return false; - } - self::edebug('Auth method selected: ' . $authtype, self::DEBUG_LOWLEVEL); - } - - if (!in_array($authtype, $this->server_caps['AUTH'])) { - $this->setError("The requested authentication method \"$authtype\" is not supported by the server"); - return false; - } - } elseif (empty($authtype)) { - $authtype = 'LOGIN'; - } - switch ($authtype) { - case 'PLAIN': - // Start authentication - if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) { - return false; - } - // Send encoded username and password - if (!$this->sendCommand( - 'User & Password', - base64_encode("\0" . $username . "\0" . $password), - 235 - ) - ) { - return false; - } - break; - case 'LOGIN': - // Start authentication - if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) { - return false; - } - if (!$this->sendCommand("Username", base64_encode($username), 334)) { - return false; - } - if (!$this->sendCommand("Password", base64_encode($password), 235)) { - return false; - } - break; - case 'XOAUTH2': - //If the OAuth Instance is not set. Can be a case when PHPMailer is used - //instead of PHPMailerOAuth - if (is_null($OAuth)) { - return false; - } - $oauth = $OAuth->getOauth64(); - - // Start authentication - if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) { - return false; - } - break; - case 'NTLM': - /* - * ntlm_sasl_client.php - * Bundled with Permission - * - * How to telnet in windows: - * http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx - * PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication - */ - require_once 'extras/ntlm_sasl_client.php'; - $temp = new stdClass; - $ntlm_client = new ntlm_sasl_client_class; - //Check that functions are available - if (!$ntlm_client->initialize($temp)) { - $this->setError($temp->error); - $this->edebug( - 'You need to enable some modules in your php.ini file: ' - . $this->error['error'], - self::DEBUG_CLIENT - ); - return false; - } - //msg1 - $msg1 = $ntlm_client->typeMsg1($realm, $workstation); //msg1 - - if (!$this->sendCommand( - 'AUTH NTLM', - 'AUTH NTLM ' . base64_encode($msg1), - 334 - ) - ) { - return false; - } - //Though 0 based, there is a white space after the 3 digit number - //msg2 - $challenge = substr($this->last_reply, 3); - $challenge = base64_decode($challenge); - $ntlm_res = $ntlm_client->NTLMResponse( - substr($challenge, 24, 8), - $password - ); - //msg3 - $msg3 = $ntlm_client->typeMsg3( - $ntlm_res, - $username, - $realm, - $workstation - ); - // send encoded username - return $this->sendCommand('Username', base64_encode($msg3), 235); - case 'CRAM-MD5': - // Start authentication - if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) { - return false; - } - // Get the challenge - $challenge = base64_decode(substr($this->last_reply, 4)); - - // Build the response - $response = $username . ' ' . $this->hmac($challenge, $password); - - // send encoded credentials - return $this->sendCommand('Username', base64_encode($response), 235); - default: - $this->setError("Authentication method \"$authtype\" is not supported"); - return false; - } - return true; - } - - /** - * Calculate an MD5 HMAC hash. - * Works like hash_hmac('md5', $data, $key) - * in case that function is not available - * @param string $data The data to hash - * @param string $key The key to hash with - * @access protected - * @return string - */ - protected function hmac($data, $key) - { - if (function_exists('hash_hmac')) { - return hash_hmac('md5', $data, $key); - } - - // The following borrowed from - // http://php.net/manual/en/function.mhash.php#27225 - - // RFC 2104 HMAC implementation for php. - // Creates an md5 HMAC. - // Eliminates the need to install mhash to compute a HMAC - // by Lance Rushing - - $bytelen = 64; // byte length for md5 - if (strlen($key) > $bytelen) { - $key = pack('H*', md5($key)); - } - $key = str_pad($key, $bytelen, chr(0x00)); - $ipad = str_pad('', $bytelen, chr(0x36)); - $opad = str_pad('', $bytelen, chr(0x5c)); - $k_ipad = $key ^ $ipad; - $k_opad = $key ^ $opad; - - return md5($k_opad . pack('H*', md5($k_ipad . $data))); - } - - /** - * Check connection state. - * @access public - * @return boolean True if connected. - */ - public function connected() - { - if (is_resource($this->smtp_conn)) { - $sock_status = stream_get_meta_data($this->smtp_conn); - if ($sock_status['eof']) { - // The socket is valid but we are not connected - $this->edebug( - 'SMTP NOTICE: EOF caught while checking if connected', - self::DEBUG_CLIENT - ); - $this->close(); - return false; - } - return true; // everything looks good - } - return false; - } - - /** - * Close the socket and clean up the state of the class. - * Don't use this function without first trying to use QUIT. - * @see quit() - * @access public - * @return void - */ - public function close() - { - $this->setError(''); - $this->server_caps = null; - $this->helo_rply = null; - if (is_resource($this->smtp_conn)) { - // close the connection and cleanup - fclose($this->smtp_conn); - $this->smtp_conn = null; //Makes for cleaner serialization - $this->edebug('Connection: closed', self::DEBUG_CONNECTION); - } - } - - /** - * Send an SMTP DATA command. - * Issues a data command and sends the msg_data to the server, - * finializing the mail transaction. $msg_data is the message - * that is to be send with the headers. Each header needs to be - * on a single line followed by a with the message headers - * and the message body being separated by and additional . - * Implements rfc 821: DATA - * @param string $msg_data Message data to send - * @access public - * @return boolean - */ - public function data($msg_data) - { - //This will use the standard timelimit - if (!$this->sendCommand('DATA', 'DATA', 354)) { - return false; - } - - /* The server is ready to accept data! - * According to rfc821 we should not send more than 1000 characters on a single line (including the CRLF) - * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into - * smaller lines to fit within the limit. - * We will also look for lines that start with a '.' and prepend an additional '.'. - * NOTE: this does not count towards line-length limit. - */ - - // Normalize line breaks before exploding - $lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data)); - - /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field - * of the first line (':' separated) does not contain a space then it _should_ be a header and we will - * process all lines before a blank line as headers. - */ - - $field = substr($lines[0], 0, strpos($lines[0], ':')); - $in_headers = false; - if (!empty($field) && strpos($field, ' ') === false) { - $in_headers = true; - } - - foreach ($lines as $line) { - $lines_out = array(); - if ($in_headers and $line == '') { - $in_headers = false; - } - //Break this line up into several smaller lines if it's too long - //Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len), - while (isset($line[self::MAX_LINE_LENGTH])) { - //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on - //so as to avoid breaking in the middle of a word - $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' '); - //Deliberately matches both false and 0 - if (!$pos) { - //No nice break found, add a hard break - $pos = self::MAX_LINE_LENGTH - 1; - $lines_out[] = substr($line, 0, $pos); - $line = substr($line, $pos); - } else { - //Break at the found point - $lines_out[] = substr($line, 0, $pos); - //Move along by the amount we dealt with - $line = substr($line, $pos + 1); - } - //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1 - if ($in_headers) { - $line = "\t" . $line; - } - } - $lines_out[] = $line; - - //Send the lines to the server - foreach ($lines_out as $line_out) { - //RFC2821 section 4.5.2 - if (!empty($line_out) and $line_out[0] == '.') { - $line_out = '.' . $line_out; - } - $this->client_send($line_out . self::CRLF); - } - } - - //Message data has been sent, complete the command - //Increase timelimit for end of DATA command - $savetimelimit = $this->Timelimit; - $this->Timelimit = $this->Timelimit * 2; - $result = $this->sendCommand('DATA END', '.', 250); - $this->recordLastTransactionID(); - //Restore timelimit - $this->Timelimit = $savetimelimit; - return $result; - } - - /** - * Send an SMTP HELO or EHLO command. - * Used to identify the sending server to the receiving server. - * This makes sure that client and server are in a known state. - * Implements RFC 821: HELO - * and RFC 2821 EHLO. - * @param string $host The host name or IP to connect to - * @access public - * @return boolean - */ - public function hello($host = '') - { - //Try extended hello first (RFC 2821) - return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host)); - } - - /** - * Send an SMTP HELO or EHLO command. - * Low-level implementation used by hello() - * @see hello() - * @param string $hello The HELO string - * @param string $host The hostname to say we are - * @access protected - * @return boolean - */ - protected function sendHello($hello, $host) - { - $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250); - $this->helo_rply = $this->last_reply; - if ($noerror) { - $this->parseHelloFields($hello); - } else { - $this->server_caps = null; - } - return $noerror; - } - - /** - * Parse a reply to HELO/EHLO command to discover server extensions. - * In case of HELO, the only parameter that can be discovered is a server name. - * @access protected - * @param string $type - 'HELO' or 'EHLO' - */ - protected function parseHelloFields($type) - { - $this->server_caps = array(); - $lines = explode("\n", $this->helo_rply); - - foreach ($lines as $n => $s) { - //First 4 chars contain response code followed by - or space - $s = trim(substr($s, 4)); - if (empty($s)) { - continue; - } - $fields = explode(' ', $s); - if (!empty($fields)) { - if (!$n) { - $name = $type; - $fields = $fields[0]; - } else { - $name = array_shift($fields); - switch ($name) { - case 'SIZE': - $fields = ($fields ? $fields[0] : 0); - break; - case 'AUTH': - if (!is_array($fields)) { - $fields = array(); - } - break; - default: - $fields = true; - } - } - $this->server_caps[$name] = $fields; - } - } - } - - /** - * Send an SMTP MAIL command. - * Starts a mail transaction from the email address specified in - * $from. Returns true if successful or false otherwise. If True - * the mail transaction is started and then one or more recipient - * commands may be called followed by a data command. - * Implements rfc 821: MAIL FROM: - * @param string $from Source address of this message - * @access public - * @return boolean - */ - public function mail($from) - { - $useVerp = ($this->do_verp ? ' XVERP' : ''); - return $this->sendCommand( - 'MAIL FROM', - 'MAIL FROM:<' . $from . '>' . $useVerp, - 250 - ); - } - - /** - * Send an SMTP QUIT command. - * Closes the socket if there is no error or the $close_on_error argument is true. - * Implements from rfc 821: QUIT - * @param boolean $close_on_error Should the connection close if an error occurs? - * @access public - * @return boolean - */ - public function quit($close_on_error = true) - { - $noerror = $this->sendCommand('QUIT', 'QUIT', 221); - $err = $this->error; //Save any error - if ($noerror or $close_on_error) { - $this->close(); - $this->error = $err; //Restore any error from the quit command - } - return $noerror; - } - - /** - * Send an SMTP RCPT command. - * Sets the TO argument to $toaddr. - * Returns true if the recipient was accepted false if it was rejected. - * Implements from rfc 821: RCPT TO: - * @param string $address The address the message is being sent to - * @access public - * @return boolean - */ - public function recipient($address) - { - return $this->sendCommand( - 'RCPT TO', - 'RCPT TO:<' . $address . '>', - array(250, 251) - ); - } - - /** - * Send an SMTP RSET command. - * Abort any transaction that is currently in progress. - * Implements rfc 821: RSET - * @access public - * @return boolean True on success. - */ - public function reset() - { - return $this->sendCommand('RSET', 'RSET', 250); - } - - /** - * Send a command to an SMTP server and check its return code. - * @param string $command The command name - not sent to the server - * @param string $commandstring The actual command to send - * @param integer|array $expect One or more expected integer success codes - * @access protected - * @return boolean True on success. - */ - protected function sendCommand($command, $commandstring, $expect) - { - if (!$this->connected()) { - $this->setError("Called $command without being connected"); - return false; - } - //Reject line breaks in all commands - if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) { - $this->setError("Command '$command' contained line breaks"); - return false; - } - $this->client_send($commandstring . self::CRLF); - - $this->last_reply = $this->get_lines(); - // Fetch SMTP code and possible error code explanation - $matches = array(); - if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) { - $code = $matches[1]; - $code_ex = (count($matches) > 2 ? $matches[2] : null); - // Cut off error code from each response line - $detail = preg_replace( - "/{$code}[ -]" . - ($code_ex ? str_replace('.', '\\.', $code_ex) . ' ' : '') . "/m", - '', - $this->last_reply - ); - } else { - // Fall back to simple parsing if regex fails - $code = substr($this->last_reply, 0, 3); - $code_ex = null; - $detail = substr($this->last_reply, 4); - } - - $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER); - - if (!in_array($code, (array)$expect)) { - $this->setError( - "$command command failed", - $detail, - $code, - $code_ex - ); - $this->edebug( - 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply, - self::DEBUG_CLIENT - ); - return false; - } - - $this->setError(''); - return true; - } - - /** - * Send an SMTP SAML command. - * Starts a mail transaction from the email address specified in $from. - * Returns true if successful or false otherwise. If True - * the mail transaction is started and then one or more recipient - * commands may be called followed by a data command. This command - * will send the message to the users terminal if they are logged - * in and send them an email. - * Implements rfc 821: SAML FROM: - * @param string $from The address the message is from - * @access public - * @return boolean - */ - public function sendAndMail($from) - { - return $this->sendCommand('SAML', "SAML FROM:$from", 250); - } - - /** - * Send an SMTP VRFY command. - * @param string $name The name to verify - * @access public - * @return boolean - */ - public function verify($name) - { - return $this->sendCommand('VRFY', "VRFY $name", array(250, 251)); - } - - /** - * Send an SMTP NOOP command. - * Used to keep keep-alives alive, doesn't actually do anything - * @access public - * @return boolean - */ - public function noop() - { - return $this->sendCommand('NOOP', 'NOOP', 250); - } - - /** - * Send an SMTP TURN command. - * This is an optional command for SMTP that this class does not support. - * This method is here to make the RFC821 Definition complete for this class - * and _may_ be implemented in future - * Implements from rfc 821: TURN - * @access public - * @return boolean - */ - public function turn() - { - $this->setError('The SMTP TURN command is not implemented'); - $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT); - return false; - } - - /** - * Send raw data to the server. - * @param string $data The data to send - * @access public - * @return integer|boolean The number of bytes sent to the server or false on error - */ - public function client_send($data) - { - $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT); - set_error_handler(array($this, 'errorHandler')); - $result = fwrite($this->smtp_conn, $data); - restore_error_handler(); - return $result; - } - - /** - * Get the latest error. - * @access public - * @return array - */ - public function getError() - { - return $this->error; - } - - /** - * Get SMTP extensions available on the server - * @access public - * @return array|null - */ - public function getServerExtList() - { - return $this->server_caps; - } - - /** - * A multipurpose method - * The method works in three ways, dependent on argument value and current state - * 1. HELO/EHLO was not sent - returns null and set up $this->error - * 2. HELO was sent - * $name = 'HELO': returns server name - * $name = 'EHLO': returns boolean false - * $name = any string: returns null and set up $this->error - * 3. EHLO was sent - * $name = 'HELO'|'EHLO': returns server name - * $name = any string: if extension $name exists, returns boolean True - * or its options. Otherwise returns boolean False - * In other words, one can use this method to detect 3 conditions: - * - null returned: handshake was not or we don't know about ext (refer to $this->error) - * - false returned: the requested feature exactly not exists - * - positive value returned: the requested feature exists - * @param string $name Name of SMTP extension or 'HELO'|'EHLO' - * @return mixed - */ - public function getServerExt($name) - { - if (!$this->server_caps) { - $this->setError('No HELO/EHLO was sent'); - return null; - } - - // the tight logic knot ;) - if (!array_key_exists($name, $this->server_caps)) { - if ($name == 'HELO') { - return $this->server_caps['EHLO']; - } - if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) { - return false; - } - $this->setError('HELO handshake was used. Client knows nothing about server extensions'); - return null; - } - - return $this->server_caps[$name]; - } - - /** - * Get the last reply from the server. - * @access public - * @return string - */ - public function getLastReply() - { - return $this->last_reply; - } - - /** - * Read the SMTP server's response. - * Either before eof or socket timeout occurs on the operation. - * With SMTP we can tell if we have more lines to read if the - * 4th character is '-' symbol. If it is a space then we don't - * need to read anything else. - * @access protected - * @return string - */ - protected function get_lines() - { - // If the connection is bad, give up straight away - if (!is_resource($this->smtp_conn)) { - return ''; - } - $data = ''; - $endtime = 0; - stream_set_timeout($this->smtp_conn, $this->Timeout); - if ($this->Timelimit > 0) { - $endtime = time() + $this->Timelimit; - } - while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) { - $str = @fgets($this->smtp_conn, 515); - $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL); - $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL); - $data .= $str; - // If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled), - // or 4th character is a space, we are done reading, break the loop, - // string array access is a micro-optimisation over strlen - if (!isset($str[3]) or (isset($str[3]) and $str[3] == ' ')) { - break; - } - // Timed-out? Log and break - $info = stream_get_meta_data($this->smtp_conn); - if ($info['timed_out']) { - $this->edebug( - 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', - self::DEBUG_LOWLEVEL - ); - break; - } - // Now check if reads took too long - if ($endtime and time() > $endtime) { - $this->edebug( - 'SMTP -> get_lines(): timelimit reached (' . - $this->Timelimit . ' sec)', - self::DEBUG_LOWLEVEL - ); - break; - } - } - return $data; - } - - /** - * Enable or disable VERP address generation. - * @param boolean $enabled - */ - public function setVerp($enabled = false) - { - $this->do_verp = $enabled; - } - - /** - * Get VERP address generation mode. - * @return boolean - */ - public function getVerp() - { - return $this->do_verp; - } - - /** - * Set error messages and codes. - * @param string $message The error message - * @param string $detail Further detail on the error - * @param string $smtp_code An associated SMTP error code - * @param string $smtp_code_ex Extended SMTP code - */ - protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '') - { - $this->error = array( - 'error' => $message, - 'detail' => $detail, - 'smtp_code' => $smtp_code, - 'smtp_code_ex' => $smtp_code_ex - ); - } - - /** - * Set debug output method. - * @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it. - */ - public function setDebugOutput($method = 'echo') - { - $this->Debugoutput = $method; - } - - /** - * Get debug output method. - * @return string - */ - public function getDebugOutput() - { - return $this->Debugoutput; - } - - /** - * Set debug output level. - * @param integer $level - */ - public function setDebugLevel($level = 0) - { - $this->do_debug = $level; - } - - /** - * Get debug output level. - * @return integer - */ - public function getDebugLevel() - { - return $this->do_debug; - } - - /** - * Set SMTP timeout. - * @param integer $timeout - */ - public function setTimeout($timeout = 0) - { - $this->Timeout = $timeout; - } - - /** - * Get SMTP timeout. - * @return integer - */ - public function getTimeout() - { - return $this->Timeout; - } - - /** - * Reports an error number and string. - * @param integer $errno The error number returned by PHP. - * @param string $errmsg The error message returned by PHP. - * @param string $errfile The file the error occurred in - * @param integer $errline The line number the error occurred on - */ - protected function errorHandler($errno, $errmsg, $errfile = '', $errline = 0) - { - $notice = 'Connection failed.'; - $this->setError( - $notice, - $errno, - $errmsg - ); - $this->edebug( - $notice . ' Error #' . $errno . ': ' . $errmsg . " [$errfile line $errline]", - self::DEBUG_CONNECTION - ); - } - - /** - * Extract and return the ID of the last SMTP transaction based on - * a list of patterns provided in SMTP::$smtp_transaction_id_patterns. - * Relies on the host providing the ID in response to a DATA command. - * If no reply has been received yet, it will return null. - * If no pattern was matched, it will return false. - * @return bool|null|string - */ - protected function recordLastTransactionID() - { - $reply = $this->getLastReply(); - - if (empty($reply)) { - $this->last_smtp_transaction_id = null; - } else { - $this->last_smtp_transaction_id = false; - foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) { - if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) { - $this->last_smtp_transaction_id = $matches[1]; - } - } - } - - return $this->last_smtp_transaction_id; - } - - /** - * Get the queue/transaction ID of the last SMTP transaction - * If no reply has been received yet, it will return null. - * If no pattern was matched, it will return false. - * @return bool|null|string - * @see recordLastTransactionID() - */ - public function getLastTransactionID() - { - return $this->last_smtp_transaction_id; - } -} diff --git a/lib/phpmailer/extras/EasyPeasyICS.php b/lib/phpmailer/extras/EasyPeasyICS.php deleted file mode 100644 index d8bfcfae..00000000 --- a/lib/phpmailer/extras/EasyPeasyICS.php +++ /dev/null @@ -1,148 +0,0 @@ - - * @author Manuel Reinhard - * - * Built with inspiration from - * http://stackoverflow.com/questions/1463480/how-can-i-use-php-to-dynamically-publish-an-ical-file-to-be-read-by-google-calend/1464355#1464355 - * History: - * 2010/12/17 - Manuel Reinhard - when it all started - * 2014 PHPMailer project becomes maintainer - */ - -/** - * Class EasyPeasyICS. - * Simple ICS data generator - * @package phpmailer - * @subpackage easypeasyics - */ -class EasyPeasyICS -{ - /** - * The name of the calendar - * @var string - */ - protected $calendarName; - /** - * The array of events to add to this calendar - * @var array - */ - protected $events = array(); - - /** - * Constructor - * @param string $calendarName - */ - public function __construct($calendarName = "") - { - $this->calendarName = $calendarName; - } - - /** - * Add an event to this calendar. - * @param string $start The start date and time as a unix timestamp - * @param string $end The end date and time as a unix timestamp - * @param string $summary A summary or title for the event - * @param string $description A description of the event - * @param string $url A URL for the event - * @param string $uid A unique identifier for the event - generated automatically if not provided - * @return array An array of event details, including any generated UID - */ - public function addEvent($start, $end, $summary = '', $description = '', $url = '', $uid = '') - { - if (empty($uid)) { - $uid = md5(uniqid(mt_rand(), true)) . '@EasyPeasyICS'; - } - $event = array( - 'start' => gmdate('Ymd', $start) . 'T' . gmdate('His', $start) . 'Z', - 'end' => gmdate('Ymd', $end) . 'T' . gmdate('His', $end) . 'Z', - 'summary' => $summary, - 'description' => $description, - 'url' => $url, - 'uid' => $uid - ); - $this->events[] = $event; - return $event; - } - - /** - * @return array Get the array of events. - */ - public function getEvents() - { - return $this->events; - } - - /** - * Clear all events. - */ - public function clearEvents() - { - $this->events = array(); - } - - /** - * Get the name of the calendar. - * @return string - */ - public function getName() - { - return $this->calendarName; - } - - /** - * Set the name of the calendar. - * @param $name - */ - public function setName($name) - { - $this->calendarName = $name; - } - - /** - * Render and optionally output a vcal string. - * @param bool $output Whether to output the calendar data directly (the default). - * @return string The complete rendered vlal - */ - public function render($output = true) - { - //Add header - $ics = 'BEGIN:VCALENDAR -METHOD:PUBLISH -VERSION:2.0 -X-WR-CALNAME:' . $this->calendarName . ' -PRODID:-//hacksw/handcal//NONSGML v1.0//EN'; - - //Add events - foreach ($this->events as $event) { - $ics .= ' -BEGIN:VEVENT -UID:' . $event['uid'] . ' -DTSTAMP:' . gmdate('Ymd') . 'T' . gmdate('His') . 'Z -DTSTART:' . $event['start'] . ' -DTEND:' . $event['end'] . ' -SUMMARY:' . str_replace("\n", "\\n", $event['summary']) . ' -DESCRIPTION:' . str_replace("\n", "\\n", $event['description']) . ' -URL;VALUE=URI:' . $event['url'] . ' -END:VEVENT'; - } - - //Add footer - $ics .= ' -END:VCALENDAR'; - - if ($output) { - //Output - $filename = $this->calendarName; - //Filename needs quoting if it contains spaces - if (strpos($filename, ' ') !== false) { - $filename = '"'.$filename.'"'; - } - header('Content-type: text/calendar; charset=utf-8'); - header('Content-Disposition: inline; filename=' . $filename . '.ics'); - echo $ics; - } - return $ics; - } -} diff --git a/lib/phpmailer/extras/README.md b/lib/phpmailer/extras/README.md deleted file mode 100644 index df8ca092..00000000 --- a/lib/phpmailer/extras/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# PHPMailer Extras - -These classes provide optional additional functions to PHPMailer. - -These are not loaded by the PHPMailer autoloader, so in some cases you may need to `require` them yourself before using them. - -## EasyPeasyICS - -This class was originally written by Manuel Reinhard and provides a simple means of generating ICS/vCal files that are used in sending calendar events. PHPMailer does not use it directly, but you can use it to generate content appropriate for placing in the `Ical` property of PHPMailer. The PHPMailer project is now its official home as Manuel has given permission for that and is no longer maintaining it himself. - -## htmlfilter - -This class by Konstantin Riabitsev and Jim Jagielski implements HTML filtering to remove potentially malicious tags, such as ` diff --git a/themes/default/news/index.php b/public/themes/default/news/index.php similarity index 98% rename from themes/default/news/index.php rename to public/themes/default/news/index.php index 70c39b11..9dfbec0f 100644 --- a/themes/default/news/index.php +++ b/public/themes/default/news/index.php @@ -1,4 +1,7 @@ -

diff --git a/themes/default/news/manage.php b/public/themes/default/news/manage.php similarity index 95% rename from themes/default/news/manage.php rename to public/themes/default/news/manage.php index 7ab6e10b..b06cbfcb 100644 --- a/themes/default/news/manage.php +++ b/public/themes/default/news/manage.php @@ -1,5 +1,8 @@ loginRequired(); ?>

diff --git a/themes/default/news/view.php b/public/themes/default/news/view.php similarity index 97% rename from themes/default/news/view.php rename to public/themes/default/news/view.php index 0fbbf8e3..db0beb73 100644 --- a/themes/default/news/view.php +++ b/public/themes/default/news/view.php @@ -1,4 +1,7 @@ -

diff --git a/themes/default/pages/add.php b/public/themes/default/pages/add.php similarity index 98% rename from themes/default/pages/add.php rename to public/themes/default/pages/add.php index cfca43a7..b719ff68 100644 --- a/themes/default/pages/add.php +++ b/public/themes/default/pages/add.php @@ -1,4 +1,7 @@ loginRequired(); ?> diff --git a/themes/default/pages/content.php b/public/themes/default/pages/content.php similarity index 92% rename from themes/default/pages/content.php rename to public/themes/default/pages/content.php index 99badcdc..69afc595 100644 --- a/themes/default/pages/content.php +++ b/public/themes/default/pages/content.php @@ -1,4 +1,7 @@

diff --git a/themes/default/pages/delete.php b/public/themes/default/pages/delete.php similarity index 100% rename from themes/default/pages/delete.php rename to public/themes/default/pages/delete.php diff --git a/themes/default/pages/edit.php b/public/themes/default/pages/edit.php similarity index 98% rename from themes/default/pages/edit.php rename to public/themes/default/pages/edit.php index ed2bab6a..4e95eab4 100644 --- a/themes/default/pages/edit.php +++ b/public/themes/default/pages/edit.php @@ -1,4 +1,7 @@ loginRequired(); ?> diff --git a/themes/default/pages/index.php b/public/themes/default/pages/index.php similarity index 98% rename from themes/default/pages/index.php rename to public/themes/default/pages/index.php index 7a261184..bb605c38 100644 --- a/themes/default/pages/index.php +++ b/public/themes/default/pages/index.php @@ -1,4 +1,7 @@ loginRequired(); ?> diff --git a/themes/default/purchase/add.php b/public/themes/default/purchase/add.php similarity index 100% rename from themes/default/purchase/add.php rename to public/themes/default/purchase/add.php diff --git a/themes/default/purchase/cart.php b/public/themes/default/purchase/cart.php similarity index 100% rename from themes/default/purchase/cart.php rename to public/themes/default/purchase/cart.php diff --git a/themes/default/purchase/checkout.php b/public/themes/default/purchase/checkout.php similarity index 100% rename from themes/default/purchase/checkout.php rename to public/themes/default/purchase/checkout.php diff --git a/themes/default/purchase/clear.php b/public/themes/default/purchase/clear.php similarity index 100% rename from themes/default/purchase/clear.php rename to public/themes/default/purchase/clear.php diff --git a/themes/default/purchase/index.php b/public/themes/default/purchase/index.php similarity index 98% rename from themes/default/purchase/index.php rename to public/themes/default/purchase/index.php index eebd9541..2fd73388 100644 --- a/themes/default/purchase/index.php +++ b/public/themes/default/purchase/index.php @@ -1,4 +1,6 @@ - +

Purchase

Items in this shop are purchased using donation credits and not real money. Donation Credits are rewarded to players who make a donation to our server, helping us cover the costs of maintaining and running the server.

serverName) ?> Item Shop

diff --git a/themes/default/purchase/pending.php b/public/themes/default/purchase/pending.php similarity index 100% rename from themes/default/purchase/pending.php rename to public/themes/default/purchase/pending.php diff --git a/themes/default/purchase/remove.php b/public/themes/default/purchase/remove.php similarity index 100% rename from themes/default/purchase/remove.php rename to public/themes/default/purchase/remove.php diff --git a/themes/default/ranking/alchemist.php b/public/themes/default/ranking/alchemist.php similarity index 97% rename from themes/default/ranking/alchemist.php rename to public/themes/default/ranking/alchemist.php index c35135b3..71d92a1e 100644 --- a/themes/default/ranking/alchemist.php +++ b/public/themes/default/ranking/alchemist.php @@ -1,4 +1,6 @@ - +

Alchemist Ranking

Top Alchemist Characters diff --git a/themes/default/ranking/blacksmith.php b/public/themes/default/ranking/blacksmith.php similarity index 97% rename from themes/default/ranking/blacksmith.php rename to public/themes/default/ranking/blacksmith.php index c98ef522..762a9da3 100644 --- a/themes/default/ranking/blacksmith.php +++ b/public/themes/default/ranking/blacksmith.php @@ -1,4 +1,6 @@ - +

Blacksmith Ranking

Top Blacksmith Characters diff --git a/themes/default/ranking/character.php b/public/themes/default/ranking/character.php similarity index 97% rename from themes/default/ranking/character.php rename to public/themes/default/ranking/character.php index 8e7e0a71..805b2cb0 100644 --- a/themes/default/ranking/character.php +++ b/public/themes/default/ranking/character.php @@ -1,4 +1,6 @@ - +

Character Ranking

Top Characters diff --git a/themes/default/ranking/death.php b/public/themes/default/ranking/death.php similarity index 97% rename from themes/default/ranking/death.php rename to public/themes/default/ranking/death.php index 6dc430cb..84a8575f 100644 --- a/themes/default/ranking/death.php +++ b/public/themes/default/ranking/death.php @@ -1,4 +1,6 @@ - +

Death Ranking

Top Most Killed Characters diff --git a/themes/default/ranking/guild.php b/public/themes/default/ranking/guild.php similarity index 96% rename from themes/default/ranking/guild.php rename to public/themes/default/ranking/guild.php index 29038c6f..ab79b292 100644 --- a/themes/default/ranking/guild.php +++ b/public/themes/default/ranking/guild.php @@ -1,4 +1,6 @@ - +

Guild Ranking

Top Guilds diff --git a/themes/default/ranking/homunculus.php b/public/themes/default/ranking/homunculus.php similarity index 97% rename from themes/default/ranking/homunculus.php rename to public/themes/default/ranking/homunculus.php index 08e8f3de..6f1074e0 100644 --- a/themes/default/ranking/homunculus.php +++ b/public/themes/default/ranking/homunculus.php @@ -1,4 +1,6 @@ - +

Homunculus Ranking

Top Homunculi diff --git a/themes/default/ranking/mvp.php b/public/themes/default/ranking/mvp.php similarity index 96% rename from themes/default/ranking/mvp.php rename to public/themes/default/ranking/mvp.php index ef8643b5..46e39287 100644 --- a/themes/default/ranking/mvp.php +++ b/public/themes/default/ranking/mvp.php @@ -1,4 +1,6 @@ - +

MVP Ranking

Search

@@ -8,11 +10,11 @@ - +

@@ -101,7 +103,7 @@ - + diff --git a/themes/default/ranking/zeny.php b/public/themes/default/ranking/zeny.php similarity index 97% rename from themes/default/ranking/zeny.php rename to public/themes/default/ranking/zeny.php index 54582251..cccbb6b0 100644 --- a/themes/default/ranking/zeny.php +++ b/public/themes/default/ranking/zeny.php @@ -1,4 +1,6 @@ - +

Zeny Ranking

Top Richest Characters diff --git a/themes/default/server/info.php b/public/themes/default/server/info.php similarity index 96% rename from themes/default/server/info.php rename to public/themes/default/server/info.php index 31c28736..a719d9cf 100644 --- a/themes/default/server/info.php +++ b/public/themes/default/server/info.php @@ -1,4 +1,6 @@ - +

diff --git a/themes/default/server/status-xml.php b/public/themes/default/server/status-xml.php similarity index 100% rename from themes/default/server/status-xml.php rename to public/themes/default/server/status-xml.php diff --git a/themes/default/server/status.php b/public/themes/default/server/status.php similarity index 96% rename from themes/default/server/status.php rename to public/themes/default/server/status.php index d771ae89..8fddfa32 100644 --- a/themes/default/server/status.php +++ b/public/themes/default/server/status.php @@ -1,4 +1,6 @@ - +

$gameServers): ?> diff --git a/themes/default/service/tos.php b/public/themes/default/service/tos.php similarity index 79% rename from themes/default/service/tos.php rename to public/themes/default/service/tos.php index 5a3dfe2f..2e1d5192 100644 --- a/themes/default/service/tos.php +++ b/public/themes/default/service/tos.php @@ -1,4 +1,6 @@ - +

diff --git a/themes/default/servicedesk/catcontrol.php b/public/themes/default/servicedesk/catcontrol.php similarity index 98% rename from themes/default/servicedesk/catcontrol.php rename to public/themes/default/servicedesk/catcontrol.php index e36c32aa..5c663bff 100644 --- a/themes/default/servicedesk/catcontrol.php +++ b/public/themes/default/servicedesk/catcontrol.php @@ -1,4 +1,7 @@ loginRequired(); ?> diff --git a/themes/default/servicedesk/create.php b/public/themes/default/servicedesk/create.php similarity index 98% rename from themes/default/servicedesk/create.php rename to public/themes/default/servicedesk/create.php index 0e40be71..e2e26425 100644 --- a/themes/default/servicedesk/create.php +++ b/public/themes/default/servicedesk/create.php @@ -1,4 +1,7 @@ loginRequired(); ?> diff --git a/themes/default/servicedesk/index.php b/public/themes/default/servicedesk/index.php similarity index 98% rename from themes/default/servicedesk/index.php rename to public/themes/default/servicedesk/index.php index 2b78123a..100d5e56 100644 --- a/themes/default/servicedesk/index.php +++ b/public/themes/default/servicedesk/index.php @@ -1,4 +1,7 @@ loginRequired(); ?> diff --git a/themes/default/servicedesk/staffindex.php b/public/themes/default/servicedesk/staffindex.php similarity index 97% rename from themes/default/servicedesk/staffindex.php rename to public/themes/default/servicedesk/staffindex.php index 08ad058d..0ed446a0 100644 --- a/themes/default/servicedesk/staffindex.php +++ b/public/themes/default/servicedesk/staffindex.php @@ -1,4 +1,7 @@ loginRequired(); ?> diff --git a/themes/default/servicedesk/staffsettings.php b/public/themes/default/servicedesk/staffsettings.php similarity index 98% rename from themes/default/servicedesk/staffsettings.php rename to public/themes/default/servicedesk/staffsettings.php index c9a2bc21..a65dc671 100644 --- a/themes/default/servicedesk/staffsettings.php +++ b/public/themes/default/servicedesk/staffsettings.php @@ -1,4 +1,7 @@ loginRequired(); ?> diff --git a/themes/default/servicedesk/staffview.php b/public/themes/default/servicedesk/staffview.php similarity index 99% rename from themes/default/servicedesk/staffview.php rename to public/themes/default/servicedesk/staffview.php index e2f31a3e..597a96d3 100644 --- a/themes/default/servicedesk/staffview.php +++ b/public/themes/default/servicedesk/staffview.php @@ -1,4 +1,7 @@ loginRequired(); ?> diff --git a/themes/default/servicedesk/staffviewclosed.php b/public/themes/default/servicedesk/staffviewclosed.php similarity index 97% rename from themes/default/servicedesk/staffviewclosed.php rename to public/themes/default/servicedesk/staffviewclosed.php index 2d331a7b..28bc870d 100644 --- a/themes/default/servicedesk/staffviewclosed.php +++ b/public/themes/default/servicedesk/staffviewclosed.php @@ -1,4 +1,7 @@ loginRequired(); ?> diff --git a/themes/default/servicedesk/view.php b/public/themes/default/servicedesk/view.php similarity index 99% rename from themes/default/servicedesk/view.php rename to public/themes/default/servicedesk/view.php index f3e06e34..ef6cbe34 100644 --- a/themes/default/servicedesk/view.php +++ b/public/themes/default/servicedesk/view.php @@ -1,4 +1,7 @@ loginRequired(); ?> diff --git a/themes/default/unauthorized/index.php b/public/themes/default/unauthorized/index.php similarity index 71% rename from themes/default/unauthorized/index.php rename to public/themes/default/unauthorized/index.php index 1755f3d8..a7839400 100644 --- a/themes/default/unauthorized/index.php +++ b/public/themes/default/unauthorized/index.php @@ -1,3 +1,5 @@ - +

diff --git a/themes/default/vending/index.php b/public/themes/default/vending/index.php similarity index 100% rename from themes/default/vending/index.php rename to public/themes/default/vending/index.php diff --git a/themes/default/vending/viewshop.php b/public/themes/default/vending/viewshop.php similarity index 82% rename from themes/default/vending/viewshop.php rename to public/themes/default/vending/viewshop.php index aaca8963..ffa99c27 100644 --- a/themes/default/vending/viewshop.php +++ b/public/themes/default/vending/viewshop.php @@ -1,4 +1,6 @@ - +

title ?>

@@ -11,11 +13,14 @@ ID Name Refine - Slot - Card0 - Card1 - Card2 - Card3 + Slots + Slot 1 + Slot 2 + Slot 3 + Slot 4 + isRenewal): ?> + + Price Amount @@ -86,7 +91,7 @@ - card0 && ($item->type == 4 || $item->type == 5) && $item->card0 != 254 && $item->card0 != 255 && $item->card0 != -256): ?> + card0 && ($item->type == $type_list['armor'] || $item->type == $type_list['weapon']) && $item->card0 != 254 && $item->card0 != 255 && $item->card0 != -256): ?> card0])): ?> linkToItem($item->card0, $cards[$item->card0]) ?> @@ -97,7 +102,7 @@ - card1 && ($item->type == 4 || $item->type == 5) && $item->card0 != 255 && $item->card0 != -256): ?> + card1 && ($item->type == $type_list['armor'] || $item->type == $type_list['weapon']) && $item->card0 != 255 && $item->card0 != -256): ?> card1])): ?> linkToItem($item->card1, $cards[$item->card1]) ?> @@ -108,7 +113,7 @@ - card2 && ($item->type == 4 || $item->type == 5) && $item->card0 != 254 && $item->card0 != 255 && $item->card0 != -256): ?> + card2 && ($item->type == $type_list['armor'] || $item->type == $type_list['weapon']) && $item->card0 != 254 && $item->card0 != 255 && $item->card0 != -256): ?> card2])): ?> linkToItem($item->card2, $cards[$item->card2]) ?> @@ -119,7 +124,7 @@ - card3 && ($item->type == 4 || $item->type == 5) && $item->card0 != 254 && $item->card0 != 255 && $item->card0 != -256): ?> + card3 && ($item->type == $type_list['armor'] || $item->type == $type_list['weapon']) && $item->card0 != 254 && $item->card0 != 255 && $item->card0 != -256): ?> card3])): ?> linkToItem($item->card3, $cards[$item->card3]) ?> @@ -129,7 +134,17 @@ None - + isRenewal): ?> + + rndopt): ?> +
    + rndopt as $rndopt) echo "
  • ".$this->itemRandOption($rndopt[0], $rndopt[1])."
  • "; ?> +
+ + None + + + price, 0, ',', ' '); ?> z diff --git a/themes/default/webcommands/index.php b/public/themes/default/webcommands/index.php old mode 100755 new mode 100644 similarity index 100% rename from themes/default/webcommands/index.php rename to public/themes/default/webcommands/index.php diff --git a/themes/default/woe/custom.php b/public/themes/default/woe/custom.php similarity index 100% rename from themes/default/woe/custom.php rename to public/themes/default/woe/custom.php diff --git a/themes/default/woe/index.php b/public/themes/default/woe/index.php similarity index 94% rename from themes/default/woe/index.php rename to public/themes/default/woe/index.php index 69686052..8cb7f193 100644 --- a/themes/default/woe/index.php +++ b/public/themes/default/woe/index.php @@ -1,4 +1,6 @@ - +

loginAthenaGroup->serverName)) ?>

diff --git a/themes/installer/footer.php b/public/themes/installer/footer.php similarity index 100% rename from themes/installer/footer.php rename to public/themes/installer/footer.php diff --git a/themes/installer/header.php b/public/themes/installer/header.php similarity index 100% rename from themes/installer/header.php rename to public/themes/installer/header.php diff --git a/themes/installer/install/index.php b/public/themes/installer/install/index.php similarity index 100% rename from themes/installer/install/index.php rename to public/themes/installer/install/index.php diff --git a/themes/installer/rathena-001.png b/public/themes/installer/rathena-001.png similarity index 100% rename from themes/installer/rathena-001.png rename to public/themes/installer/rathena-001.png diff --git a/lib/Flux/Addon.php b/src/Addon.php similarity index 57% rename from lib/Flux/Addon.php rename to src/Addon.php index 8f222d54..5ba126a5 100644 --- a/lib/Flux/Addon.php +++ b/src/Addon.php @@ -1,7 +1,8 @@ name = $name; - $this->addonDir = is_null($addonDir) ? FLUX_ADDON_DIR."/$name" : $addonDir; - $this->configDir = "{$this->addonDir}/config"; - $this->moduleDir = "{$this->addonDir}/modules"; - $this->themeDir = "{$this->addonDir}/themes"; - + $this->name = $name; + $this->addonDir = is_null($addonDir) ? FLUX_ADDON_DIR . "/$name" : $addonDir; + $this->configDir = "{$this->addonDir}/config"; + $this->moduleDir = "{$this->addonDir}/modules"; + $this->themeDir = "{$this->addonDir}/themes"; + $files = array( - 'addonConfig' => "{$this->configDir}/addon.php", - 'accessConfig' => "{$this->configDir}/access.php", + 'addonConfig' => "{$this->configDir}/addon.php", + 'accessConfig' => "{$this->configDir}/access.php", //'messagesConfig' => "{$this->configDir}/messages.php" // Deprecated. ); - + foreach ($files as $configName => $filename) { if (file_exists($filename)) { $this->{$configName} = Flux::parseConfigFile($filename); } - - if (!($this->{$configName} instanceOf Flux_Config)) { + + if (!($this->{$configName} instanceOf Config)) { $tempArr = array(); - $this->{$configName} = new Flux_Config($tempArr); + $this->{$configName} = new Config($tempArr); } } - + // Use new language system for messages (also supports addons). $this->messagesConfig = Flux::parseLanguageConfigFile($name); } - + public function respondsTo($module, $action = null) { $path = is_null($action) ? "{$this->moduleDir}/$module" : "{$this->moduleDir}/$module/$action.php"; if ((is_null($action) && is_dir($path)) || file_exists($path)) { return true; - } - else { + } else { return false; } } - public function getView(Flux_Template $template, $module, $action) + public function getView(Template $template, $module, $action) { - $path = "{$this->themeDir}/". $template->getName() . "/{$module}/{$action}.php"; + $path = "{$this->themeDir}/" . $template->getName() . "/{$module}/{$action}.php"; if (file_exists($path)) { return $path; } if (!empty($template->parentTemplate)) { - return $this->getView( $template->parentTemplate, $module, $action); + return $this->getView($template->parentTemplate, $module, $action); } return false; } } -?> diff --git a/lib/Flux/Athena.php b/src/Athena.php similarity index 69% rename from lib/Flux/Athena.php rename to src/Athena.php index 0819775c..2980c545 100644 --- a/lib/Flux/Athena.php +++ b/src/Athena.php @@ -1,5 +1,9 @@ loginServer = $loginServer; - $this->charServer = $charServer; - $this->mapServer = $mapServer; - $this->loginDatabase = $loginServer->config->getDatabase(); - - $this->serverName = $charMapConfig->getServerName(); - $this->expRates = $charMapConfig->getExpRates()->toArray(); - $this->dropRates = $charMapConfig->getDropRates()->toArray(); - $this->isRenewal = (boolean)$charMapConfig->getRenewal(); - $this->maxCharSlots = (int)$charMapConfig->getMaxCharSlots(); - $this->dateTimezone = $charMapConfig->getDateTimezone(); + $this->loginServer = $loginServer; + $this->charServer = $charServer; + $this->mapServer = $mapServer; + $this->loginDatabase = $loginServer->config->getDatabase(); + + $this->serverName = $charMapConfig->getServerName(); + $this->expRates = $charMapConfig->getExpRates()->toArray(); + $this->dropRates = $charMapConfig->getDropRates()->toArray(); + $this->isRenewal = (boolean)$charMapConfig->getRenewal(); + $this->maxCharSlots = (int)$charMapConfig->getMaxCharSlots(); + $this->dateTimezone = $charMapConfig->getDateTimezone(); $this->charMapDatabase = $charMapConfig->getDatabase(); - + $resetDenyMaps = $charMapConfig->getResetDenyMaps(); if (!$resetDenyMaps) { $this->resetDenyMaps = array('sec_pri'); - } - elseif (!is_array($resetDenyMaps)) { + } elseif (!is_array($resetDenyMaps)) { $this->resetDenyMaps = array($resetDenyMaps); - } - else { + } else { $this->resetDenyMaps = $resetDenyMaps->toArray(); } - + // Get WoE times specific in servers config. $woeDayTimes = $charMapConfig->getWoeDayTimes(); - if ($woeDayTimes instanceOf Flux_Config) { + if ($woeDayTimes instanceOf Config) { $woeDayTimes = $woeDayTimes->toArray(); foreach ($woeDayTimes as $dayTime) { if (!is_array($dayTime) || count($dayTime) < 4) { continue; } - + list ($sDay, $sTime, $eDay, $eTime) = array_slice($dayTime, 0, 4); $sTime = trim($sTime); $eTime = trim($eTime); - + if ($sDay < 0 || $sDay > 6 || $eDay < 0 || $eDay > 6 || - !preg_match('/^\d{2}:\d{2}$/', $sTime) || !preg_match('/^\d{2}:\d{2}$/', $eTime)) { + !preg_match('/^\d{2}:\d{2}$/', $sTime) || !preg_match('/^\d{2}:\d{2}$/', $eTime)) { continue; } - + $this->woeDayTimes[] = array( - 'startingDay' => $sDay, + 'startingDay' => $sDay, 'startingTime' => $sTime, - 'endingDay' => $eDay, - 'endingTime' => $eTime + 'endingDay' => $eDay, + 'endingTime' => $eTime ); } } - + // Config used for disallowing access to certain modules during WoE. - $woeDisallow = $charMapConfig->getWoeDisallow(); - $_tempArray = array(); - $this->woeDisallow = new Flux_Config($_tempArray); - - if ($woeDisallow instanceOf Flux_Config) { - $woeDisallow = $woeDisallow->toArray(); - + $woeDisallow = $charMapConfig->getWoeDisallow(); + $_tempArray = array(); + $this->woeDisallow = new Config($_tempArray); + + if ($woeDisallow instanceOf Config) { + $woeDisallow = $woeDisallow->toArray(); + foreach ($woeDisallow as $disallow) { if (array_key_exists('module', $disallow)) { $module = $disallow['module']; if (array_key_exists('action', $disallow)) { $action = $disallow['action']; $this->woeDisallow->set("$module.$action", true); - } - else { + } else { $this->woeDisallow->set($module, true); } } } } } - + /** * Set connection object. * - * @param Flux_Connection $connection - * @return Flux_Connection + * @param Connection $connection + * @return Connection */ - public function setConnection(Flux_Connection $connection) + public function setConnection(Connection $connection) { - $this->connection = $connection; + $this->connection = $connection; $this->logsDatabase = $connection->logsDbConfig->getDatabase(); - + return $connection; } - + /** * Set cart object. * - * @param Flux_ItemShop_Cart $cart - * @return Flux_ItemShop_Cart + * @param Cart $cart + * @return Cart */ - public function setCart(Flux_ItemShop_Cart $cart) + public function setCart(Cart $cart) { $this->cart = $cart; return $cart; } - + /** * When casted to a string, the server name should be used. * @@ -275,11 +277,11 @@ public function __toString() { return $this->serverName; } - + /** * Transfer credits from one account to another. * - * @param int $fromAccountID Account ID + * @param int $fromAccountID Account ID * @param string $targetCharName Character name of person receiving credits * @param int $credits Amount of credits */ @@ -293,50 +295,50 @@ public function transferCredits($fromAccountID, $targetCharName, $credits) // true = Successful transfer // false = Error // - + $sql = "SELECT account_id, char_id, name AS char_name FROM {$this->charMapDatabase}.`char` WHERE `char`.name = ? LIMIT 1"; $sth = $this->connection->getStatement($sql); - - if (!$sth->execute(array($targetCharName)) || !($char=$sth->fetch())) { + + if (!$sth->execute(array($targetCharName)) || !($char = $sth->fetch())) { // Unknown character. return -3; } - + $targetAccountID = $char->account_id; - $targetCharID = $char->char_id; - - - $sql = "SELECT COUNT(account_id) AS accounts FROM {$this->loginDatabase}.login WHERE "; + $targetCharID = $char->char_id; + + + $sql = "SELECT COUNT(account_id) AS accounts FROM {$this->loginDatabase}.login WHERE "; $sql .= "account_id = ? OR account_id = ? LIMIT 2"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + if (!$sth->execute(array($fromAccountID, $targetAccountID)) || $sth->fetch()->accounts != 2) { // One or the other, from or to, are non-existent accounts. return -1; } - + if (!$this->loginServer->hasCreditsRecord($fromAccountID)) { // Sender has a zero balance. return -2; } - + $creditsTable = Flux::config('FluxTables.CreditsTable'); - $xferTable = Flux::config('FluxTables.CreditTransferTable'); - + $xferTable = Flux::config('FluxTables.CreditTransferTable'); + // Get balance of sender. $sql = "SELECT balance FROM {$this->loginDatabase}.$creditsTable WHERE account_id = ? LIMIT 1"; $sth = $this->connection->getStatement($sql); - + if (!$sth->execute(array($fromAccountID))) { // Error. return false; } - + if ($sth->fetch()->balance < $credits) { // Insufficient balance. return -2; } - + // Take credits from fromAccount first. if ($this->loginServer->depositCredits($fromAccountID, -$credits)) { // Then deposit to targetAccount next. @@ -344,36 +346,34 @@ public function transferCredits($fromAccountID, $targetCharName, $credits) // Attempt to restore credits if deposit to toAccount failed. $this->loginServer->depositCredits($fromAccountID, $credits); return false; - } - else { - $sql = "INSERT INTO {$this->charMapDatabase}.$xferTable "; + } else { + $sql = "INSERT INTO {$this->charMapDatabase}.$xferTable "; $sql .= "(from_account_id, target_account_id, target_char_id, amount, transfer_date) "; $sql .= "VALUES (?, ?, ?, ?, NOW())"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + // Log transfer. $sth->execute(array($fromAccountID, $targetAccountID, $targetCharID, $credits)); - + return true; } - } - else { + } else { return false; } } - + /** * Set loginAthenaGroup object. * - * @param Flux_LoginAthenaGroup $loginAthenaGroup - * @return Flux_LoginAthenaGroup + * @param LoginAthenaGroup $loginAthenaGroup + * @return LoginAthenaGroup */ - public function setLoginAthenaGroup(Flux_LoginAthenaGroup $loginAthenaGroup) + public function setLoginAthenaGroup(LoginAthenaGroup $loginAthenaGroup) { $this->loginAthenaGroup = $loginAthenaGroup; return $loginAthenaGroup; } - + /** * Check if a character exists with a particular char ID. * @@ -382,14 +382,13 @@ public function setLoginAthenaGroup(Flux_LoginAthenaGroup $loginAthenaGroup) */ public function charExists($charID) { - $sql = "SELECT char_id FROM {$this->charMapDatabase}.`char` WHERE "; + $sql = "SELECT char_id FROM {$this->charMapDatabase}.`char` WHERE "; $sql .= "`char`.char_id = ? LIMIT 1"; - $sth = $this->connection->getStatement($sql); - - if ($sth->execute(array($charID)) && ($char=$sth->fetch()) && $char->char_id) { + $sth = $this->connection->getStatement($sql); + + if ($sth->execute(array($charID)) && ($char = $sth->fetch()) && $char->char_id) { return true; - } - else { + } else { return false; } } @@ -403,18 +402,17 @@ public function charExists($charID) */ public function charBelongsToAccount($charID, $accountID) { - $sql = "SELECT char_id FROM {$this->charMapDatabase}.`char` WHERE "; + $sql = "SELECT char_id FROM {$this->charMapDatabase}.`char` WHERE "; $sql .= "`char`.char_id = ? AND `char`.account_id = ? LIMIT 1"; - $sth = $this->connection->getStatement($sql); - - if ($sth->execute(array($charID, $accountID)) && ($char=$sth->fetch()) && $char->char_id) { + $sth = $this->connection->getStatement($sql); + + if ($sth->execute(array($charID, $accountID)) && ($char = $sth->fetch()) && $char->char_id) { return true; - } - else { + } else { return false; } } - + /** * Check if char with charID is online. * @@ -423,18 +421,17 @@ public function charBelongsToAccount($charID, $accountID) */ public function charIsOnline($charID) { - $sql = "SELECT char_id FROM {$this->charMapDatabase}.`char` WHERE `char`.online > 0 "; + $sql = "SELECT char_id FROM {$this->charMapDatabase}.`char` WHERE `char`.online > 0 "; $sql .= "AND `char`.char_id = ? LIMIT 1"; - $sth = $this->connection->getStatement($sql); - - if ($sth->execute(array($charID)) && ($char=$sth->fetch()) && $char->char_id) { + $sth = $this->connection->getStatement($sql); + + if ($sth->execute(array($charID)) && ($char = $sth->fetch()) && $char->char_id) { return true; - } - else { + } else { return false; } } - + /** * Check if account has any online characters at the moment. * @@ -443,58 +440,56 @@ public function charIsOnline($charID) */ public function accountHasOnlineChars($accountID) { - $sql = "SELECT char_id FROM {$this->charMapDatabase}.`char` WHERE `char`.online > 0 "; + $sql = "SELECT char_id FROM {$this->charMapDatabase}.`char` WHERE `char`.online > 0 "; $sql .= "AND `char`.account_id = ? ORDER BY `char`.online DESC LIMIT 1"; - $sth = $this->connection->getStatement($sql); - - if ($sth->execute(array($accountID)) && ($char=$sth->fetch()) && $char->char_id) { + $sth = $this->connection->getStatement($sql); + + if ($sth->execute(array($accountID)) && ($char = $sth->fetch()) && $char->char_id) { return true; - } - else { + } else { return false; } } - + /** * Get character data of charID. * * @param int $charID - * @return mixed Returns Flux_DataObject or false. + * @return mixed Returns rAthena\FluxCp\Flux_DataObject or false. */ public function getCharacter($charID) { - $sql = "SELECT `char`.* FROM {$this->charMapDatabase}.`char` WHERE "; + $sql = "SELECT `char`.* FROM {$this->charMapDatabase}.`char` WHERE "; $sql .= "`char`.char_id = ? LIMIT 1"; - $sth = $this->connection->getStatement($sql); - - if ($sth->execute(array($charID)) && ($char=$sth->fetch())) { + $sth = $this->connection->getStatement($sql); + + if ($sth->execute(array($charID)) && ($char = $sth->fetch())) { return $char; - } - else { + } else { return false; } } - + /** * Get character prefs. * * @param int $charID Character ID * @param array $prefs Only these prefs? - * @return mixed Flux_Config or false. + * @return mixed rAthena\FluxCp\Flux_Config or false. */ public function getPrefs($charID, array $prefs = array()) { $sql = "SELECT account_id FROM {$this->charMapDatabase}.`char` WHERE char_id = ? LIMIT 1"; $sth = $this->connection->getStatement($sql); - - if ($sth->execute(array($charID)) && ($char=$sth->fetch())) { + + if ($sth->execute(array($charID)) && ($char = $sth->fetch())) { $charPrefsTable = Flux::config('FluxTables.CharacterPrefsTable'); - + $pref = array(); $bind = array($char->account_id, $charID); - $sql = "SELECT name, value FROM {$this->charMapDatabase}.$charPrefsTable "; + $sql = "SELECT name, value FROM {$this->charMapDatabase}.$charPrefsTable "; $sql .= "WHERE account_id = ? AND char_id = ?"; - + if ($prefs) { foreach ($prefs as $p) { $pref[] = "name = ?"; @@ -502,26 +497,24 @@ public function getPrefs($charID, array $prefs = array()) } $sql .= sprintf(' AND (%s)', implode(' OR ', $pref)); } - + $sth = $this->connection->getStatement($sql); - + if ($sth->execute($bind)) { $prefsArray = array(); foreach ($sth->fetchAll() as $p) { $prefsArray[$p->name] = $p->value; } - - return new Flux_Config($prefsArray); - } - else { + + return new Config($prefsArray); + } else { return false; } - } - else { + } else { return false; } } - + /** * Set character prefs. * @@ -533,15 +526,15 @@ public function setPrefs($charID, array $prefsArray) { $sql = "SELECT account_id FROM {$this->charMapDatabase}.`char` WHERE char_id = ? LIMIT 1"; $sth = $this->connection->getStatement($sql); - - if ($sth->execute(array($charID)) && ($char=$sth->fetch())) { + + if ($sth->execute(array($charID)) && ($char = $sth->fetch())) { $charPrefsTable = Flux::config('FluxTables.CharacterPrefsTable'); - + $pref = array(); $bind = array($char->account_id, $charID); - $sql = "SELECT id, name, value FROM {$this->charMapDatabase}.$charPrefsTable "; + $sql = "SELECT id, name, value FROM {$this->charMapDatabase}.$charPrefsTable "; $sql .= "WHERE account_id = ? AND char_id = ?"; - + if ($prefsArray) { foreach ($prefsArray as $prefName => $prefValue) { $pref[] = "name = ?"; @@ -549,47 +542,44 @@ public function setPrefs($charID, array $prefsArray) } $sql .= sprintf(' AND (%s)', implode(' OR ', $pref)); } - + $sth = $this->connection->getStatement($sql); - + if ($sth->execute($bind)) { - $prefs = $sth->fetchAll(); + $prefs = $sth->fetchAll(); $update = array(); - - $usql = "UPDATE {$this->charMapDatabase}.$charPrefsTable "; - $usql .= "SET value = ? WHERE id = ?"; - $usth = $this->connection->getStatement($usql); - - $isql = "INSERT INTO {$this->charMapDatabase}.$charPrefsTable "; - $isql .= "(account_id, char_id, name, value, create_date) "; - $isql .= "VALUES (?, ?, ?, ?, NOW())"; - $isth = $this->connection->getStatement($isql); - + + $usql = "UPDATE {$this->charMapDatabase}.$charPrefsTable "; + $usql .= "SET value = ? WHERE id = ?"; + $usth = $this->connection->getStatement($usql); + + $isql = "INSERT INTO {$this->charMapDatabase}.$charPrefsTable "; + $isql .= "(account_id, char_id, name, value, create_date) "; + $isql .= "VALUES (?, ?, ?, ?, NOW())"; + $isth = $this->connection->getStatement($isql); + foreach ($prefs as $p) { $update[$p->name] = $p->id; } - + foreach ($prefsArray as $pref => $value) { if (array_key_exists($pref, $update)) { $id = $update[$pref]; $usth->execute(array($value, $id)); - } - else { + } else { $isth->execute(array($char->account_id, $charID, $pref, $value)); } } - + return true; - } - else { + } else { return false; } - } - else { + } else { return false; } } - + /** * Get a single character pref. * @@ -600,14 +590,13 @@ public function setPrefs($charID, array $prefsArray) public function getPref($charID, $pref) { $prefs = $this->getPrefs($charID, array($pref)); - if ($prefs instanceOf Flux_Config) { + if ($prefs instanceOf Config) { return $prefs->get($pref); - } - else { + } else { return false; } } - + /** * Set a single character pref. * @@ -620,7 +609,7 @@ public function setPref($charID, $pref, $value) { return $this->setPrefs($charID, array($pref => $value)); } - + /** * Re-set the appearance of a character. * @@ -634,38 +623,37 @@ public function resetLook($charID) // -2 = Unknown character. // false = Failed to reset. // true = Successfully reset. - + $char = $this->getCharacter($charID); - + if (!$char) { return -2; } if ($char->online) { return -1; } - - $sql = "UPDATE {$this->charMapDatabase}.inventory SET "; + + $sql = "UPDATE {$this->charMapDatabase}.inventory SET "; $sql .= "equip = 0 WHERE char_id = ?"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + if (!$sth->execute(array($charID))) { return false; } - - $sql = "UPDATE {$this->charMapDatabase}.`char` SET "; + + $sql = "UPDATE {$this->charMapDatabase}.`char` SET "; $sql .= "hair = 1, hair_color = 0, clothes_color = 0, weapon = 0, shield = 0, "; - $sql .= "head_top = 0, head_mid = 0, head_bottom = 0 "; + $sql .= "head_top = 0, head_mid = 0, head_bottom = 0, body = 0"; $sql .= "WHERE char_id = ?"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + if (!$sth->execute(array($charID))) { return false; - } - else { + } else { return true; } } - + /** * Re-set the position of a character. * @@ -680,16 +668,16 @@ public function resetPosition($charID) // -3 = Unknown character. // false = Failed to reset. // true = Successfully reset. - + $char = $this->getCharacter($charID); - + if (!$char) { return -3; } if ($char->online) { return -1; } - + $charMap = basename($char->last_map, '.gat'); foreach ($this->resetDenyMaps as $map) { $denyMap = basename($map, '.gat'); @@ -697,20 +685,19 @@ public function resetPosition($charID) return -2; } } - - $sql = "UPDATE {$this->charMapDatabase}.`char` AS ch SET "; + + $sql = "UPDATE {$this->charMapDatabase}.`char` AS ch SET "; $sql .= "ch.last_map = ch.save_map, ch.last_x = ch.save_x, ch.last_y = ch.save_y "; $sql .= "WHERE ch.char_id = ?"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + if ($sth->execute(array($charID))) { return true; - } - else { + } else { return false; } } - + /** * Get the current server time, based on the DateTimezone servers.php config. * @@ -725,7 +712,7 @@ public function getServerTime($format = 'U') } return $dateTime->format($format); } - + /** * Check if it currently WoE according to the configured hours and timezone. * @@ -734,20 +721,19 @@ public function getServerTime($format = 'U') public function isWoe() { $serverTime = (int)$this->getServerTime(); - $dayNames = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'); - + $dayNames = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'); + foreach ($this->woeDayTimes as $woeDayTime) { - $sDay = $dayNames[$woeDayTime['startingDay']]; - $eDay = $dayNames[$woeDayTime['endingDay']]; + $sDay = $dayNames[$woeDayTime['startingDay']]; + $eDay = $dayNames[$woeDayTime['endingDay']]; $start = strtotime("$sDay {$woeDayTime['startingTime']}"); - $end = strtotime("$eDay {$woeDayTime['endingTime']}"); - + $end = strtotime("$eDay {$woeDayTime['endingTime']}"); + if ($serverTime > $start && $serverTime < $end) { return true; } } - + return false; } } -?> diff --git a/lib/Flux/Authorization.php b/src/Authorization.php similarity index 73% rename from lib/Flux/Authorization.php rename to src/Authorization.php index 28fc704b..e296885f 100644 --- a/lib/Flux/Authorization.php +++ b/src/Authorization.php @@ -1,65 +1,67 @@ config = $accessConfig; + $this->config = $accessConfig; $this->session = $sessionData; } - + /** * Get authorization instance, creates one if it doesn't already exist. * - * @param Flux_Config $accessConfig - * @param Flux_SessionData $sessionData - * @return Flux_Authorization + * @param Config $accessConfig + * @param SessionData $sessionData + * @return Authorization * @access public */ public static function getInstance($accessConfig = null, $sessionData = null) { if (!self::$auth) { - self::$auth = new Flux_Authorization($accessConfig, $sessionData); + self::$auth = new Authorization($accessConfig, $sessionData); } - return self::$auth; + return self::$auth; } - + /** * Checks whether or not the current user is able to perform a particular * action based on his/her group level and id. @@ -72,34 +74,33 @@ public static function getInstance($accessConfig = null, $sessionData = null) public function actionAllowed($moduleName, $actionName = 'index') { $accessConfig = $this->config->get('modules'); - $accessKeys = array("$moduleName.$actionName", "$moduleName.*"); + $accessKeys = array("$moduleName.$actionName", "$moduleName.*"); $accountLevel = $this->session->account->group_level; $existentKeys = array(); - if ($accessConfig instanceOf Flux_Config) { + if ($accessConfig instanceOf Config) { foreach ($accessKeys as $accessKey) { $accessLevel = $accessConfig->get($accessKey); - + if (!is_null($accessLevel)) { $existentKeys[] = $accessKey; - + if ($accessLevel == AccountLevel::ANYONE || $accessLevel == $accountLevel || ($accessLevel != AccountLevel::UNAUTH && $accessLevel <= $accountLevel)) { - + return true; } } } } - + if (empty($existentKeys)) { return -1; - } - else { + } else { return false; } } - + /** * Checks whether or not the current user is allowed to use a particular * feature based on his/her group level and id. @@ -112,20 +113,20 @@ public function featureAllowed($featureName) { $accessConfig = $this->config->get('features'); $accountLevel = $this->session->account->group_level; - - if (($accessConfig instanceOf Flux_Config)) { + + if (($accessConfig instanceOf Config)) { $accessLevel = $accessConfig->get($featureName); - + if (!is_null($accessLevel) && ($accessLevel == AccountLevel::ANYONE || $accessLevel == $accountLevel || - ($accessLevel != AccountLevel::UNAUTH && $accessLevel <= $accountLevel))) { - + ($accessLevel != AccountLevel::UNAUTH && $accessLevel <= $accountLevel))) { + return true; } } return false; } - + /** * Provides convenient getters such as `allowedTo' and * `getGroupLevelTo'. @@ -136,31 +137,28 @@ public function __get($prop) { if (preg_match("/^allowedTo(.+)/i", $prop, $m)) { return $this->featureAllowed($m[1]); - } - elseif (preg_match("/^getGroupLevelTo(.+)/i", $prop, $m)) { + } elseif (preg_match("/^getGroupLevelTo(.+)/i", $prop, $m)) { $accessConfig = $this->config->get('features'); - if ($accessConfig instanceOf Flux_Config) { + if ($accessConfig instanceOf Config) { return $accessConfig->get($m[1]); } } } - + /** * Wrapper method for setting and getting values from the access config. * * @param string $key * @param mixed $value - * @param arary $options + * @param array $options * @access public */ public function config($key, $value = null, $options = array()) { if (!is_null($value)) { return $this->config->set($key, $value, $options); - } - else { + } else { return $this->config->get($key); } } } -?> diff --git a/lib/Flux/BaseServer.php b/src/BaseServer.php similarity index 83% rename from lib/Flux/BaseServer.php rename to src/BaseServer.php index 2f42f49b..4d5a5120 100644 --- a/lib/Flux/BaseServer.php +++ b/src/BaseServer.php @@ -1,29 +1,32 @@ config = $config; } - + /** * Checks whether the server is up and running (accepting connections). * Will return true/false based on the server status. @@ -36,14 +39,12 @@ public function isUp() $addr = $this->config->getAddress(); $port = $this->config->getPort(); $sock = @fsockopen($addr, $port, $errno, $errstr, (int)Flux::config('ServerStatusTimeout')); - + if (is_resource($sock)) { fclose($sock); return true; - } - else { + } else { return false; } } } -?> diff --git a/lib/Flux/Captcha.php b/src/Captcha.php similarity index 75% rename from lib/Flux/Captcha.php rename to src/Captcha.php index 59d9bf08..f88d1633 100644 --- a/lib/Flux/Captcha.php +++ b/src/Captcha.php @@ -1,8 +1,11 @@ options = array_merge( array( - 'chars' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWWXYZ0123456789', - 'length' => 5, - 'background' => FLUX_DATA_DIR.'/captcha/background.png', - 'fontPath' => FLUX_DATA_DIR.'/captcha/fonts', - 'fontName' => 'default.ttf', - 'fontSize' => 28, - 'yPosition' => 40, + 'chars' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWWXYZ0123456789', + 'length' => 5, + 'background' => FLUX_DATA_DIR . '/captcha/background.png', + 'fontPath' => realpath(FLUX_DATA_DIR . '/captcha/fonts'), + 'fontName' => 'default.ttf', + 'fontSize' => 28, + 'yPosition' => 40, 'useDistort' => true, 'distortion' => 10 ), $options ); - + // Let GD know where our fonts are. //putenv("GDFONTPATH={$this->options['fontPath']}"); // Possibly breaks on Windows? - + // Generate security code. $this->generateCode(); - + // Generate CAPTCHA image. $this->generateImage(); } - + /** * Generate the security code to be used. * @@ -64,17 +67,17 @@ public function __construct($options = array()) */ protected function generateCode() { - $code = ''; + $code = ''; $chars = str_split($this->options['chars']); - + for ($i = 0; $i < $this->options['length']; ++$i) { $code .= $chars[array_rand($chars)]; } - + $this->code = $code; return $code; } - + /** * Generate the image. * @@ -83,32 +86,31 @@ protected function generateCode() protected function generateImage() { $this->gd = imagecreatefrompng($this->options['background']); - $yPos = $this->options['yPosition']; - $font = "{$this->options['fontPath']}/{$this->options['fontName']}"; - $size = $this->options['fontSize']; + $yPos = $this->options['yPosition']; + $font = "{$this->options['fontPath']}/{$this->options['fontName']}"; + $size = $this->options['fontSize']; $shade1 = imagecolorallocate($this->gd, 240, 240, 240); $shade2 = imagecolorallocate($this->gd, 60, 60, 60); $shade3 = imagecolorallocate($this->gd, 0, 0, 0); - + if (function_exists('imagettftext')) { $distA = -$this->options['distortion']; $distB = +$this->options['distortion']; - + foreach (str_split($this->code, 1) as $i => $char) { imagettftext($this->gd, $size + 2, $this->options['useDistort'] ? rand($distA, $distB) : 0, ((28 * $i) + 10), $yPos, $shade3, $font, $char); imagettftext($this->gd, $size + 4, $this->options['useDistort'] ? rand($distA, $distB) : 0, ((28 * $i) + 10), $yPos, $shade2, $font, $char); - imagettftext($this->gd, $size , $this->options['useDistort'] ? rand($distA, $distB) : 0, ((28 * $i) + 10), $yPos, $shade1, $font, $char); + imagettftext($this->gd, $size, $this->options['useDistort'] ? rand($distA, $distB) : 0, ((28 * $i) + 10), $yPos, $shade1, $font, $char); } - } - else { - $text = "FreeType2 is needed\n"; + } else { + $text = "FreeType2 is needed\n"; $text .= "for CAPTCHA support.\n"; foreach (explode("\n", $text) as $i => $line) { imagestring($this->gd, 3, 5, (12 * ($i + 1)), $line, $shade1); } } } - + /** * Display image. * @@ -120,10 +122,9 @@ public function display() imagepng($this->gd); exit; } - + public function __destruct() { imagedestroy($this->gd); } } -?> diff --git a/src/CashShop.php b/src/CashShop.php new file mode 100644 index 00000000..e26c6987 --- /dev/null +++ b/src/CashShop.php @@ -0,0 +1,109 @@ +server = $server; + } + + /** + * Add an item to the cash shop. + */ + public function add($tab, $itemID, $price) + { + $db = $this->server->charMapDatabase; + $sql = "INSERT INTO $db.`item_cash_db` (tab, item_id, price) VALUES (?, ?, ?)"; + $sth = $this->server->connection->getStatement($sql); + $res = $sth->execute(array($tab, $itemID, $price)); + + if ($res) { + return true; + } else { + return false; + } + } + + /** + * Modify item info in the shop. + */ + public function edit($shopItemID, $tab = null, $price = null) + { + $tabQ = ''; + $priceQ = ''; + $bind = array(); + + if (!is_null($tab)) { + $tabQ = "tab = ? "; + $bind[] = (int)$tab; + } + + if (!is_null($price)) { + if ($tabQ) { + $priceQ = ", price = ? "; + } else { + $priceQ = "price = ? "; + } + $bind[] = (int)$price; + } + + if (empty($bind)) { + return false; + } + + $db = $this->server->charMapDatabase; + $sql = "UPDATE $db.`item_cash_db` SET $tabQ $priceQ WHERE item_id = ?"; + $sth = $this->server->connection->getStatement($sql); + + $bind[] = $shopItemID; + return $sth->execute($bind); + } + + /** + * + */ + public function delete($ItemID) + { + $db = $this->server->charMapDatabase; + $sql = "DELETE FROM $db.`item_cash_db` WHERE item_id = ?"; + $sth = $this->server->connection->getStatement($sql); + + return $sth->execute(array($ItemID)); + } + + /** + * + */ + public function getItem($shopItemID) + { + $db = $this->server->charMapDatabase; + + if ($this->server->isRenewal) { + $fromTables = array("$db.item_db_re", "$db.item_db2_re"); + } else { + $fromTables = array("$db.item_db", "$db.item_db2"); + } + + $temp = new TemporaryTable($this->server->connection, "$db.items", $fromTables); + $shop = 'item_cash_db'; + $col = "$shop.item_id AS shop_item_id, $shop.tab AS shop_item_tab, $shop.price AS shop_item_price, "; + $col .= "items.name_english AS shop_item_name"; + $sql = "SELECT $col FROM $db.$shop LEFT OUTER JOIN $db.items ON items.id = $shop.item_id WHERE $shop.item_id = ?"; + $sth = $this->server->connection->getStatement($sql); + + if ($sth->execute(array($shopItemID))) { + return $sth->fetch(); + } else { + return false; + } + } + +} diff --git a/src/CharServer.php b/src/CharServer.php new file mode 100644 index 00000000..b4e9b486 --- /dev/null +++ b/src/CharServer.php @@ -0,0 +1,11 @@ + true, 'force' => true); - + /** * This is here for any developer's convenience, just in case he/she would * like to re-use this library without having to depend on the Flux_Error - * class to do so. This will cause Flux_Config to raise the exception class + * class to do so. This will cause Config to raise the exception class * of your choice. * * It's preferable that the developer change the value directly from the @@ -36,20 +35,20 @@ class Flux_Config { * @access private * @var string */ - private $exceptionClass = 'Flux_Error'; - + private $exceptionClass = 'rAthena\FluxCp\Error'; + /** - * Construct a Flux_Config instance which acts as a more convenient + * Construct a Config instance which acts as a more convenient * accessor to the specified configuration array. * * @param array $configArray Configuration array. * @access public */ - public function __construct(array &$configArr) + public function __construct(array &$configArray) { - $this->configArr = &$configArr; + $this->configArray = &$configArray; } - + /** * This is here... for no real GOOD reason, but should the need arise, at * least you aren't deprived of access to it. @@ -59,81 +58,77 @@ public function __construct(array &$configArr) */ public function &toArray() { - return $this->configArr; + return $this->configArray; } - + /** * Goes through each child in the array which is also an array, and returns - * them collectively as an array of Flux_Config instances. + * them collectively as an array of Config instances. * - * @return array Array of Flux_Config instances of all children arrays. + * @return array Array of Config instances of all children arrays. * @access public */ public function &getChildrenConfigs() { $children = array(); - foreach ($this->configArr as $key => &$child) { + foreach ($this->configArray as $key => &$child) { if (is_array($child)) { - $children[$key] = new Flux_Config($child); + $children[$key] = new Config($child); } } return $children; } - + /** * Get the value held by the specified key. If the value is an array it - * will be returned as an instance of Flux_Config by default, unless + * will be returned as an instance of Config by default, unless * $configObjectIfArray is set to false. * * Keys are specified in an object-like format, such as: 'Foo.Bar.Baz' * where each dot would denote the difference in depth from key-to-key. * * @param string $key Key sequence. - * @param bool $configObjectIfArray True/false whether or not to return Flux_Config instances for values that are an array. + * @param bool $configObjectIfArray True/false whether or not to return Config instances for values that are an array. * @access public */ public function get($key, $configObjectIfArray = true) { $keys = explode('.', $key); - $base = &$this->configArr; + $base = &$this->configArray; $size = count($keys) - 1; - + for ($i = 0; $i < $size; ++$i) { $currentKey = $keys[$i]; if (is_array($base) && array_key_exists($currentKey, $base)) { $base = &$base[$currentKey]; - } - else { + } else { // Short-circuit and return null. return null; } } - + $currentKey = $keys[$size]; if (array_key_exists($currentKey, $base)) { $value = &$base[$currentKey]; if (is_array($value) && $configObjectIfArray) { $configClassName = get_class($this); return new $configClassName($value); - } - elseif ($value instanceOf Flux_Config && !$configObjectIfArray) { + } elseif ($value instanceOf Config && !$configObjectIfArray) { return $value->toArray(); - } - else { + } else { return $value; } - } - else { + } else { // We want to avoid a traditional PHP error when referencing // non-existent keys, so we'll silently return null as an // alternative ;) return null; } } - + /** * Set a key to hold the specified value. The format for specifying a key - * is 100% identical to Flux_Config::get(). + * is 100% identical to Config::get(). * * Options outline: * overwrite - true/false to overwrite existing keys. @@ -148,33 +143,31 @@ public function set($key, $value, $options = array()) { $opts = array_merge($this->defaultSetOptions, $options); $keys = explode('.', $key); - $base = &$this->configArr; + $base = &$this->configArray; $size = count($keys) - 1; - + for ($i = 0; $i < $size; ++$i) { $currentKey = $keys[$i]; if (is_array($base) && array_key_exists($currentKey, $base)) { $base = &$base[$currentKey]; - } - elseif ($opts['force']) { + } elseif ($opts['force']) { $base[$currentKey] = array(); $base = &$base[$currentKey]; - } - else { + } else { // Short-circuit and return false. return false; } } - + $currentKey = $keys[$size]; if (array_key_exists($currentKey, $base) && !$opts['overwrite']) { return false; } - + $base[$currentKey] = $value; return $value; } - + /** * Convenience method for raising an internal exception. * @@ -186,40 +179,37 @@ public function raise($message) $exceptionClass = $this->exceptionClass; throw new $exceptionClass($message); } - + /** * Adds the ability to call set() as native methods. * * @param string $method - * @param arary $args + * @param array $args * @access public */ public function __call($method, $args = array()) { if (preg_match('/^get(\S+)$/', $method, $m)) { return $this->get($m[1]); - } - elseif (preg_match('/^set(\S+)$/', $method, $m)) { + } elseif (preg_match('/^set(\S+)$/', $method, $m)) { $options = array(); - $argc = count($args); + $argc = count($args); if ($argc > 1) { $options = $args[1]; - } - elseif ($argc < 1) { + } elseif ($argc < 1) { $class = get_class($this); $this->raise("Missing value argument in $class::$method()"); } return $this->set($m[1], $args[0], $options); } } - + /** * */ - public function merge(Flux_Config $config, $recursive = true) + public function merge(Config $config, $recursive = true) { - $mergeMethod = $recursive ? 'array_merge_recursive' : 'array_merge'; - $this->configArr = $mergeMethod($this->configArr, $config->toArray()); + $mergeMethod = $recursive ? 'array_merge_recursive' : 'array_merge'; + $this->configArray = $mergeMethod($this->configArray, $config->toArray()); } } -?> diff --git a/lib/Flux/Connection.php b/src/Connection.php similarity index 73% rename from lib/Flux/Connection.php rename to src/Connection.php index 3e63d928..5c4f969e 100644 --- a/lib/Flux/Connection.php +++ b/src/Connection.php @@ -1,6 +1,9 @@ dbConfig = $dbConfig; + $this->dbConfig = $dbConfig; $this->logsDbConfig = $logsDbConfig; } - + /** * Establish connection to server based on config. * - * @param Flux_Config $dbConfig + * @param Config $dbConfig * @return PDO * @access private */ - private function connect(Flux_Config $dbConfig) + private function connect(Config $dbConfig) { $dsn = 'mysql:'; - + // Differentiate between a socket-type connection or an ip:port // connection. - if ($sock=$dbConfig->getSocket()) { + if ($sock = $dbConfig->getSocket()) { $dsn .= "unix_socket=$sock"; - } - else { - $dsn .= 'host='.$dbConfig->getHostname(); - if ($port=$dbConfig->getPort()) { + } else { + $dsn .= 'host=' . $dbConfig->getHostname(); + if ($port = $dbConfig->getPort()) { $dsn .= ";port=$port"; } } - + // May or may not have a database name specified. - if ($dbName=$dbConfig->getDatabase()) { + if ($dbName = $dbConfig->getDatabase()) { $dsn .= ";dbname=$dbName"; } - + $persistent = array(PDO::ATTR_PERSISTENT => (bool)$dbConfig->getPersistent()); return new PDO($dsn, $dbConfig->getUsername(), $dbConfig->getPassword(), $persistent); } - + /** * Get the PDO instance for the main database server connection. * @@ -91,21 +94,21 @@ private function getConnection() { if (!$this->pdoMain) { // Establish connection for main databases. - $pdoMain = $this->connect($this->dbConfig); + $pdoMain = $this->connect($this->dbConfig); $this->pdoMain = $pdoMain; - - if ($encoding=$this->dbConfig->getEncoding()) { + + if ($encoding = $this->dbConfig->getEncoding()) { $sth = $this->getStatement("SET NAMES ?"); $sth->execute(array($encoding)); } - if ($timezone=$this->dbConfig->getTimezone()) { + if ($timezone = $this->dbConfig->getTimezone()) { $sth = $this->getStatement("SET time_zone = ?"); $sth->execute(array($timezone)); } } return $this->pdoMain; } - + /** * Get the PDO instance for the logs database server connection. * @@ -116,21 +119,21 @@ private function getLogsConnection() { if (!$this->pdoLogs) { // Establish separate connection just for the log database. - $pdoLogs = $this->connect($this->logsDbConfig); + $pdoLogs = $this->connect($this->logsDbConfig); $this->pdoLogs = $pdoLogs; - - if ($encoding=$this->logsDbConfig->getEncoding()) { + + if ($encoding = $this->logsDbConfig->getEncoding()) { $sth = $this->getStatementForLogs("SET NAMES ?"); $sth->execute(array($encoding)); } - if ($timezone=$this->logsDbConfig->getTimezone()) { + if ($timezone = $this->logsDbConfig->getTimezone()) { $sth = $this->getStatementForLogs("SET time_zone = ?"); $sth->execute(array($timezone)); } } return $this->pdoLogs; } - + /** * Select database to use. * @@ -142,52 +145,49 @@ public function useDatabase($dbName) { if ($this->pdoMain) { return $this->getStatement("USE $dbName")->execute(); - } - else { + } else { return false; } } - + /** * Instanciate a PDOStatement without obtaining a PDO handler before-hand. * - * @return PDOStatement + * @return Statement * @access public */ public function getStatement($statement, $options = array()) { $dbh = $this->getConnection(); $sth = $dbh->prepare($statement, $options); - @$sth->setFetchMode(PDO::FETCH_CLASS, 'Flux_DataObject', array(null, array('dbconfig' => $this->dbConfig))); - + @$sth->setFetchMode(PDO::FETCH_CLASS, 'rAthena\FluxCp\DataObject', array(null, array('dbconfig' => $this->dbConfig))); + if ($sth) { - return new Flux_Connection_Statement($sth); - } - else { + return new Statement($sth); + } else { return false; } } - + /** * Instanciate a PDOStatement without obtaining a PDO handler before-hand. * - * @return PDOStatement + * @return Statement * @access public */ public function getStatementForLogs($statement, $options = array()) { $dbh = $this->getLogsConnection(); $sth = $dbh->prepare($statement, $options); - @$sth->setFetchMode(PDO::FETCH_CLASS, 'Flux_DataObject', array(null, array('dbconfig' => $this->logsDbConfig))); - + @$sth->setFetchMode(PDO::FETCH_CLASS, 'rAthena\FluxCp\DataObject', array(null, array('dbconfig' => $this->logsDbConfig))); + if ($sth) { - return new Flux_Connection_Statement($sth); - } - else { + return new Statement($sth); + } else { return false; } } - + /** * */ @@ -196,14 +196,14 @@ public function reconnectAs($username, $password) if ($this->pdoMain) { $this->pdoMain = null; } - + $this->dbConfig->setPersistent(false); $this->dbConfig->setUsername($username); $this->dbConfig->setPassword($password); return true; } - + /** * */ @@ -213,14 +213,12 @@ public function isCaseSensitive($database, $table, $column, $useLogsConnection = $sql = 'SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND COLUMN_NAME = ?'; $sth = $this->$stm($sql); $sth->execute(array($database, $table, $column)); - + $row = $sth->fetch(); if (preg_match('/_ci$/', $row->COLLATION_NAME)) { return false; - } - else { + } else { return true; } } } -?> diff --git a/src/Connection/Statement.php b/src/Connection/Statement.php new file mode 100644 index 00000000..a7f7941f --- /dev/null +++ b/src/Connection/Statement.php @@ -0,0 +1,76 @@ +stmt = $stmt; + + if (!self::$errorLog) { + self::$errorLog = new LogFile(FLUX_DATA_DIR . '/logs/mysql/errors/' . date('Ymd') . '.log', 'a'); + } + } + + private function getParamType($param) + { + switch (true) { + case is_bool($param): + return PDO::PARAM_BOOL; + case is_int($param): + return PDO::PARAM_INT; + case is_null($param): + return PDO::PARAM_NULL; + } + return PDO::PARAM_STR; + } + + public function execute(array $inputParameters = array(), $bind_param = false) + { + if ($bind_param) { + foreach ($inputParameters as $key => &$param) { + if ($key[0] == ":") { + if (is_array($param)) { + // $params = [ :param => [ val, PDO::PARAM_ ], ... ]; + $this->stmt->bindParam($key, $param[0], $param[1]); + } else { + // $params = [ :param => val, ... ]; + $this->stmt->bindParam($key, $param, $this->getParamType($param)); + } + } else { + // $params = [ val, ... ]; + $this->stmt->bindParam($key+1, $param, $this->getParamType($param)); + } + } + $res = $this->stmt->execute(); + } else { + $res = $this->stmt->execute(empty($inputParameters) ? null : $inputParameters); + } + + Flux::$numberOfQueries++; + if ((int)$this->stmt->errorCode()) { + $info = $this->stmt->errorInfo(); + self::$errorLog->puts('[SQLSTATE=%s] Err %s: %s', $info[0], $info[1], $info[2]); + if (Flux::config('DebugMode')) { + $message = sprintf('MySQL error (SQLSTATE: %s, ERROR: %s): %s', $info[0], $info[1], $info[2]); + throw new Error($message); + } + } + return $res; + } + + public function __call($method, $args) + { + return call_user_func_array(array($this->stmt, $method), $args); + } +} diff --git a/lib/Flux/DataObject.php b/src/DataObject.php similarity index 80% rename from lib/Flux/DataObject.php rename to src/DataObject.php index 2a8eeb8e..5426e4f8 100644 --- a/lib/Flux/DataObject.php +++ b/src/DataObject.php @@ -1,11 +1,14 @@ _dbConfig = $defaults['dbconfig']; unset($defaults['dbconfig']); - } - else { + } else { $tmpArr = array(); - $this->_dbConfig = new Flux_Config($tmpArr); + $this->_dbConfig = new Config($tmpArr); } - + $this->_encFrom = $this->_dbConfig->getEncoding(); - $this->_encTo = $this->_encFrom ? $this->_dbConfig->get('Convert') : false; + $this->_encTo = $this->_encFrom ? $this->_dbConfig->get('Convert') : false; if (!is_null($data)) { $this->_data = $data; } - + foreach ($defaults as $prop => $value) { if (!isset($this->_data[$prop])) { $this->_data[$prop] = $value; } } - + if ($this->_encTo) { foreach ($this->_data as $prop => $value) { $this->_data[$prop] = iconv($this->_encFrom, $this->_encTo, $value); } } } - + public function __set($prop, $value) { $this->_data[$prop] = $value; return $value; } - + public function __get($prop) { if (isset($this->_data[$prop])) { return $this->_data[$prop]; - } - else { + } else { return null; } } } -?> diff --git a/lib/Flux/Dispatcher.php b/src/Dispatcher.php similarity index 65% rename from lib/Flux/Dispatcher.php rename to src/Dispatcher.php index 726612cd..b20921da 100644 --- a/lib/Flux/Dispatcher.php +++ b/src/Dispatcher.php @@ -1,6 +1,6 @@ get('basePath'); - $paramsArr = $config->get('params'); - $modulePath = $config->get('modulePath'); - $themePath = $config->get('themePath'); - $defaultModule = $config->get('defaultModule'); - $themeName = $config->get('themeName'); - $defaultAction = $config->get('defaultAction'); + $config = new Config($options); + $basePath = $config->get('basePath'); + $paramsArr = $config->get('params'); + $modulePath = $config->get('modulePath'); + $themePath = $config->get('themePath'); + $defaultModule = $config->get('defaultModule'); + $themeName = $config->get('themeName'); + $defaultAction = $config->get('defaultAction'); $missingActionModuleAction = $config->get('missingActionModuleAction'); - $missingViewModuleAction = $config->get('missingViewModuleAction'); - $useCleanUrls = $config->get('useCleanUrls'); - + $missingViewModuleAction = $config->get('missingViewModuleAction'); + $useCleanUrls = $config->get('useCleanUrls'); + if (!$defaultModule && $this->defaultModule) { $defaultModule = $this->defaultModule; } if (!$defaultAction && $this->defaultAction) { $defaultAction = $this->defaultAction; } - + if (!$defaultModule) { - throw new Flux_Error('Please set the default module with $dispatcher->setDefaultModule()'); + throw new Error('Please set the default module with $dispatcher->setDefaultModule()'); + } elseif (!$defaultAction) { + throw new Error('Please set the default action with $dispatcher->setDefaultAction()'); } - elseif (!$defaultAction) { - throw new Flux_Error('Please set the default action with $dispatcher->setDefaultAction()'); - } - + if (!$paramsArr) { $paramsArr = &$_REQUEST; } - + // Provide easier access to parameters. - $params = new Flux_Config($paramsArr); + $params = new Config($paramsArr); $baseURI = Flux::config('BaseURI'); - + if ($params->get('module')) { - $safetyArr = array('..', '/', '\\'); + $safetyArr = array('..', '/', '\\'); $moduleName = str_replace($safetyArr, '', $params->get('module')); if ($params->get('action')) { $actionName = str_replace($safetyArr, '', $params->get('action')); - } - else { + } else { $actionName = $defaultAction; } - } - elseif (Flux::config('UseCleanUrls')) { - $baseURI = preg_replace('&/+&', '/', rtrim($baseURI, '/')).'/'; - $requestURI = preg_replace('&/+&', '/', rtrim($_SERVER['REQUEST_URI'], '/')).'/'; + } elseif (Flux::config('UseCleanUrls')) { + $baseURI = preg_replace('&/+&', '/', rtrim($baseURI, '/')) . '/'; + $requestURI = preg_replace('&/+&', '/', rtrim($_SERVER['REQUEST_URI'], '/')) . '/'; $requestURI = preg_replace('&\?.*?$&', '', $requestURI); $components = explode('/', trim((string)substr($requestURI, strlen($baseURI)), '/')); $moduleName = empty($components[0]) ? $defaultModule : $components[0]; $actionName = empty($components[1]) ? $defaultAction : $components[1]; - } - elseif (!$params->get('module') && !$params->get('action')) { + } elseif (!$params->get('module') && !$params->get('action')) { $moduleName = $defaultModule; $actionName = $defaultAction; } - + // Authorization handling. - $auth = Flux_Authorization::getInstance(); + $auth = Authorization::getInstance(); if ($auth->actionAllowed($moduleName, $actionName) === false) { if (!Flux::$sessionData->isLoggedIn()) { Flux::$sessionData->setMessageData('Please log-in to continue.'); $this->loginRequired($baseURI); - } - else { + } else { $moduleName = 'unauthorized'; $actionName = $this->defaultAction; } } - + $params->set('module', $moduleName); $params->set('action', $actionName); - - $templateArray = array( - 'params' => $params, - 'basePath' => $basePath, - 'modulePath' => $modulePath, - 'moduleName' => $moduleName, - 'themePath' => $themePath, - 'themeName' => $themeName, - 'actionName' => $actionName, - 'viewName' => $actionName, - 'headerName' => 'header', - 'footerName' => 'footer', + + $templateArray = array( + 'params' => $params, + 'basePath' => $basePath, + 'modulePath' => $modulePath, + 'moduleName' => $moduleName, + 'themePath' => $themePath, + 'themeName' => $themeName, + 'actionName' => $actionName, + 'viewName' => $actionName, + 'headerName' => 'header', + 'footerName' => 'footer', 'missingActionModuleAction' => $missingActionModuleAction, - 'missingViewModuleAction' => $missingViewModuleAction, - 'useCleanUrls' => $useCleanUrls + 'missingViewModuleAction' => $missingViewModuleAction, + 'useCleanUrls' => $useCleanUrls ); - $templateConfig = new Flux_Config($templateArray); - $template = new Flux_Template($templateConfig); - + $templateConfig = new Config($templateArray); + $template = new Template($templateConfig); + // Default data available to all actions and views. $data = array( - 'auth' => Flux_Authorization::getInstance(), + 'auth' => Authorization::getInstance(), 'session' => Flux::$sessionData, - 'params' => $params + 'params' => $params ); $template->setDefaultData($data); - + // Render template! :D $template->render(); } - + /** * This usually needs to be called after instanciating the dispatcher, as * it's very necessary to the dispatcher's failsafe functionality. @@ -183,7 +179,7 @@ public function setDefaultModule($module) $this->defaultModule = $module; return $module; } - + /** * (DEPRECATED) By default, 'index' is the default action for any module, but you may * override that by using this method. @@ -197,7 +193,7 @@ public function setDefaultAction($action) $this->defaultAction = $action; return $action; } - + /** * Redirect to login page if the user is not currently logged in. * @@ -212,21 +208,19 @@ public function loginRequired($baseURI, $message = null, $loginModule = 'account if (!$message) { $message = 'Please login to continue.'; } - + if (!$session->isLoggedIn()) { if (Flux::config('UseCleanUrls')) { $loginURL = sprintf('%s/%s/%s/?return_url=%s', $baseURI, $loginModule, $loginAction, rawurlencode($_SERVER['REQUEST_URI'])); - } - else { + } else { $loginURL = sprintf('%s/?module=%s&action=%s&return_url=%s', $baseURI, rawurlencode($loginModule), rawurlencode($loginAction), rawurlencode($_SERVER['REQUEST_URI'])); } - + $session->setMessageData($message); - header('Location: '.preg_replace('&/{2,}&', '/', $loginURL)); + header('Location: ' . preg_replace('&/{2,}&', '/', $loginURL)); exit; } } } -?> diff --git a/lib/Flux/EmblemExporter.php b/src/EmblemExporter.php similarity index 76% rename from lib/Flux/EmblemExporter.php rename to src/EmblemExporter.php index 6a0a5289..b3d6a5f9 100644 --- a/lib/Flux/EmblemExporter.php +++ b/src/EmblemExporter.php @@ -1,96 +1,100 @@ loginAthenaGroup = $loginAthenaGroup; } - + /** * */ - public function addAthenaServer(Flux_Athena $athenaServer) + public function addAthenaServer(Athena $athenaServer) { if (!in_array($athenaServer, $this->loginAthenaGroup->athenaServers, true)) { - throw new Flux_Error( + throw new Error( "{$athenaServer->serverName} is not a valid char/map server defined in the {$this->loginAthenaGroup->serverName} group."); } - + $this->athenaServers[$athenaServer->serverName] = $athenaServer; } - + /** * */ public function exportArchive() { - $topDir = $this->sanitizePathName($this->loginAthenaGroup->serverName); - $tmpDir = FLUX_DATA_DIR.'/tmp'; + $topDir = $this->sanitizePathName($this->loginAthenaGroup->serverName); + $tmpDir = FLUX_DATA_DIR . '/tmp'; $tmpFile = tempnam($tmpDir, 'zip'); - + // Create zip archive. $zip = new ZipArchive(); - $zip->open($tmpFile, ZIPARCHIVE::OVERWRITE); + $zip->open($tmpFile, ZipArchive::OVERWRITE); $zip->addEmptyDir($topDir); - + foreach ($this->athenaServers as $athenaServer) { $athenaDir = $this->sanitizePathName($athenaServer->serverName); $zip->addEmptyDir("$topDir/$athenaDir"); - + $sql = "SELECT name, emblem_data FROM {$athenaServer->charMapDatabase}.guild WHERE emblem_len > 0 ORDER BY name ASC"; $sth = $athenaServer->connection->getStatement($sql); $sth->execute(); - + $guilds = $sth->fetchAll(); if ($guilds) { foreach ($guilds as $guild) { - $emblemData = @gzuncompress(pack('H*', $guild->emblem_data)); + $emblemData = @gzuncompress(pack('H*', $guild->emblem_data)); $emblemImage = imagecreatefrombmpstring($emblemData); - + ob_start(); imagepng($emblemImage); $data = ob_get_clean(); - - $emblemName = sprintf('%s.png', $this->sanitizePathName($guild->name)); + + $emblemName = sprintf('%s.png', $this->sanitizePathName($guild->name)); $zip->addFromString("$topDir/$athenaDir/$emblemName", $data); } } } - + // Close archive. $zip->close(); - + // Send out appropriate HTTP headers. $filename = urlencode(sprintf('%s-%s-emblems.zip', strtolower($topDir), date('Ymd'))); header('Content-Type: application/zip'); - header('Content-Length: '.filesize($tmpFile)); + header('Content-Length: ' . filesize($tmpFile)); header("Content-Disposition: attachment; filename=$filename"); - + // Read contents of the file. readfile($tmpFile); - + // Remove temporary file. unlink($tmpFile); exit; } - + /** * */ @@ -99,4 +103,3 @@ private function sanitizePathName($pathName) return preg_replace('/[^\w\d ]+/', '', $pathName); } } -?> diff --git a/lib/Flux/Error.php b/src/Error.php similarity index 58% rename from lib/Flux/Error.php rename to src/Error.php index 31c6b3c3..961d5cd0 100644 --- a/lib/Flux/Error.php +++ b/src/Error.php @@ -1,9 +1,13 @@ diff --git a/lib/Flux/FileLoad.php b/src/FileLoad.php similarity index 76% rename from lib/Flux/FileLoad.php rename to src/FileLoad.php index e024312b..fba2fe1a 100644 --- a/lib/Flux/FileLoad.php +++ b/src/FileLoad.php @@ -1,7 +1,9 @@ 'A PHP extension stopped the file upload' ); - public function load($file, $path){ + public function load($file, $path) + { $this->path = $path; if($file->get('error')){ return $this->errorCodeMessages[$file->get('error')]; } - if(is_uploaded_file($file->get('tmp_name'))) { - if(move_uploaded_file($file->get('tmp_name'), $path)) { + if (is_uploaded_file($file->get('tmp_name'))) { + if (move_uploaded_file($file->get('tmp_name'), $path)) { return true; } } return 'During the boot file error occurred'; } - public function delete(){ + public function delete() + { unlink($this->path); } } diff --git a/lib/Flux.php b/src/Flux.php similarity index 62% rename from lib/Flux.php rename to src/Flux.php index 8d91dcb4..75aeb96e 100644 --- a/lib/Flux.php +++ b/src/Flux.php @@ -1,108 +1,100 @@ getChildrenConfigs() as $key => $config) { - $connection = new Flux_Connection($config->getDbConfig(), $config->getLogsDbConfig()); - $loginServer = new Flux_LoginServer($config->getLoginServer()); - + $connection = new Connection($config->getDbConfig(), $config->getLogsDbConfig()); + $loginServer = new LoginServer($config->getLoginServer()); + // LoginAthenaGroup maintains the grouping of a central login // server and its underlying Athena objects. - self::$servers[$key] = new Flux_LoginAthenaGroup($config->getServerName(), $connection, $loginServer); - + self::$servers[$key] = new LoginAthenaGroup($config->getServerName(), $connection, $loginServer); + // Add into registry. self::registerServerGroup($config->getServerName(), self::$servers[$key]); - + foreach ($config->getCharMapServers()->getChildrenConfigs() as $charMapServer) { - $charServer = new Flux_CharServer($charMapServer->getCharServer()); - $mapServer = new Flux_MapServer($charMapServer->getMapServer()); - - // Create the collective server object, Flux_Athena. - $athena = new Flux_Athena($charMapServer, $loginServer, $charServer, $mapServer); + $charServer = new CharServer($charMapServer->getCharServer()); + $mapServer = new MapServer($charMapServer->getMapServer()); + + // Create the collective server object, Athena. + $athena = new Athena($charMapServer, $loginServer, $charServer, $mapServer); self::$servers[$key]->addAthenaServer($athena); - + // Add into registry. self::registerAthenaServer($config->getServerName(), $charMapServer->getServerName(), $athena); } } } - + /** * */ @@ -173,44 +165,43 @@ public static function initializeAddons() if (!is_dir(FLUX_ADDON_DIR)) { return false; } - - foreach (glob(FLUX_ADDON_DIR.'/*') as $addonDir) { + + foreach (glob(FLUX_ADDON_DIR . '/*') as $addonDir) { if (is_dir($addonDir)) { - $addonName = basename($addonDir); - $addonObject = new Flux_Addon($addonName, $addonDir); + $addonName = basename($addonDir); + $addonObject = new Addon($addonName, $addonDir); self::$addons[$addonName] = $addonObject; - + // Merge configurations. self::$appConfig->merge($addonObject->addonConfig); self::$messagesConfig->merge($addonObject->messagesConfig, false); } } } - + /** * Wrapper method for setting and getting values from the appConfig. * * @param string $key * @param mixed $value - * @param arary $options + * @param array $options * @access public */ public static function config($key, $value = null, $options = array()) { if (!is_null($value)) { return self::$appConfig->set($key, $value, $options); - } - else { + } else { return self::$appConfig->get($key); } } - + /** * Wrapper method for setting and getting values from the messagesConfig. * * @param string $key * @param mixed $value - * @param arary $options + * @param array $options * @access public */ public static function message($key, $value = null, $options = array()) @@ -218,73 +209,72 @@ public static function message($key, $value = null, $options = array()) if (!is_null($value)) { return self::$messagesConfig->set($key, $value, $options); } - if (!is_null($tmp=self::$messagesConfig->get($key))) + if (!is_null($tmp = self::$messagesConfig->get($key))) return $tmp; else - return ' '.$key; + return ' ' . $key; } - + /** - * Convenience method for raising Flux_Error exceptions. + * Convenience method for raising Error exceptions. * * @param string $message Message to pass to constructor. - * @throws Flux_Error + * @throws Error * @access public */ public static function raise($message) { - throw new Flux_Error($message); + throw new Error($message); } /** - * Parse PHP array into Flux_Config instance. + * Parse PHP array into Config instance. * * @param array $configArr * @access public */ public static function parseConfig(array $configArr) { - return new Flux_Config($configArr); + return new Config($configArr); } - + /** * Parse a PHP array returned as the result of an included file into a - * Flux_Config configuration object. + * Config configuration object. * * @param string $filename * @access public */ - public static function parseConfigFile($filename, $cache=true) + public static function parseConfigFile($filename, $cache = true) { - $basename = basename(str_replace(' ', '', ucwords(str_replace(array('/', '\\', '_'), ' ', $filename))), '.php').'.cache.php'; - $cachefile = FLUX_DATA_DIR."/tmp/$basename"; - + $basename = basename(str_replace(' ', '', ucwords(str_replace(array('/', '\\', '_'), ' ', $filename))), '.php') . '.cache.php'; + $cachefile = FLUX_DATA_DIR . "/tmp/$basename"; + if ($cache && file_exists($cachefile) && filemtime($cachefile) > filemtime($filename)) { return unserialize(file_get_contents($cachefile, null, null, 28)); - } - else { + } else { ob_start(); // Uses require, thus assumes the file returns an array. $config = require $filename; ob_end_clean(); - + // Cache config file. $cf = self::parseConfig($config); if ($cache) { $fp = fopen($cachefile, 'w'); - if ( !$fp ){ - self::raise("Failed to write ".$cachefile." permission error or data/tmp not exist in Flux::parseConfigFile()"); + if (!$fp) { + self::raise("Failed to write " . $cachefile . " permission error or data/tmp not exist in Flux::parseConfigFile()"); } fwrite($fp, ''); - fwrite($fp, $s=serialize($cf), strlen($s)); + fwrite($fp, $s = serialize($cf), strlen($s)); fclose($fp); } - + return $cf; } } - + /** * Parse a file in an application-config specific manner. * @@ -294,35 +284,34 @@ public static function parseConfigFile($filename, $cache=true) public static function parseAppConfigFile($filename) { $config = self::parseConfigFile($filename, false); - + if (!$config->getServerAddress()) { self::raise("ServerAddress must be specified in your application config."); } if (count($themes = $config->get('ThemeName', false)) < 1) { self::raise('ThemeName is required in application configuration.'); - } - else { + } else { foreach ($themes as $themeName) { if (!self::themeExists($themeName)) { self::raise("The selected theme '$themeName' does not exist."); } - } } - if (!($config->getPayPalReceiverEmails() instanceOf Flux_Config)) { + } + } + if (!($config->getPayPalReceiverEmails() instanceOf Config)) { self::raise("PayPalReceiverEmails must be an array."); } - + // Sanitize BaseURI. (leading forward slash is mandatory.) $baseURI = $config->get('BaseURI'); if (strlen($baseURI) && $baseURI[0] != '/') { $config->set('BaseURI', "/$baseURI"); - } - elseif (trim($baseURI) === '') { + } elseif (trim($baseURI) === '') { $config->set('BaseURI', '/'); } - + return $config; } - + /** * Parse a file in a servers-config specific manner. This method gets a bit * nasty so beware of ugly code ;) @@ -332,120 +321,115 @@ public static function parseAppConfigFile($filename) */ public static function parseServersConfigFile($filename) { - $config = self::parseConfigFile($filename); - $options = array('overwrite' => false, 'force' => true); // Config::set() options. - $serverNames = array(); + $config = self::parseConfigFile($filename); + $options = array('overwrite' => false, 'force' => true); // Config::set() options. + $serverNames = array(); $athenaServerNames = array(); - + if (!count($config->toArray())) { self::raise('At least one server configuration must be present.'); } - + foreach ($config->getChildrenConfigs() as $topConfig) { // // Top-level normalization. // - + if (!($serverName = $topConfig->getServerName())) { self::raise('ServerName is required for each top-level server configuration, check your servers configuration file.'); - } - elseif (in_array($serverName, $serverNames)) { + } elseif (in_array($serverName, $serverNames)) { self::raise("The server name '$serverName' has already been configured. Please use another name."); } - + $serverNames[] = $serverName; $athenaServerNames[$serverName] = array(); - + $topConfig->setDbConfig(array(), $options); $topConfig->setLogsDbConfig(array(), $options); $topConfig->setLoginServer(array(), $options); $topConfig->setCharMapServers(array(), $options); - - $dbConfig = $topConfig->getDbConfig(); + + $dbConfig = $topConfig->getDbConfig(); $logsDbConfig = $topConfig->getLogsDbConfig(); - $loginServer = $topConfig->getLoginServer(); - + $loginServer = $topConfig->getLoginServer(); + foreach (array($dbConfig, $logsDbConfig) as $_dbConfig) { $_dbConfig->setHostname('localhost', $options); $_dbConfig->setUsername('ragnarok', $options); $_dbConfig->setPassword('ragnarok', $options); $_dbConfig->setPersistent(true, $options); } - + $loginServer->setDatabase($dbConfig->getDatabase(), $options); $loginServer->setUseMD5(true, $options); - + // Raise error if missing essential configuration directives. if (!$loginServer->getAddress()) { self::raise('Address is required for each LoginServer section in your servers configuration.'); - } - elseif (!$loginServer->getPort()) { + } elseif (!$loginServer->getPort()) { self::raise('Port is required for each LoginServer section in your servers configuration.'); } - + if (!$topConfig->getCharMapServers() || !count($topConfig->getCharMapServers()->toArray())) { self::raise('CharMapServers must be an array and contain at least 1 char/map server entry.'); } - + foreach ($topConfig->getCharMapServers()->getChildrenConfigs() as $charMapServer) { // // Char/Map normalization. // $expRates = array( - 'Base' => 100, - 'Job' => 100, - 'Mvp' => 100 + 'Base' => 100, + 'Job' => 100, + 'Mvp' => 100 ); $dropRates = array( - 'Common' => 100, - 'CommonBoss' => 100, - 'Heal' => 100, - 'HealBoss' => 100, - 'Useable' => 100, + 'Common' => 100, + 'CommonBoss' => 100, + 'Heal' => 100, + 'HealBoss' => 100, + 'Useable' => 100, 'UseableBoss' => 100, - 'Equip' => 100, - 'EquipBoss' => 100, - 'Card' => 100, - 'CardBoss' => 100, - 'MvpItem' => 100 + 'Equip' => 100, + 'EquipBoss' => 100, + 'Card' => 100, + 'CardBoss' => 100, + 'MvpItem' => 100 ); $charMapServer->setExpRates($expRates, $options); $charMapServer->setDropRates($dropRates, $options); $charMapServer->setRenewal(true, $options); $charMapServer->setCharServer(array(), $options); $charMapServer->setMapServer(array(), $options); - $charMapServer->setDatabase($dbConfig->getDatabase(), $options); - + $charMapServer->setDatabase($dbConfig->getDatabase(), $options); + if (!($athenaServerName = $charMapServer->getServerName())) { self::raise('ServerName is required for each CharMapServers pair in your servers configuration.'); - } - elseif (in_array($athenaServerName, $athenaServerNames[$serverName])) { + } elseif (in_array($athenaServerName, $athenaServerNames[$serverName])) { self::raise("The server name '$athenaServerName' under '$serverName' has already been configured. Please use another name."); } - + $athenaServerNames[$serverName][] = $athenaServerName; $charServer = $charMapServer->getCharServer(); - + if (!$charServer->getAddress()) { self::raise('Address is required for each CharServer section in your servers configuration.'); - } - elseif (!$charServer->getPort()) { + } elseif (!$charServer->getPort()) { self::raise('Port is required for each CharServer section in your servers configuration.'); } - + $mapServer = $charMapServer->getMapServer(); if (!$mapServer->getAddress()) { self::raise('Address is required for each MapServer section in your servers configuration.'); - } - elseif (!$mapServer->getPort()) { + } elseif (!$mapServer->getPort()) { self::raise('Port is required for each MapServer section in your servers configuration.'); } } } - + return $config; } - + /** * Parses a messages configuration file. (Deprecated) * @@ -458,7 +442,7 @@ public static function parseMessagesConfigFile($filename) // Nothing yet. return $config; } - + /** * Parses a language configuration file, can also parse a language config * for any addon. @@ -466,39 +450,37 @@ public static function parseMessagesConfigFile($filename) * @param string $addonName * @access public */ - public static function parseLanguageConfigFile($addonName=null) + public static function parseLanguageConfigFile($addonName = null) { - $default = $addonName ? FLUX_ADDON_DIR."/$addonName/lang/en_us.php" : FLUX_LANG_DIR.'/en_us.php'; + $default = $addonName ? FLUX_ADDON_DIR . "/$addonName/lang/en_us.php" : FLUX_LANG_DIR . '/en_us.php'; $current = $default; - - if ($lang=self::config('DefaultLanguage')) { - $current = $addonName ? FLUX_ADDON_DIR."/$addonName/lang/$lang.php" : FLUX_LANG_DIR."/$lang.php"; + + if ($lang = self::config('DefaultLanguage')) { + $current = $addonName ? FLUX_ADDON_DIR . "/$addonName/lang/$lang.php" : FLUX_LANG_DIR . "/$lang.php"; } $languages = self::getAvailableLanguages(); - if(!empty($_COOKIE["language"]) && array_key_exists($_COOKIE["language"], $languages)) - { + if (!empty($_COOKIE["language"]) && array_key_exists($_COOKIE["language"], $languages)) { $lang = $_COOKIE["language"]; - $current = $addonName ? FLUX_ADDON_DIR."/$addonName/lang/$lang.php" : FLUX_LANG_DIR."/$lang.php"; + $current = $addonName ? FLUX_ADDON_DIR . "/$addonName/lang/$lang.php" : FLUX_LANG_DIR . "/$lang.php"; } if (file_exists($default)) { $def = self::parseConfigFile($default); - } - else { + } else { $tmp = array(); - $def = new Flux_Config($tmp); + $def = new Config($tmp); } - + if ($current != $default && file_exists($current)) { $cur = self::parseConfigFile($current); $def->merge($cur, false); } - + return $def; } - + /** * Check whether or not a theme exists. * @@ -507,82 +489,80 @@ public static function parseLanguageConfigFile($addonName=null) */ public static function themeExists($themeName) { - return is_dir(FLUX_THEME_DIR."/$themeName"); + return is_dir(FLUX_THEME_DIR . "/$themeName"); } - + /** * Register the server group into the registry. * * @param string $serverName Server group's name. - * @param Flux_LoginAthenaGroup Server group object. - * @return Flux_LoginAthenaGroup + * @param LoginAthenaGroup Server group object. + * @return LoginAthenaGroup * @access private */ - private static function registerServerGroup($serverName, Flux_LoginAthenaGroup $serverGroup) + private static function registerServerGroup($serverName, LoginAthenaGroup $serverGroup) { self::$loginAthenaGroupRegistry[$serverName] = $serverGroup; return $serverGroup; } - + /** * Register the Athena server into the registry. * * @param string $serverName Server group's name. * @param string $athenaServerName Athena server's name. - * @param Flux_Athena $athenaServer Athena server object. - * @return Flux_Athena + * @param Athena $athenaServer Athena server object. + * @return Athena * @access private */ - private static function registerAthenaServer($serverName, $athenaServerName, Flux_Athena $athenaServer) + private static function registerAthenaServer($serverName, $athenaServerName, Athena $athenaServer) { if (!array_key_exists($serverName, self::$athenaServerRegistry) || !is_array(self::$athenaServerRegistry[$serverName])) { self::$athenaServerRegistry[$serverName] = array(); } - + self::$athenaServerRegistry[$serverName][$athenaServerName] = $athenaServer; return $athenaServer; } - + /** - * Get Flux_LoginAthenaGroup server object by its ServerName. + * Get LoginAthenaGroup server object by its ServerName. * * @param string $serverName Server group name. - * @return mixed Returns Flux_LoginAthenaGroup instance or false on failure. + * @return mixed Returns LoginAthenaGroup instance or false on failure. * @access public */ public static function getServerGroupByName($serverName) { $registry = &self::$loginAthenaGroupRegistry; - - if (array_key_exists($serverName, $registry) && $registry[$serverName] instanceOf Flux_LoginAthenaGroup) { + + if (array_key_exists($serverName, $registry) && $registry[$serverName] instanceOf LoginAthenaGroup) { return $registry[$serverName]; - } - else { + } else { return false; } } - + /** - * Get Flux_Athena instance by its group/server names. + * Get Athena instance by its group/server names. * * @param string $serverName Server group name. * @param string $athenaServerName Athena server name. - * @return mixed Returns Flux_Athena instance or false on failure. + * @return mixed Returns Athena instance or false on failure. * @access public */ public static function getAthenaServerByName($serverName, $athenaServerName) { $registry = &self::$athenaServerRegistry; if (array_key_exists($serverName, $registry) && array_key_exists($athenaServerName, $registry[$serverName]) && - $registry[$serverName][$athenaServerName] instanceOf Flux_Athena) { - + $registry[$serverName][$athenaServerName] instanceOf Athena) { + return $registry[$serverName][$athenaServerName]; - } - else { + } else { return false; } } - + /** * Hashes a password for use in comparison with the login.user_pass column. * @@ -595,7 +575,7 @@ public static function hashPassword($password) // Default hashing schema is MD5. return md5($password); } - + /** * Get the job class name from a job ID. * @@ -605,17 +585,16 @@ public static function hashPassword($password) */ public static function getJobClass($id) { - $key = "JobClasses.$id"; + $key = "JobClasses.$id"; $class = self::config($key); - + if ($class) { return $class; - } - else { + } else { return false; } } - + /** * Get the job ID from a job class name. * @@ -628,12 +607,11 @@ public static function getJobID($class) $index = self::config('JobClassIndex')->toArray(); if (array_key_exists($class, $index)) { return $index[$class]; - } - else { + } else { return false; } } - + /** * Get the homunculus class name from a homun class ID. * @@ -643,13 +621,12 @@ public static function getJobID($class) */ public static function getHomunClass($id) { - $key = "HomunClasses.$id"; + $key = "HomunClasses.$id"; $class = self::config($key); - + if ($class) { return $class; - } - else { + } else { return false; } } @@ -657,146 +634,151 @@ public static function getHomunClass($id) /** * Get the item type name from an item type. * - * @param int $id - * @param int $id2 + * @param string $id * @return mixed Item Type or false. * @access public */ - public static function getItemType($id, $id2) - { - $key = "ItemTypes.$id"; - $type = self::config($key); - - if ($id2) { - $key = "ItemTypes2.$id.$id2"; - $type2 = self::config($key); - - if ($type && $type2) { - $type .= ' - ' . $type2; - } - else if ($type2) { - $type = $type2; - } - } - - if ($type) { - return $type; - } - else { - return false; - } - } - - /** - * Get the equip location combination name from an equip location combination type. - * - * @param int $id - * @return mixed Equip Location Combination or false. - * @access public - */ - public static function getEquipLocationCombination($id) - { - $key = "EquipLocationCombinations.$id"; - $combination = self::config($key); - - if ($combination) { - return $combination; - } - else { - return false; - } - } - + public static function getItemType($id) + { + $type = self::config("ItemTypes")->toArray(); + + if ($type[strtolower($id)] != NULL) { + return $type[strtolower($id)]; + } + else { + return false; + } + } + + public static function getItemSubType($id1, $id2) + { + $subtype = "ItemSubTypes.$id1.$id2"; + $result = self::config($subtype); + + if ($result) { + return $result; + } + else { + return false; + } + } + + /** + * return random option description. + */ + public static function getRandOption($id1) + { + $key = "RandomOptions.$id1"; + $option = self::config($key); + + if ($option) { + return $option; + } + else { + return false; + } + } + + /** + * Get the equip location combination name from an equip location combination type. + * + * @return array Equip Location Combination + * @access public + */ + public static function getEquipLocationCombination() + { + return Flux::config('EquipLocationCombinations')->toArray(); + } + /** * Process donations that have been put on hold. */ public static function processHeldCredits() { - $txnLogTable = self::config('FluxTables.TransactionTable'); - $trustTable = self::config('FluxTables.DonationTrustTable'); - $loginAthenaGroups = self::$loginAthenaGroupRegistry; + $txnLogTable = self::config('FluxTables.TransactionTable'); + $trustTable = self::config('FluxTables.DonationTrustTable'); + $loginAthenaGroups = self::$loginAthenaGroupRegistry; list ($cancel, $accept) = array(array(), array()); - + foreach ($loginAthenaGroups as $loginAthenaGroup) { - $sql = "SELECT account_id, payer_email, credits, mc_gross, txn_id, hold_until "; + $sql = "SELECT account_id, payer_email, credits, mc_gross, txn_id, hold_until "; $sql .= "FROM {$loginAthenaGroup->loginDatabase}.$txnLogTable "; $sql .= "WHERE account_id > 0 AND hold_until IS NOT NULL AND payment_status = 'Completed'"; - $sth = $loginAthenaGroup->connection->getStatement($sql); - - if ($sth->execute() && ($txn=$sth->fetchAll())) { + $sth = $loginAthenaGroup->connection->getStatement($sql); + + if ($sth->execute() && ($txn = $sth->fetchAll())) { foreach ($txn as $t) { - $sql = "SELECT id FROM {$loginAthenaGroup->loginDatabase}.$txnLogTable "; + $sql = "SELECT id FROM {$loginAthenaGroup->loginDatabase}.$txnLogTable "; $sql .= "WHERE payment_status IN ('Cancelled_Reversed', 'Reversed', 'Refunded') AND parent_txn_id = ? LIMIT 1"; - $sth = $loginAthenaGroup->connection->getStatement($sql); - - if ($sth->execute(array($t->txn_id)) && ($r=$sth->fetch()) && $r->id) { + $sth = $loginAthenaGroup->connection->getStatement($sql); + + if ($sth->execute(array($t->txn_id)) && ($r = $sth->fetch()) && $r->id) { $cancel[] = $t->txn_id; - } - elseif (strtotime($t->hold_until) <= time()) { + } elseif (strtotime($t->hold_until) <= time()) { $accept[] = $t; } } } - + if (!empty($cancel)) { - $ids = implode(', ', array_fill(0, count($cancel), '?')); - $sql = "UPDATE {$loginAthenaGroup->loginDatabase}.$txnLogTable "; + $ids = implode(', ', array_fill(0, count($cancel), '?')); + $sql = "UPDATE {$loginAthenaGroup->loginDatabase}.$txnLogTable "; $sql .= "SET credits = 0, hold_until = NULL WHERE txn_id IN ($ids)"; - $sth = $loginAthenaGroup->connection->getStatement($sql); + $sth = $loginAthenaGroup->connection->getStatement($sql); $sth->execute($cancel); } - - $sql2 = "INSERT INTO {$loginAthenaGroup->loginDatabase}.$trustTable (account_id, email, create_date)"; - $sql2 .= "VALUES (?, ?, NOW())"; - $sth2 = $loginAthenaGroup->connection->getStatement($sql2); - - $sql3 = "SELECT id FROM {$loginAthenaGroup->loginDatabase}.$trustTable WHERE "; - $sql3 .= "delete_date IS NULL AND account_id = ? AND email = ? LIMIT 1"; - $sth3 = $loginAthenaGroup->connection->getStatement($sql3); - + + $sql2 = "INSERT INTO {$loginAthenaGroup->loginDatabase}.$trustTable (account_id, email, create_date)"; + $sql2 .= "VALUES (?, ?, NOW())"; + $sth2 = $loginAthenaGroup->connection->getStatement($sql2); + + $sql3 = "SELECT id FROM {$loginAthenaGroup->loginDatabase}.$trustTable WHERE "; + $sql3 .= "delete_date IS NULL AND account_id = ? AND email = ? LIMIT 1"; + $sth3 = $loginAthenaGroup->connection->getStatement($sql3); + $idvals = array(); - + foreach ($accept as $txn) { $loginAthenaGroup->loginServer->depositCredits($txn->account_id, $txn->credits, $txn->mc_gross); $sth3->execute(array($txn->account_id, $txn->payer_email)); $row = $sth3->fetch(); - + if (!$row) { $sth2->execute(array($txn->account_id, $txn->payer_email)); } - + $idvals[] = $txn->txn_id; } - + if (!empty($idvals)) { - $ids = implode(', ', array_fill(0, count($idvals), '?')); - $sql = "UPDATE {$loginAthenaGroup->loginDatabase}.$txnLogTable "; + $ids = implode(', ', array_fill(0, count($idvals), '?')); + $sql = "UPDATE {$loginAthenaGroup->loginDatabase}.$txnLogTable "; $sql .= "SET hold_until = NULL WHERE txn_id IN ($ids)"; - $sth = $loginAthenaGroup->connection->getStatement($sql); + $sth = $loginAthenaGroup->connection->getStatement($sql); $sth->execute($idvals); } } } - + /** * */ public static function pruneUnconfirmedAccounts() { - $tbl = Flux::config('FluxTables.AccountCreateTable'); - + $tbl = Flux::config('FluxTables.AccountCreateTable'); + foreach (self::$loginAthenaGroupRegistry as $loginAthenaGroup) { - $db = $loginAthenaGroup->loginDatabase; - $sql = "DELETE $db.login, $db.$tbl FROM $db.login INNER JOIN $db.$tbl "; + $db = $loginAthenaGroup->loginDatabase; + $sql = "DELETE $db.login, $db.$tbl FROM $db.login INNER JOIN $db.$tbl "; $sql .= "WHERE login.account_id = $tbl.account_id AND $tbl.confirmed = 0 "; $sql .= "AND $tbl.confirm_code IS NOT NULL AND $tbl.confirm_expire <= NOW()"; - $sth = $loginAthenaGroup->connection->getStatement($sql); - + $sth = $loginAthenaGroup->connection->getStatement($sql); + $sth->execute(); } } - + /** * Get array of equip_location bits. (bit => loc_name pairs) * @return array @@ -806,26 +788,61 @@ public static function getEquipLocationList() $equiplocations = Flux::config('EquipLocations')->toArray(); return $equiplocations; } - - /** - * Get array of equip_upper bits. (bit => upper_name pairs) - * @return array - */ - public static function getEquipUpperList() - { - $equipupper = Flux::config('EquipUpper')->toArray(); - return $equipupper; - } - - /** - * Get array of equip_jobs bits. (bit => job_name pairs) - */ - public static function getEquipJobsList() - { - $equipjobs = Flux::config('EquipJobs')->toArray(); - return $equipjobs; - } - + + /** + * Get array of equip_upper bits. (bit => upper_name pairs) + * + * @param bool $isRenewal + * @return array + */ + public static function getEquipUpperList(bool $isRenewal = true) + { + $equipupper = Flux::config('EquipUpper.0')->toArray(); + + if($isRenewal) + $equipupper = array_merge($equipupper, Flux::config('EquipUpper.1')->toArray()); + + return $equipupper; + } + + /** + * Get array of equip_jobs bits. (bit => job_name pairs) + * + * @param bool $isRenewal + * @return array + */ + public static function getEquipJobsList(bool $isRenewal = true) + { + $equipjobs = Flux::config('EquipJobs.0')->toArray(); + + if($isRenewal) + $equipjobs = array_merge($equipjobs, Flux::config('EquipJobs.1')->toArray()); + + return $equipjobs; + } + + /** + * Get array of trade restrictions + * + * @return array + */ + public static function getTradeRestrictionList() + { + $restrictions = Flux::config('TradeRestriction')->toArray(); + return $restrictions; + } + + /** + * Get array of item flags + * + * @return array + */ + public static function getItemFlagList() + { + $flags = Flux::config('ItemFlags')->toArray(); + return $flags; + } + /** * Check whether a particular item type is stackable. * @param int $type @@ -836,47 +853,28 @@ public static function isStackableItemType($type) $nonstackables = array(1, 4, 5, 7, 8, 9); return !in_array($type, $nonstackables); } - - /** - * Perform a bitwise AND from each bit in getEquipLocationList() on $bitmask - * to determine which bits have been set. - * @param int $bitmask - * @return array - */ - public static function equipLocationsToArray($bitmask) - { - $arr = array(); - $bits = self::getEquipLocationList(); - - foreach ($bits as $bit => $name) { - if ($bitmask & $bit) { - $arr[] = $bit; - } - } - - return $arr; - } - - /** - * Perform a bitwise AND from each bit in getEquipUpperList() on $bitmask - * to determine which bits have been set. - * @param int $bitmask - * @return array - */ - public static function equipUpperToArray($bitmask) - { - $arr = array(); - $bits = self::getEquipUpperList(); - - foreach ($bits as $bit => $name) { - if ($bitmask & $bit) { - $arr[] = $bit; - } - } - - return $arr; - } - + + /** + * Perform a bitwise AND from each bit in getEquipUpperList() on $bitmask + * to determine which bits have been set. + * @param int $bitmask + * @param bool $isRenewal + * @return array + */ + public static function equipUpperToArray($bitmask, $isRenewal = true) + { + $arr = array(); + $bits = self::getEquipUpperList($isRenewal); + + foreach ($bits as $bit => $name) { + if ($bitmask & $bit) { + $arr[] = $bit; + } + } + + return $arr; + } + /** * Perform a bitwise AND from each bit in getEquipJobsList() on $bitmask * to determine which bits have been set. @@ -885,72 +883,70 @@ public static function equipUpperToArray($bitmask) */ public static function equipJobsToArray($bitmask) { - $arr = array(); + $arr = array(); $bits = self::getEquipJobsList(); - + foreach ($bits as $bit => $name) { if ($bitmask & $bit) { $arr[] = $bit; } } - + return $arr; } - + /** * */ public static function monsterModeToArray($bitmask) { - $arr = array(); + $arr = array(); $bits = self::config('MonsterModes')->toArray(); - + foreach ($bits as $bit => $name) { if ($bitmask & $bit) { $arr[] = $bit; } } - + return $arr; } - + /** * */ - public static function elementName($ele) - { - $neutral = Flux::config('Elements.0'); - $element = Flux::config("Elements.$ele"); - - return is_null($element) ? $neutral : $element; - } - + public static function elementName($ele) + { + $element = Flux::config("Elements")->toArray(); + return is_null($element[$ele]) ? $element['Neutral'] : $element[$ele]; + } + /** * */ - public static function monsterRaceName($race) - { - $race = Flux::config("MonsterRaces.$race"); - return $race; - } - + public static function monsterRaceName($race) + { + $races = Flux::config("MonsterRaces")->toArray(); + return is_null($races[$race]) ? $races['Formless'] : $races[$race]; + } + /** * */ - public static function monsterSizeName($size) - { - $size = Flux::config("MonsterSizes.$size"); - return $size; - } + public static function monsterSizeName($size) + { + $sizes = Flux::config("MonsterSizes")->toArray(); + return is_null($sizes[$size]) ? $sizes['Small'] : $sizes[$size]; + } public static function getAvailableLanguages() { $langs_available = array_diff(scandir(FLUX_LANG_DIR), array('..', '.')); $dictionary = []; - foreach($langs_available as $lang_file) { + foreach ($langs_available as $lang_file) { $lang_key = str_replace('.php', '', $lang_file); - $lang_conf = self::parseConfigFile(FLUX_LANG_DIR.'/'.$lang_file); + $lang_conf = self::parseConfigFile(FLUX_LANG_DIR . '/' . $lang_file); $lang_name = $lang_conf->get('Language'); $dictionary[$lang_key] = $lang_name; @@ -959,4 +955,5 @@ public static function getAvailableLanguages() return $dictionary; } } + ?> diff --git a/lib/Flux/Installer.php b/src/Installer.php similarity index 84% rename from lib/Flux/Installer.php rename to src/Installer.php index 82d13555..d358d9ab 100644 --- a/lib/Flux/Installer.php +++ b/src/Installer.php @@ -1,41 +1,45 @@ $loginAthenaGroup) { - $this->servers[$serverName] = new Flux_Installer_MainServer($loginAthenaGroup); + $this->servers[$serverName] = new MainServer($loginAthenaGroup); } } - + /** * */ public static function getInstance() { if (!self::$installer) { - self::$installer = new Flux_Installer(); + self::$installer = new Installer(); } return self::$installer; } - + /** * */ @@ -57,7 +61,7 @@ public function updateNeeded() } return false; } - + /** * */ @@ -79,4 +83,3 @@ public function updateAll() } } } -?> diff --git a/src/Installer/CharMapServer.php b/src/Installer/CharMapServer.php new file mode 100644 index 00000000..49643b70 --- /dev/null +++ b/src/Installer/CharMapServer.php @@ -0,0 +1,35 @@ +mainServer = $mainServer; + $this->athena = $athena; + $this->schemas = Schema::getSchemas($mainServer, $this); + } +} diff --git a/lib/Flux/Installer/MainServer.php b/src/Installer/MainServer.php similarity index 61% rename from lib/Flux/Installer/MainServer.php rename to src/Installer/MainServer.php index 16dfc483..6003ef6c 100644 --- a/lib/Flux/Installer/MainServer.php +++ b/src/Installer/MainServer.php @@ -1,41 +1,45 @@ loginAthenaGroup = $loginAthenaGroup; - $this->schemas = Flux_Installer_Schema::getSchemas($this); - + $this->loginAthenaGroup = $loginAthenaGroup; + $this->schemas = Schema::getSchemas($this); + if (array_key_exists($loginAthenaGroup->serverName, Flux::$athenaServerRegistry)) { foreach (Flux::$athenaServerRegistry[$loginAthenaGroup->serverName] as $athena) { - $this->charMapServers[$athena->serverName] = new Flux_Installer_CharMapServer($this, $athena); + $this->charMapServers[$athena->serverName] = new CharMapServer($this, $athena); } } } - + /** * */ @@ -55,4 +59,3 @@ public function updateAll() } } } -?> diff --git a/lib/Flux/Installer/Schema.php b/src/Installer/Schema.php similarity index 69% rename from lib/Flux/Installer/Schema.php rename to src/Installer/Schema.php index 3e53f278..9eca1974 100644 --- a/lib/Flux/Installer/Schema.php +++ b/src/Installer/Schema.php @@ -1,77 +1,82 @@ mainServerName = $dataArray['mainServerName']; - $this->charMapServerName = $dataArray['charMapServerName']; - $this->databaseName = $dataArray['databaseName']; - $this->connection = $dataArray['connection']; + $this->mainServerName = $dataArray['mainServerName']; + $this->charMapServerName = $dataArray['charMapServerName']; + $this->databaseName = $dataArray['databaseName']; + $this->connection = $dataArray['connection']; $this->availableSchemaDir = $dataArray['availableSchemaDir']; $this->installedSchemaDir = $dataArray['installedSchemaDir']; - $this->schemaInfo = $dataArray['schemaInfo']; - + $this->schemaInfo = $dataArray['schemaInfo']; + ksort($this->schemaInfo['versions']); $this->determineInstalledVersions(); } - + /** * */ @@ -81,12 +86,12 @@ protected function determineInstalledVersions() if ($installed) { $this->versionInstalled = $version; } - + $this->latestVersion = $version; $this->latestVersionInstalled = $installed; } } - + /** * */ @@ -95,14 +100,14 @@ public function install($version) if (!array_key_exists($version, $this->schemaInfo['versions']) || !$this->schemaInfo['versions'][$version]) { // Switch database. $this->connection->useDatabase($this->databaseName); - + // Get schema content. $sql = file_get_contents($this->schemaInfo['files'][$version]); $sth = $this->connection->getStatement($sql); - + // Execute. $sth->execute(); - + if ($sth->errorCode()) { $errorInfo = $sth->errorInfo(); if (count($errorInfo) > 1) { @@ -110,14 +115,13 @@ public function install($version) } else { $errmsg = implode(', ', $errorInfo); } - + if (!empty($errnum) && $errnum == 1045) { - throw new Flux_Error("Critical MySQL error in Installer/Updater: $errnum: $errmsg"); - } - elseif (!empty($errnum) && $errnum == 1142) { + throw new Error("Critical MySQL error in Installer/Updater: $errnum: $errmsg"); + } elseif (!empty($errnum) && $errnum == 1142) { // Bail-out. $message = "MySQL error: $errmsg\n\n"; - throw new Flux_Installer_SchemaPermissionError( + throw new SchemaPermissionError( $message, $this->schemaInfo['files'][$version], $this->databaseName, @@ -125,25 +129,23 @@ public function install($version) $this->charMapServerName, $sql ); - } - elseif (!empty($errmsg) && strcmp($errmsg,'00000') != 0) { + } elseif (!empty($errmsg) && strcmp($errmsg, '00000') != 0) { // Only quit with an error if there is actually an error. - throw new Flux_Error("Critical MySQL error in Installer/Updater: $errmsg"); + throw new Error("Critical MySQL error in Installer/Updater: $errmsg"); } } - + $this->schemaInfo['versions'][$version] = true; $this->determineInstalledVersions(); - + // Create file indicating schema is installed. $file = "{$this->schemaInfo['name']}.$version.txt"; fclose(fopen("{$this->installedSchemaDir}/{$file}", 'w')); - } - else { + } else { return false; } } - + /** * */ @@ -156,12 +158,11 @@ public function update() } } return true; - } - else { + } else { return false; } } - + /** * */ @@ -170,7 +171,7 @@ public function versionInstalled($version) $installed = array_key_exists($version, $this->schemaInfo['versions']) && $this->schemaInfo['versions'][$version]; return $installed; } - + /** * */ @@ -178,35 +179,34 @@ public function isLatest() { return $this->latestVersionInstalled; } - + /** * */ - public static function getSchemas(Flux_Installer_MainServer $mainServer, Flux_Installer_CharMapServer $charMapServer = null) + public static function getSchemas(MainServer $mainServer, CharMapServer $charMapServer = null) { $mainServerName = $mainServer->loginAthenaGroup->serverName; - + if (is_null($charMapServer)) { - $charMapServerName = null; - $databaseName = $mainServer->loginAthenaGroup->loginDatabase; - $connection = $mainServer->loginAthenaGroup->connection; - $availableSchemaDir = array(FLUX_DATA_DIR."/schemas/logindb"); - $installedSchemaDir = FLUX_DATA_DIR."/logs/schemas/logindb/$mainServerName"; - + $charMapServerName = null; + $databaseName = $mainServer->loginAthenaGroup->loginDatabase; + $connection = $mainServer->loginAthenaGroup->connection; + $availableSchemaDir = array(FLUX_DATA_DIR . "/schemas/logindb"); + $installedSchemaDir = FLUX_DATA_DIR . "/logs/schemas/logindb/$mainServerName"; + foreach (Flux::$addons as $addon) { $_schemaDir = "{$addon->addonDir}/schemas/logindb"; if (file_exists($_schemaDir) && is_dir($_schemaDir)) { $availableSchemaDir[] = $_schemaDir; } } - } - else { - $charMapServerName = $charMapServer->athena->serverName; - $databaseName = $charMapServer->athena->charMapDatabase; - $connection = $charMapServer->athena->connection; - $availableSchemaDir = array(FLUX_DATA_DIR."/schemas/charmapdb"); - $installedSchemaDir = FLUX_DATA_DIR."/logs/schemas/charmapdb/$mainServerName/{$charMapServer->athena->serverName}"; - + } else { + $charMapServerName = $charMapServer->athena->serverName; + $databaseName = $charMapServer->athena->charMapDatabase; + $connection = $charMapServer->athena->connection; + $availableSchemaDir = array(FLUX_DATA_DIR . "/schemas/charmapdb"); + $installedSchemaDir = FLUX_DATA_DIR . "/logs/schemas/charmapdb/$mainServerName/{$charMapServer->athena->serverName}"; + foreach (Flux::$addons as $addon) { $_schemaDir = "{$addon->addonDir}/schemas/charmapdb"; if (file_exists($_schemaDir) && is_dir($_schemaDir)) { @@ -214,78 +214,77 @@ public static function getSchemas(Flux_Installer_MainServer $mainServer, Flux_In } } } - + $dataArray = array( - 'mainServerName' => $mainServerName, - 'charMapServerName' => $charMapServerName, - 'databaseName' => $databaseName, - 'connection' => $connection, + 'mainServerName' => $mainServerName, + 'charMapServerName' => $charMapServerName, + 'databaseName' => $databaseName, + 'connection' => $connection, //'availableSchemaDir' => $availableSchemaDir, 'installedSchemaDir' => $installedSchemaDir, ); - + $availableSchemas = array(); $installedSchemas = array(); - + $directories = array(); foreach ($availableSchemaDir as $dir) { $directories[] = array($dir, 'availableSchemas', 'sql'); } $directories[] = array($installedSchemaDir, 'installedSchemas', 'txt'); - + foreach ($directories as $directory) { list ($schemaDir, $schemaArray, $fileExt) = $directory; $schemas = &$$schemaArray; - $sFiles = glob("$schemaDir/*.$fileExt"); - + $sFiles = glob("$schemaDir/*.$fileExt"); + if (!$sFiles) { $sFiles = array(); } - + foreach ($sFiles as $schemaFilePath) { $schemaName = basename($schemaFilePath, ".$fileExt"); if (preg_match('/^(\w+)\.(\d+)$/', $schemaName, $m)) { - $schemaName = $m[1]; + $schemaName = $m[1]; $schemaVersion = $m[2]; - + // Dynamically set schema directory. $dataArray['availableSchemaDir'] = $directory; - + if (!array_key_exists($schemaName, $schemas)) { $schemas[$schemaName] = array( - 'name' => $schemaName, + 'name' => $schemaName, 'versions' => array(), ); } - + $schemas[$schemaName]['versions'][$schemaFilePath] = $schemaVersion; } } } - + $objects = array(); foreach ($availableSchemas as $schemaName => $schema) { $schemaInfo = array( - 'name' => $schemaName, + 'name' => $schemaName, 'versions' => array_flip($schema['versions']), - 'files' => array_flip($schema['versions']) + 'files' => array_flip($schema['versions']) ); - + foreach ($schemaInfo['versions'] as $key => $value) { $schemaInfo['versions'][$key] = false; } - + if (array_key_exists($schemaName, $installedSchemas)) { foreach ($installedSchemas[$schemaName]['versions'] as $key => $value) { $schemaInfo['versions'][$value] = true; } } - + $dataArray['schemaInfo'] = $schemaInfo; - $objects[] = new Flux_Installer_Schema($dataArray); + $objects[] = new Schema($dataArray); } - + return $objects; } } -?> diff --git a/lib/Flux/Installer/SchemaPermissionError.php b/src/Installer/SchemaPermissionError.php similarity index 59% rename from lib/Flux/Installer/SchemaPermissionError.php rename to src/Installer/SchemaPermissionError.php index 4065855a..36a99f93 100644 --- a/lib/Flux/Installer/SchemaPermissionError.php +++ b/src/Installer/SchemaPermissionError.php @@ -1,32 +1,34 @@ schemaFile = $schemaFile; - $this->databaseName = $databaseName; - $this->mainServerName = $mainServerName; - $this->charMapServerName = $charMapServerName; - $this->query = $query; + + $this->schemaFile = $schemaFile; + $this->databaseName = $databaseName; + $this->mainServerName = $mainServerName; + $this->charMapServerName = $charMapServerName; + $this->query = $query; } - + public function isLoginDbSchema() { return $this->mainServerName && !$this->charMapServerName; } - + public function isCharMapDbSchema() { return $this->mainServerName && $this->charMapServerName; } } -?> diff --git a/src/ItemExistsError.php b/src/ItemExistsError.php new file mode 100644 index 00000000..7cf10565 --- /dev/null +++ b/src/ItemExistsError.php @@ -0,0 +1,8 @@ +server = $server; + } + + /** + * Add an item to the shop. + */ + public function add($itemID, $categoryID, $cost, $quantity, $info, $useExisting = 0) + { + $db = $this->server->charMapDatabase; + $table = Flux::config('FluxTables.ItemShopTable'); + $sql = "INSERT INTO $db.$table (nameid, category, quantity, cost, info, use_existing, create_date) VALUES (?, ?, ?, ?, ?, ?, NOW())"; + $sth = $this->server->connection->getStatement($sql); + $res = $sth->execute(array($itemID, $categoryID, $quantity, $cost, $info, $useExisting)); + $sth2 = $this->server->connection->getStatement('SELECT LAST_INSERT_ID() AS insID'); + $res2 = $sth2->execute(); + + if ($res && $res2 && ($insertID = $sth2->fetch()->insID)) { + return $insertID; + } else { + return false; + } + } + + /** + * Modify item info in the shop. + */ + public function edit($shopItemID, $categoryID = null, $cost = null, $quantity = null, $info = null, $useExisting = null) + { + $catQ = ''; + $crdQ = ''; + $qtyQ = ''; + $infQ = ''; + $imgQ = ''; + $bind = array(); + + if (!is_null($categoryID)) { + $catQ = "category = ? "; + $bind[] = (int)$categoryID; + } + + if (!is_null($cost)) { + if ($catQ) { + $crdQ = ", cost = ? "; + } else { + $crdQ = "cost = ? "; + } + + $bind[] = (int)$cost; + } + + if (!is_null($quantity)) { + if ($crdQ) { + $qtyQ = ', quantity = ? '; + } else { + $qtyQ = "quantity = ? "; + } + + $bind[] = (int)$quantity; + } + + if (!is_null($info)) { + if ($qtyQ) { + $infQ = ', info = ? '; + } else { + $infQ = "info = ? "; + } + + $bind[] = trim($info); + } + + if (!is_null($useExisting)) { + if ($infQ) { + $imgQ = ', use_existing = ? '; + } else { + $imgQ = "use_existing = ? "; + } + + $bind[] = (int)$useExisting; + } + + if (empty($bind)) { + return false; + } + + $db = $this->server->charMapDatabase; + $table = Flux::config('FluxTables.ItemShopTable'); + $sql = "UPDATE $db.$table SET $catQ $crdQ $qtyQ $infQ $imgQ WHERE id = ?"; + $sth = $this->server->connection->getStatement($sql); + + $bind[] = $shopItemID; + return $sth->execute($bind); + } + + /** + * + */ + public function delete($shopItemID) + { + $db = $this->server->charMapDatabase; + $table = Flux::config('FluxTables.ItemShopTable'); + $sql = "DELETE FROM $db.$table WHERE id = ?"; + $sth = $this->server->connection->getStatement($sql); + + return $sth->execute(array($shopItemID)); + } + + /** + * + */ + public function buy(DataObject $account, $shopItemID) + { + + } + + /** + * + */ + public function getItem($shopItemID) + { + $db = $this->server->charMapDatabase; + + if ($this->server->isRenewal) { + $fromTables = array("$db.item_db_re", "$db.item_db2_re"); + } else { + $fromTables = array("$db.item_db", "$db.item_db2"); + } + + $temp = new TemporaryTable($this->server->connection, "$db.items", $fromTables); + $shop = Flux::config('FluxTables.ItemShopTable'); + $col = "$shop.id AS shop_item_id, $shop.category AS shop_item_category, $shop.cost AS shop_item_cost, $shop.quantity AS shop_item_qty, $shop.use_existing AS shop_item_use_existing, "; + $col .= "$shop.nameid AS shop_item_nameid, $shop.info AS shop_item_info, items.name_english AS shop_item_name"; + $sql = "SELECT $col FROM $db.$shop LEFT OUTER JOIN $db.items ON items.id = $shop.nameid WHERE $shop.id = ?"; + $sth = $this->server->connection->getStatement($sql); + + if ($sth->execute(array($shopItemID))) { + return $sth->fetch(); + } else { + return false; + } + } + + /** + * + */ + public function getItems($paginator, $categoryID = null) + { + $sqlpartial = ""; + $bind = array(); + $db = $this->server->charMapDatabase; + + if ($this->server->isRenewal) { + $fromTables = array("$db.item_db_re", "$db.item_db2_re"); + } else { + $fromTables = array("$db.item_db", "$db.item_db2"); + } + + $temp = new TemporaryTable($this->server->connection, "$db.items", $fromTables); + $shop = Flux::config('FluxTables.ItemShopTable'); + $col = "$shop.id AS shop_item_id, $shop.cost AS shop_item_cost, $shop.quantity AS shop_item_qty, $shop.use_existing AS shop_item_use_existing, "; + $col .= "$shop.nameid AS shop_item_nameid, $shop.info AS shop_item_info, items.name_english AS shop_item_name"; + if (!is_null($categoryID)) { + $sqlpartial = " WHERE $shop.category = ?"; + $bind[] = $categoryID; + } + $sql = $paginator->getSQL("SELECT $col FROM $db.$shop LEFT OUTER JOIN $db.items ON items.id = $shop.nameid $sqlpartial"); + $sth = $this->server->connection->getStatement($sql); + + if ($sth->execute($bind)) { + return $sth->fetchAll(); + } else { + return false; + } + } + + /** + * + */ + public function deleteShopItemImage($shopItemID) + { + $serverName = $this->server->loginAthenaGroup->serverName; + $athenaServerName = $this->server->serverName; + $dir = FLUX_DATA_DIR . "/itemshop/$serverName/$athenaServerName"; + $files = glob("$dir/$shopItemID.*"); + + foreach ($files as $file) { + unlink($file); + } + + return true; + } + + /** + * + */ + public function uploadShopItemImage($shopItemID, Config $file) + { + if ($file->get('rAthena\FluxCp\Error')) { + return false; + } + + $validexts = array_map('strtolower', Flux::config('ShopImageExtensions')->toArray()); + $extension = strtolower(pathinfo($file->get('name'), PATHINFO_EXTENSION)); + + if (!in_array($extension, $validexts)) { + return false; + } + + $serverName = $this->server->loginAthenaGroup->serverName; + $athenaServerName = $this->server->serverName; + $dir = FLUX_DATA_DIR . "/itemshop/$serverName/$athenaServerName"; + + if (!is_dir(FLUX_DATA_DIR . "/itemshop/$serverName")) { + mkdir(FLUX_DATA_DIR . "/itemshop/$serverName"); + } + + if (!is_dir($dir)) { + mkdir($dir); + } + + $this->deleteShopItemImage($shopItemID); + + if (move_uploaded_file($file->get('tmp_name'), "$dir/$shopItemID.$extension")) { + return true; + } else { + return false; + } + } +} diff --git a/lib/Flux/ItemShop/Cart.php b/src/ItemShop/Cart.php similarity index 70% rename from lib/Flux/ItemShop/Cart.php rename to src/ItemShop/Cart.php index ddfe869a..3578a587 100644 --- a/lib/Flux/ItemShop/Cart.php +++ b/src/ItemShop/Cart.php @@ -1,98 +1,102 @@ account = $account; return $account; } - + public function requiresAccount() { if (!$this->account) { - throw new Flux_Error('Account is required to use the shopping cart.'); + throw new Error('Account is required to use the shopping cart.'); } } - - public function add(Flux_DataObject $item) + + public function add(DataObject $item) { $this->cart[] = $item; return $item; } - - public function delete(Flux_DataObject $item, $deleteAll = false) + + public function delete(DataObject $item, $deleteAll = false) { $deleted = array(); - + foreach ($this->cart as $cartItem) { if ($cartItem == $item) { if ($deleteAll) { $deleted[] = $cartItem; - } - else { + } else { return $cartItem; } } } - + if ($deleted) { return $deleted; - } - else { + } else { return false; } } - - public function deleteAll(Flux_DataObject $item) + + public function deleteAll(DataObject $item) { return $this->delete($item, true); } - + public function clear() { - $itemCount = count($this->cart); + $itemCount = count($this->cart); $this->cart = array(); return $itemCount; } - - public function buy(Flux_ItemShop $fromShop) + + public function buy(ItemShop $fromShop) { if (!$this->hasFunds()) { return false; } - + $successful = array(); - + foreach ($this->cart as $cartItem) { $successful[] = array( - 'item' => $cartItem, - 'name' => $cartItem->shop_item_name, - 'cost' => $cartItem->shop_item_cost, + 'item' => $cartItem, + 'name' => $cartItem->shop_item_name, + 'cost' => $cartItem->shop_item_cost, 'quantity' => $cartItem->shop_item_qty, - 'success' => $fromShop->buy($cartItem->shop_item_id) + 'success' => $fromShop->buy($cartItem->shop_item_id) ); } - + $this->clear(); return $successful; } - + public function getCartItems() { return $this->cart; } - + public function getCartItemNames() { $names = array(); @@ -101,7 +105,7 @@ public function getCartItemNames() } return $names; } - + public function getTotal() { $total = 0; @@ -110,21 +114,20 @@ public function getTotal() } return $total; } - + public function hasFunds() { $this->requiresAccount(); $creditsAvailable = $this->account->balance; - $creditsNeeded = $this->getTotal(); - + $creditsNeeded = $this->getTotal(); + if ($creditsAvailable < $creditsNeeded) { return false; - } - else { + } else { return true; } } - + /** * Check if the cart is empty. */ @@ -133,26 +136,24 @@ public function isEmpty() $empty = !count($this->cart); return $empty; } - + public function deleteByItemNum($num) { if (!is_array($num)) { $num = array((int)$num); - } - else { + } else { $num = array_map('intval', $num); } - + $nDeleted = 0; - + foreach ($num as $n) { if (array_key_exists($n, $this->cart)) { unset($this->cart[$n]); $nDeleted += 1; } } - + return $nDeleted; } } -?> diff --git a/lib/Flux/LogFile.php b/src/LogFile.php similarity index 84% rename from lib/Flux/LogFile.php rename to src/LogFile.php index 87cf7b03..06a20c83 100644 --- a/lib/Flux/LogFile.php +++ b/src/LogFile.php @@ -1,8 +1,11 @@ filename = "$filename.php"; - $isNewFile = !file_exists($this->filename); + $this->filename = "$filename.php"; + $isNewFile = !file_exists($this->filename); if ($isNewFile) { touch($this->filename); @@ -64,20 +67,18 @@ public function __destruct() * Write a line to the log file. * * @param string $format - * @param string $var, ... + * @param string $var , ... * @access public */ public function puts() { $args = func_get_args(); if (count($args) > 0) { - $args[0] = sprintf("%s%s\n", date($this->dateFormat), $args[0]); + $args[0] = sprintf("%s%s\n", date($this->dateFormat), $args[0]); $arguments = array_merge(array($this->fp), $args); return call_user_func_array('fprintf', $arguments); - } - else { + } else { return false; } } } -?> diff --git a/lib/Flux/LoginAthenaGroup.php b/src/LoginAthenaGroup.php similarity index 73% rename from lib/Flux/LoginAthenaGroup.php rename to src/LoginAthenaGroup.php index 19de6dd5..bfe6f659 100644 --- a/lib/Flux/LoginAthenaGroup.php +++ b/src/LoginAthenaGroup.php @@ -1,9 +1,13 @@ serverName = $serverName; - $this->connection = $connection; - $this->loginServer = $loginServer; + $this->serverName = $serverName; + $this->connection = $connection; + $this->loginServer = $loginServer; $this->loginDatabase = $loginServer->config->getDatabase(); - $this->logsDatabase = $connection->logsDbConfig->getDatabase(); - + $this->logsDatabase = $connection->logsDbConfig->getDatabase(); + // Assign connection to LoginServer, used mainly to enable // authentication feature. $this->loginServer->setConnection($connection); - + foreach ($athenaServers as $athenaServer) { $this->addAthenaServer($athenaServer); } } - + /** * Add an Athena instance to the current collection. * * @return mixed Returns false if login servers aren't identical. * @access public */ - public function addAthenaServer(Flux_Athena $athenaServer) + public function addAthenaServer(Athena $athenaServer) { if ($athenaServer->loginServer === $this->loginServer) { $athenaServer->setLoginAthenaGroup($this); $athenaServer->setConnection($this->connection); $this->athenaServers[] = $athenaServer; return $this->athenaServers; - } - else { + } else { return false; } } - + /** - * See Flux_LoginServer->isAuth(). + * See LoginServer->isAuth(). * * @param string $username * @param string $password @@ -106,4 +109,3 @@ public function isAuth($username, $password) return $this->loginServer->isAuth($username, $password); } } -?> diff --git a/src/LoginError.php b/src/LoginError.php new file mode 100644 index 00000000..58f9275d --- /dev/null +++ b/src/LoginError.php @@ -0,0 +1,15 @@ +loginDatabase = $config->getDatabase(); } - + /** * Set the connection object to be used for this LoginServer instance. * - * @param Flux_Connection $connection - * @return Flux_Connection + * @param Connection $connection + * @return Connection * @access public */ - public function setConnection(Flux_Connection $connection) + public function setConnection(Connection $connection) { - $this->connection = $connection; + $this->connection = $connection; $this->logsDatabase = $connection->logsDbConfig->getDatabase(); - + return $connection; } - + /** * Validate credentials against the login server's database information. * @@ -69,115 +70,111 @@ public function isAuth($username, $password) if ($this->config->get('UseMD5')) { $password = Flux::hashPassword($password); } - + if (trim($username) == '' || trim($password) == '') { return false; } - - $sql = "SELECT userid FROM {$this->loginDatabase}.login WHERE sex != 'S' AND group_id >= 0 "; + + $sql = "SELECT userid FROM {$this->loginDatabase}.login WHERE sex != 'S' AND group_id >= 0 "; if ($this->config->getNoCase()) { $sql .= 'AND LOWER(userid) = LOWER(?) '; - } - else { + } else { $sql .= 'AND CAST(userid AS BINARY) = ? '; } $sql .= "AND user_pass = ? LIMIT 1"; - $sth = $this->connection->getStatement($sql); + $sth = $this->connection->getStatement($sql); $sth->execute(array($username, $password)); - + $res = $sth->fetch(); if ($res) { return true; - } - else { + } else { return false; } } - + /** * */ - public function register($username, $password, $confirmPassword, $email,$email2, $gender, $birthdate, $securityCode) + public function register($username, $password, $confirmPassword, $email, $email2, $gender, $birthdate, $securityCode) { if (preg_match('/[^' . Flux::config('UsernameAllowedChars') . ']/', $username)) { - throw new Flux_RegisterError('Invalid character(s) used in username', Flux_RegisterError::INVALID_USERNAME); + throw new RegisterError('Invalid character(s) used in username', RegisterError::INVALID_USERNAME); } elseif (strlen($username) < Flux::config('MinUsernameLength')) { - throw new Flux_RegisterError('Username is too short', Flux_RegisterError::USERNAME_TOO_SHORT); + throw new RegisterError('Username is too short', RegisterError::USERNAME_TOO_SHORT); } elseif (strlen($username) > Flux::config('MaxUsernameLength')) { - throw new Flux_RegisterError('Username is too long', Flux_RegisterError::USERNAME_TOO_LONG); + throw new RegisterError('Username is too long', RegisterError::USERNAME_TOO_LONG); } elseif (!Flux::config('AllowUserInPassword') && stripos($password, $username) !== false) { - throw new Flux_RegisterError('Password contains username', Flux_RegisterError::USERNAME_IN_PASSWORD); + throw new RegisterError('Password contains username', RegisterError::PASSWORD_HAS_USERNAME); } elseif (!ctype_graph($password)) { - throw new Flux_RegisterError('Invalid character(s) used in password', Flux_RegisterError::INVALID_PASSWORD); + throw new RegisterError('Invalid character(s) used in password', RegisterError::INVALID_PASSWORD); } elseif (strlen($password) < Flux::config('MinPasswordLength')) { - throw new Flux_RegisterError('Password is too short', Flux_RegisterError::PASSWORD_TOO_SHORT); + throw new RegisterError('Password is too short', RegisterError::PASSWORD_TOO_SHORT); } elseif (strlen($password) > Flux::config('MaxPasswordLength')) { - throw new Flux_RegisterError('Password is too long', Flux_RegisterError::PASSWORD_TOO_LONG); + throw new RegisterError('Password is too long', RegisterError::PASSWORD_TOO_LONG); } elseif ($password !== $confirmPassword) { - throw new Flux_RegisterError('Passwords do not match', Flux_RegisterError::PASSWORD_MISMATCH); + throw new RegisterError('Passwords do not match', RegisterError::PASSWORD_MISMATCH); } elseif (Flux::config('PasswordMinUpper') > 0 && preg_match_all('/[A-Z]/', $password, $matches) < Flux::config('PasswordMinUpper')) { - throw new Flux_RegisterError('Passwords must contain at least ' + intval(Flux::config('PasswordMinUpper')) + ' uppercase letter(s)', Flux_RegisterError::PASSWORD_NEED_UPPER); + throw new RegisterError('Passwords must contain at least ' . intval(Flux::config('PasswordMinUpper')) . ' uppercase letter(s)', RegisterError::PASSWORD_NEED_UPPER); } elseif (Flux::config('PasswordMinLower') > 0 && preg_match_all('/[a-z]/', $password, $matches) < Flux::config('PasswordMinLower')) { - throw new Flux_RegisterError('Passwords must contain at least ' + intval(Flux::config('PasswordMinLower')) + ' lowercase letter(s)', Flux_RegisterError::PASSWORD_NEED_LOWER); + throw new RegisterError('Passwords must contain at least ' . intval(Flux::config('PasswordMinLower')) . ' lowercase letter(s)', RegisterError::PASSWORD_NEED_LOWER); } elseif (Flux::config('PasswordMinNumber') > 0 && preg_match_all('/[0-9]/', $password, $matches) < Flux::config('PasswordMinNumber')) { - throw new Flux_RegisterError('Passwords must contain at least ' + intval(Flux::config('PasswordMinNumber')) + ' number(s)', Flux_RegisterError::PASSWORD_NEED_NUMBER); + throw new RegisterError('Passwords must contain at least ' . intval(Flux::config('PasswordMinNumber')) . ' number(s)', RegisterError::PASSWORD_NEED_NUMBER); } elseif (Flux::config('PasswordMinSymbol') > 0 && preg_match_all('/[^A-Za-z0-9]/', $password, $matches) < Flux::config('PasswordMinSymbol')) { - throw new Flux_RegisterError('Passwords must contain at least ' + intval(Flux::config('PasswordMinSymbol')) + ' symbol(s)', Flux_RegisterError::PASSWORD_NEED_SYMBOL); + throw new RegisterError('Passwords must contain at least ' . intval(Flux::config('PasswordMinSymbol')) . ' symbol(s)', RegisterError::PASSWORD_NEED_SYMBOL); } elseif (!preg_match('/^(.+?)@(.+?)$/', $email)) { - throw new Flux_RegisterError('Invalid e-mail address', Flux_RegisterError::INVALID_EMAIL_ADDRESS); + throw new RegisterError('Invalid e-mail address', RegisterError::INVALID_EMAIL_ADDRESS); } elseif ($email!==$email2) { - throw new Flux_RegisterError('Email do not match', Flux_RegisterError::INVALID_EMAIL_CONF); - } + throw new RegisterError('Email do not match', RegisterError::INVALID_EMAIL_CONF); + } elseif (!in_array(strtoupper($gender), array('M', 'F'))) { - throw new Flux_RegisterError('Invalid gender', Flux_RegisterError::INVALID_GENDER); + throw new RegisterError('Invalid gender', RegisterError::INVALID_GENDER); } elseif (($birthdatestamp = strtotime($birthdate)) === false || date('Y-m-d', $birthdatestamp) != $birthdate) { - throw new Flux_RegisterError('Invalid birthdate', Flux_RegisterError::INVALID_BIRTHDATE); + throw new RegisterError('Invalid birthdate', RegisterError::INVALID_BIRTHDATE); } elseif (Flux::config('UseCaptcha')) { if (Flux::config('EnableReCaptcha')) { - if(isset($_POST['g-recaptcha-response']) && $_POST['g-recaptcha-response'] != ""){ - $response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=".Flux::config('ReCaptchaPrivateKey')."&response=".$_POST['g-recaptcha-response']."&remoteip=".$_SERVER['REMOTE_ADDR']); + if (isset($_POST['g-recaptcha-response']) && $_POST['g-recaptcha-response'] != "") { + $response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=" . Flux::config('ReCaptchaPrivateKey') . "&response=" . $_POST['g-recaptcha-response'] . "&remoteip=" . $_SERVER['REMOTE_ADDR']); } - $responseKeys = json_decode($response,true); - if(intval($responseKeys["success"]) !== 1) { - throw new Flux_RegisterError('Invalid security code', Flux_RegisterError::INVALID_SECURITY_CODE); + $responseKeys = json_decode($response, true); + if (intval($responseKeys["success"]) !== 1) { + throw new RegisterError('Invalid security code', RegisterError::INVALID_SECURITY_CODE); } - } - elseif (strtolower($securityCode) !== strtolower(Flux::$sessionData->securityCode)) { - throw new Flux_RegisterError('Invalid security code', Flux_RegisterError::INVALID_SECURITY_CODE); + } elseif (strtolower($securityCode) !== strtolower(Flux::$sessionData->securityCode)) { + throw new RegisterError('Invalid security code', RegisterError::INVALID_SECURITY_CODE); } } - - $sql = "SELECT userid FROM {$this->loginDatabase}.login WHERE "; + + $sql = "SELECT userid FROM {$this->loginDatabase}.login WHERE "; if ($this->config->getNoCase()) { $sql .= 'LOWER(userid) = LOWER(?) '; - } - else { + } else { $sql .= 'BINARY userid = ? '; } $sql .= 'LIMIT 1'; - $sth = $this->connection->getStatement($sql); + $sth = $this->connection->getStatement($sql); $sth->execute(array($username)); - + $res = $sth->fetch(); if ($res) { - throw new Flux_RegisterError('Username is already taken', Flux_RegisterError::USERNAME_ALREADY_TAKEN); + throw new RegisterError('Username is already taken', RegisterError::USERNAME_ALREADY_TAKEN); } - + if (!Flux::config('AllowDuplicateEmails')) { $sql = "SELECT email FROM {$this->loginDatabase}.login WHERE email = ? LIMIT 1"; $sth = $this->connection->getStatement($sql); @@ -185,80 +182,77 @@ public function register($username, $password, $confirmPassword, $email,$email2, $res = $sth->fetch(); if ($res) { - throw new Flux_RegisterError('E-mail address is already in use', Flux_RegisterError::EMAIL_ADDRESS_IN_USE); + throw new RegisterError('E-mail address is already in use', RegisterError::EMAIL_ADDRESS_IN_USE); } } - + if ($this->config->getUseMD5()) { $password = Flux::hashPassword($password); } - + $sql = "INSERT INTO {$this->loginDatabase}.login (userid, user_pass, email, sex, group_id, birthdate) VALUES (?, ?, ?, ?, ?, ?)"; $sth = $this->connection->getStatement($sql); $res = $sth->execute(array($username, $password, $email, $gender, (int)$this->config->getGroupID(), date('Y-m-d', $birthdatestamp))); - + if ($res) { $idsth = $this->connection->getStatement("SELECT LAST_INSERT_ID() AS account_id"); $idsth->execute(); - + $idres = $idsth->fetch(); $createTable = Flux::config('FluxTables.AccountCreateTable'); - - $sql = "INSERT INTO {$this->loginDatabase}.{$createTable} (account_id, userid, user_pass, sex, email, reg_date, reg_ip, confirmed) "; + + $sql = "INSERT INTO {$this->loginDatabase}.{$createTable} (account_id, userid, user_pass, sex, email, reg_date, reg_ip, confirmed) "; $sql .= "VALUES (?, ?, ?, ?, ?, NOW(), ?, 1)"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + $sth->execute(array($idres->account_id, $username, $password, $gender, $email, $_SERVER['REMOTE_ADDR'])); return $idres->account_id; - } - else { + } else { return false; } } - + /** * */ public function temporarilyBan($bannedBy, $banReason, $accountID, $until) { $table = Flux::config('FluxTables.AccountBanTable'); - - $sql = "INSERT INTO {$this->loginDatabase}.$table (account_id, banned_by, ban_type, ban_until, ban_date, ban_reason) "; + + $sql = "INSERT INTO {$this->loginDatabase}.$table (account_id, banned_by, ban_type, ban_until, ban_date, ban_reason) "; $sql .= "VALUES (?, ?, 1, ?, NOW(), ?)"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + if ($sth->execute(array($accountID, $bannedBy, $until, $banReason))) { - $ts = strtotime($until); - $sql = "UPDATE {$this->loginDatabase}.login SET state = 0, unban_time = '$ts' WHERE account_id = ?"; - $sth = $this->connection->getStatement($sql); + $ts = strtotime($until); + $sql = "UPDATE {$this->loginDatabase}.login SET state = 0, unban_time = '$ts' WHERE account_id = ?"; + $sth = $this->connection->getStatement($sql); return $sth->execute(array($accountID)); - } - else { + } else { return false; } } - + /** * */ public function permanentlyBan($bannedBy, $banReason, $accountID) { $table = Flux::config('FluxTables.AccountBanTable'); - - $sql = "INSERT INTO {$this->loginDatabase}.$table (account_id, banned_by, ban_type, ban_until, ban_date, ban_reason) "; + + $sql = "INSERT INTO {$this->loginDatabase}.$table (account_id, banned_by, ban_type, ban_until, ban_date, ban_reason) "; $sql .= "VALUES (?, ?, 2, '9999-12-31 23:59:59', NOW(), ?)"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + if ($sth->execute(array($accountID, $bannedBy, $banReason))) { - $sql = "UPDATE {$this->loginDatabase}.login SET state = 5, unban_time = 0 WHERE account_id = ?"; - $sth = $this->connection->getStatement($sql); + $sql = "UPDATE {$this->loginDatabase}.login SET state = 5, unban_time = 0 WHERE account_id = ?"; + $sth = $this->connection->getStatement($sql); return $sth->execute(array($accountID)); - } - else { + } else { return false; } } - + /** * */ @@ -266,111 +260,106 @@ public function unban($unbannedBy, $unbanReason, $accountID) { $table = Flux::config('FluxTables.AccountBanTable'); $createTable = Flux::config('FluxTables.AccountCreateTable'); - - $sql = "INSERT INTO {$this->loginDatabase}.$table (account_id, banned_by, ban_type, ban_until, ban_date, ban_reason) "; + + $sql = "INSERT INTO {$this->loginDatabase}.$table (account_id, banned_by, ban_type, ban_until, ban_date, ban_reason) "; $sql .= "VALUES (?, ?, 0, '1000-01-01 00:00:00', NOW(), ?)"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + if ($sth->execute(array($accountID, $unbannedBy, $unbanReason))) { - $sql = "UPDATE {$this->loginDatabase}.$createTable SET confirmed = 1, confirm_expire = NULL WHERE account_id = ?"; - $sth = $this->connection->getStatement($sql); + $sql = "UPDATE {$this->loginDatabase}.$createTable SET confirmed = 1, confirm_expire = NULL WHERE account_id = ?"; + $sth = $this->connection->getStatement($sql); $sth->execute(array($accountID)); - - $sql = "UPDATE {$this->loginDatabase}.login SET state = 0, unban_time = 0 WHERE account_id = ?"; - $sth = $this->connection->getStatement($sql); + + $sql = "UPDATE {$this->loginDatabase}.login SET state = 0, unban_time = 0 WHERE account_id = ?"; + $sth = $this->connection->getStatement($sql); return $sth->execute(array($accountID)); - } - else { + } else { return false; } } - + /** * */ public function getBanInfo($accountID) { $table = Flux::config('FluxTables.AccountBanTable'); - $col = "$table.id, $table.account_id, $table.banned_by, $table.ban_type, "; - $col .= "$table.ban_until, $table.ban_date, $table.ban_reason, login.userid"; - $sql = "SELECT $col FROM {$this->loginDatabase}.$table "; - $sql .= "LEFT OUTER JOIN {$this->loginDatabase}.login ON login.account_id = $table.banned_by "; - $sql .= "WHERE $table.account_id = ? ORDER BY $table.ban_date DESC "; - $sth = $this->connection->getStatement($sql); - $res = $sth->execute(array($accountID)); - + $col = "$table.id, $table.account_id, $table.banned_by, $table.ban_type, "; + $col .= "$table.ban_until, $table.ban_date, $table.ban_reason, login.userid"; + $sql = "SELECT $col FROM {$this->loginDatabase}.$table "; + $sql .= "LEFT OUTER JOIN {$this->loginDatabase}.login ON login.account_id = $table.banned_by "; + $sql .= "WHERE $table.account_id = ? ORDER BY $table.ban_date DESC "; + $sth = $this->connection->getStatement($sql); + $res = $sth->execute(array($accountID)); + if ($res) { $ban = $sth->fetchAll(); return $ban; - } - else { + } else { return false; } } - + /** * */ public function addIpBan($bannedBy, $banReason, $unbanTime, $ipAddress) { $table = Flux::config('FluxTables.IpBanTable'); - - $sql = "INSERT INTO {$this->loginDatabase}.$table (ip_address, banned_by, ban_type, ban_until, ban_date, ban_reason) "; + + $sql = "INSERT INTO {$this->loginDatabase}.$table (ip_address, banned_by, ban_type, ban_until, ban_date, ban_reason) "; $sql .= "VALUES (?, ?, 1, ?, NOW(), ?)"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + if ($sth->execute(array($ipAddress, $bannedBy, $unbanTime, $banReason))) { - $sql = "INSERT INTO {$this->loginDatabase}.ipbanlist (list, reason, rtime, btime) "; + $sql = "INSERT INTO {$this->loginDatabase}.ipbanlist (list, reason, rtime, btime) "; $sql .= "VALUES (?, ?, ?, NOW())"; - $sth = $this->connection->getStatement($sql); + $sth = $this->connection->getStatement($sql); return $sth->execute(array($ipAddress, $banReason, $unbanTime)); - } - else { + } else { return false; } } - + /** * */ public function removeIpBan($unbannedBy, $unbanReason, $ipAddress) { $table = Flux::config('FluxTables.IpBanTable'); - - $sql = "INSERT INTO {$this->loginDatabase}.$table (ip_address, banned_by, ban_type, ban_until, ban_date, ban_reason) "; + + $sql = "INSERT INTO {$this->loginDatabase}.$table (ip_address, banned_by, ban_type, ban_until, ban_date, ban_reason) "; $sql .= "VALUES (?, ?, 0, '1000-01-01 00:00:00', NOW(), ?)"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + if ($sth->execute(array($ipAddress, $unbannedBy, $unbanReason))) { - $sql = "DELETE FROM {$this->loginDatabase}.ipbanlist WHERE list = ?"; - $sth = $this->connection->getStatement($sql); + $sql = "DELETE FROM {$this->loginDatabase}.ipbanlist WHERE list = ?"; + $sth = $this->connection->getStatement($sql); return $sth->execute(array($ipAddress)); - } - else { + } else { return false; } } - + /** * */ public function hasCreditsRecord($accountID) { $creditsTable = Flux::config('FluxTables.CreditsTable'); - + $sql = "SELECT COUNT(account_id) AS hasRecord FROM {$this->loginDatabase}.$creditsTable WHERE account_id = ?"; $sth = $this->connection->getStatement($sql); - + $sth->execute(array($accountID)); - + if ($sth->fetch()->hasRecord) { return true; - } - else { + } else { return false; } } - + /** * */ @@ -378,53 +367,52 @@ public function depositCredits($targetAccountID, $credits, $donationAmount = nul { $sql = "SELECT COUNT(account_id) AS accountExists FROM {$this->loginDatabase}.login WHERE account_id = ?"; $sth = $this->connection->getStatement($sql); - + if (!$sth->execute(array($targetAccountID)) || !$sth->fetch()->accountExists) { return false; // Account doesn't exist. } - + $creditsTable = Flux::config('FluxTables.CreditsTable'); - + if (!$this->hasCreditsRecord($targetAccountID)) { $fields = 'account_id, balance'; $values = '?, ?'; - + if (!is_null($donationAmount)) { $fields .= ', last_donation_date, last_donation_amount'; $values .= ', NOW(), ?'; } - - $sql = "INSERT INTO {$this->loginDatabase}.$creditsTable ($fields) VALUES ($values)"; - $sth = $this->connection->getStatement($sql); + + $sql = "INSERT INTO {$this->loginDatabase}.$creditsTable ($fields) VALUES ($values)"; + $sth = $this->connection->getStatement($sql); $vals = array($targetAccountID, $credits); - + if (!is_null($donationAmount)) { $vals[] = $donationAmount; } - + return $sth->execute($vals); - } - else { + } else { $vals = array(); - $sql = "UPDATE {$this->loginDatabase}.$creditsTable SET balance = balance + ? "; + $sql = "UPDATE {$this->loginDatabase}.$creditsTable SET balance = balance + ? "; if (!is_null($donationAmount)) { $sql .= ", last_donation_date = NOW(), last_donation_amount = ? "; } - + $vals[] = $credits; if (!is_null($donationAmount)) { $vals[] = $donationAmount; } $vals[] = $targetAccountID; - + $sql .= "WHERE account_id = ?"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + return $sth->execute($vals); } } - + /** * */ @@ -432,15 +420,15 @@ public function getPrefs($accountID, array $prefs = array()) { $sql = "SELECT account_id FROM {$this->loginDatabase}.`login` WHERE account_id = ? LIMIT 1"; $sth = $this->connection->getStatement($sql); - - if ($sth->execute(array($accountID)) && ($char=$sth->fetch())) { + + if ($sth->execute(array($accountID)) && ($char = $sth->fetch())) { $accountPrefsTable = Flux::config('FluxTables.AccountPrefsTable'); - + $pref = array(); $bind = array($accountID); - $sql = "SELECT name, value FROM {$this->loginDatabase}.$accountPrefsTable "; + $sql = "SELECT name, value FROM {$this->loginDatabase}.$accountPrefsTable "; $sql .= "WHERE account_id = ?"; - + if ($prefs) { foreach ($prefs as $p) { $pref[] = "name = ?"; @@ -448,26 +436,24 @@ public function getPrefs($accountID, array $prefs = array()) } $sql .= sprintf(' AND (%s)', implode(' OR ', $pref)); } - + $sth = $this->connection->getStatement($sql); - + if ($sth->execute($bind)) { $prefsArray = array(); foreach ($sth->fetchAll() as $p) { $prefsArray[$p->name] = $p->value; } - - return new Flux_Config($prefsArray); - } - else { + + return new Config($prefsArray); + } else { return false; } - } - else { + } else { return false; } } - + /** * */ @@ -475,15 +461,15 @@ public function setPrefs($accountID, array $prefsArray) { $sql = "SELECT account_id FROM {$this->loginDatabase}.`login` WHERE account_id = ? LIMIT 1"; $sth = $this->connection->getStatement($sql); - - if ($sth->execute(array($accountID)) && ($char=$sth->fetch())) { + + if ($sth->execute(array($accountID)) && ($char = $sth->fetch())) { $accountPrefsTable = Flux::config('FluxTables.AccountPrefsTable'); - + $pref = array(); $bind = array($accountID); - $sql = "SELECT id, name, value FROM {$this->loginDatabase}.$accountPrefsTable "; + $sql = "SELECT id, name, value FROM {$this->loginDatabase}.$accountPrefsTable "; $sql .= "WHERE account_id = ?"; - + if ($prefsArray) { foreach ($prefsArray as $prefName => $prefValue) { $pref[] = "name = ?"; @@ -491,61 +477,57 @@ public function setPrefs($accountID, array $prefsArray) } $sql .= sprintf(' AND (%s)', implode(' OR ', $pref)); } - + $sth = $this->connection->getStatement($sql); - + if ($sth->execute($bind)) { - $prefs = $sth->fetchAll(); + $prefs = $sth->fetchAll(); $update = array(); - - $usql = "UPDATE {$this->loginDatabase}.$accountPrefsTable "; - $usql .= "SET value = ? WHERE id = ?"; - $usth = $this->connection->getStatement($usql); - - $isql = "INSERT INTO {$this->loginDatabase}.$accountPrefsTable "; - $isql .= "(account_id, name, value, create_date) "; - $isql .= "VALUES (?, ?, ?, NOW())"; - $isth = $this->connection->getStatement($isql); - + + $usql = "UPDATE {$this->loginDatabase}.$accountPrefsTable "; + $usql .= "SET value = ? WHERE id = ?"; + $usth = $this->connection->getStatement($usql); + + $isql = "INSERT INTO {$this->loginDatabase}.$accountPrefsTable "; + $isql .= "(account_id, name, value, create_date) "; + $isql .= "VALUES (?, ?, ?, NOW())"; + $isth = $this->connection->getStatement($isql); + foreach ($prefs as $p) { $update[$p->name] = $p->id; } - + foreach ($prefsArray as $pref => $value) { if (array_key_exists($pref, $update)) { $id = $update[$pref]; $usth->execute(array($value, $id)); - } - else { + } else { $isth->execute(array($accountID, $pref, $value)); } } - + return true; - } - else { + } else { return false; } - } - else { + } else { return false; } } - + /** * */ public function getPref($accountID, $pref) { $prefs = $this->getPrefs($accountID, array($pref)); - if ($prefs instanceOf Flux_Config) { + if ($prefs instanceOf Config) { return $prefs->get($pref); - } - else { + } else { return false; } } - + /** * */ @@ -553,7 +535,7 @@ public function setPref($accountID, $pref, $value) { return $this->setPrefs($accountID, array($pref => $value)); } - + /** * */ @@ -562,33 +544,31 @@ public function isIpBanned($ip = null) if (is_null($ip)) { $ip = $_SERVER['REMOTE_ADDR']; } - + $ip = trim($ip); if (!preg_match('/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/', $ip, $m)) { // Invalid IP. return false; } - - $sql = "SELECT list FROM {$this->loginDatabase}.ipbanlist WHERE "; + + $sql = "SELECT list FROM {$this->loginDatabase}.ipbanlist WHERE "; $sql .= "rtime > NOW() AND (list = ? OR list = ? OR list = ? OR list = ?) LIMIT 1"; - $sth = $this->connection->getStatement($sql); - + $sth = $this->connection->getStatement($sql); + $list = array( sprintf('%u.*.*.*', $m[1]), sprintf('%u.%u.*.*', $m[1], $m[2]), sprintf('%u.%u.%u.*', $m[1], $m[2], $m[3]), sprintf('%u.%u.%u.%u', $m[1], $m[2], $m[3], $m[4]) ); - + $sth->execute($list); $ipban = $sth->fetch(); - + if ($ipban) { return true; - } - else { + } else { return false; } } } -?> diff --git a/lib/Flux/Mailer.php b/src/Mailer.php similarity index 63% rename from lib/Flux/Mailer.php rename to src/Mailer.php index 7aa515a3..07f8776a 100644 --- a/lib/Flux/Mailer.php +++ b/src/Mailer.php @@ -1,65 +1,66 @@ pm = $pm = new PHPMailer(); - $this->errLog = self::$errLog; - $this->log = self::$log; - + + $this->pm = $pm = new PHPMailer(); + if (Flux::config('MailerUseSMTP')) { $pm->IsSMTP(); - - if (is_array($hosts=Flux::config('MailerSMTPHosts'))) { + + if (is_array($hosts = Flux::config('MailerSMTPHosts'))) { $hosts = implode(';', $hosts); } - + $pm->Host = $hosts; - - if ($user=Flux::config('MailerSMTPUsername')) { + + if ($user = Flux::config('MailerSMTPUsername')) { $pm->SMTPAuth = true; - + if (Flux::config('MailerSMTPUseTLS')) { $pm->SMTPSecure = 'tls'; } if (Flux::config('MailerSMTPUseSSL')) { $pm->SMTPSecure = 'ssl'; } - if ($port=Flux::config('MailerSMTPPort')) { + if ($port = Flux::config('MailerSMTPPort')) { $pm->Port = (int)$port; } - + $pm->Username = $user; - - if ($pass=Flux::config('MailerSMTPPassword')) { + + if ($pass = Flux::config('MailerSMTPPassword')) { $pm->Password = $pass; } } } - + // From address. - $pm->setFrom(Flux::config('MailerFromAddress'), Flux::config('MailerFromName')); + $pm->setFrom(Flux::config('MailerFromAddress'), Flux::config('MailerFromName')); } - + public function send($recipient, $subject, $template, array $templateVars = array()) { if (array_key_exists('_ignoreTemplate', $templateVars) && $templateVars['_ignoreTemplate']) { $content = $template; } else { - $templatePath = FLUX_DATA_DIR."/templates/$template.php"; + $templatePath = FLUX_DATA_DIR . "/templates/$template.php"; if (!file_exists($templatePath)) { return false; } @@ -68,14 +69,14 @@ public function send($recipient, $subject, $template, array $templateVars = arra $repl = array(); foreach ($templateVars as $key => $value) { - $find[] = '{'.$key.'}'; + $find[] = '{' . $key . '}'; $repl[] = $value; } ob_start(); include $templatePath; $content = ob_get_clean(); - + if (!empty($find) && !empty($repl)) { $content = str_replace($find, $repl, $content); } @@ -84,14 +85,14 @@ public function send($recipient, $subject, $template, array $templateVars = arra $this->pm->AddAddress($recipient); $this->pm->Subject = $subject; $this->pm->msgHTML($content); - - if ($sent=$this->pm->Send()) { + + if ($sent = $this->pm->Send()) { self::$log->puts("sent e-mail -- Recipient: $recipient, Subject: $subject"); - } - else { + } else { self::$errLog->puts("{$this->pm->ErrorInfo} (while attempting -- Recipient: $recipient, Subject: $subject)"); } return $sent; } } + ?> diff --git a/src/MapServer.php b/src/MapServer.php new file mode 100644 index 00000000..fceef6f4 --- /dev/null +++ b/src/MapServer.php @@ -0,0 +1,11 @@ +requestURI = $requestURI; - + $perPage = Flux::config('ResultsPerPage'); if (!$perPage) { $perPage = 20; } - + $pagesToShow = Flux::config('PagesToShow'); if (!$pagesToShow) { $pagesToShow = 10; } - + $showSinglePage = (bool)Flux::config('ShowSinglePage'); - + $options = array_merge( array( 'showSinglePage' => $showSinglePage, - 'perPage' => $perPage, - 'pagesToShow' => $pagesToShow, - 'pageVariable' => 'p', - 'pageSeparator' => '|'), + 'perPage' => $perPage, + 'pagesToShow' => $pagesToShow, + 'pageVariable' => 'p', + 'pageSeparator' => '|'), $options ); - - $this->total = (int)$total; + + $this->total = (int)$total; $this->showSinglePage = $options['showSinglePage']; - $this->perPage = $options['perPage']; - $this->pagesToShow = $options['pagesToShow']; - $this->pageVariable = $options['pageVariable']; - $this->pageSeparator = $options['pageSeparator']; - $this->currentPage = isset($_GET[$this->pageVariable]) && $_GET[$this->pageVariable] > 0 ? $_GET[$this->pageVariable] : 1; - + $this->perPage = $options['perPage']; + $this->pagesToShow = $options['pagesToShow']; + $this->pageVariable = $options['pageVariable']; + $this->pageSeparator = $options['pageSeparator']; + $this->currentPage = isset($_GET[$this->pageVariable]) && $_GET[$this->pageVariable] > 0 ? $_GET[$this->pageVariable] : 1; + $this->calculatePages(); } - + /** * Calculate the number of pages. * @@ -149,7 +154,7 @@ private function calculatePages() { $this->numberOfPages = (int)ceil($this->total / $this->perPage); } - + /** * Get an SQL query with the "LIMIT offset,num" and appropriate "ORDER BY" * strings appended to the end. @@ -161,52 +166,50 @@ private function calculatePages() public function getSQL($sql) { $orderBy = false; - + foreach ($this->sortableColumns as $column => $value) { if (strpos($column, '.') !== false) { list ($table, $column) = explode('.', $column, 2); $param = "{$table}_{$column}_order"; $columnName = "`{$table}`.`{$column}`"; - } - else { + } else { $table = false; $param = "{$column}_order"; $columnName = "`$column`"; } - + $sortValues = array('ASC', 'DESC', 'NONE'); - + // First, check if a GET parameter was passed for this column. if (isset($_GET[$param]) && in_array(strtoupper($_GET[$param]), $sortValues)) { $value = $_GET[$param]; } - + // Check again just in case we're working with the default here. - if (!is_null($value) && in_array( ($value=strtoupper($value)), $sortValues ) && $value != 'NONE') { + if (!is_null($value) && in_array(($value = strtoupper($value)), $sortValues) && $value != 'NONE') { $this->currentSortOrder[str_replace("`", "", $columnName)] = $value; - + if (!$orderBy) { $sql .= ' ORDER BY'; $orderBy = true; } - + if ($value == 'ASC') { $sql .= " (CASE WHEN $columnName IS NULL THEN 1 ELSE 0 END) ASC, $columnName ASC,"; - } - else { + } else { $sql .= " $columnName $value,"; } } } - + if ($orderBy) { $sql = rtrim($sql, ','); } - + $offset = ($this->perPage * $this->currentPage) - $this->perPage; return "$sql LIMIT $offset,{$this->perPage}"; } - + /** * Generate some basic HTML which creates a list of page numbers. Will * return an empty string if DisplaySinglePages config is set to false. @@ -219,67 +222,64 @@ public function getHTML() if (!Flux::config('DisplaySinglePages') && $this->numberOfPages === 1) { return ''; } - + $pages = array(); $start = (floor(($this->currentPage - 1) / $this->pagesToShow) * $this->pagesToShow) + 1; - $end = $start + $this->pagesToShow + 1; - + $end = $start + $this->pagesToShow + 1; + if ($end > $this->numberOfPages) { $end = $this->numberOfPages + 1; - } - else { + } else { $end = $end - 1; } - + $hasPrev = $start > 1; $hasNext = $end < $this->numberOfPages; - + for ($i = $start; $i < $end; ++$i) { $request = $this->getPageURI($i); - + if ($i == $this->currentPage) { $pages[] = sprintf( '%d', $i, $i ); - } - else { + } else { $pages[] = sprintf( '%d', $request, $i, $i ); } } - + if ($hasPrev) { array_unshift($pages, sprintf('Prev. ', $this->getPageURI($start - 1), $start - 1)); } - + if ($hasNext) { array_push($pages, sprintf(' Next', $this->getPageURI($end), $end)); } - - $links = sprintf('
%s
', implode(" {$this->pageSeparator} ", $pages))."\n"; - + + $links = sprintf('
%s
', implode(" {$this->pageSeparator} ", $pages)) . "\n"; + if (Flux::config('ShowPageJump') && $this->numberOfPages > Flux::config('PageJumpMinimumPages')) { // This is some tricky shit. Don't even attempt to understand it =( // Page jumping is entirely JavaScript dependent. $pageVar = preg_quote($this->pageVariable); - $event = "location.href='".$this->getPageURI(0)."'"; - $event = preg_replace("/$pageVar=0/", "{$this->pageVariable}='+this.value+'", $event); - $jump = ''; - $jump = sprintf($jump, $event); - $links .= sprintf('
%s
', $jump); + $event = "location.href='" . $this->getPageURI(0) . "'"; + $event = preg_replace("/$pageVar=0/", "{$this->pageVariable}='+this.value+'", $event); + $jump = ''; + $jump = sprintf($jump, $event); + $links .= sprintf('
%s
', $jump); } - + if (!$this->showSinglePage && $this->numberOfPages === 1) { return null; - } - else { + } else { return $links; } } - + /** * Create a link to the current request with a different page number. * @@ -293,27 +293,27 @@ protected function getPageURI($pageNumber) $qString = $_SERVER['QUERY_STRING']; $pageVar = preg_quote($this->pageVariable); $pageNum = (int)$pageNumber; - - $qStringVars = array(); + + $qStringVars = array(); $qStringLines = preg_split('/&/', $qString, -1, PREG_SPLIT_NO_EMPTY); - + foreach ($qStringLines as $qStringVar) { if (strpos($qStringVar, '=') !== false) { list($qStringKey, $qStringVal) = explode('=', $qStringVar, 2); $qStringVars[$qStringKey] = $qStringVal; } } - + $qStringVars[$pageVar] = $pageNum; $qStringLines = array(); - + foreach ($qStringVars as $qStringKey => $qStringVal) { $qStringLines[] = sprintf('%s=%s', $qStringKey, $qStringVal); } - + return sprintf('%s?%s', $request, implode('&', $qStringLines)); } - + /** * Specify an array (or a string single column name) of columns that are * sortable by the paginator's features. @@ -327,23 +327,22 @@ public function setSortableColumns($columns) if (!is_array($columns)) { $columns = array($columns); } - + foreach ($columns as $key => $column) { - + if (!is_numeric($key)) { - $value = $column; + $value = $column; $column = $key; + } else { + $value = null; } - else { - $value = null; - } - + $this->sortableColumns[$column] = $value; } - + return $this->sortableColumns; } - + /** * Get an HTML anchor which automatically links to the current request * based on current sorting conditions and sets ascending/descending @@ -359,24 +358,22 @@ public function sortableColumn($column, $name = null) if (!$name) { $name = $column; } - + if (!array_key_exists($column, $this->sortableColumns)) { return htmlspecialchars($name); - } - else { + } else { if (strpos($column, '.') !== false) { list ($_table, $_column) = explode('.', $column, 2); $param = "{$_table}_{$_column}_order"; - } - else { + } else { $param = "{$column}_order"; } - - $order = 'asc'; - $format = '%s'; - $name = htmlspecialchars($name); + + $order = 'asc'; + $format = '%s'; + $name = htmlspecialchars($name); $request = $_SERVER['REQUEST_URI']; - + if (isset($this->currentSortOrder[$column])) { switch (strtolower($this->currentSortOrder[$column])) { case 'asc': @@ -392,39 +389,35 @@ public function sortableColumn($column, $name = null) break; } } - + if ($order) { $value = "$param=$order"; if (preg_match("/$param=(\w*)/", $request)) { $request = preg_replace("/$param=(\w*)/", $value, $request); - } - elseif (empty($_SERVER['QUERY_STRING'])) { + } elseif (empty($_SERVER['QUERY_STRING'])) { $request = "$request?$value"; - } - else { + } else { $request = "$request&$value"; } return sprintf($format, $request, $name); - } - else { + } else { $request = rtrim(preg_replace("%(?:(\?)$param=(?:\w*)&?|&?$param=(?:\w*))%", '$1', $request), '?'); return sprintf($format, $request, $name); } } } - + /** * */ public function infoText() { $currPage = $this->currentPage; - $results = $this->perPage; + $results = $this->perPage; $infoText = sprintf( Flux::message('FoundSearchResults'), - $this->total, $this->numberOfPages, ($currPage*$results-($results - 1)), $currPage * $results < $this->total ? ($currPage*$results) : ($this->total) + $this->total, $this->numberOfPages, ($currPage * $results - ($results - 1)), $currPage * $results < $this->total ? ($currPage * $results) : ($this->total) ); return sprintf('

%s

', $infoText); } } -?> diff --git a/lib/Flux/PaymentNotifyRequest.php b/src/PaymentNotifyRequest.php similarity index 75% rename from lib/Flux/PaymentNotifyRequest.php rename to src/PaymentNotifyRequest.php index 38f26bb7..14a23156 100644 --- a/lib/Flux/PaymentNotifyRequest.php +++ b/src/PaymentNotifyRequest.php @@ -1,17 +1,17 @@ ppLogFile = new Flux_LogFile(FLUX_DATA_DIR.'/logs/paypal.log'); - $this->ppServer = Flux::config('PayPalIpnUrl'); + $this->ppLogFile = new LogFile(FLUX_DATA_DIR . '/logs/paypal.log'); + $this->ppServer = Flux::config('PayPalIpnUrl'); $this->myBusinessEmail = Flux::config('PayPalBusinessEmail'); - $this->myCurrencyCode = strtoupper(Flux::config('DonationCurrency')); - $this->ipnVariables = new Flux_Config($ipnPostVars); - $this->txnLogTable = Flux::config('FluxTables.TransactionTable'); - $this->creditsTable = Flux::config('FluxTables.CreditsTable'); + $this->myCurrencyCode = strtoupper(Flux::config('DonationCurrency')); + $this->ipnVariables = new Config($ipnPostVars); + $this->txnLogTable = Flux::config('FluxTables.TransactionTable'); + $this->creditsTable = Flux::config('FluxTables.CreditsTable'); } /** @@ -102,28 +102,28 @@ protected function logPayPal() $func = array($this->ppLogFile, 'puts'); return call_user_func_array($func, $args); } - + /** - * Get user IP. - * Checks if CloudFlare used to get real IP. - * - * @access public - */ - protected function fetchIP() - { - $alt_ip = $_SERVER['REMOTE_ADDR']; - if (isset($_SERVER['HTTP_X_REAL_IP'])) { - $alt_ip = $_SERVER['HTTP_X_REAL_IP']; - } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { - $alt_ip = $_SERVER['HTTP_X_FORWARDED_FOR']; - } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { - $alt_ip = $_SERVER['HTTP_CLIENT_IP']; - } elseif (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) { - $alt_ip = $_SERVER['HTTP_CF_CONNECTING_IP']; - } - - return $alt_ip; - } + * Get user IP. + * Checks if CloudFlare used to get real IP. + * + * @access public + */ + protected function fetchIP() + { + $alt_ip = $_SERVER['REMOTE_ADDR']; + if (isset($_SERVER['HTTP_X_REAL_IP'])) { + $alt_ip = $_SERVER['HTTP_X_REAL_IP']; + } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $alt_ip = $_SERVER['HTTP_X_FORWARDED_FOR']; + } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { + $alt_ip = $_SERVER['HTTP_CLIENT_IP']; + } elseif (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) { + $alt_ip = $_SERVER['HTTP_CF_CONNECTING_IP']; + } + + return $alt_ip; + } /** * Process transaction. @@ -144,30 +144,28 @@ public function process() $receiverEmail = $this->ipnVariables->get('receiver_email'); $transactionID = $this->ipnVariables->get('txn_id'); $paymentStatus = $this->ipnVariables->get('payment_status'); - $payerEmail = $this->ipnVariables->get('payer_email'); - $currencyCode = strtoupper(substr($this->ipnVariables->get('mc_currency'), 0, 3)); - $trusted = true; + $payerEmail = $this->ipnVariables->get('payer_email'); + $currencyCode = strtoupper(substr($this->ipnVariables->get('mc_currency'), 0, 3)); + $trusted = true; // Identify transaction number. $this->logPayPal('Transaction identified as %s.', $transactionID); if (!in_array($receiverEmail, $accountEmails)) { $this->logPayPal('Receiver e-mail (%s) is not recognized, unauthorized to continue.', $receiverEmail); - } - else { - $customArray = @unserialize(base64_decode((string)$this->ipnVariables->get('custom'))); - $customArray = $customArray && is_array($customArray) ? $customArray : array(); - $customData = new Flux_Config($customArray); - $accountID = $customData->get('account_id'); - $serverName = $customData->get('server_name'); + } else { + $customArray = @unserialize(base64_decode((string)$this->ipnVariables->get('custom'))); + $customArray = $customArray && is_array($customArray) ? $customArray : array(); + $customData = new Config($customArray); + $accountID = $customData->get('account_id'); + $serverName = $customData->get('server_name'); if ($currencyCode != $this->myCurrencyCode) { $this->logPayPal('Transaction currency not exchangeable, accepting anyways. (recv: %s, expected: %s)', $currencyCode, $this->myCurrencyCode); $exchangeableCurrency = false; - } - else { + } else { $exchangeableCurrency = true; } @@ -175,7 +173,7 @@ public function process() $this->logPayPal('Received %s (%s).', $this->ipnVariables->get('mc_gross'), $currencyCode); // How much will be deposited? - $settleAmount = $this->ipnVariables->get('settle_amount'); + $settleAmount = $this->ipnVariables->get('settle_amount'); $settleCurrency = $this->ipnVariables->get('settle_currency'); if ($settleAmount && $settleCurrency) { @@ -188,11 +186,9 @@ public function process() if (!$accountID || !$serverName) { $this->logPayPal('Account ID and/or game server name absent, cannot exchange for credits.'); - } - elseif ($this->ipnVariables->get('txn_type') != 'web_accept') { + } elseif ($this->ipnVariables->get('txn_type') != 'web_accept') { $this->logPayPal('Transaction type is not web_accept, amount will not be exchanged for credits.'); - } - elseif (!($servGroup = Flux::getServerGroupByName($serverName))) { + } elseif (!($servGroup = Flux::getServerGroupByName($serverName))) { $this->logPayPal('Unknown game server "%s", cannot process donation for credits.', $serverName); } @@ -207,18 +203,17 @@ public function process() if (!$res) { $this->logPayPal('Unknown account #%s on server %s, cannot exchange for credits.', $accountID, $serverName); - } - else { + } else { if (!$servGroup->loginServer->hasCreditsRecord($accountID)) { $this->logPayPal('Identified as first-time donation to the server from this account.'); } - $amount = (float)$this->ipnVariables->get('mc_gross'); + $amount = (float)$this->ipnVariables->get('mc_gross'); $minimum = (float)Flux::config('MinDonationAmount'); if ($amount >= $minimum) { $trustTable = Flux::config('FluxTables.DonationTrustTable'); - $holdHours = +(int)Flux::config('HoldUntrustedAccount'); + $holdHours = +(int)Flux::config('HoldUntrustedAccount'); if ($holdHours) { $sql = "SELECT account_id, email FROM {$servGroup->loginDatabase}.$trustTable WHERE account_id = ? AND email = ? LIMIT 1"; @@ -229,13 +224,12 @@ public function process() if ($res && $res->account_id) { $this->logPayPal('Account ID and e-mail are trusted.'); $trusted = true; - } - else { + } else { $trusted = false; } } - $rate = Flux::config('CreditExchangeRate'); + $rate = Flux::config('CreditExchangeRate'); $credits = floor($amount / $rate); if ($trusted) { @@ -249,30 +243,25 @@ public function process() if ($res) { $this->logPayPal('Deposited credits.'); - } - else { + } else { $this->logPayPal('Failed to deposit credits.'); } - } - else { + } else { $this->logPayPal('Account/e-mail is not trusted, holding donation credits for %d hours.', $holdHours); } - } - else { + } else { $this->logPayPal('User has donated less than the configured minimum, not exchanging credits.'); } } } - } - else { + } else { $this->logPayPal('Incomplete payment status: %s (exchanging for credits will not take place)', $paymentStatus); $banStatuses = Flux::config('BanPaymentStatuses'); - if ($banStatuses instanceOf Flux_Config) { + if ($banStatuses instanceOf Config) { $banStatuses = $banStatuses->toArray(); - } - else { + } else { $banStatuses = array(); } @@ -288,8 +277,7 @@ public function process() null, "Banned for invalid payment status: $paymentStatus", $accountID ); - } - else { + } else { $this->logPayPal("Couldn't ban account, it's unknown."); } } @@ -299,8 +287,7 @@ public function process() foreach (Flux::$loginAthenaGroupRegistry as $servGroup) { $this->logToPayPalTable($servGroup, $accountID, $serverName, $trusted); } - } - else { + } else { if (empty($credits)) { $credits = 0; } @@ -309,34 +296,30 @@ public function process() $this->logPayPal('Saving transaction details for %s...', $transactionID); - if ($logFile=$this->saveDetailsToFile()) { + if ($logFile = $this->saveDetailsToFile()) { $this->logPayPal('Saved transaction details for %s to: %s', $transactionID, $logFile); - } - else { + } else { $this->logPayPal('Failed to save transaction details for %s to file.', $transactionID); } $this->logPayPal('Done processing %s.', $transactionID); } - } - else { + } else { $this->logPayPal('Transaction invalid, aborting.'); - - if(!in_array($received_from, $allowed_hosts) && Flux::config('PaypalHackNotify')){ - require_once 'Flux/Mailer.php'; - - $customArray = @unserialize(base64_decode((string)$this->ipnVariables->get('custom'))); - $customArray = $customArray && is_array($customArray) ? $customArray : array(); - $customData = new Flux_Config($customArray); - $accountID = $customData->get('account_id'); - $serverName = $customData->get('server_name'); - - $mail = new Flux_Mailer(); - + + if (!in_array($received_from, $allowed_hosts) && Flux::config('PaypalHackNotify')) { + $customArray = @unserialize(base64_decode((string)$this->ipnVariables->get('custom'))); + $customArray = $customArray && is_array($customArray) ? $customArray : array(); + $customData = new Config($customArray); + $accountID = $customData->get('account_id'); + $serverName = $customData->get('server_name'); + + $mail = new Mailer(); + $tmpl = "

Paypal hack detected!

"; - $tmpl .= "

Account: ".$accountID."

"; - $tmpl .= "

serverName: ".$serverName."

"; - + $tmpl .= "

Account: " . $accountID . "

"; + $tmpl .= "

serverName: " . $serverName . "

"; + $tmpl .= "


"; $tmpl .= "

======= IP Info ========

"; $tmpl .= nl2br(var_export(['ip' => $this->fetchIP(), 'host' => $received_from], true)); @@ -349,14 +332,14 @@ public function process() $tmpl .= "

======= Transaction Info ========

"; $tmpl .= nl2br(var_export($this->ipnVariables->toArray(), true)); $tmpl .= "

======= End Transaction Info ========

"; - + $accountEmails = Flux::config('PayPalReceiverEmails'); $accountEmails = array_merge(array($this->myBusinessEmail), $accountEmails->toArray()); - - foreach($accountEmails as $email) { - $sent = $mail->send($email, '['.Flux::config('SiteTitle').'] Paypal hack', $tmpl, array('_ignoreTemplate' => true)); + + foreach ($accountEmails as $email) { + $sent = $mail->send($email, '[' . Flux::config('SiteTitle') . '] Paypal hack', $tmpl, array('_ignoreTemplate' => true)); } - + $this->logPayPal('Hack detected!'); } } @@ -393,23 +376,22 @@ private function ipnVarsToQueryString() */ private function verify() { - $qString = 'cmd=_notify-validate&'.$this->ipnVarsToQueryString(); - $request = "POST /cgi-bin/webscr HTTP/1.1\r\n"; + $qString = 'cmd=_notify-validate&' . $this->ipnVarsToQueryString(); + $request = "POST /cgi-bin/webscr HTTP/1.1\r\n"; $request .= "Content-Type: application/x-www-form-urlencoded\r\n"; - $request .= 'Content-Length: '.strlen($qString)."\r\n"; - $request .= 'Host: '.$this->ppServer."\r\n"; + $request .= 'Content-Length: ' . strlen($qString) . "\r\n"; + $request .= 'Host: ' . $this->ppServer . "\r\n"; $request .= "Connection: close\r\n\r\n"; $request .= $qString; $this->logPayPal('Query string: %s', $qString); $this->logPayPal('Establishing connection to PayPal server at %s:443...', $this->ppServer); - $fp = @fsockopen('ssl://'.$this->ppServer, 443, $errno, $errstr, 20); + $fp = @fsockopen('ssl://' . $this->ppServer, 443, $errno, $errstr, 20); if (!$fp) { $this->logPayPal("Failed to connect to PayPal server: [%d] %s", $errno, $errstr); return false; - } - else { + } else { $this->logPayPal('Connected. Sending request back to PayPal...'); // Send POST request just as PayPal sent it. @@ -418,8 +400,8 @@ private function verify() $this->logPayPal('Reading back response from PayPal...'); // Read until body starts - while (!feof($fp) && ($line = trim(fgets($fp))) != ''); - + while (!feof($fp) && ($line = trim(fgets($fp))) != '') ; + $line = ''; // Read until EOF, contains VERIFIED or INVALID. @@ -435,8 +417,7 @@ private function verify() $this->logPayPal('Notification verified. (recv: %s)', $line); $this->txnIsValid = true; return true; - } - else { + } else { $this->logPayPal('Notification failed to verify. (recv: %s)', $line); return false; } @@ -453,10 +434,10 @@ private function verify() private function saveDetailsToFile() { if ($this->txnIsValid) { - $logDir1 = realpath(FLUX_DATA_DIR.'/logs/transactions'); - $logDir2 = $logDir1.'/'.$this->ipnVariables->get('txn_type'); - $logDir3 = $logDir2.'/'.$this->ipnVariables->get('payment_status'); - $logFile = $logDir3.'/'.$this->ipnVariables->get('txn_id').'.log.php'; + $logDir1 = realpath(FLUX_DATA_DIR . '/logs/transactions'); + $logDir2 = $logDir1 . '/' . $this->ipnVariables->get('txn_type'); + $logDir3 = $logDir2 . '/' . $this->ipnVariables->get('payment_status'); + $logFile = $logDir3 . '/' . $this->ipnVariables->get('txn_id') . '.log.php'; if (!is_dir($logDir2)) { mkdir($logDir2, 0600); @@ -481,30 +462,29 @@ private function saveDetailsToFile() /** * Log the transaction details into the flux_paypal_transactions table. * - * @param Flux_LoginAthenaGroup $servGroup + * @param LoginAthenaGroup $servGroup * @param string $accountID * @param string $serverName * @access private */ - private function logToPayPalTable(Flux_LoginAthenaGroup $servGroup, $accountID, $serverName, $trusted, $credits = 0) + private function logToPayPalTable(LoginAthenaGroup $servGroup, $accountID, $serverName, $trusted, $credits = 0) { if ($this->txnIsValid) { $holdUntil = null; if (!$trusted) { $email = $this->ipnVariables->get('payer_email'); - $sql = "SELECT hold_until FROM {$servGroup->loginDatabase}.{$this->txnLogTable} "; - $sql .= "WHERE account_id = ? AND payer_email = ? AND hold_until > NOW() AND payment_status = 'Completed' LIMIT 1"; - $sth = $sth = $servGroup->connection->getStatement($sql); + $sql = "SELECT hold_until FROM {$servGroup->loginDatabase}.{$this->txnLogTable} "; + $sql .= "WHERE account_id = ? AND payer_email = ? AND hold_until > NOW() AND payment_status = 'Completed' LIMIT 1"; + $sth = $sth = $servGroup->connection->getStatement($sql); $sth->execute(array($accountID, $email)); $row = $sth->fetch(); if ($row && $row->hold_until) { $holdUntil = $row->hold_until; - } - else { - $hours = +(int)Flux::config('HoldUntrustedAccount'); - $holdUntil = date('Y-m-d H:i:s', time()+($hours*60*60)); + } else { + $hours = +(int)Flux::config('HoldUntrustedAccount'); + $holdUntil = date('Y-m-d H:i:s', time() + ($hours * 60 * 60)); } } @@ -592,12 +572,10 @@ private function logToPayPalTable(Flux_LoginAthenaGroup $servGroup, $accountID, $serverName = '(unknown)'; } $this->logPayPal('Stored information in PayPal transactions table for server %s.', $serverName); - } - else { + } else { $errorInfo = implode('/', $sth->errorInfo()); $this->logPayPal('Failed to save information in PayPal transactions table. (%s)', $errorInfo); } } } } -?> diff --git a/src/PermissionError.php b/src/PermissionError.php new file mode 100644 index 00000000..1cae938c --- /dev/null +++ b/src/PermissionError.php @@ -0,0 +1,8 @@ +sessionData = &$sessionData; if ($logout) { $this->logout(); - } - else { + } else { $this->initialize(); } } - + /** * Initialize session data. * @@ -73,7 +75,7 @@ public function __construct(array &$sessionData, $logout = false) * @access private */ private function initialize($force = false) - { + { $keysToInit = array('username', 'serverName', 'athenaServerName', 'securityCode', 'theme'); foreach ($keysToInit as $key) { if ($force || !$this->{$key}) { @@ -88,50 +90,48 @@ private function initialize($force = false) $loggedIn = false; $cfgAthenaServerName = Flux::config('DefaultCharMapServer'); $cfgLoginAthenaGroup = Flux::config('DefaultLoginGroup'); - - if (Flux::getServerGroupByName($cfgLoginAthenaGroup)){ + + if (Flux::getServerGroupByName($cfgLoginAthenaGroup)) { $this->setServerNameData($cfgLoginAthenaGroup); - } - else { + } else { $defaultServerName = current(array_keys(Flux::$loginAthenaGroupRegistry)); $this->setServerNameData($defaultServerName); } } - - + + if ($this->serverName && ($this->loginAthenaGroup = Flux::getServerGroupByName($this->serverName))) { $this->loginServer = $this->loginAthenaGroup->loginServer; - + if (!$loggedIn && $cfgAthenaServerName && $this->getAthenaServer($cfgAthenaServerName)) { $this->setAthenaServerNameData($cfgAthenaServerName); } - + if (!$this->athenaServerName || ((!$loggedIn && !$this->getAthenaServer($cfgAthenaServerName)) || !$this->getAthenaServer($this->athenaServerName))) { $this->setAthenaServerNameData(current($this->getAthenaServerNames())); } } - + // Get new account data every request. - if ($this->loginAthenaGroup && $this->username && ($account = $this->getAccount($this->loginAthenaGroup, $this->username))) { + if ($this->loginAthenaGroup && $this->username && ($account = $this->getAccount($this->loginAthenaGroup, $this->username))) { $this->account = $account; $this->account->group_level = AccountLevel::getGroupLevel($account->group_id); - + // Automatically log out of account when detected as banned. $permBan = ($account->state == 5 && !Flux::config('AllowPermBanLogin')); $tempBan = (($account->unban_time > 0 && $account->unban_time < time()) && !Flux::config('AllowTempBanLogin')); - + if ($permBan || $tempBan) { $this->logout(); } + } else { + $this->account = new DataObject(null, array('group_level' => AccountLevel::UNAUTH)); } - else { - $this->account = new Flux_DataObject(null, array('group_level' => AccountLevel::UNAUTH)); - } - + if (!is_array($this->cart)) { $this->setCartData(array()); } - + if ($this->account->account_id && $this->loginAthenaGroup) { if (!array_key_exists($this->loginAthenaGroup->serverName, $this->cart)) { $this->cart[$this->loginAthenaGroup->serverName] = array(); @@ -139,31 +139,31 @@ private function initialize($force = false) foreach ($this->getAthenaServerNames() as $athenaServerName) { $athenaServer = $this->getAthenaServer($athenaServerName); - $cartArray = &$this->cart[$this->loginAthenaGroup->serverName]; - $accountID = $this->account->account_id; - + $cartArray = &$this->cart[$this->loginAthenaGroup->serverName]; + $accountID = $this->account->account_id; + if (!array_key_exists($accountID, $cartArray)) { $cartArray[$accountID] = array(); } - + if (!array_key_exists($athenaServerName, $cartArray[$accountID])) { - $cartArray[$accountID][$athenaServerName] = new Flux_ItemShop_Cart(); + $cartArray[$accountID][$athenaServerName] = new Cart(); } $cartArray[$accountID][$athenaServerName]->setAccount($this->account); $athenaServer->setCart($cartArray[$accountID][$athenaServerName]); } } - + if (!$this->theme || $this->theme === 'installer') { // always update if coming from installer $this->setThemeData(Flux::config('ThemeName.0')); } return true; } - + /** * Log current user out. - * + * * @return bool * @access public */ @@ -173,24 +173,24 @@ public function logout() $this->loginServer = null; return $this->initialize(true); } - + public function __call($method, $args) { if (count($args) && preg_match('/set(.+?)Data/', $method, $m)) { - $arg = current($args); - $meth = $m[1]; + $arg = current($args); + $meth = $m[1]; $meth[0] = strtolower($meth[0]); - + if (array_key_exists($meth, $this->dataFilters)) { foreach ($this->dataFilters[$meth] as $callback) { $arg = call_user_func($callback, $arg); } } - + $this->sessionData[$meth] = $arg; } } - + public function &__get($prop) { $value = null; @@ -199,7 +199,7 @@ public function &__get($prop) } return $value; } - + /** * Set session data. * @@ -216,7 +216,7 @@ public function setData(array $keys, $value) } return $value; } - + /** * Add a session data setter filter. * @@ -230,11 +230,11 @@ public function addDataFilter($key, $callback) if (!array_key_exists($key, $this->dataFilters)) { $this->dataFilters[$key] = array(); } - + $this->dataFilters[$key][] = $callback; return $callback; } - + /** * Checks whether the current user is logged in. */ @@ -242,55 +242,54 @@ public function isLoggedIn() { return $this->account->group_level >= AccountLevel::NORMAL; } - + /** * User login. * * @param string $server Server name * @param string $username * @param string $password - * @throws Flux_LoginError + * @throws LoginError * @access public */ public function login($server, $username, $password, $securityCode = null) { $loginAthenaGroup = Flux::getServerGroupByName($server); if (!$loginAthenaGroup) { - throw new Flux_LoginError('Invalid server.', Flux_LoginError::INVALID_SERVER); + throw new LoginError('Invalid server.', LoginError::INVALID_SERVER); } - + if ($loginAthenaGroup->loginServer->isIpBanned() && !Flux::config('AllowIpBanLogin')) { - throw new Flux_LoginError('IP address is banned', Flux_LoginError::IPBANNED); + throw new LoginError('IP address is banned', LoginError::IPBANNED); } - + if ($securityCode !== false && Flux::config('UseLoginCaptcha')) { if (strtolower($securityCode) != strtolower($this->securityCode)) { - throw new Flux_LoginError('Invalid security code', Flux_LoginError::INVALID_SECURITY_CODE); - } - elseif (Flux::config('EnableReCaptcha')) { - if(isset($_POST['g-recaptcha-response']) && $_POST['g-recaptcha-response'] != ""){ - $response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=".Flux::config('ReCaptchaPrivateKey')."&response=".$_POST['g-recaptcha-response']."&remoteip=".$_SERVER['REMOTE_ADDR']); + throw new LoginError('Invalid security code', LoginError::INVALID_SECURITY_CODE); + } elseif (Flux::config('EnableReCaptcha')) { + if (isset($_POST['g-recaptcha-response']) && $_POST['g-recaptcha-response'] != "") { + $response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=" . Flux::config('ReCaptchaPrivateKey') . "&response=" . $_POST['g-recaptcha-response'] . "&remoteip=" . $_SERVER['REMOTE_ADDR']); } - $responseKeys = json_decode($response,true); - if(intval($responseKeys["success"]) !== 1) { - throw new Flux_LoginError('Invalid security code', Flux_LoginError::INVALID_SECURITY_CODE); + $responseKeys = json_decode($response, true); + if (intval($responseKeys["success"]) !== 1) { + throw new LoginError('Invalid security code', LoginError::INVALID_SECURITY_CODE); } } } - + if (!$loginAthenaGroup->isAuth($username, $password)) { - throw new Flux_LoginError('Invalid login', Flux_LoginError::INVALID_LOGIN); + throw new LoginError('Invalid login', LoginError::INVALID_LOGIN); } - - $creditsTable = Flux::config('FluxTables.CreditsTable'); + + $creditsTable = Flux::config('FluxTables.CreditsTable'); $creditColumns = 'credits.balance, credits.last_donation_date, credits.last_donation_amount'; - - $sql = "SELECT login.*, {$creditColumns} FROM {$loginAthenaGroup->loginDatabase}.login "; + + $sql = "SELECT login.*, {$creditColumns} FROM {$loginAthenaGroup->loginDatabase}.login "; $sql .= "LEFT OUTER JOIN {$loginAthenaGroup->loginDatabase}.{$creditsTable} AS credits ON login.account_id = credits.account_id "; $sql .= "WHERE login.sex != 'S' AND login.group_id >= 0 AND login.userid = ? LIMIT 1"; - $smt = $loginAthenaGroup->connection->getStatement($sql); - $res = $smt->execute(array($username)); - + $smt = $loginAthenaGroup->connection->getStatement($sql); + $res = $smt->execute(array($username)); + if ($res && ($row = $smt->fetch())) { if ($row->unban_time > 0) { if (time() >= $row->unban_time) { @@ -298,67 +297,64 @@ public function login($server, $username, $password, $securityCode = null) $sql = "UPDATE {$loginAthenaGroup->loginDatabase}.login SET unban_time = 0 WHERE account_id = ?"; $sth = $loginAthenaGroup->connection->getStatement($sql); $sth->execute(array($row->account_id)); - } - elseif (!Flux::config('AllowTempBanLogin')) { - throw new Flux_LoginError('Temporarily banned', Flux_LoginError::BANNED); + } elseif (!Flux::config('AllowTempBanLogin')) { + throw new LoginError('Temporarily banned', LoginError::BANNED); } } if ($row->state == 5) { $createTable = Flux::config('FluxTables.AccountCreateTable'); - $sql = "SELECT id FROM {$loginAthenaGroup->loginDatabase}.$createTable "; + $sql = "SELECT id FROM {$loginAthenaGroup->loginDatabase}.$createTable "; $sql .= "WHERE account_id = ? AND confirmed = 0"; - $sth = $loginAthenaGroup->connection->getStatement($sql); + $sth = $loginAthenaGroup->connection->getStatement($sql); $sth->execute(array($row->account_id)); $row2 = $sth->fetch(); - + if ($row2 && $row2->id) { - throw new Flux_LoginError('Pending confirmation', Flux_LoginError::PENDING_CONFIRMATION); + throw new LoginError('Pending confirmation', LoginError::PENDING_CONFIRMATION); } } if (!Flux::config('AllowPermBanLogin') && $row->state == 5) { - throw new Flux_LoginError('Permanently banned', Flux_LoginError::PERMABANNED); + throw new LoginError('Permanently banned', LoginError::PERMABANNED); } - + $this->setServerNameData($server); $this->setUsernameData($username); $this->initialize(false); + } else { + $message = "Unexpected error during login.\n"; + $message .= 'PDO error info, if any: ' . print_r($smt->errorInfo(), true); + throw new LoginError($message, LoginError::UNEXPECTED); } - else { - $message = "Unexpected error during login.\n"; - $message .= 'PDO error info, if any: '.print_r($smt->errorInfo(), true); - throw new Flux_LoginError($message, Flux_LoginError::UNEXPECTED); - } - + return true; } - + /** * Get account object for a particular user name. * - * @param Flux_LoginAthenaGroup $loginAthenaGroup + * @param LoginAthenaGroup $loginAthenaGroup * @param string $username * @return mixed * @access private */ - private function getAccount(Flux_LoginAthenaGroup $loginAthenaGroup, $username) + private function getAccount(LoginAthenaGroup $loginAthenaGroup, $username) { - $creditsTable = Flux::config('FluxTables.CreditsTable'); + $creditsTable = Flux::config('FluxTables.CreditsTable'); $creditColumns = 'credits.balance, credits.last_donation_date, credits.last_donation_amount'; - - $sql = "SELECT login.*, {$creditColumns} FROM {$loginAthenaGroup->loginDatabase}.login "; + + $sql = "SELECT login.*, {$creditColumns} FROM {$loginAthenaGroup->loginDatabase}.login "; $sql .= "LEFT OUTER JOIN {$loginAthenaGroup->loginDatabase}.{$creditsTable} AS credits ON login.account_id = credits.account_id "; $sql .= "WHERE login.sex != 'S' AND login.group_id >= 0 AND login.userid = ? LIMIT 1"; - $smt = $loginAthenaGroup->connection->getStatement($sql); - $res = $smt->execute(array($username)); - + $smt = $loginAthenaGroup->connection->getStatement($sql); + $res = $smt->execute(array($username)); + if ($res && ($row = $smt->fetch())) { return $row; - } - else { + } else { return false; } } - + /** * Get available server names. * @@ -372,15 +368,14 @@ public function getAthenaServerNames() $names[] = $server->serverName; } return $names; - } - else { + } else { return array(); } } - + /** * Get a Flux_Athena instance by its name based on current server settings. - * + * * @param string $name * @access public */ @@ -389,15 +384,14 @@ public function getAthenaServer($name = null) if (is_null($name) && $this->athenaServerName) { return $this->getAthenaServer($this->athenaServerName); } - + if ($this->loginAthenaGroup && ($server = Flux::getAthenaServerByName($this->serverName, $name))) { return $server; - } - else { + } else { return false; } } - + /** * Get flash message. * @@ -411,4 +405,5 @@ public function getMessage() return $message; } } + ?> diff --git a/lib/Flux/Template.php b/src/Template.php similarity index 72% rename from lib/Flux/Template.php rename to src/Template.php index fadfd78b..ada2e045 100644 --- a/lib/Flux/Template.php +++ b/src/Template.php @@ -1,5 +1,8 @@ params = $config->get('params'); - $this->basePath = $config->get('basePath'); - $this->modulePath = $config->get('modulePath'); - $this->moduleName = $config->get('moduleName'); - $this->themePath = $config->get('themePath'); - $this->themeName = $config->get('themeName'); - $this->actionName = $config->get('actionName'); - $this->viewName = $config->get('viewName'); - $this->headerName = $config->get('headerName'); - $this->footerName = $config->get('footerName'); - $this->useCleanUrls = $config->get('useCleanUrls'); + $this->params = $config->get('params'); + $this->basePath = $config->get('basePath'); + $this->modulePath = $config->get('modulePath'); + $this->moduleName = $config->get('moduleName'); + $this->themePath = $config->get('themePath'); + $this->themeName = $config->get('themeName'); + $this->actionName = $config->get('actionName'); + $this->viewName = $config->get('viewName'); + $this->headerName = $config->get('headerName'); + $this->footerName = $config->get('footerName'); + $this->useCleanUrls = $config->get('useCleanUrls'); $this->missingActionModuleAction = $config->get('missingActionModuleAction', false); - $this->missingViewModuleAction = $config->get('missingViewModuleAction', false); - $this->referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; + $this->missingViewModuleAction = $config->get('missingViewModuleAction', false); + $this->referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''; // Read manifest file if exists - if (file_exists($this->themePath.'/'.$this->themeName.'/manifest.php')) { - $manifest = include($this->themePath.'/'.$this->themeName.'/manifest.php'); + if (file_exists($this->themePath . '/' . $this->themeName . '/manifest.php')) { + $manifest = include($this->themePath . '/' . $this->themeName . '/manifest.php'); // Inherit views and controllers from another template if (!empty($manifest['inherit'])) { if (in_array($manifest['inherit'], self::$themeLoaded)) { - throw new Flux_Error('Circular dependencies in themes : ' . implode(' -> ', self::$themeLoaded) . ' -> ' . $manifest['inherit']); + throw new Error('Circular dependencies in themes : ' . implode(' -> ', self::$themeLoaded) . ' -> ' . $manifest['inherit']); } $config->set('themeName', $manifest['inherit']); - self::$themeLoaded[] = $manifest['inherit']; - $this->parentTemplate = new Flux_Template($config); + self::$themeLoaded[] = $manifest['inherit']; + $this->parentTemplate = new Template($config); } } @@ -277,10 +281,10 @@ public function render(array $dataArr = array()) ini_set('zlib.output_compression', 'On'); ini_set('zlib.output_compression_level', (int)Flux::config('GzipCompressionLevel')); } - + $addon = false; $this->actionPath = sprintf('%s/%s/%s.php', $this->modulePath, $this->moduleName, $this->actionName); - + if (!file_exists($this->actionPath)) { foreach (Flux::$addons as $_tmpAddon) { if ($_tmpAddon->respondsTo($this->moduleName, $this->actionName)) { @@ -288,59 +292,58 @@ public function render(array $dataArr = array()) $this->actionPath = sprintf('%s/%s/%s.php', $addon->moduleDir, $this->moduleName, $this->actionName); } } - + if (!$addon) { $this->moduleName = $this->missingActionModuleAction[0]; $this->actionName = $this->missingActionModuleAction[1]; - $this->viewName = $this->missingActionModuleAction[1]; + $this->viewName = $this->missingActionModuleAction[1]; $this->actionPath = sprintf('%s/%s/%s.php', $this->modulePath, $this->moduleName, $this->actionName); } } - + $this->viewPath = $this->themePath(sprintf('%s/%s.php', $this->moduleName, $this->actionName), true); - + if (!file_exists($this->viewPath) && $addon) { - $this->viewPath = $addon->getView( $this, $this->moduleName, $this->actionName); - - if ( $this->viewPath === false ) { + $this->viewPath = $addon->getView($this, $this->moduleName, $this->actionName); + + if ($this->viewPath === false) { $this->moduleName = $this->missingViewModuleAction[0]; $this->actionName = $this->missingViewModuleAction[1]; - $this->viewName = $this->missingViewModuleAction[1]; + $this->viewName = $this->missingViewModuleAction[1]; $this->actionPath = sprintf('%s/%s/%s.php', $this->modulePath, $this->moduleName, $this->actionName); - $this->viewPath = $this->themePath(sprintf('%s/%s.php', $this->moduleName, $this->viewName), true); + $this->viewPath = $this->themePath(sprintf('%s/%s.php', $this->moduleName, $this->viewName), true); } } - $this->headerPath = $this->themePath($this->headerName.'.php', true); - $this->footerPath = $this->themePath($this->footerName.'.php', true); - $this->url = $this->url($this->moduleName, $this->actionName); - $this->urlWithQS = $this->url; - + $this->headerPath = $this->themePath($this->headerName . '.php', true); + $this->footerPath = $this->themePath($this->footerName . '.php', true); + $this->url = $this->url($this->moduleName, $this->actionName); + $this->urlWithQS = $this->url; + if (!empty($_SERVER['QUERY_STRING'])) { if ($this->useCleanUrls) { $this->urlWithQS .= "?{$_SERVER['QUERY_STRING']}"; - } - else { + } else { foreach (explode('&', trim($_SERVER['QUERY_STRING'], '&')) as $line) { - list ($key,$val) = explode('=', $line, 2); + list ($key, $val) = explode('=', $line, 2); $key = urldecode($key); $val = urldecode($val); - + if ($key != 'module' && $key != 'action') { $this->urlWithQS .= sprintf('&%s=%s', urlencode($key), urlencode($val)); } } } } - + // Compatibility. - $this->urlWithQs = $this->urlWithQS; - + $this->urlWithQs = $this->urlWithQS; + // Tidy up! if (Flux::config('OutputCleanHTML')) { - $dispatcher = Flux_Dispatcher::getInstance(); + $dispatcher = Dispatcher::getInstance(); $tidyIgnore = false; - if (($tidyIgnores = Flux::config('TidyIgnore')) instanceOf Flux_Config) { + if (($tidyIgnores = Flux::config('TidyIgnore')) instanceOf Config) { foreach ($tidyIgnores->getChildrenConfigs() as $ignore) { $ignore = $ignore->toArray(); if (is_array($ignore) && array_key_exists('module', $ignore)) { @@ -356,35 +359,35 @@ public function render(array $dataArr = array()) ob_start(); } } - + // Merge with default data. $data = array_merge($this->defaultData, $dataArr); - + // Extract data array and make them appear as though they were global // variables from the template. extract($data, EXTR_REFS); - + // Files object. - $files = new Flux_Config($_FILES); - + $files = new Config($_FILES); + $preprocessorPath = sprintf('%s/main/preprocess.php', $this->modulePath); if (file_exists($preprocessorPath)) { include $preprocessorPath; } - + include $this->actionPath; - - $pageMenuFile = FLUX_ROOT."/modules/{$this->moduleName}/pagemenu/{$this->actionName}.php"; - $pageMenuItems = array(); - + + $pageMenuFile = FLUX_ROOT . "/modules/{$this->moduleName}/pagemenu/{$this->actionName}.php"; + $pageMenuItems = array(); + // Get the main menu file first (located in the actual module). if (file_exists($pageMenuFile)) { ob_start(); $pageMenuItems = include $pageMenuFile; ob_end_clean(); } - - $addonPageMenuFiles = glob(FLUX_ADDON_DIR."/*/modules/{$this->moduleName}/pagemenu/{$this->actionName}.php"); + + $addonPageMenuFiles = glob(FLUX_ADDON_DIR . "/*/modules/{$this->moduleName}/pagemenu/{$this->actionName}.php"); if ($addonPageMenuFiles) { foreach ($addonPageMenuFiles as $addonPageMenuFile) { ob_start(); @@ -392,17 +395,17 @@ public function render(array $dataArr = array()) ob_end_clean(); } } - + if (file_exists($this->headerPath)) { include $this->headerPath; } - + include $this->viewPath; - + if (file_exists($this->footerPath)) { include $this->footerPath; } - + // Really, tidy up! if (Flux::config('OutputCleanHTML') && !$tidyIgnore && function_exists('tidy_repair_string')) { $content = ob_get_clean(); @@ -410,7 +413,7 @@ public function render(array $dataArr = array()) echo $content; } } - + /** * Returns an array of menu items that should be diplayed from the theme. * Only menu items the current user (and their group level) have access to @@ -420,16 +423,16 @@ public function render(array $dataArr = array()) */ public function getMenuItems($adminMenus = false) { - $auth = Flux_Authorization::getInstance(); - $adminMenuLevel = Flux::config('AdminMenuGroupLevel'); - $defaultAction = Flux_Dispatcher::getInstance()->defaultAction; - $menuItems = Flux::config('MenuItems'); - $allowedItems = array(); - - if (!($menuItems instanceOf Flux_Config)) { + $auth = Authorization::getInstance(); + $adminMenuLevel = Flux::config('AdminMenuGroupLevel'); + $defaultAction = Dispatcher::getInstance()->defaultAction; + $menuItems = Flux::config('MenuItems'); + $allowedItems = array(); + + if (!($menuItems instanceOf Config)) { return array(); } - + foreach ($menuItems->toArray() as $categoryName => $menu) { foreach ($menu as $menuName => $menuItem) { $module = array_key_exists('module', $menuItem) ? $menuItem['module'] : false; @@ -439,52 +442,50 @@ public function getMenuItems($adminMenus = false) if ($adminMenus) { if ($auth->actionAllowed($module, $action) && $auth->config("modules.$module.$action") >= $adminMenuLevel) { $allowedItems[] = array( - 'name' => $menuName, + 'name' => $menuName, 'exturl' => null, 'module' => $module, 'action' => $action, - 'url' => $this->url($module, $action) + 'url' => $this->url($module, $action) ); } - } - else { + } else { if (empty($allowedItems[$categoryName])) { $allowedItems[$categoryName] = array(); } - + if ($exturl) { $allowedItems[$categoryName][] = array( - 'name' => $menuName, + 'name' => $menuName, 'exturl' => $exturl, 'module' => null, 'action' => null, - 'url' => $exturl + 'url' => $exturl ); - } - elseif ($auth->actionAllowed($module, $action) && $auth->config("modules.$module.$action") < $adminMenuLevel) { + } elseif ($auth->actionAllowed($module, $action) && $auth->config("modules.$module.$action") < $adminMenuLevel) { $allowedItems[$categoryName][] = array( - 'name' => $menuName, + 'name' => $menuName, 'exturl' => null, 'module' => $module, 'action' => $action, - 'url' => $this->url($module, $action) + 'url' => $this->url($module, $action) ); } } } } - + return $allowedItems; } - + /** - * @see Flux_Template::getMenuItems() + * @see Template::getMenuItems() */ public function getAdminMenuItems() { return $this->getMenuItems(true); } - + /** * Get sub-menu items for a particular module. * @@ -493,24 +494,24 @@ public function getAdminMenuItems() */ public function getSubMenuItems($moduleName = null) { - $auth = Flux_Authorization::getInstance(); - $moduleName = $moduleName ? $moduleName : $this->moduleName; + $auth = Authorization::getInstance(); + $moduleName = $moduleName ? $moduleName : $this->moduleName; $subMenuItems = Flux::config('SubMenuItems'); $allowedItems = array(); - - if (!($subMenuItems instanceOf Flux_Config) || !( ($menus = $subMenuItems->get($moduleName)) instanceOf Flux_Config )) { + + if (!($subMenuItems instanceOf Config) || !(($menus = $subMenuItems->get($moduleName)) instanceOf Config)) { return array(); } - + foreach ($menus->toArray() as $actionName => $menuName) { if ($auth->actionAllowed($moduleName, $actionName)) { $allowedItems[] = array('name' => $menuName, 'module' => $moduleName, 'action' => $actionName); } } - + return $allowedItems; } - + /** * Get an array of login server names. * @@ -520,7 +521,7 @@ public function getServerNames() { return array_keys(Flux::$loginAthenaGroupRegistry); } - + /** * Determine if more than 1 server exists. * @@ -530,7 +531,7 @@ public function hasManyServers() { return count(Flux::$loginAthenaGroupRegistry) > 1; } - + /** * Obtain the absolute web path of the specified user path. Specify the * path as a relative path. @@ -573,17 +574,17 @@ public function themePath($path, $included = false) $path = substr($path, 0, -strlen($frag)); } - $uri = $this->path("{$this->themePath}/{$this->themeName}/{$path}", $included); + $uri = $this->path("{$this->themePath}/{$this->themeName}/{$path}", $included); // normalized basePath. - $base = preg_replace('/(\/+)$/', '', $this->basePath ) . '/'; - $base = preg_quote( $base, '/' ); - $chk = FLUX_ROOT .'/'. preg_replace('/^('.$base.')/', '', $uri ); + $base = preg_replace('/(\/+)$/', '', $this->basePath) . '/'; + $base = preg_quote($base, '/'); + $chk = FLUX_ROOT . '/public/' . preg_replace('/^(' . $base . ')/', '', $uri); // If file not found, search in parent's template. if (!file_exists($chk) && !empty($this->parentTemplate)) { $path = $this->parentTemplate->themePath($path, $included); - $chk = FLUX_ROOT .'/'. preg_replace('/^('.$base.')/', '', $path ); + $chk = FLUX_ROOT . '/public/' . preg_replace('/^(' . $base . ')/', '', $path); if (file_exists($chk)) { $uri = $path; @@ -592,7 +593,7 @@ public function themePath($path, $included = false) return $uri . $frag; } - + /** * Create a URI based on the setting of $useCleanUrls. This will determine * whether or not we will create a mod_rewrite-based clean URL or just a @@ -604,42 +605,40 @@ public function themePath($path, $included = false) */ public function url($moduleName, $actionName = null, $params = array()) { - $defaultAction = Flux_Dispatcher::getInstance()->defaultAction; + $defaultAction = Dispatcher::getInstance()->defaultAction; $serverProtocol = ''; - $serverAddress = ''; - - if ($params instanceOf Flux_Config) { + $serverAddress = ''; + + if ($params instanceOf Config) { $params = $params->toArray(); } - + if (array_key_exists('_host', $params)) { - $_host = $params['_host']; + $_host = $params['_host']; $_https = false; - - if ($_host && ($addr=Flux::config('ServerAddress'))) { + + if ($_host && ($addr = Flux::config('ServerAddress'))) { if (array_key_exists('_https', $params)) { $_https = $params['_https']; - } - elseif (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== "off") { + } elseif (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== "off") { $_https = true; - } - else { + } else { $_https = false; } $serverProtocol = $_https ? 'https://' : 'http://'; - $serverAddress = $addr; + $serverAddress = $addr; } - + unset($params['_host']); - + if (array_key_exists('_https', $params)) { unset($params['_https']); } } - + $queryString = ''; - + if (count($params)) { $queryString .= Flux::config('UseCleanUrls') ? '?' : '&'; foreach ($params as $param => $value) { @@ -647,26 +646,23 @@ public function url($moduleName, $actionName = null, $params = array()) } $queryString = rtrim($queryString, '&'); } - + if ($this->useCleanUrls) { if ($actionName && $actionName != $defaultAction) { $url = sprintf('%s/%s/%s/%s', $this->basePath, $moduleName, $actionName, $queryString); - } - else { + } else { $url = sprintf('%s/%s/%s', $this->basePath, $moduleName, $queryString); } - } - else { + } else { if ($actionName && $actionName != $defaultAction) { $url = sprintf('%s/?module=%s&action=%s%s', $this->basePath, $moduleName, $actionName, $queryString); - } - else { + } else { $url = sprintf('%s/?module=%s%s', $this->basePath, $moduleName, $queryString); } } - return $serverProtocol.preg_replace('&/{2,}&', '/', "$serverAddress/$url"); + return $serverProtocol . preg_replace('&/{2,}&', '/', "$serverAddress/$url"); } - + /** * Format currency strings. * @@ -684,7 +680,7 @@ public function formatCurrency($number) ); return $amount; } - + /** * Format a MySQL DATE column according to the DateFormat config. * @@ -697,7 +693,7 @@ public function formatDate($date = null) $ts = $date ? strtotime($date) : time(); return date(Flux::config('DateFormat'), $ts); } - + /** * Format a MySQL DATETIME column according to the DateTimeFormat config. * @@ -710,7 +706,7 @@ public function formatDateTime($dateTime = null) $ts = $dateTime ? strtotime($dateTime) : time(); return date(Flux::config('DateTimeFormat'), $ts); } - + /** * Create a series of select fields matching a MySQL DATE format. * @@ -722,59 +718,56 @@ public function formatDateTime($dateTime = null) */ public function dateField($name, $value = null, $fowardYears = null, $backwardYears = null) { - if(!isset($fowardYears)) { + if (!isset($fowardYears)) { $fowardYears = (int)Flux::config('ForwardYears'); } - if(!isset($backwardYears)) { + if (!isset($backwardYears)) { $backwardYears = (int)Flux::config('BackwardYears'); } - - $ts = $value && !preg_match('/^0000-00-00(?: 00:00:00)?$/', $value) ? strtotime($value) : time(); - $year = ($year =$this->params->get("{$name}_year")) ? $year : date('Y', $ts); - $month = ($month=$this->params->get("{$name}_month")) ? $month : date('m', $ts); - $day = ($day =$this->params->get("{$name}_day")) ? $day : date('d', $ts); - $fw = $year + $fowardYears; - $bw = $year - $backwardYears; - + + $ts = $value && !preg_match('/^0000-00-00(?: 00:00:00)?$/', $value) ? strtotime($value) : time(); + $year = ($year = $this->params->get("{$name}_year")) ? $year : date('Y', $ts); + $month = ($month = $this->params->get("{$name}_month")) ? $month : date('m', $ts); + $day = ($day = $this->params->get("{$name}_day")) ? $day : date('d', $ts); + $fw = $year + $fowardYears; + $bw = $year - $backwardYears; + // Get years. $years = sprintf(''; - + // Get months. $months = sprintf(''; - + // Get days. $days = sprintf(''; - + return sprintf('%s-%s-%s', $years, $months, $days); } - + /** * Create a series of select fields matching a MySQL DATETIME format. * @@ -785,50 +778,47 @@ public function dateField($name, $value = null, $fowardYears = null, $backwardYe public function dateTimeField($name, $value = null) { $dateField = $this->dateField($name, $value); - $ts = $value ? strtotime($value) : strtotime('00:00:00'); - $hour = date('H', $ts); - $minute = date('i', $ts); - $second = date('s', $ts); - + $ts = $value ? strtotime($value) : strtotime('00:00:00'); + $hour = date('H', $ts); + $minute = date('i', $ts); + $second = date('s', $ts); + // Get hours. $hours = sprintf(''; - + // Get minutes. $minutes = sprintf(''; - + // Get seconds. $seconds = sprintf(''; - + return sprintf('%s @ %s:%s:%s', $dateField, $hours, $minutes, $seconds); } - + /** * Returns "up" or "down" in a span HTML element with either the class * .up or .down, based on the value of $bool. True returns up, false @@ -842,7 +832,7 @@ public function serverUpDown($bool) $class = $bool ? 'up' : 'down'; return sprintf('%s', $class, $bool ? 'Online' : 'Offline'); } - + /** * Redirect client to another location. Script execution is terminated * after instructing the client to redirect. @@ -854,11 +844,11 @@ public function redirect($location = null) if (is_null($location)) { $location = $this->basePath; } - + header("Location: $location"); exit; } - + /** * Guess the HTTP server's current full URL. * @@ -867,35 +857,34 @@ public function redirect($location = null) */ public function entireUrl($withRequest = true) { - $proto = empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === "off" ? 'http://' : 'https://'; + $proto = empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === "off" ? 'http://' : 'https://'; $hostname = empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST']; - $request = $_SERVER['REQUEST_URI']; - + $request = $_SERVER['REQUEST_URI']; + if ($withRequest) { - $url = $proto.$hostname.$request; - } - else { - $url = $proto.$hostname.'/'.$this->basePath; + $url = $proto . $hostname . $request; + } else { + $url = $proto . $hostname . '/' . $this->basePath; } - + $url = rtrim(preg_replace('&/{2,}&', '/', $url), '/'); return $url; } - + /** * Convenience method for retrieving a paginator instance. * * @param int $total Total number of records. * @param array $options Paginator options. - * @return Flux_Paginator + * @return Paginator * @access public */ public function getPaginator($total, array $options = array()) { - $paginator = new Flux_Paginator($total, $this->url($this->moduleName, $this->actionName, array('_host' => false)), $options); + $paginator = new Paginator($total, $this->url($this->moduleName, $this->actionName, array('_host' => false)), $options); return $paginator; } - + /** * Link to an account view page. * @@ -909,12 +898,11 @@ public function linkToAccount($accountID, $text) if ($accountID) { $url = $this->url('account', 'view', array('id' => $accountID)); return sprintf('', $url, htmlspecialchars($text)); - } - else { + } else { return false; } } - + /** * Link to an account search. * @@ -928,12 +916,11 @@ public function linkToAccountSearch($params, $text) if (is_array($params) && count($params)) { $url = $this->url('account', 'index', $params); return sprintf('', $url, htmlspecialchars($text)); - } - else { + } else { return false; } } - + /** * Link to a character view page. * @@ -949,15 +936,14 @@ public function linkToCharacter($charID, $text, $server = null) if ($server) { $params['preferred_server'] = $server; } - + $url = $this->url('character', 'view', $params); return sprintf('%s', $url, htmlspecialchars($text)); - } - else { + } else { return false; } } - + /** * Deny entry to a page if called. This method should be used from a module * script, and no where else. @@ -967,7 +953,7 @@ public function deny() $location = $this->url('unauthorized'); $this->redirect($location); } - + /** * Get the full gender string from a gender letter (e.g. M for Male). * @@ -992,7 +978,7 @@ public function genderText($gender) break; } } - + /** * Get the account state name corresponding to the state number. * @@ -1002,29 +988,28 @@ public function genderText($gender) */ public function accountStateText($state) { - $text = false; + $text = false; $state = (int)$state; - + switch ($state) { case 0: - $text = Flux::message('AccountStateNormal'); + $text = Flux::message('AccountStateNormal'); $class = 'state-normal'; break; case 5: - $text = Flux::message('AccountStatePermBanned'); + $text = Flux::message('AccountStatePermBanned'); $class = 'state-permanently-banned'; break; } - + if ($text) { $text = htmlspecialchars($text); return sprintf('