diff --git a/README.md b/README.md index 1f06112f34..85bb568ec9 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,8 @@ Previous Releases: https://modx.com/download/evolution/previous-releases.html Extras: -https://extras.evolution-cms.com +https://extras.evo.im Documentation: +http://docs.evo.im https://evolution-docs.com diff --git a/assets/docs/changelog.txt b/assets/docs/changelog.txt index be3e4b2c10..b421d79090 100755 --- a/assets/docs/changelog.txt +++ b/assets/docs/changelog.txt @@ -1,6 +1,212 @@ This file shows the changes in recent releases of Evolution CMS. The most current release is usually the development release, and is only shown to give an idea of what's currently in the pipeline. + +Evolution CMS 1.4.7 (Dec 10, 2018) +* [GitHub:#92a15c0b6] - [fix] for php7: ddmultiplefields.php http://modx.im/blog/addons/4265.html#comment44232 (Dmi3yy) +* [GitHub:#fa8ba4219] - [fix] typo for 7.3 (Dmi3yy) +* [GitHub:#e132703e4] - [fix] phpthumb to 1.3.3 (Agel_Nash) +* [GitHub:#116f383be] - [fix] Php Thumb image cache path #896 (Nicola) +* [GitHub:#e4ef60a24] - [fix] Undefined index (Agel_Nash) +* [GitHub:#24bd8dd49] - [fix] Save module name and code, if module exist (issue #892) (Serg) +* [GitHub:#4afe71703] - [fix] Form attribute "action" fixes (issue #892) (Serg) +* [GitHub:#e88614d3c] - [fix] #892 duplicated element name issue (Serg) +* [GitHub:#e194b6b59] - [fix] sort modules by name (#887) (Nicola) +* [GitHub:#288a6f96b] - [fix] sort elements by name (#887) (Nicola) +* [GitHub:#e353554f3] - [fix] #888 The FileSource 0.1 is dependent on the mootools (Serg) +* [GitHub:#c5b019ca9] - [fix] #874 Remove fullstop at end of new password displayed on screen(Serg) +* [GitHub:#24eaa5a3d] - [Fix] #882 broken extras module link in RSS check (Nicola) +* [GitHub:#f644a6b1e] - [fix] #869 (missing 1 lexicon) (Agel_Nash) +* [GitHub:#30f27489c] - [fix] update ElementsInTree 1.5.10 (Agel_Nash) +* [GitHub:#403e590d1] - [fix] Update DocInfo and DocLister (Agel_Nash) +* [GitHub:#aa5086c01] - [improvement]colorpicker added (mnoskov) +* [GitHub:#eb2e24936] - [improvement] Enable Mootools Setting Option (Nicola) +* [GitHub:#d4200c3f2] - [improvement] rename extras.evolution-cms.com to extras.evo.im (Dmi3yy) +* [GitHub:#cadb97e2a] - [typo] format code save_user_processor (Serg) +* [GitHub:#d9b8e3c84] - [typo] fix typo in color mode name (Nicola) +* [GitHub:#8130c764c] - [typo] code tag for singleton example (Nicola) +* [GitHub:#91e36991d] - [delete] deprecated snippet DLBuildMenu (Pathologic) +* [GitHub:#a97b1b5f7] - [info] Update 1.4.7 Version Noticies (help) (Nicola) +* [GitHub:#9a174d0b2] - [info] 1.4.6 Version Noticies (help) (Nicola) +* [GitHub:#9e209b4ef] - [info] 1.4.5 Version Noticies (help) (Nicola) +* [GitHub:#bdce11559] - [info] 1.4.4 Version Noticies (help) (Nicola) +* [GitHub:#fd5dfab2c] - [info] 1.4.3 Version Noticies (help) (Nicola) +* [GitHub:#918a14bab] - [info] 1.4.2 Version Noticies (help) (Nicola) +* [GitHub:#a9830af28] - [lang] Polish translation (#891) (Piotr Matysiak) +* [GitHub:#640eea798] - [lang] Updated Italian Language (#861) (Nicola) +* [GitHub:#c28388868] - [lang] Resolve #869 (Agel_Nash) +* [GitHub:#c443927e4] - [lang] #859 (missing 6 manager, 2 installer) https://github.com/evolution-cms/evolution/issues/853#issuecomment-435479192 (Agel_Nash) + + +Evolution CMS 1.4.6 (Nov 02, 2018) +* [GitHub:#3d445623f] - OutdatedExtrasCheck add url for check Outdated (Dmi3yy) +* [GitHub:#4265bc48e] - Исправлена бага. Если создать ресурс через modResource и получить для него урл и Использовать AliasListing только для Папок [(aliaslistingfolder)] стояло Да то получал /{doc_id}.html вместо нормального урла (dzhuryn) +* [GitHub:#bad13152e] - Исправлена бага. Если создать ресурс через modResource и получить для него урл то в место /proizvoditeli/proizvoditel_1541140716/kolekciya_1541140716/tovar_1541140716.html получал /tovar_1541140716.html из за отсутствия alias_visible (dzhuryn) +* [GitHub:#9aa1c9369] - Remove debug (Agel_Nash) +* [GitHub:#c7cd2ccce] - Update OutdatedExtrasCheck (Agel_Nash) +* [GitHub:#d232ae622] - fix existes GET[q] (Serg) +* [GitHub:#d5827b63c] - moved menu item version in config menu (Serg) +* [GitHub:#cfbe776cd] - Code refactoring the OutdatedExtrasCheck plugin (Agel_Nash) +* [GitHub:#c0a82df48] - Update the OutdatedExtrasCheck lexicon (Agel_Nash) +* [GitHub:#e3d08940d] - Reformat source code the OutdatedExtrasCheck plugin (Agel_Nash) +* [GitHub:#5b837b592] - Up version OutdatedExtrasCheck (Agel_Nash) +* [GitHub:#31e1e651c] - Move source code the OutdatedExtrasCheck plugin into file (Agel_Nash) +* [GitHub:#907a44ea2] - Resolve #845 (Agel_Nash) +* [GitHub:#0a902dab3] - remove redundant property (Pathologic) +* [GitHub:#a23c162bc] - DocLister 2.4.0 (Agel_Nash) +* [GitHub:#ad905490f] - update Filters.php (Pathologic) +* [GitHub:#e5da5675c] - change PHP version in lexicons (Pathologic) +* [GitHub:#a315fe63f] - remove dot from password output (Pathologic) +* [GitHub:#faba1ef7a] - update FormLister to 1.8.0 (Pathologic) +* [GitHub:#917cdb6f9] - Relation to #876 (Agel_Nash) +* [GitHub:#57682bc13] - Refactor the send_errormail cell (Agel_Nash) +* [GitHub:#811f5903b] - #868 (Installer + Update date) (Agel_Nash) +* [GitHub:#11aad77cb] - Polish translations (Manager) (Piotr Matysiak) +* [GitHub:#39654dc2a] - Polish translations (Installer) (Piotr Matysiak) +* [GitHub:#49343d989] - Rename "Создать PHP-файл" to "Создать файл" (#872) (Ser1ous) +* [GitHub:#31ace520a] - Resolve #868 (Agel_Nash) +* [GitHub:#c3ddd2228] - Remove duplicate lexicon (Agel_Nash) +* [GitHub:#c907375de] - Replacing div to pre at the messageQuit method (Agel_Nash) +* [GitHub:#0442323ea] - Fix #825 (Agel_Nash) +* [GitHub:#2e247bfd9] - errorHandlers (Agel_Nash) +* [GitHub:#4d5566bb1] - Resolve #792 (Agel_Nash) +* [GitHub:#343ff4070] - Update phpthumb snippet (Agel_Nash) +* [GitHub:#6aea8b048] - phpthumb 1.7.15 (Agel_Nash) +* [GitHub:#a233a3ff6] - Update DL for compability https://github.com/evolution-cms/evolution/commit/49fab5242971a42eb225c3186238d5649f2e328e (Agel_Nash) +* [GitHub:#f1b0d559b] - fix JS event for radio[chunk_processor] (Serg) +* [GitHub:#de24eaa3f] - add JS event for radio[chunk_processor] (Serg) +* [GitHub:#dc02ce968] - MM removed unused script Tips (Serg) +* [GitHub:#64fccfefa] - fix #818 (Serg) +* [GitHub:#b59bc534d] - fix ip lenght for work with ipw6 #849 (#850) (Ser1ous) +* [GitHub:#49fab5242] - Fix #848 (Agel_Nash) +* [GitHub:#81e10ea54] - Fix #280 (Agel_Nash) +* [GitHub:#2ffdb4e68] - #834 (Agel_Nash) +* [GitHub:#ca4cb5498] - Fix #834 (Agel_Nash) +* [GitHub:#fcc2024e4] - addOutput method (Agel_Nash) +* [GitHub:#c57a5d844] - FIX Lighness Navbar Logo (#827) (Nicola) +* [GitHub:#ada15c795] - event reference fix (#844) (mnoskov) +* [GitHub:#99ba335ac] - fix style loginform in dark mode (Serg) +* [GitHub:#07ca6dea6] - remove mootools.js (Serg) +* [GitHub:#7043a5321] - fix sysalert.display.inc.php (Serg) +* [GitHub:#c2b01a5a6] - fix popup.wrap (Serg) +* [GitHub:#3f846155d] - phpMailer update to 6.0.5 (Dmi3yy) +* [GitHub:#47011d823] - up ajaxSearch version to 1.12.0 in OutdatedExtrasCheck (Dmi3yy) +* [GitHub:#402a5e99d] - Fix #806 (Agel_Nash) +* [GitHub:#3261911f4] - Update snippet.docinfo.php (#806) (Anton Kanopkin) +* [GitHub:#ab1c9ec5a] - events stack (mnoskov) +* [GitHub:#1e59390d4] - events stack (mnoskov) +* [GitHub:#3d15cb1c7] - removing debug statement (Agel_Nash) +* [GitHub:#05a80d9f8] - Fix JS error – typo (esszett) +* [GitHub:#e8025d501] - Fix #26 (Agel_Nash) +* [GitHub:#be22213f0] - Change checking of manager mode / Part 2 (Agel_Nash) +* [GitHub:#46eaa39e6] - Resolve review in PR #779 (Agel_Nash) +* [GitHub:#e4231e872] - Fix #793 (Agel_Nash) +* [GitHub:#3c5aa9b8a] - Fix #828 (Agel_Nash) +* [GitHub:#270ae36c5] - Fix mysql 8.0 bug with copy tv #809 (Ser1ous) +* [GitHub:#615841010] - Refactoring DocumentParser::getHiddenIdFromAlias() (Agel_Nash) +* [GitHub:#6fa6950f0] - Fix #790 (Agel_Nash) +* [GitHub:#1684460b4] - Fix #784 (Agel_Nash) +* [GitHub:#af38bca42] - Fix #797 (Agel_Nash) +* [GitHub:#288068bb1] - Fix #535 (Agel_Nash) +* [GitHub:#27dce74cc] - resolve #819 (Agel_Nash) +* [GitHub:#0ca34ccf0] - improved loginbox styles (Nicola) +* [GitHub:#082db9992] - Update tree.php (Mr B) +* [GitHub:#9a956458d] - [I] Add title for theme mode icon (Mr B) +* [GitHub:#5abf6da33] - fix style on login light (Nicola) +* [GitHub:#4e9a12007] - wrong position (Nicola) +* [GitHub:#c824e55f1] - manager_theme_mode_message #818 (Nicola) +* [GitHub:#cc47a7c1c] - fix light login styles (Nicola) +* [GitHub:#128e35b88] - fix light login fields (Nicola) +* [GitHub:#9d2a81ada] - Updated extrascheck plugin v1.4.5 (Nicola) +* [GitHub:#f4e8d1b76] - Login form style Settings #800 (Nicola) +* [GitHub:#f786a4180] - [F] Fix unable to uncheck permissions (Mr B) +* [GitHub:#9799c7e13] - fix browser resize issues of kcfinder (Pathologic) +* [GitHub:#5471839a9] - fix escape name components (Serg) +* [GitHub:#f4632e571] - fix escape for widget docs (Serg) +* [GitHub:#f6d50671e] - fix escape search result (Serg) +* [GitHub:#9201cd8ea] - fix view svg (Serg) +* [GitHub:#f99b291dd] - Update search.static.php (luigif) +* [GitHub:#373c31cfe] - Update search.static.php (luigif) +* [GitHub:#bc457c79a] - Rename 01About_EVO.php to 01About_Title.php (luigif) +* [GitHub:#6385ac4ba] - Update mutate_categories.dynamic.php (luigif) +* [GitHub:#841ac1ff9] - fix not working clientResize option (Pathologic) +* [GitHub:#473725d08] - fixed #794 (Serg) +* [GitHub:#dc005e5cd] - fix #794 (Serg) +* [GitHub:#85094c9e5] - fix #780 (Serg) +* [GitHub:#149fdb0a2] - Revert "fix #792" (Serg) +* [GitHub:#86eebdd5c] - fix #792 (Serg) +* [GitHub:#a176c043e] - fix notice php7 (Serg) +* [GitHub:#8e30682a4] - Fix some XSS (Agel_Nash) +* [GitHub:#a7fe1cfbc] - Security Fix (Agel_Nash) +* [GitHub:#b59d1f57b] - Fix #789 (Agel_Nash) +* [GitHub:#2b8aaa622] - Fix #788 (Agel_Nash) +* [GitHub:#1845b64b2] - html_escape function (Agel_Nash) +* [GitHub:#79edb9ef5] - Change checking of manager mode (thalegion) + + +Evolution CMS 1.4.5 (Aug 07, 2018) +* [GitHub:#18627a876] - [F] fix #693 Drag/drop sortable lists (Serg) +* [GitHub:#9cdf9e173] - [F] fix #770 Restyle manager lockout page (Serg) +* [GitHub:#c4a06df62] - [F] fix tree update "Save and Quit" (Serg) +* [GitHub:#f11a627fb] - [I] add file browser events (Pathologic) +* [GitHub:#6ef91bc82] - [I] add more events (Pathologic) +* [GitHub:#618f4313f] - [F] fix #692 Manager left menu charset issue (dmi3yy) +* [GitHub:#a6fc60de7] - [F] fix #755 cookie context and lifetime (dmi3yy) +* [GitHub:#08aad4482] - [F] fix doclister (Pathologic) +* [GitHub:#b219ec85e] - [I] add support mysql 8.0 (Ser1ous) +* [GitHub:#6198dc5ac] - [F] fix #624 Issues for manager with no 'Interface Access' setting (Pathologic) +* [GitHub:#a1c3d37ab] - [F] fix #769 plugin settings get lost while upgrading to newer version (Pathologic) +* [GitHub:#26a430eb6] - [F] fix #730 Retain Plugin Event Execution Order When Upgrading (Pathologic) +* [GitHub:#c8080596b] - [F] update FormLister to 1.7.21 (Pathologic) +* [GitHub:#db41ba731] - [F] fix #767 Web Users not showing in Online Users (Pathologic) +* [GitHub:#747985a47] - [F] fix #368 problem with dublicete snippet (Pathologic) +* [GitHub:#a0c7f264c] - [F] fix for work with mysql 8.0 (Ser1ous) +* [GitHub:#04863cd88] - [I] Update mutate_user.dynamic.php (Mr B) +* [GitHub:#83550c437] - [I] Add username label (Mr B) +* [GitHub:#3130df11c] - [F] fix memory leak (Pathologic) +* [GitHub:#61cd0c0eb] - [F] fix #763 Evolution 1.4.5RC2 Does not work logo replacement(Serg) +* [GitHub:#3bed43eb9] - [F] fix text color in darkness mode (Serg) +* [GitHub:#196e815be] - [F] Fix saving web users (Mr B) +* [GitHub:#841db700d] - [F] fix #552 Weird Chunk Rendering When minifyphp_incache is enabled (Pathologic) +* [GitHub:#ce83e5411] - [F] fix checkVersion (Pathologic) +* [GitHub:#7626ccfbd] - [I] update FormLister (Pathologic) +* [GitHub:#553ff5332] - [F] fix #519 2 functions parseProperties (Pathologic) +* [GitHub:#b637d20ce] - [F] fix #556 Cli mode (Pathologic) +* [GitHub:#86ecaec70] - [F] fix #300 OnDocPublished add automatic start (Pathologic) +* [GitHub:#ac3033f12] - [F] fix #233 Disabling function touch generates error "Cannot access or create thumbnails folder." in media manager (Pathologic) +* [GitHub:#5223b3ab4] - [I] alter recent info table (Mr B) +* [GitHub:#d753660e0] - [I] add OnFileBrowserInit event (Pathologic) +* [GitHub:#5e0a3510f] - [F] fix #749 not bloced user (Serg) +* [GitHub:#5af0c3c4f] - [I] cancel close tabs for components (Serg) +* [GitHub:#b8a27cad0] - [F] fix #758 modxlink plugin (Pathologic) +* [GitHub:#3db936dab] - [I] events of directory delete (Pathologic) +* [GitHub:#57da95fee] - [F] fix #736 backup button back into the dashboard (dmi3yy) +* [GitHub:#63b229bf3] - [F] fix #750 tinymce 4 - link to images folder, not only to files (Pathologic) +* [GitHub:#3032cd717] - [I] stop username wrap if has spaces (Mr B) +* [GitHub:#f3639c642] - [F] Fix saving web user permissions (Mr B) +* [GitHub:#8e083becb] - [I] add File Browser events, skip thumbnails creation (Pathologic) +* [GitHub:#471b9e41a] - [I] add more File Browser events (Pathologic) +* [GitHub:#8ad6402a6] - [F] Fix #737 (Serg) +* [GitHub:#4a1f6972d] - [I] Update mainmenu.css (Mr B) +* [GitHub:#bc539c054] - [I] Update style.php (Mr B) +* [GitHub:#7132beb6b] - [I] Add time to dashboard resource edit dates (Mr B) +* [GitHub:#118f69e47] - [R] russian-UTF8.inc.php #728 (Agel_Nash) +* [GitHub:#62285b7b4] - [R] Update english.inc.php (Mr B) +* [GitHub:#d5d170404] - [I] Add confirmation for purge plugins (Mr B) +* [GitHub:#4143fea6b] - [F] remove docs from core FormLister #366 (dmi3yy) +* [GitHub:#3d178f654] - [F] fix #727 Ampersand (&) in Site Name escaped infinitely (Serg) +* [GitHub:#b5b88d912] - [F] Save and close global tabs (Serg) +* [GitHub:#239fda8a2] - [F] Fix html (Serg) +* [GitHub:#4d909750f] - [F] fix validator in FormLister (dmi3yy) +* [GitHub:#44ff0ff10] - [F] Fix #722 Issues with managing users (Serg) +* [GitHub:#9a64f25aa] - [F] Fix style left-menu position (Serg) +* [GitHub:#51f9102e0] - [F] Fix theme ajax.php (Serg) +* [GitHub:#3eda7b7d6] - [F] Fix add images in settings (Serg) +* [GitHub:#005993658] - [F] Fix notice variables (Serg) +* [GitHub:#952c85d0a] - [I] Action name for dashboard (Mr B) +* [GitHub:#25140784a] - [I] Add date to active users hit time (Mr B) + + Evolution CMS 1.4.4 (Jun 08, 2018) * [GitHub:#5d177a4ea] - [I] Auto set Sender (Евгений Борисов) * [GitHub:#f13d19d60] - [I] Move color switcher icon (Mr B) diff --git a/assets/lib/APIHelpers.class.php b/assets/lib/APIHelpers.class.php index f03d058373..c387279bc8 100644 --- a/assets/lib/APIHelpers.class.php +++ b/assets/lib/APIHelpers.class.php @@ -80,7 +80,7 @@ public static function getkey($data, $key, $default = null, $validate = null) if (is_array($data) && (is_int($key) || is_string($key)) && $key !== '' && array_key_exists($key, $data)) { $out = $data[$key]; } - if (!empty($validate) && is_callable($validate)) { + if (! empty($validate) && is_callable($validate)) { $out = (($validate($out) === true) ? $out : $default); } return $out; @@ -94,14 +94,14 @@ public static function getkey($data, $key, $default = null, $validate = null) * @license GNU General Public License (GPL), http://www.gnu.org/copyleft/gpl.html * @param string $email проверяемый email * @param boolean $dns проверять ли DNS записи - * @return boolean Результат проверки почтового ящика + * @return boolean|string Результат проверки почтового ящика * @author Anton Shevchuk */ public static function emailValidate($email, $dns = true) { if (filter_var($email, FILTER_VALIDATE_EMAIL)) { list(, $domain) = explode("@", $email, 2); - if (!$dns || ($dns && checkdnsrr($domain, "MX") && checkdnsrr($domain, "A"))) { + if (! $dns || ($dns && checkdnsrr($domain, "MX") && checkdnsrr($domain, "A"))) { $error = false; } else { $error = 'dns'; @@ -232,7 +232,7 @@ public static function getUserIP($default = '127.0.0.1') case ($tmp = self::getEnv('HTTP_X_FORWARDED_FOR')): $out = $tmp; break; - case (!empty($_SERVER['REMOTE_ADDR'])): + case (! empty($_SERVER['REMOTE_ADDR'])): $out = $_SERVER['REMOTE_ADDR']; break; default: @@ -270,13 +270,14 @@ public static function sanitarTag( $out = str_replace( array_keys($chars), array_values($chars), - is_null($charset) ? $data : self::e($data, $charset) + $charset === null ? $data : self::e($data, $charset) ); break; case is_array($data): - $out = $data; - foreach ($out as $key => &$val) { - $val = self::sanitarTag($val, $charset, $chars); + $out = array(); + foreach ($data as $key => $val) { + $key = self::sanitarTag($key, $charset, $chars); + $out[$key] = self::sanitarTag($val, $charset, $chars); } break; default: @@ -402,9 +403,7 @@ public static function cleanIDs($IDs, $sep = ',', $ignore = array()) foreach ($IDs as $item) { $item = trim($item); if (is_scalar($item) && (int)$item >= 0) { //Fix 0xfffffffff - if (!empty($ignore) && in_array((int)$item, $ignore, true)) { - $this->log[] = 'Ignore id ' . (int)$item; - } else { + if (empty($ignore) || !\in_array((int)$item, $ignore, true)) { $out[] = (int)$item; } } diff --git a/assets/lib/Formatter/CSSMinify.php b/assets/lib/Formatter/CSSMinify.php old mode 100755 new mode 100644 index 821aa813d6..1f72c60fd5 --- a/assets/lib/Formatter/CSSMinify.php +++ b/assets/lib/Formatter/CSSMinify.php @@ -6,7 +6,7 @@ class CSSMinify public function __construct($cssFilesPath = array()) { - if (is_array($cssFilesPath) && !empty($cssFilesPath)) { + if (is_array($cssFilesPath) && ! empty($cssFilesPath)) { $this->cssPath = $cssFilesPath; } } diff --git a/assets/lib/Formatter/SqlFormatter.php b/assets/lib/Formatter/SqlFormatter.php index ccc0a96365..50f795cbf2 100644 --- a/assets/lib/Formatter/SqlFormatter.php +++ b/assets/lib/Formatter/SqlFormatter.php @@ -834,7 +834,7 @@ protected static function getNextToken($string, $previous = null) } // Non-quoted variable name else { preg_match('/^(' . $string[0] . '[a-zA-Z0-9\._\$]+)/', $string, $matches); - if (!empty($matches)) { + if (! empty($matches)) { $ret[self::TOKEN_VALUE] = $matches[1]; } } @@ -863,7 +863,7 @@ protected static function getNextToken($string, $previous = null) // A reserved word cannot be preceded by a '.' // this makes it so in "mytable.from", "from" is not considered a reserved word - if (!$previous || !isset($previous[self::TOKEN_VALUE]) || $previous[self::TOKEN_VALUE] !== '.') { + if (! $previous || !isset($previous[self::TOKEN_VALUE]) || $previous[self::TOKEN_VALUE] !== '.') { $upper = strtoupper($string); // Top Level Reserved Word if (preg_match('/^(' . self::$regex_reserved_toplevel . ')($|\s|' . self::$regex_boundaries . ')/', $upper, @@ -1158,7 +1158,7 @@ public static function format($string, $highlight = true) $return = rtrim($return, ' '); } - if (!$inline_parentheses) { + if (! $inline_parentheses) { $increase_block_indent = true; // Add a newline after the parentheses $newline = true; @@ -1191,7 +1191,7 @@ public static function format($string, $highlight = true) } // Add a newline before the closing parentheses (if not already added) - if (!$added_newline) { + if (! $added_newline) { $return .= "\n" . str_repeat($tab, $indent_level); } } // Top level reserved words start a new line and increase the special indent level @@ -1208,7 +1208,7 @@ public static function format($string, $highlight = true) // Add a newline after the top level reserved word $newline = true; // Add a newline before the top level reserved word (if not already added) - if (!$added_newline) { + if (! $added_newline) { $return .= "\n" . str_repeat($tab, $indent_level); } // If we already added a newline, redo the indentation since it may be different now else { @@ -1222,14 +1222,14 @@ public static function format($string, $highlight = true) $highlighted = preg_replace('/\s+/', ' ', $highlighted); } //if SQL 'LIMIT' clause, start variable to reset newline - if ($token[self::TOKEN_VALUE] === 'LIMIT' && !$inline_parentheses) { + if ($token[self::TOKEN_VALUE] === 'LIMIT' && ! $inline_parentheses) { $clause_limit = true; } } // Checks if we are out of the limit clause elseif ($clause_limit && $token[self::TOKEN_VALUE] !== "," && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_NUMBER && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) { $clause_limit = false; } // Commas start a new line (unless within inline parentheses or SQL 'LIMIT' clause) - elseif ($token[self::TOKEN_VALUE] === ',' && !$inline_parentheses) { + elseif ($token[self::TOKEN_VALUE] === ',' && ! $inline_parentheses) { //If the previous TOKEN_VALUE is 'LIMIT', resets new line if ($clause_limit === true) { $newline = false; @@ -1241,7 +1241,7 @@ public static function format($string, $highlight = true) } // Newline reserved words start a new line elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED_NEWLINE) { // Add a newline before the reserved word (if not already added) - if (!$added_newline) { + if (! $added_newline) { $return .= "\n" . str_repeat($tab, $indent_level); } @@ -1335,7 +1335,7 @@ public static function splitQuery($string) foreach ($tokens as $token) { // If this is a query separator if ($token[self::TOKEN_VALUE] === ';') { - if (!$empty) { + if (! $empty) { $queries[] = $current_query . ';'; } $current_query = ''; @@ -1351,7 +1351,7 @@ public static function splitQuery($string) $current_query .= $token[self::TOKEN_VALUE]; } - if (!$empty) { + if (! $empty) { $queries[] = trim($current_query); } diff --git a/assets/lib/Helpers/Assets.php b/assets/lib/Helpers/Assets.php old mode 100755 new mode 100644 index 73829d61f8..3e4f5efd83 --- a/assets/lib/Helpers/Assets.php +++ b/assets/lib/Helpers/Assets.php @@ -12,8 +12,10 @@ class AssetsHelper * @var \DocumentParser * @access protected */ - protected $modx = null; - protected $fs = null; + protected $modx; + + /** @var \Helpers\FS */ + protected $fs; /** * @var AssetsHelper cached reference to singleton instance @@ -52,7 +54,6 @@ private function __construct(DocumentParser $modx) */ private function __clone() { - } /** @@ -62,7 +63,6 @@ private function __clone() */ private function __wakeup() { - } /** @@ -94,12 +94,12 @@ public function registerJQuery() public function registerScript($name, $params) { $out = ''; - if (!isset($this->modx->loadedjscripts[$name])) { + if (! isset($this->modx->loadedjscripts[$name])) { $src = $params['src']; - $remote = strpos($src, "http") !== false; - if (!$remote) { + $remote = strpos($src, 'http') === 0 || strpos($src, '//') === 0; + if (! $remote) { $src = $this->modx->config['site_url'] . $src; - if (!$this->fs->checkFile($params['src'])) { + if (! $this->fs->checkFile($params['src'])) { $this->modx->logEvent(0, 3, 'Cannot load ' . $src, 'Assets helper'); return $out; @@ -116,7 +116,6 @@ public function registerScript($name, $params) } $this->modx->loadedjscripts[$name] = $params; - } return $out; @@ -129,7 +128,9 @@ public function registerScript($name, $params) public function registerScriptsList($list = array()) { $out = ''; - if (!is_array($list)) return $out; + if (! \is_array($list)) { + return $out; + } foreach ($list as $script => $params) { $out .= $this->registerScript($script, $params); diff --git a/assets/lib/Helpers/Collection.php b/assets/lib/Helpers/Collection.php index a68ddc370f..fbae59571c 100644 --- a/assets/lib/Helpers/Collection.php +++ b/assets/lib/Helpers/Collection.php @@ -93,7 +93,7 @@ public function partition(Closure $p) /** * @param $offset - * @param null $length + * @param null|int $length * @return array */ public function slice($offset, $length = null) @@ -132,7 +132,7 @@ public function append($value) /** * @param $data - * @param null $id + * @param null|int|string $id * @return $this */ public function add($data, $id = null) @@ -280,10 +280,13 @@ public function offsetGet($offset) */ public function offsetSet($offset, $value) { - if (! isset($offset)) { - return $this->add($value); + if ($offset !== null) { + $this->set($offset, $value); + } else { + $this->add($value); } - $this->set($offset, $value); + + return $this; } /** diff --git a/assets/lib/Helpers/Config.php b/assets/lib/Helpers/Config.php index e8166c2187..f82b5367ec 100644 --- a/assets/lib/Helpers/Config.php +++ b/assets/lib/Helpers/Config.php @@ -10,7 +10,8 @@ class Config { private $_cfg = array(); - protected $fs = null; + /** @var FS */ + protected $fs; protected $path = ''; /** @@ -20,7 +21,7 @@ class Config */ public function __construct($cfg = array()) { - if (!empty($cfg)) { + if (! empty($cfg)) { $this->setConfig($cfg); } $this->fs = FS::getInstance(); @@ -69,7 +70,9 @@ public function loadConfig($name) if ($this->fs->checkFile($configFile)) { $json = file_get_contents(MODX_BASE_PATH . $configFile); - $config = array_merge($config, jsonHelper::jsonDecode($json, array('assoc' => true), true)); + /** @var array $json */ + $json = jsonHelper::jsonDecode($json, array('assoc' => true), true); + $config = array_merge($config, $json); } } @@ -90,7 +93,7 @@ public function getConfig() /** * Сохранение массива настроек * @param array $cfg массив настроек - * @return int результат сохранения настроек + * @return int|bool результат сохранения настроек */ public function setConfig($cfg, $overwrite = false) { @@ -106,7 +109,7 @@ public function setConfig($cfg, $overwrite = false) /** * @param $name - * @param null $def + * @param mixed $def * @return mixed */ public function getCFGDef($name, $def = null) diff --git a/assets/lib/Helpers/FS.php b/assets/lib/Helpers/FS.php old mode 100755 new mode 100644 index 67310ae852..3c8db115db --- a/assets/lib/Helpers/FS.php +++ b/assets/lib/Helpers/FS.php @@ -107,7 +107,7 @@ public function takeFileName($file) /** * @param $file - * @param bool $lower + * @param bool $lower * @return string */ public function takeFileExt($file, $lower = true) @@ -127,7 +127,7 @@ public function checkFile($file) { $f = is_scalar($file) ? MODX_BASE_PATH . $this->relativePath($file) : ''; - return (!empty($f) && is_file($f) && is_readable($f)); + return (! empty($f) && is_file($f) && is_readable($f)); } /** @@ -138,7 +138,7 @@ public function checkDir($path) { $f = is_scalar($path) ? $this->relativePath($path) : ''; - return (!empty($f) && is_dir(MODX_BASE_PATH . $f) && is_readable(MODX_BASE_PATH . $f)); + return (! empty($f) && is_dir(MODX_BASE_PATH . $f) && is_readable(MODX_BASE_PATH . $f)); } /** @@ -152,14 +152,14 @@ public function fileSize($file, $format = false) if ($this->checkFile($file)) { $out = filesize(MODX_BASE_PATH . $this->relativePath($file)); } - + if($format === true) $format = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); if (is_array($format)) { $size = $out > 0 ? floor(log($out, 1024)) : 0; $type = isset($format[$size]) ? ' '.$format[$size] : ''; $out = number_format($out / pow(1024, $size), 2, '.', ',') . $type; } - + return $out; } @@ -228,7 +228,7 @@ public function takeFileMIME($file) */ public function makeDir($path, $perm = 0755) { - if (!$this->checkDir($path)) { + if (! $this->checkDir($path)) { $path = MODX_BASE_PATH . $this->relativePath($path); $flag = mkdir($path, $this->toOct($perm), true); } else { diff --git a/assets/lib/Helpers/Mailer.php b/assets/lib/Helpers/Mailer.php index 397fa01b4f..c4ab8c7630 100644 --- a/assets/lib/Helpers/Mailer.php +++ b/assets/lib/Helpers/Mailer.php @@ -17,8 +17,8 @@ class Mailer /** * @var MODxMailer $mail */ - protected $mail = null; - protected $modx = null; + protected $mail; + protected $modx; public $config = array(); protected $debug = false; protected $queuePath = 'assets/cache/mail/'; @@ -43,7 +43,7 @@ public function __construct(DocumentParser $modx, $cfg, $debug = false) { $this->modx = $modx; $this->noemail = (bool)(isset($cfg['noemail']) ? $cfg['noemail'] : 0); - if (!$this->noemail) { + if (! $this->noemail) { $this->mail = new MODxMailer(); if (method_exists('MODxMailer', 'init')) { $this->mail->init($modx); @@ -61,7 +61,7 @@ public function __construct(DocumentParser $modx, $cfg, $debug = false) */ public function addAddressToMailer($type, $addr) { - if (!$this->noemail && !empty($addr)) { + if (! $this->noemail && ! empty($addr)) { $a = array_filter(array_map('trim', explode(',', $addr))); foreach ($a as $address) { switch ($type) { @@ -89,7 +89,7 @@ public function addAddressToMailer($type, $addr) */ public function attachFiles($filelist = array()) { - if (!$this->noemail) { + if (! $this->noemail) { $contentType = "application/octetstream"; foreach ($filelist as $file) { if (is_file($file['filepath']) && is_readable($file['filepath'])) { @@ -108,7 +108,7 @@ public function attachFiles($filelist = array()) public function send($report) { //если отправлять некуда или незачем, то делаем вид, что отправили - if (!$this->getCFGDef('to') || $this->noemail) { + if (! $this->getCFGDef('to') || $this->noemail) { return true; } elseif (empty($report)) { return false; @@ -127,12 +127,12 @@ public function send($report) /** * @param $report - * @return bool + * @return bool|string */ public function toQueue($report) { //если отправлять некуда или незачем, то делаем вид, что отправили - if (!$this->getCFGDef('to') || $this->noemail) { + if (! $this->getCFGDef('to') || $this->noemail) { return true; } elseif (empty($report)) { return false; @@ -165,7 +165,7 @@ public function toQueue($report) */ public function setQueuePath($path = '') { - if (!empty($path)) { + if (! empty($path)) { $this->queuePath = $path; return true; } else { diff --git a/assets/lib/Helpers/PHPThumb.php b/assets/lib/Helpers/PHPThumb.php index 508c892406..98fc1b482f 100644 --- a/assets/lib/Helpers/PHPThumb.php +++ b/assets/lib/Helpers/PHPThumb.php @@ -10,8 +10,10 @@ class PHPThumb { - private $thumb = null; - protected $fs = null; + /** @var \phpthumb */ + private $thumb; + /** @var FS */ + protected $fs; public $debugMessages = ''; /** diff --git a/assets/lib/Helpers/Video.php b/assets/lib/Helpers/Video.php index 315826d144..842c920b36 100644 --- a/assets/lib/Helpers/Video.php +++ b/assets/lib/Helpers/Video.php @@ -90,7 +90,7 @@ class Video */ public function __construct($link = null, $autostart = true, $info = false) { - if (!empty($link)) { + if (! empty($link)) { $this->setLink($link); $this->setInfo($info); if ($autostart) { @@ -181,10 +181,10 @@ public function setLink($link) /** Обработка ссылки. Возвращает идентификатор видеохостинга или false */ public function process($link = null, $info = null) { - if (!empty($link)) { + if (! empty($link)) { $this->setLink($link); } - if (!empty($info)) { + if (! empty($info)) { $this->setInfo($info); } @@ -208,11 +208,11 @@ public function process($link = null, $info = null) /** Скачать превью. Если не указать имя файла для записи - функция вернет содержимое файла */ public function fetchImage($filename = null) { - if (!$url = $this->getImage()) { + if (! $url = $this->getImage()) { return false; } - if (!$res = $this->fetchPage($url)) { + if (! $res = $this->fetchPage($url)) { return false; } @@ -228,7 +228,7 @@ protected function cleanLink() $this->link = 'http://' . $this->link; } - if (!$this->link_parts = parse_url($this->link)) { + if (! $this->link_parts = parse_url($this->link)) { return false; } @@ -244,7 +244,7 @@ protected function maybeYoutube() if ('youtube.com' == $h) { parse_str($this->link_parts['query'], $q); - if ('/watch' == $p && !empty($q['v'])) { + if ('/watch' == $p && ! empty($q['v'])) { return $this->foundYoutube($q['v']); } if (0 === strpos($p, '/embed/')) { @@ -396,7 +396,7 @@ public function getEmbed($options) $class = isset($options['class']) ? $options['class'] : ''; $url = $this->getVideo($autoplay); - if (!empty($class)) { + if (! empty($class)) { $class = ' class="' . $class . '"'; } diff --git a/assets/lib/MODxAPI/MODx.php b/assets/lib/MODxAPI/MODx.php index 3d5bf6a436..67eae07d2e 100644 --- a/assets/lib/MODxAPI/MODx.php +++ b/assets/lib/MODxAPI/MODx.php @@ -90,9 +90,9 @@ abstract class MODxAPI extends MODxAPIhelpers protected $default_field = array(); /** - * @var null|integer|string + * @var mixed */ - protected $id = null; + protected $id; /** * @var array @@ -198,11 +198,11 @@ public function getDefaultFields() protected function getTime($value) { $value = trim($value); - if (!empty($value)) { - if (!is_numeric($value)) { + if (! empty($value)) { + if (! is_numeric($value)) { $value = (int)strtotime($value); } - if (!empty($value)) { + if (! empty($value)) { $value += $this->modxConfig('server_offset_time'); } } @@ -226,7 +226,7 @@ final public function modxConfig($name, $default = null) */ public function addQuery($q) { - if (is_scalar($q) && !empty($q)) { + if (is_scalar($q) && ! empty($q)) { $this->_query[] = $q; } @@ -260,7 +260,7 @@ final public function query($SQL) */ final public function escape($value) { - if (!is_scalar($value)) { + if (! is_scalar($value)) { $value = ''; } else { $value = $this->modx->db->escape($value); @@ -292,7 +292,7 @@ final public function invokeEvent($name, $data = array(), $flag = false) */ final public function getInvokeEventResult($name, $data = array(), $flag = null) { - $flag = (isset($flag) && $flag != '') ? (bool)$flag : false; + $flag = (isset($flag) && $flag !== '') ? (bool)$flag : false; return $flag ? $this->modx->invokeEvent($name, $data) : false; } @@ -400,7 +400,7 @@ public function switchObject($id) //Если уже загружен объект, с которым мы хотим временно поработать case ($this->getID() == $id && $id): //Если $id не указан, но уже загружен какой-то объект - case (!$id && null !== $this->getID()): + case (! $id && null !== $this->getID()): default: $obj = $this; break; @@ -435,7 +435,7 @@ public function hasIgnore() */ public function set($key, $value) { - if ((is_scalar($value) || $this->isJsonField($key)) && is_scalar($key) && !empty($key)) { + if ((is_scalar($value) || $this->isJsonField($key)) && is_scalar($key) && ! empty($key)) { $this->field[$key] = $value; } @@ -484,7 +484,7 @@ public function fromArray($data) */ final protected function Uset($key, $id = '') { - if (!isset($this->field[$key])) { + if (! isset($this->field[$key])) { $tmp = "`{$key}`=''"; $this->log[] = "{$key} is empty"; } else { @@ -494,7 +494,7 @@ final protected function Uset($key, $id = '') throw new Exception("{$key} is invalid
" . print_r($this->field[$key], true) . "
"); } } - if (!empty($tmp) && $this->isChanged($key)) { + if (! empty($tmp) && $this->isChanged($key)) { if ($id == '') { $this->set[] = $tmp; } else { @@ -528,7 +528,7 @@ public function store($data = array()) */ public function rollback($key = '') { - if (!empty($key) && isset($this->store[$key])) { + if (! empty($key) && isset($this->store[$key])) { $this->set($key, $this->store[$key]); } else { $this->fromArray($this->store); @@ -545,7 +545,7 @@ public function rollback($key = '') */ public function isChanged($key) { - $flag = !isset($this->store[$key]) || (isset($this->store[$key]) && $this->store[$key] != $this->field[$key]); + $flag = ! isset($this->store[$key]) || (isset($this->store[$key]) && $this->store[$key] != $this->field[$key]); return $flag; } @@ -572,7 +572,7 @@ final public function cleanIDs($IDs, $sep = ',', $ignore = array()) */ final public function fromJson($data, $callback = null) { - if (is_scalar($data) && !empty($data)) { + if (is_scalar($data) && ! empty($data)) { $json = json_decode($data); } else { throw new Exception("json is not string with json data"); @@ -654,7 +654,7 @@ public function toArray($prefix = '', $suffix = '', $sep = '_') $out = array(); $fields = $this->field; $fields[$this->fieldPKName()] = $this->getID(); - if ($tpl != $plh) { + if ($tpl !== $plh) { foreach ($fields as $key => $value) { $out[str_replace($plh, $key, $tpl)] = $value; } @@ -690,7 +690,7 @@ final public function makeTable($table) */ final public function sanitarIn($data, $sep = ',') { - if (!is_array($data)) { + if (! is_array($data)) { $data = explode($sep, $data); } $out = array(); @@ -732,11 +732,7 @@ public function checkUnique($table, $field, $PK = 'id') if ($where != '') { $sql = $this->query("SELECT `" . $this->escape($PK) . "` FROM " . $this->makeTable($table) . " WHERE " . $where); $id = $this->modx->db->getValue($sql); - if (!$id || (!$this->newDoc && $id == $this->getID())) { - $flag = true; - } else { - $flag = false; - } + $flag = (! $id || (! $this->newDoc && $id == $this->getID())); } else { $flag = false; } @@ -836,7 +832,7 @@ final protected function checkVersion($version, $dmi3yy = true) if (version_compare($tmp, $version, '>=')) { $flag = true; if ($dmi3yy) { - $flag = (boolean)preg_match('/^' . $tmp . '(.*)\-d/', $currentVer); + $flag = $flag || (boolean)preg_match('/^' . $tmp . '(.*)\-d/', $currentVer); } } @@ -845,7 +841,7 @@ final protected function checkVersion($version, $dmi3yy = true) /** * @param string $name - * @return bool|mixed + * @return bool|string|int */ protected function eraseField($name) { diff --git a/assets/lib/MODxAPI/autoTable.abstract.php b/assets/lib/MODxAPI/autoTable.abstract.php index 3ea788bf82..4c1c53adda 100644 --- a/assets/lib/MODxAPI/autoTable.abstract.php +++ b/assets/lib/MODxAPI/autoTable.abstract.php @@ -90,12 +90,12 @@ public function save($fire_events = false, $clearCache = false) if ($this->newDoc && $this->get($key) === null && $this->get($key) !== $value) { $this->set($key, $value); } - if ((!$this->generateField || isset($fld[$key])) && $this->get($key) !== null) { + if ((! $this->generateField || isset($fld[$key])) && $this->get($key) !== null) { $this->Uset($key); } unset($fld[$key]); } - if (!empty($this->set)) { + if (! empty($this->set)) { if ($this->newDoc) { $SQL = "INSERT {$this->ignoreError} INTO {$this->makeTable($this->table)} SET " . implode(', ', $this->set); @@ -125,9 +125,9 @@ public function save($fire_events = false, $clearCache = false) public function delete($ids, $fire_events = false) { $_ids = $this->cleanIDs($ids, ','); - if (is_array($_ids) && $_ids != array()) { + if (is_array($_ids) && $_ids !== array()) { $id = $this->sanitarIn($_ids); - if (!empty($id)) { + if (! empty($id)) { $this->query("DELETE from {$this->makeTable($this->table)} where `" . $this->pkName . "` IN ({$id})"); } $this->clearCache($fire_events); diff --git a/assets/lib/MODxAPI/modManagers.php b/assets/lib/MODxAPI/modManagers.php index dedef4be23..9472b489f2 100644 --- a/assets/lib/MODxAPI/modManagers.php +++ b/assets/lib/MODxAPI/modManagers.php @@ -143,7 +143,7 @@ public function edit($id) $this->close(); $this->newDoc = false; - if (!$find = $this->findUser($id)) { + if (! $find = $this->findUser($id)) { $this->id = null; } else { $this->set('editedon', time()); @@ -175,7 +175,7 @@ public function edit($id) */ public function set($key, $value) { - if (is_scalar($value) && is_scalar($key) && !empty($key)) { + if (is_scalar($value) && is_scalar($key) && ! empty($key)) { switch ($key) { case 'password': $this->givenPassword = $value; @@ -233,20 +233,20 @@ public function save($fire_events = false, $clearCache = false) return false; } - if (!$this->checkUnique('manager_users', 'username')) { + if (! $this->checkUnique('manager_users', 'username')) { $this->log['UniqueUsername'] = 'username not unique
' . print_r($this->get('username'),
                     true) . '
'; return false; } - if (!$this->checkUnique('user_attributes', 'email', 'internalKey')) { + if (! $this->checkUnique('user_attributes', 'email', 'internalKey')) { $this->log['UniqueEmail'] = 'Email not unique
' . print_r($this->get('email'), true) . '
'; return false; } - if(!$this->get('role')) { + if(! $this->get('role')) { $this->log['UniqueEmail'] = 'Wrong manager role
' . print_r($this->get('role'), true) . '
'; } @@ -260,7 +260,7 @@ public function save($fire_events = false, $clearCache = false) $this->Uset($key, 'user'); unset($fld[$key]); } - if (!empty($this->set['user'])) { + if (! empty($this->set['user'])) { if ($this->newDoc) { $SQL = "INSERT into {$this->makeTable('manager_users')} SET " . implode(', ', $this->set['user']); } else { @@ -282,7 +282,7 @@ public function save($fire_events = false, $clearCache = false) $this->Uset($key, 'attribute'); unset($fld[$key]); } - if (!empty($this->set['attribute'])) { + if (! empty($this->set['attribute'])) { if ($this->newDoc) { $this->set('internalKey', $this->id)->Uset('internalKey', 'attribute'); $SQL = "INSERT into {$this->makeTable('user_attributes')} SET " . implode(', ', @@ -295,7 +295,7 @@ public function save($fire_events = false, $clearCache = false) } unset($fld['id']); foreach ($fld as $key => $value) { - if ($value == '' || !$this->isChanged($key)) { + if ($value == '' || ! $this->isChanged($key)) { continue; } $result = $this->query("SELECT `setting_value` FROM {$this->makeTable('user_settings')} WHERE `user` = '{$this->id}' AND `setting_name` = '{$key}'"); @@ -306,7 +306,7 @@ public function save($fire_events = false, $clearCache = false) } } // TODO - if (!$this->newDoc && $this->givenPassword) { + if (! $this->newDoc && $this->givenPassword) { $this->invokeEvent('OnManagerChangePassword', array( 'userObj' => $this, 'userid' => $this->id, @@ -316,7 +316,7 @@ public function save($fire_events = false, $clearCache = false) ), $fire_events); } - if (!empty($this->groupIds)) { + if (! empty($this->groupIds)) { $this->setUserGroups($this->id, $this->groupIds); } // TODO @@ -412,7 +412,7 @@ public function checkBlock($id = 0) $b = $tmp->get('blocked'); $bu = $tmp->get('blockeduntil'); $ba = $tmp->get('blockedafter'); - $flag = (($b && !$bu && !$ba) || ($bu && $now < $bu) || ($ba && $now > $ba)); + $flag = (($b && ! $bu && ! $ba) || ($bu && $now < $bu) || ($ba && $now > $ba)); unset($tmp); return $flag; @@ -434,7 +434,7 @@ public function testAuth($id, $password, $blocker, $fire_events = false) $flag = $pluginFlag = false; if ( - (null !== $tmp->getID()) && (!$blocker || ($blocker && !$tmp->checkBlock($id))) + (null !== $tmp->getID()) && (! $blocker || ($blocker && ! $tmp->checkBlock($id))) ) { $_password = $tmp->get('password'); $eventResult = $this->getInvokeEventResult('OnManagerAuthentication', array( @@ -451,7 +451,7 @@ public function testAuth($id, $password, $blocker, $fire_events = false) } else { $pluginFlag = (bool)$eventResult; } - if (!$pluginFlag) { + if (! $pluginFlag) { $hashType = $this->getPasswordHashType($_password); switch ($hashType) { case 'phpass': @@ -488,7 +488,7 @@ public function testAuth($id, $password, $blocker, $fire_events = false) */ public function logOut($cookieName = 'modx_remember_manager', $fire_events = false) { - if (!$uid = $this->modx->getLoginUserID('mgr')) { + if (! $uid = $this->modx->getLoginUserID('mgr')) { return; } $params = array( @@ -534,7 +534,7 @@ protected function SessionHandler($directive, $cookieName, $remember = true) $_SESSION['mgrPermissions'] = $this->mgrPermissions; $_SESSION['mgrDocgroups'] = $this->getDocumentGroups(); $_SESSION['mgrToken'] = md5($this->get('sessionid')); - if (!empty($remember)) { + if (! empty($remember)) { $this->setAutoLoginCookie($cookieName, $remember); } } @@ -584,7 +584,7 @@ public function isSecure() */ public function setAutoLoginCookie($cookieName, $remember = true) { - if (!empty($cookieName) && $this->getID() !== null) { + if (! empty($cookieName) && $this->getID() !== null) { $secure = $this->isSecure(); $remember = is_bool($remember) ? $this->getRememberTime() : (int)$remember; $cookieValue = $this->get('username'); @@ -659,7 +659,7 @@ public function setUserGroups($userID = 0, $groupIds = array()) foreach ($groupIds as $gid) { $this->query("REPLACE INTO {$this->makeTable('member_groups')} (`user_group`, `member`) VALUES ('{$gid}', '{$uid}')"); } - if (!$this->newDoc) { + if (! $this->newDoc) { $groupIds = empty($groupIds) ? '0' : implode(',', $groupIds); $this->query("DELETE FROM {$this->makeTable('member_groups')} WHERE `member`={$uid} AND `user_group` NOT IN ({$groupIds})"); } diff --git a/assets/lib/MODxAPI/modResource.php b/assets/lib/MODxAPI/modResource.php index d671a87d50..ec9c9180cd 100644 --- a/assets/lib/MODxAPI/modResource.php +++ b/assets/lib/MODxAPI/modResource.php @@ -1,1126 +1,1132 @@ - 'document', - 'contentType' => 'text/html', - 'pagetitle' => 'New document', - 'longtitle' => '', - 'description' => '', - 'alias' => '', - 'link_attributes' => '', - 'published' => 1, - 'pub_date' => 0, - 'unpub_date' => 0, - 'parent' => 0, - 'isfolder' => 0, - 'introtext' => '', - 'content' => '', - 'richtext' => 1, - 'template' => 0, - 'menuindex' => 0, - 'searchable' => 1, - 'cacheable' => 1, - 'createdon' => 0, - 'createdby' => 0, - 'editedon' => 0, - 'editedby' => 0, - 'deleted' => 0, - 'deletedon' => 0, - 'deletedby' => 0, - 'publishedon' => 0, - 'publishedby' => 0, - 'menutitle' => '', - 'donthit' => 0, - 'privateweb' => 0, - 'privatemgr' => 0, - 'content_dispo' => 0, - 'hidemenu' => 0, - 'alias_visible' => 1 - ); - /** - * @var array - */ - private $table = array( - '"' => '_', - "'" => '_', - ' ' => '_', - '.' => '_', - ',' => '_', - 'а' => 'a', - 'б' => 'b', - 'в' => 'v', - 'г' => 'g', - 'д' => 'd', - 'е' => 'e', - 'ё' => 'e', - 'ж' => 'zh', - 'з' => 'z', - 'и' => 'i', - 'й' => 'y', - 'к' => 'k', - 'л' => 'l', - 'м' => 'm', - 'н' => 'n', - 'о' => 'o', - 'п' => 'p', - 'р' => 'r', - 'с' => 's', - 'т' => 't', - 'у' => 'u', - 'ф' => 'f', - 'х' => 'h', - 'ц' => 'c', - 'ч' => 'ch', - 'ш' => 'sh', - 'щ' => 'sch', - 'ь' => '', - 'ы' => 'y', - 'ъ' => '', - 'э' => 'e', - 'ю' => 'yu', - 'я' => 'ya', - 'А' => 'A', - 'Б' => 'B', - 'В' => 'V', - 'Г' => 'G', - 'Д' => 'D', - 'Е' => 'E', - 'Ё' => 'E', - 'Ж' => 'Zh', - 'З' => 'Z', - 'И' => 'I', - 'Й' => 'Y', - 'К' => 'K', - 'Л' => 'L', - 'М' => 'M', - 'Н' => 'N', - 'О' => 'O', - 'П' => 'P', - 'Р' => 'R', - 'С' => 'S', - 'Т' => 'T', - 'У' => 'U', - 'Ф' => 'F', - 'Х' => 'H', - 'Ц' => 'C', - 'Ч' => 'Ch', - 'Ш' => 'Sh', - 'Щ' => 'Sch', - 'Ь' => '', - 'Ы' => 'Y', - 'Ъ' => '', - 'Э' => 'E', - 'Ю' => 'Yu', - 'Я' => 'Ya', - ); - /** - * @var array массив ТВшек где name это ключ массива, а ID это значение - */ - private $tv = array(); - /** - * @var array массив ТВшек где ID это ключ массива, а name это значение - */ - private $tvid = array(); - /** - * @var array значения по умолчанию для ТВ параметров - */ - private $tvd = array(); - - /** @var array связи ТВ и шаблонов */ - private $tvTpl = array(); - - /** @var array параметры ТВ с массивами */ - protected $tvaFields = array(); - - /** - * Массив администраторов - * @var DLCollection - */ - private $managerUsers = null; - /** @var array группы документов */ - protected $groupIds = array(); - - /** - * modResource constructor. - * @param DocumentParser $modx - * @param bool $debug - */ - public function __construct($modx, $debug = false) - { - parent::__construct($modx, $debug); - $this->get_TV(); - $uTable = $this->makeTable("manager_users"); - $aTable = $this->makeTable("user_attributes"); - $query = "SELECT `u`.`id`, `a`.`email`, `u`.`username` FROM " . $aTable . " as `a` LEFT JOIN " . $uTable . " as `u` ON `u`.`id`=`a`.`internalKey`"; - $query = $this->query($query); - $this->managerUsers = new DLCollection($modx, empty($query) ? array() : $query); - } - - /** - * @return array - */ - public function toArrayMain() - { - $out = array_intersect_key(parent::toArray(), $this->default_field); - - return $out; - } - - /** - * @param bool $render - * @return array - */ - public function toArrayTV($render = false) - { - $out = array_diff_key(parent::toArray(), $this->default_field); - $tpl = $this->get('template'); - $tvTPL = APIHelpers::getkey($this->tvTpl, $tpl, array()); - foreach ($tvTPL as $item) { - if (isset($this->tvid[$item]) && !array_key_exists($this->tvid[$item], $out)) { - $value = $this->get($this->tvid[$item]); - $out[$this->tvid[$item]] = empty($value) ? $this->tvd[$this->tvid[$item]] : $value; - } - - } - if ($render) { - foreach ($out as $key => $val) { - $out[$key] = $this->renderTV($key); - } - } - - return $out; - } - - /** - * @param string $prefix - * @param string $suffix - * @param string $sep - * @param bool $render - * @return array - */ - public function toArray($prefix = '', $suffix = '', $sep = '_', $render = true) - { - $out = array_merge( - $this->toArrayMain(), - $this->toArrayTV($render), - array($this->fieldPKName() => $this->getID()) - ); - - return \APIhelpers::renameKeyArr($out, $prefix, $suffix, $sep); - } - - /** - * @return null|string - */ - public function getUrl() - { - $out = null; - $id = (int)$this->getID(); - if (!empty($id)) { - $out = $this->modx->makeUrl($id); - } - - return $out; - } - - /** - * @param string $main - * @param string $second - * @return mixed - */ - public function getTitle($main = 'menutitle', $second = 'pagetitle') - { - $title = $this->get($main); - if (empty($title) && $title !== '0') { - $title = $this->get($second); - } - - return $title; - } - - /** - * @return bool - */ - public function isWebShow() - { - $pub = ($this->get('publishedon') < time() && $this->get('published')); - $unpub = ($this->get('unpub_date') == 0 || $this->get('unpub_date') > time()); - $del = ($this->get('deleted') == 0 && ($this->get('deletedon') == 0 || $this->get('deletedon') > time())); - - return ($pub && $unpub && $del); - } - - /** - * @return $this - */ - public function touch() - { - $this->set('editedon', time()); - - return $this; - } - - /** - * @param $tvname - * @return null|string - */ - public function renderTV($tvname) - { - $out = null; - if ($this->getID() > 0) { - include_once MODX_MANAGER_PATH . "includes/tmplvars.format.inc.php"; - include_once MODX_MANAGER_PATH . "includes/tmplvars.commands.inc.php"; - $tvval = $this->get($tvname); - if ($this->isTVarrayField($tvname) && is_array($tvval)) { - $tvval = implode('||', $tvval); - } - $param = APIHelpers::getkey($this->tvd, $tvname, array()); - $display = APIHelpers::getkey($param, 'display', ''); - $display_params = APIHelpers::getkey($param, 'display_params', ''); - $type = APIHelpers::getkey($param, 'type', ''); - $out = getTVDisplayFormat($tvname, $tvval, $display, $display_params, $type, $this->getID(), ''); - } - - return $out; - } - - /** - * @param $key - * @return mixed - */ - public function get($key) - { - $out = parent::get($key); - if (isset($this->tv[$key])) { - $tpl = $this->get('template'); - $tvTPL = APIHelpers::getkey($this->tvTpl, $tpl, array()); - $tvID = APIHelpers::getkey($this->tv, $key, 0); - if (in_array($tvID, $tvTPL) && is_null($out)) { - $out = APIHelpers::getkey($this->tvd, $key, null); - $out = $out['default']; - } - } - - return $out; - } - - /** - * @param $key - * @param $value - * @return $this - */ - public function set($key, $value) - { - if ((is_scalar($value) || $this->isTVarrayField($key) || $this->isJsonField($key)) && is_scalar($key) && !empty($key)) { - switch ($key) { - case 'parent': - $value = (int)$value; - break; - case 'template': - $value = trim($value); - $value = $this->setTemplate($value); - break; - case 'published': - $value = (int)((bool)$value); - if ($value) { - $this->field['publishedon'] = time() + $this->modxConfig('server_offset_time'); - } - break; - case 'pub_date': - $value = $this->getTime($value); - if ($value > 0 && time() + $this->modxConfig('server_offset_time') > $value) { - $this->field['published'] = 1; - $this->field['publishedon'] = $value; - } - break; - case 'unpub_date': - $value = $this->getTime($value); - if ($value > 0 && time() + $this->modxConfig('server_offset_time') > $value) { - $this->field['published'] = 0; - $this->field['publishedon'] = 0; - } - break; - case 'deleted': - $value = (int)((bool)$value); - if ($value) { - $this->field['deletedon'] = time() + $this->modxConfig('server_offset_time'); - } else { - $this->field['deletedon'] = 0; - } - break; - case 'deletedon': - $value = $this->getTime($value); - if ($value > 0 && time() + $this->modxConfig('server_offset_time') < $value) { - $value = 0; - } - if ($value) { - $this->field['deleted'] = 1; - } - break; - case 'editedon': - case 'createdon': - case 'publishedon': - $value = $this->getTime($value); - break; - case 'publishedby': - case 'editedby': - case 'createdby': - case 'deletedby': - $value = $this->getUser($value, $this->default_field[$key]); - break; - } - $this->field[$key] = $value; - } - - return $this; - } - - /** - * @param $value - * @param int $default - * @return int|mixed - */ - protected function getUser($value, $default = 0) - { - $currentAdmin = APIHelpers::getkey($_SESSION, 'mgrInternalKey', 0); - $value = (int)$value; - if (!empty($value)) { - $by = $this->findUserBy($value); - $exists = $this->managerUsers->exists(function ($key, Helpers\Collection $val) use ($by, $value) { - return ($val->containsKey($by) && $val->get($by) === (string)$value); - }); - if (!$exists) { - $value = 0; - } - } - if (empty($value)) { - $value = empty($currentAdmin) ? $default : $currentAdmin; - } - - return $value; - } - - /** - * @param $data - * @return bool|string - */ - protected function findUserBy($data) - { - switch (true) { - case (is_int($data) || ((int)$data > 0 && (string)intval($data) === $data)): - $find = 'id'; - break; - case filter_var($data, FILTER_VALIDATE_EMAIL): - $find = 'email'; - break; - case is_scalar($data): - $find = 'username'; - break; - default: - $find = false; - } - - return $find; - } - - /** - * @param array $data - * @return $this - */ - public function create($data = array()) - { - $this->close(); - $fld = array(); - foreach ($this->tvd as $name => $tv) { - $fld[$name] = $tv['default']; - }; - $this->store($fld); - - $this->fromArray(array_merge($fld, $data)); - $this->set('createdby', null) - ->set('editedby', null) - ->set('createdon', time()) - ->touch(); - - return $this; - } - - /** - * @param $id - * @return $this - */ - public function edit($id) - { - $id = is_scalar($id) ? trim($id) : ''; - if ($this->getID() != $id) { - $this->close(); - $this->markAllEncode(); - $this->newDoc = false; - $result = $this->query("SELECT * from {$this->makeTable('site_content')} where `id`=" . (int)$id); - $this->fromArray($this->modx->db->getRow($result)); - $result = $this->query("SELECT * from {$this->makeTable('site_tmplvar_contentvalues')} where `contentid`=" . (int)$id); - while ($row = $this->modx->db->getRow($result)) { - $this->field[$this->tvid[$row['tmplvarid']]] = $row['value']; - } - $fld = array(); - foreach ($this->tvd as $name => $tv) { - if ($this->belongsToTemplate($this->tv[$name])) { - $fld[$name] = $tv['default']; - } - }; - $this->store(array_merge($fld, $this->field)); - if (empty($this->field['id'])) { - $this->id = null; - } else { - $this->id = $this->field['id']; - $this->set('editedby', null)->touch(); - $this->decodeFields(); - } - unset($this->field['id']); - } - - return $this; - } - - /** - * @param bool $fire_events - * @param bool $clearCache - * @return bool|null - */ - public function save($fire_events = false, $clearCache = false) - { - $parent = null; - if ($this->field['pagetitle'] == '') { - $this->log['emptyPagetitle'] = 'Pagetitle is empty in
' . print_r($this->field, true) . '
'; - - return false; - } - - $uid = $this->modx->getLoginUserID('mgr'); - - if ( - $this->field['parent'] == 0 && - !$this->modxConfig('udperms_allowroot') && - !($uid && isset($_SESSION['mgrRole']) && $_SESSION['mgrRole'] == 1) - ) { - $this->log['rootForbidden'] = 'Only Administrators can create documents in the root folder because udperms_allowroot setting is off'; - - return false; - } - - $this->set('alias', $this->getAlias()); - - $this->invokeEvent('OnBeforeDocFormSave', array( - 'mode' => $this->newDoc ? "new" : "upd", - 'id' => isset($this->id) ? $this->id : '', - 'doc' => $this->toArray(), - 'docObj' => $this - ), $fire_events); - - $fld = $this->encodeFields()->toArray(null, null, null, false); - foreach ($this->default_field as $key => $value) { - $tmp = $this->get($key); - if ($this->newDoc && (!is_int($tmp) && $tmp == '')) { - if ($tmp == $value) { - switch ($key) { - case 'cacheable': - $value = $this->modxConfig('cache_default'); - break; - case 'template': - $value = $value = $this->modxConfig('default_template'); - break; - case 'published': - $value = $this->modxConfig('publish_default'); - break; - case 'searchable': - $value = $this->modxConfig('search_default'); - break; - case 'donthit': - $value = $this->modxConfig('track_visitors'); - break; - } - } - $this->field[$key] = $value; - } - switch (true) { - case $key == 'parent': - $parent = (int)$this->get($key); - $q = $this->query("SELECT count(`id`) FROM {$this->makeTable('site_content')} WHERE `id`='{$parent}'"); - if ($this->modx->db->getValue($q) != 1) { - $parent = 0; - } - $this->field[$key] = $parent; - $this->Uset($key); - break; - case ($key == 'alias_visible' && !$this->checkVersion('1.0.10', true)): - $this->eraseField('alias_visible'); - break; - default: - $this->Uset($key); - } - unset($fld[$key]); - } - - if (!empty($this->set)) { - if ($this->newDoc) { - $SQL = "INSERT into {$this->makeTable('site_content')} SET " . implode(', ', $this->set); - } else { - $SQL = "UPDATE {$this->makeTable('site_content')} SET " . implode(', ', - $this->set) . " WHERE `id` = " . $this->id; - } - $this->query($SQL); - - if ($this->newDoc) { - $this->id = $this->modx->db->getInsertId(); - } - - if ($parent > 0) { - $this->query("UPDATE {$this->makeTable('site_content')} SET `isfolder`='1' WHERE `id`='{$parent}'"); - } - } - - $_deleteTVs = $_insertTVs = array(); - foreach ($fld as $key => $value) { - if (empty($this->tv[$key]) || !$this->isChanged($key) || !$this->belongsToTemplate($this->tv[$key])) { - continue; - } elseif ($value === '' || is_null($value) || (isset($this->tvd[$key]) && $value == $this->tvd[$key]['default'])) { - $_deleteTVs[] = $this->tv[$key]; - } else { - $_insertTVs[$this->tv[$key]] = $this->escape($value); - } - } - - if (!empty($_insertTVs)) { - $values = array(); - foreach ($_insertTVs as $id => $value) { - $values[] = "({$this->id}, {$id}, '{$value}')"; - } - $values = implode(',', $values); - $this->query("INSERT INTO {$this->makeTable('site_tmplvar_contentvalues')} (`contentid`,`tmplvarid`,`value`) VALUES {$values} ON DUPLICATE KEY UPDATE - `value` = VALUES(`value`)"); - } - - if (!empty($_deleteTVs)) { - $ids = implode(',', $_deleteTVs); - $this->query("DELETE FROM {$this->makeTable('site_tmplvar_contentvalues')} WHERE `contentid` = '{$this->id}' AND `tmplvarid` IN ({$ids})"); - } - - if (!isset($this->mode)) { - $this->mode = $this->newDoc ? "new" : "upd"; - $this->newDoc = false; - } - - if (!empty($this->groupIds)) { - $this->setDocumentGroups($this->id, $this->groupIds); - } - $this->invokeEvent('OnDocFormSave', array( - 'mode' => $this->mode, - 'id' => isset($this->id) ? $this->id : '', - 'doc' => $this->toArray(), - 'docObj' => $this - ), $fire_events); - - if ($clearCache) { - $this->clearCache($fire_events); - } - $this->decodeFields(); - - return $this->id; - } - - /** - * @param $tvId - * @return bool - */ - protected function belongsToTemplate($tvId) - { - $template = $this->get('template'); - - return isset($this->tvTpl[$template]) && in_array($tvId, $this->tvTpl[$template]); - } - - /** - * @param $ids - * @return $this - * @throws Exception - */ - public function toTrash($ids) - { - $ignore = $this->systemID(); - $_ids = $this->cleanIDs($ids, ',', $ignore); - if (is_array($_ids) && $_ids != array()) { - $id = $this->sanitarIn($_ids); - $uid = (int)$this->modx->getLoginUserId(); - $deletedon = time() + $this->modxConfig('server_offset_time'); - $this->query("UPDATE {$this->makeTable('site_content')} SET `deleted`=1, `deletedby`={$uid}, `deletedon`={$deletedon} WHERE `id` IN ({$id})"); - } else { - throw new Exception('Invalid IDs list for mark trash:
' . print_r($ids,
-                    1) . '
please, check ignore list:
' . print_r($ignore, 1) . '
'); - } - - return $this; - } - - /** - * @param bool $fire_events - * @return $this - */ - public function clearTrash($fire_events = false) - { - $q = $this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `deleted`='1'"); - $_ids = $this->modx->db->getColumn('id', $q); - if (is_array($_ids) && $_ids != array()) { - $this->invokeEvent('OnBeforeEmptyTrash', array( - "ids" => $_ids - ), $fire_events); - - $id = $this->sanitarIn($_ids); - $this->query("DELETE from {$this->makeTable('site_content')} where `id` IN ({$id})"); - $this->query("DELETE from {$this->makeTable('site_tmplvar_contentvalues')} where `contentid` IN ({$id})"); - - $this->invokeEvent('OnEmptyTrash', array( - "ids" => $_ids - ), $fire_events); - } - - return $this; - } - - /** - * @param $ids - * @param int|bool $depth - * @return array - */ - public function children($ids, $depth) - { - $_ids = $this->cleanIDs($ids, ','); - if (is_array($_ids) && $_ids != array()) { - $id = $this->sanitarIn($_ids); - if (!empty($id)) { - $q = $this->query("SELECT `id` FROM {$this->makeTable('site_content')} where `parent` IN ({$id})"); - $id = $this->modx->db->getColumn('id', $q); - if ($depth > 0 || $depth === true) { - $id = $this->children($id, is_bool($depth) ? $depth : ($depth - 1)); - } - $_ids = array_merge($_ids, $id); - } - } - - return $_ids; - } - - /** - * @param string|array $ids - * @param bool $fire_events - * @return $this - * @throws Exception - */ - public function delete($ids, $fire_events = false) - { - $ids = $this->children($ids, true); - $_ids = $this->cleanIDs($ids, ',', $this->systemID()); - $this->invokeEvent('OnBeforeDocFormDelete', array( - 'ids' => $_ids - ), $fire_events); - $this->toTrash($_ids); - $this->invokeEvent('OnDocFormDelete', array( - 'ids' => $_ids - ), $fire_events); - - return $this; - } - - /** - * @return array - */ - private function systemID() - { - $ignore = array( - 0, //empty document - (int)$this->modxConfig('site_start'), - (int)$this->modxConfig('error_page'), - (int)$this->modxConfig('unauthorized_page'), - (int)$this->modxConfig('site_unavailable_page') - ); - $data = $this->query("SELECT DISTINCT setting_value FROM {$this->makeTable('web_user_settings')} WHERE `setting_name`='login_home' AND `setting_value`!=''"); - $data = $this->modx->db->makeArray($data); - foreach ($data as $item) { - $ignore[] = (int)$item['setting_value']; - } - - return array_unique($ignore); - - } - - /** - * @param $alias - * @return string - */ - protected function checkAlias($alias) - { - $alias = strtolower($alias); - if ($this->modxConfig('friendly_urls')) { - $_alias = $this->escape($alias); - if ((!$this->modxConfig('allow_duplicate_alias') && !$this->modxConfig('use_alias_path')) || ($this->modxConfig('allow_duplicate_alias') && $this->modxConfig('use_alias_path'))) { - $flag = $this->modx->db->getValue($this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `alias`='{$_alias}' AND `parent`={$this->get('parent')} LIMIT 1")); - } else { - $flag = $this->modx->db->getValue($this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `alias`='{$_alias}' LIMIT 1")); - } - if (($flag && $this->newDoc) || (!$this->newDoc && $flag && $this->id != $flag)) { - $suffix = substr($alias, -2); - if (preg_match('/-(\d+)/', $suffix, $tmp) && isset($tmp[1]) && (int)$tmp[1] > 1) { - $suffix = (int)$tmp[1] + 1; - $alias = substr($alias, 0, -2) . '-' . $suffix; - } else { - $alias .= '-2'; - } - $alias = $this->checkAlias($alias); - } - } - - return $alias; - } - - /** - * @param $key - * @return bool - */ - public function issetField($key) - { - return (array_key_exists($key, $this->default_field) || (array_key_exists($key, $this->tv) && $this->belongsToTemplate($this->tv[$key]))); - } - - /** - * @param bool $reload - * @return $this - */ - protected function get_TV($reload = false) - { - $this->modx->_TVnames = $this->loadFromCache('_TVnames'); - if ($this->modx->_TVnames === false || empty($this->modx->_TVnames) || $reload) { - $this->modx->_TVnames = array(); - $result = $this->query('SELECT `id`,`name`,`default_text`,`type`,`display`,`display_params` FROM ' . $this->makeTable('site_tmplvars')); - while ($row = $this->modx->db->GetRow($result)) { - $this->modx->_TVnames[$row['name']] = array( - 'id' => $row['id'], - 'type' => $row['type'], - 'default' => $row['default_text'], - 'display' => $row['display'], - 'display_params' => $row['display_params'] - ); - } - $this->saveToCache($this->modx->_TVnames, '_TVnames'); - } - $arrayTypes = array('checkbox', 'listbox-multiple'); - $arrayTVs = array(); - foreach ($this->modx->_TVnames as $name => $data) { - $this->tvid[$data['id']] = $name; - $this->tv[$name] = $data['id']; - if (in_array($data['type'], $arrayTypes)) { - $arrayTVs[] = $name; - } - } - if (empty($this->tvaFields)) { - $this->tvaFields = $arrayTVs; - } - $this->loadTVTemplate()->loadTVDefault(array_values($this->tv)); - - return $this; - } - - /** - * @return $this - */ - protected function loadTVTemplate() - { - $this->tvTpl = $this->loadFromCache('_tvTpl'); - if ($this->tvTpl === false) { - $q = $this->query("SELECT `tmplvarid`, `templateid` FROM " . $this->makeTable('site_tmplvar_templates')); - $this->tvTpl = array(); - while ($item = $this->modx->db->getRow($q)) { - $this->tvTpl[$item['templateid']][] = $item['tmplvarid']; - } - $this->saveToCache($this->tvTpl, '_tvTpl'); - } - - return $this; - } - - /** - * @param array $tvId - * @return $this - */ - protected function loadTVDefault(array $tvId = array()) - { - if (is_array($tvId) && !empty($tvId)) { - $this->tvd = array(); - foreach ($tvId as $id) { - $name = $this->tvid[$id]; - $this->tvd[$name] = $this->modx->_TVnames[$name]; - } - } - - return $this; - } - - /** - * @param $tpl - * @return int - * @throws Exception - */ - public function setTemplate($tpl) - { - if (!is_numeric($tpl) || $tpl != (int)$tpl) { - if (is_scalar($tpl)) { - $sql = "SELECT `id` FROM {$this->makeTable('site_templates')} WHERE `templatename` = '" . $this->escape($tpl) . "'"; - $rs = $this->query($sql); - if (!$rs || $this->modx->db->getRecordCount($rs) <= 0) { - throw new Exception("Template {$tpl} is not exists"); - } - $tpl = $this->modx->db->getValue($rs); - } else { - throw new Exception("Invalid template name: " . print_r($tpl, 1)); - } - } - - return (int)$tpl; - } - - /** - * @return string - */ - protected function getAlias() - { - if ($this->modxConfig('friendly_urls') && $this->modxConfig('automatic_alias') && $this->get('alias') == '') { - $alias = strtr($this->get('pagetitle'), $this->table); - } else { - if ($this->get('alias') != '') { - $alias = $this->get('alias'); - } else { - $alias = ''; - } - } - $alias = $this->modx->stripAlias($alias); - - return $this->checkAlias($alias); - } - - /** - * @param int $parent - * @param string $criteria - * @param string $dir - * @return $this - * - * Пересчет menuindex по полю таблицы site_content - */ - public function updateMenuindex($parent, $criteria = 'id', $dir = 'asc') - { - $dir = strtolower($dir) == 'desc' ? 'desc' : 'asc'; - if (is_integer($parent) && $criteria !== '') { - $this->query("SET @index := 0"); - $this->query("UPDATE {$this->makeTable('site_content')} SET `menuindex` = (@index := @index + 1) WHERE `parent`={$parent} ORDER BY {$criteria} {$dir}"); - } - - return $this; - } - - /** - * Устанавливает значение шаблона согласно системной настройке - * - * @return $this - */ - public function setDefaultTemplate() - { - $parent = $this->get('parent'); - $template = $this->modxConfig('default_template'); - switch ($this->modxConfig('auto_template_logic')) { - case 'sibling': - if (!$parent) { - $site_start = $this->modxConfig('site_start'); - $where = "sc.isfolder=0 AND sc.id!={$site_start}"; - $sibl = $this->modx->getDocumentChildren($parent, 1, 0, 'template', $where, 'menuindex', 'ASC', 1); - if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') { - $template = $sibl[0]['template']; - } - } else { - $sibl = $this->modx->getDocumentChildren($parent, 1, 0, 'template', 'isfolder=0', 'menuindex', - 'ASC', 1); - if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') { - $template = $sibl[0]['template']; - } else { - $sibl = $this->modx->getDocumentChildren($parent, 0, 0, 'template', 'isfolder=0', 'menuindex', - 'ASC', 1); - if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') { - $template = $sibl[0]['template']; - } - } - } - break; - case 'parent': - if ($parent) { - $_parent = $this->modx->getPageInfo($parent, 0, 'template'); - if (isset($_parent['template'])) { - $template = $_parent['template']; - } - } - break; - } - $this->set('template', $template); - - return $this; - } - - /** - * Декодирует конкретное поле - * @param string $field Имя поля - * @param bool $store обновить распакованное поле - * @return array ассоциативный массив с данными из json строки - */ - public function decodeField($field, $store = false) - { - $out = array(); - if ($this->isDecodableField($field)) { - $data = $this->get($field); - if ($this->isTVarrayField($field)) { - $out = explode('||', $data); - } else { - $out = jsonHelper::jsonDecode($data, array('assoc' => true), true); - } - } - if ($store) { - $this->field[$field] = $out; - $this->markAsDecode($field); - } - - return $out; - } - - /** - * Запаковывает конкретное поле в JSON - * @param string $field Имя поля - * @param bool $store обновить запакованное поле - * @return string|null json строка - */ - public function encodeField($field, $store = false) - { - $out = null; - if ($this->isEncodableField($field)) { - $data = $this->get($field); - if ($this->isTVarrayField($field)) { - $out = is_array($data) ? implode('||', $data) : (string)$data; - } else { - $out = json_encode($data); - } - } - if ($store) { - $this->field[$field] = $out; - $this->markAsEncode($field); - } - - return $out; - } - - /** - * Может ли содержать данное поле json массив - * @param string $field имя поля - * @return boolean - */ - public function isTVarrayField($field) - { - return (is_scalar($field) && in_array($field, $this->tvaFields)); - } - - /** - * Пометить все поля как запакованные - * @return $this - */ - public function markAllEncode() - { - parent::markAllEncode(); - foreach ($this->tvaFields as $field) { - $this->markAsEncode($field); - } - - return $this; - } - - /** - * Пометить все поля как распакованные - * @return $this - */ - public function markAllDecode() - { - parent::markAllDecode(); - foreach ($this->tvaFields as $field) { - $this->markAsDecode($field); - } - - return $this; - } - - /** - * @param int $docId - */ - public function getDocumentGroups($docId = 0) - { - $out = array(); - $doc = $this->switchObject($docId); - if (null !== $doc->getID()) { - $doc_groups = $this->makeTable('document_groups'); - $docgroup_names = $this->makeTable('documentgroup_names'); - - $rs = $this->query("SELECT `dg`.`document_group`, `dgn`.`name` FROM {$doc_groups} as `dg` INNER JOIN {$docgroup_names} as `dgn` ON `dgn`.`id`=`dg`.`document_group` - WHERE `dg`.`document` = " . $doc->getID()); - while ($row = $this->modx->db->getRow($rs)) { - $out[$row['document_group']] = $row['name']; - } - - } - unset($doc); - - return $out; - } - - /** - * @param int $docId - * @param array $groupIds - * @return $this - */ - public function setDocumentGroups($docId = 0, $groupIds = array()) - { - if (!is_array($groupIds)) { - return $this; - } - if ($this->newDoc && $docId == 0) { - $this->groupIds = $groupIds; - } else { - $doc = $this->switchObject($docId); - if ($id = $doc->getID()) { - foreach ($groupIds as $gid) { - $this->query("REPLACE INTO {$this->makeTable('document_groups')} (`document_group`, `document`) VALUES ('{$gid}', '{$id}')"); - } - if (!$this->newDoc) { - $groupIds = empty($groupIds) ? '0' : implode(',', $groupIds); - $this->query("DELETE FROM {$this->makeTable('document_groups')} WHERE `document`={$id} AND `document_group` NOT IN ({$groupIds})"); - } - } - unset($doc); - $this->groupIds = array(); - } - - return $this; - } -} + 'document', + 'contentType' => 'text/html', + 'pagetitle' => 'New document', + 'longtitle' => '', + 'description' => '', + 'alias' => '', + 'link_attributes' => '', + 'published' => 1, + 'pub_date' => 0, + 'unpub_date' => 0, + 'parent' => 0, + 'isfolder' => 0, + 'introtext' => '', + 'content' => '', + 'richtext' => 1, + 'template' => 0, + 'menuindex' => 0, + 'searchable' => 1, + 'cacheable' => 1, + 'createdon' => 0, + 'createdby' => 0, + 'editedon' => 0, + 'editedby' => 0, + 'deleted' => 0, + 'deletedon' => 0, + 'deletedby' => 0, + 'publishedon' => 0, + 'publishedby' => 0, + 'menutitle' => '', + 'donthit' => 0, + 'privateweb' => 0, + 'privatemgr' => 0, + 'content_dispo' => 0, + 'hidemenu' => 0, + 'alias_visible' => 1 + ); + /** + * @var array + */ + private $table = array( + '"' => '_', + "'" => '_', + ' ' => '_', + '.' => '_', + ',' => '_', + 'а' => 'a', + 'б' => 'b', + 'в' => 'v', + 'г' => 'g', + 'д' => 'd', + 'е' => 'e', + 'ё' => 'e', + 'ж' => 'zh', + 'з' => 'z', + 'и' => 'i', + 'й' => 'y', + 'к' => 'k', + 'л' => 'l', + 'м' => 'm', + 'н' => 'n', + 'о' => 'o', + 'п' => 'p', + 'р' => 'r', + 'с' => 's', + 'т' => 't', + 'у' => 'u', + 'ф' => 'f', + 'х' => 'h', + 'ц' => 'c', + 'ч' => 'ch', + 'ш' => 'sh', + 'щ' => 'sch', + 'ь' => '', + 'ы' => 'y', + 'ъ' => '', + 'э' => 'e', + 'ю' => 'yu', + 'я' => 'ya', + 'А' => 'A', + 'Б' => 'B', + 'В' => 'V', + 'Г' => 'G', + 'Д' => 'D', + 'Е' => 'E', + 'Ё' => 'E', + 'Ж' => 'Zh', + 'З' => 'Z', + 'И' => 'I', + 'Й' => 'Y', + 'К' => 'K', + 'Л' => 'L', + 'М' => 'M', + 'Н' => 'N', + 'О' => 'O', + 'П' => 'P', + 'Р' => 'R', + 'С' => 'S', + 'Т' => 'T', + 'У' => 'U', + 'Ф' => 'F', + 'Х' => 'H', + 'Ц' => 'C', + 'Ч' => 'Ch', + 'Ш' => 'Sh', + 'Щ' => 'Sch', + 'Ь' => '', + 'Ы' => 'Y', + 'Ъ' => '', + 'Э' => 'E', + 'Ю' => 'Yu', + 'Я' => 'Ya', + ); + /** + * @var array массив ТВшек где name это ключ массива, а ID это значение + */ + private $tv = array(); + /** + * @var array массив ТВшек где ID это ключ массива, а name это значение + */ + private $tvid = array(); + /** + * @var array значения по умолчанию для ТВ параметров + */ + private $tvd = array(); + + /** @var array связи ТВ и шаблонов */ + private $tvTpl = array(); + + /** @var array параметры ТВ с массивами */ + protected $tvaFields = array(); + + /** + * Массив администраторов + * @var DLCollection + */ + private $managerUsers = null; + /** @var array группы документов */ + protected $groupIds = array(); + + /** + * modResource constructor. + * @param DocumentParser $modx + * @param bool $debug + */ + public function __construct($modx, $debug = false) + { + parent::__construct($modx, $debug); + $this->get_TV(); + $uTable = $this->makeTable("manager_users"); + $aTable = $this->makeTable("user_attributes"); + $query = "SELECT `u`.`id`, `a`.`email`, `u`.`username` FROM " . $aTable . " as `a` LEFT JOIN " . $uTable . " as `u` ON `u`.`id`=`a`.`internalKey`"; + $query = $this->query($query); + $this->managerUsers = new DLCollection($modx, empty($query) ? array() : $query); + } + + /** + * @return array + */ + public function toArrayMain() + { + $out = array_intersect_key(parent::toArray(), $this->default_field); + + return $out; + } + + /** + * @param bool $render + * @return array + */ + public function toArrayTV($render = false) + { + $out = array_diff_key(parent::toArray(), $this->default_field); + $tpl = $this->get('template'); + $tvTPL = APIHelpers::getkey($this->tvTpl, $tpl, array()); + foreach ($tvTPL as $item) { + if (isset($this->tvid[$item]) && !array_key_exists($this->tvid[$item], $out)) { + $value = $this->get($this->tvid[$item]); + $out[$this->tvid[$item]] = empty($value) ? $this->tvd[$this->tvid[$item]] : $value; + } + + } + if ($render) { + foreach ($out as $key => $val) { + $out[$key] = $this->renderTV($key); + } + } + + return $out; + } + + /** + * @param string $prefix + * @param string $suffix + * @param string $sep + * @param bool $render + * @return array + */ + public function toArray($prefix = '', $suffix = '', $sep = '_', $render = true) + { + $out = array_merge( + $this->toArrayMain(), + $this->toArrayTV($render), + array($this->fieldPKName() => $this->getID()) + ); + + return \APIhelpers::renameKeyArr($out, $prefix, $suffix, $sep); + } + + /** + * @return null|string + */ + public function getUrl() + { + $out = null; + $id = (int)$this->getID(); + if (! empty($id)) { + $out = $this->modx->makeUrl($id); + } + + return $out; + } + + /** + * @param string $main + * @param string $second + * @return mixed + */ + public function getTitle($main = 'menutitle', $second = 'pagetitle') + { + $title = $this->get($main); + if (empty($title) && $title !== '0') { + $title = $this->get($second); + } + + return $title; + } + + /** + * @return bool + */ + public function isWebShow() + { + $pub = ($this->get('publishedon') < time() && $this->get('published')); + $unpub = ($this->get('unpub_date') == 0 || $this->get('unpub_date') > time()); + $del = ($this->get('deleted') == 0 && ($this->get('deletedon') == 0 || $this->get('deletedon') > time())); + + return ($pub && $unpub && $del); + } + + /** + * @return $this + */ + public function touch() + { + $this->set('editedon', time()); + + return $this; + } + + /** + * @param $tvname + * @return null|string + */ + public function renderTV($tvname) + { + $out = null; + if ($this->getID() > 0) { + include_once MODX_MANAGER_PATH . "includes/tmplvars.format.inc.php"; + include_once MODX_MANAGER_PATH . "includes/tmplvars.commands.inc.php"; + $tvval = $this->get($tvname); + if ($this->isTVarrayField($tvname) && is_array($tvval)) { + $tvval = implode('||', $tvval); + } + $param = APIHelpers::getkey($this->tvd, $tvname, array()); + $display = APIHelpers::getkey($param, 'display', ''); + $display_params = APIHelpers::getkey($param, 'display_params', ''); + $type = APIHelpers::getkey($param, 'type', ''); + $out = getTVDisplayFormat($tvname, $tvval, $display, $display_params, $type, $this->getID(), ''); + } + + return $out; + } + + /** + * @param $key + * @return mixed + */ + public function get($key) + { + $out = parent::get($key); + if (isset($this->tv[$key])) { + $tpl = $this->get('template'); + $tvTPL = APIHelpers::getkey($this->tvTpl, $tpl, array()); + $tvID = APIHelpers::getkey($this->tv, $key, 0); + if (in_array($tvID, $tvTPL) && is_null($out)) { + $out = APIHelpers::getkey($this->tvd, $key, null); + $out = $out['default']; + } + } + + return $out; + } + + /** + * @param $key + * @param $value + * @return $this + */ + public function set($key, $value) + { + if ((is_scalar($value) || $this->isTVarrayField($key) || $this->isJsonField($key)) && is_scalar($key) && ! empty($key)) { + switch ($key) { + case 'donthit': + $value = (int)((bool)$value); + break; + case 'parent': + $value = (int)$value; + break; + case 'template': + $value = trim($value); + $value = $this->setTemplate($value); + break; + case 'published': + $value = (int)((bool)$value); + if ($value) { + $this->field['publishedon'] = time() + $this->modxConfig('server_offset_time'); + } + break; + case 'pub_date': + $value = $this->getTime($value); + if ($value > 0 && time() + $this->modxConfig('server_offset_time') > $value) { + $this->field['published'] = 1; + $this->field['publishedon'] = $value; + } + break; + case 'unpub_date': + $value = $this->getTime($value); + if ($value > 0 && time() + $this->modxConfig('server_offset_time') > $value) { + $this->field['published'] = 0; + $this->field['publishedon'] = 0; + } + break; + case 'deleted': + $value = (int)((bool)$value); + if ($value) { + $this->field['deletedon'] = time() + $this->modxConfig('server_offset_time'); + } else { + $this->field['deletedon'] = 0; + } + break; + case 'deletedon': + $value = $this->getTime($value); + if ($value > 0 && time() + $this->modxConfig('server_offset_time') < $value) { + $value = 0; + } + if ($value) { + $this->field['deleted'] = 1; + } + break; + case 'editedon': + case 'createdon': + case 'publishedon': + $value = $this->getTime($value); + break; + case 'publishedby': + case 'editedby': + case 'createdby': + case 'deletedby': + $value = $this->getUser($value, $this->default_field[$key]); + break; + } + $this->field[$key] = $value; + } + + return $this; + } + + /** + * @param $value + * @param int $default + * @return int|mixed + */ + protected function getUser($value, $default = 0) + { + $currentAdmin = APIHelpers::getkey($_SESSION, 'mgrInternalKey', 0); + $value = (int)$value; + if (! empty($value)) { + $by = $this->findUserBy($value); + $exists = $this->managerUsers->exists(function ($key, Helpers\Collection $val) use ($by, $value) { + return ($val->containsKey($by) && $val->get($by) === (string)$value); + }); + if (! $exists) { + $value = 0; + } + } + if (empty($value)) { + $value = empty($currentAdmin) ? $default : $currentAdmin; + } + + return $value; + } + + /** + * @param $data + * @return bool|string + */ + protected function findUserBy($data) + { + switch (true) { + case (is_int($data) || ((int)$data > 0 && (string)intval($data) === $data)): + $find = 'id'; + break; + case filter_var($data, FILTER_VALIDATE_EMAIL): + $find = 'email'; + break; + case is_scalar($data): + $find = 'username'; + break; + default: + $find = false; + } + + return $find; + } + + /** + * @param array $data + * @return $this + */ + public function create($data = array()) + { + $this->close(); + $fld = array(); + foreach ($this->tvd as $name => $tv) { + $fld[$name] = $tv['default']; + }; + $this->store($fld); + + $this->fromArray(array_merge($fld, $data)); + $this->set('createdby', null) + ->set('editedby', null) + ->set('createdon', time()) + ->touch(); + + return $this; + } + + /** + * @param $id + * @return $this + */ + public function edit($id) + { + $id = is_scalar($id) ? trim($id) : ''; + if ($this->getID() != $id) { + $this->close(); + $this->markAllEncode(); + $this->newDoc = false; + $result = $this->query("SELECT * from {$this->makeTable('site_content')} where `id`=" . (int)$id); + $this->fromArray($this->modx->db->getRow($result)); + $result = $this->query("SELECT * from {$this->makeTable('site_tmplvar_contentvalues')} where `contentid`=" . (int)$id); + while ($row = $this->modx->db->getRow($result)) { + $this->field[$this->tvid[$row['tmplvarid']]] = $row['value']; + } + $fld = array(); + foreach ($this->tvd as $name => $tv) { + if ($this->belongsToTemplate($this->tv[$name])) { + $fld[$name] = $tv['default']; + } + }; + $this->store(array_merge($fld, $this->field)); + if (empty($this->field['id'])) { + $this->id = null; + } else { + $this->id = $this->field['id']; + $this->set('editedby', null)->touch(); + $this->decodeFields(); + } + unset($this->field['id']); + } + + return $this; + } + + /** + * @param bool $fire_events + * @param bool $clearCache + * @return mixed + */ + public function save($fire_events = false, $clearCache = false) + { + $parent = null; + if ($this->field['pagetitle'] == '') { + $this->log['emptyPagetitle'] = 'Pagetitle is empty in
' . print_r($this->field, true) . '
'; + + return false; + } + + $uid = $this->modx->getLoginUserID('mgr'); + + if ( + empty($this->field['parent']) && + ! $this->modxConfig('udperms_allowroot') && + !($uid && isset($_SESSION['mgrRole']) && $_SESSION['mgrRole'] == 1) + ) { + $this->log['rootForbidden'] = 'Only Administrators can create documents in the root folder because udperms_allowroot setting is off'; + + return false; + } + + $this->set('alias', $this->getAlias()); + + $this->invokeEvent('OnBeforeDocFormSave', array( + 'mode' => $this->newDoc ? "new" : "upd", + 'id' => isset($this->id) ? $this->id : '', + 'doc' => $this->toArray(), + 'docObj' => $this + ), $fire_events); + + $fld = $this->encodeFields()->toArray(null, null, null, false); + foreach ($this->default_field as $key => $value) { + $tmp = $this->get($key); + if ($this->newDoc && (!is_int($tmp) && $tmp == '')) { + if ($tmp == $value) { + switch ($key) { + case 'cacheable': + $value = (int)$this->modxConfig('cache_default'); + break; + case 'template': + $value = (int)$this->modxConfig('default_template'); + break; + case 'published': + $value = (int)$this->modxConfig('publish_default'); + break; + case 'searchable': + $value = (int)$this->modxConfig('search_default'); + break; + case 'donthit': + $value = (int)$this->modxConfig('track_visitors'); + break; + } + } + $this->field[$key] = $value; + } + switch (true) { + case $key == 'parent': + $parent = (int)$this->get($key); + $q = $this->query("SELECT count(`id`) FROM {$this->makeTable('site_content')} WHERE `id`='{$parent}'"); + if ($this->modx->db->getValue($q) != 1) { + $parent = 0; + } + $this->field[$key] = $parent; + $this->Uset($key); + break; + case ($key == 'alias_visible' && ! $this->checkVersion('1.0.10', true)): + $this->eraseField('alias_visible'); + break; + default: + $this->Uset($key); + } + unset($fld[$key]); + } + + if (! empty($this->set)) { + if ($this->newDoc) { + $SQL = "INSERT into {$this->makeTable('site_content')} SET " . implode(', ', $this->set); + } else { + $SQL = "UPDATE {$this->makeTable('site_content')} SET " . implode(', ', + $this->set) . " WHERE `id` = " . $this->id; + } + $this->query($SQL); + + if ($this->newDoc) { + $this->id = $this->modx->db->getInsertId(); + } + + if ($parent > 0) { + $this->query("UPDATE {$this->makeTable('site_content')} SET `isfolder`='1' WHERE `id`='{$parent}'"); + } + } + + $_deleteTVs = $_insertTVs = array(); + foreach ($fld as $key => $value) { + if (empty($this->tv[$key]) || ! $this->isChanged($key) || ! $this->belongsToTemplate($this->tv[$key])) { + continue; + } elseif ($value === '' || is_null($value) || (isset($this->tvd[$key]) && $value == $this->tvd[$key]['default'])) { + $_deleteTVs[] = $this->tv[$key]; + } else { + $_insertTVs[$this->tv[$key]] = $this->escape($value); + } + } + + if (! empty($_insertTVs)) { + $values = array(); + foreach ($_insertTVs as $id => $value) { + $values[] = "({$this->id}, {$id}, '{$value}')"; + } + $values = implode(',', $values); + $this->query("INSERT INTO {$this->makeTable('site_tmplvar_contentvalues')} (`contentid`,`tmplvarid`,`value`) VALUES {$values} ON DUPLICATE KEY UPDATE + `value` = VALUES(`value`)"); + } + + if (! empty($_deleteTVs)) { + $ids = implode(',', $_deleteTVs); + $this->query("DELETE FROM {$this->makeTable('site_tmplvar_contentvalues')} WHERE `contentid` = '{$this->id}' AND `tmplvarid` IN ({$ids})"); + } + + if (!isset($this->mode)) { + $this->mode = $this->newDoc ? "new" : "upd"; + $this->newDoc = false; + } + + if (! empty($this->groupIds)) { + $this->setDocumentGroups($this->id, $this->groupIds); + } + $this->invokeEvent('OnDocFormSave', array( + 'mode' => $this->mode, + 'id' => isset($this->id) ? $this->id : '', + 'doc' => $this->toArray(), + 'docObj' => $this + ), $fire_events); + + + $this->modx->getAliasListing($this->id); + + if ($clearCache) { + $this->clearCache($fire_events); + } + $this->decodeFields(); + + return $this->id; + } + + /** + * @param $tvId + * @return bool + */ + protected function belongsToTemplate($tvId) + { + $template = $this->get('template'); + + return isset($this->tvTpl[$template]) && in_array($tvId, $this->tvTpl[$template]); + } + + /** + * @param $ids + * @return $this + * @throws Exception + */ + public function toTrash($ids) + { + $ignore = $this->systemID(); + $_ids = $this->cleanIDs($ids, ',', $ignore); + if (is_array($_ids) && $_ids != array()) { + $id = $this->sanitarIn($_ids); + $uid = (int)$this->modx->getLoginUserId(); + $deletedon = time() + $this->modxConfig('server_offset_time'); + $this->query("UPDATE {$this->makeTable('site_content')} SET `deleted`=1, `deletedby`={$uid}, `deletedon`={$deletedon} WHERE `id` IN ({$id})"); + } else { + throw new Exception('Invalid IDs list for mark trash:
' . print_r($ids,
+                    1) . '
please, check ignore list:
' . print_r($ignore, 1) . '
'); + } + + return $this; + } + + /** + * @param bool $fire_events + * @return $this + */ + public function clearTrash($fire_events = false) + { + $q = $this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `deleted`='1'"); + $_ids = $this->modx->db->getColumn('id', $q); + if (is_array($_ids) && $_ids != array()) { + $this->invokeEvent('OnBeforeEmptyTrash', array( + "ids" => $_ids + ), $fire_events); + + $id = $this->sanitarIn($_ids); + $this->query("DELETE from {$this->makeTable('site_content')} where `id` IN ({$id})"); + $this->query("DELETE from {$this->makeTable('site_tmplvar_contentvalues')} where `contentid` IN ({$id})"); + + $this->invokeEvent('OnEmptyTrash', array( + "ids" => $_ids + ), $fire_events); + } + + return $this; + } + + /** + * @param $ids + * @param int|bool $depth + * @return array + */ + public function children($ids, $depth) + { + $_ids = $this->cleanIDs($ids, ','); + if (is_array($_ids) && $_ids != array()) { + $id = $this->sanitarIn($_ids); + if (! empty($id)) { + $q = $this->query("SELECT `id` FROM {$this->makeTable('site_content')} where `parent` IN ({$id})"); + $id = $this->modx->db->getColumn('id', $q); + if ($depth > 0 || $depth === true) { + $id = $this->children($id, is_bool($depth) ? $depth : ($depth - 1)); + } + $_ids = array_merge($_ids, $id); + } + } + + return $_ids; + } + + /** + * @param string|array $ids + * @param bool $fire_events + * @return $this + * @throws Exception + */ + public function delete($ids, $fire_events = false) + { + $ids = $this->children($ids, true); + $_ids = $this->cleanIDs($ids, ',', $this->systemID()); + $this->invokeEvent('OnBeforeDocFormDelete', array( + 'ids' => $_ids + ), $fire_events); + $this->toTrash($_ids); + $this->invokeEvent('OnDocFormDelete', array( + 'ids' => $_ids + ), $fire_events); + + return $this; + } + + /** + * @return array + */ + private function systemID() + { + $ignore = array( + 0, //empty document + (int)$this->modxConfig('site_start'), + (int)$this->modxConfig('error_page'), + (int)$this->modxConfig('unauthorized_page'), + (int)$this->modxConfig('site_unavailable_page') + ); + $data = $this->query("SELECT DISTINCT setting_value FROM {$this->makeTable('web_user_settings')} WHERE `setting_name`='login_home' AND `setting_value`!=''"); + $data = $this->modx->db->makeArray($data); + foreach ($data as $item) { + $ignore[] = (int)$item['setting_value']; + } + + return array_unique($ignore); + + } + + /** + * @param $alias + * @return string + */ + protected function checkAlias($alias) + { + $alias = strtolower($alias); + if ($this->modxConfig('friendly_urls')) { + $_alias = $this->escape($alias); + if ((! $this->modxConfig('allow_duplicate_alias') && ! $this->modxConfig('use_alias_path')) || ($this->modxConfig('allow_duplicate_alias') && $this->modxConfig('use_alias_path'))) { + $flag = $this->modx->db->getValue($this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `alias`='{$_alias}' AND `parent`={$this->get('parent')} LIMIT 1")); + } else { + $flag = $this->modx->db->getValue($this->query("SELECT `id` FROM {$this->makeTable('site_content')} WHERE `alias`='{$_alias}' LIMIT 1")); + } + if (($flag && $this->newDoc) || (! $this->newDoc && $flag && $this->id != $flag)) { + $suffix = substr($alias, -2); + if (preg_match('/-(\d+)/', $suffix, $tmp) && isset($tmp[1]) && (int)$tmp[1] > 1) { + $suffix = (int)$tmp[1] + 1; + $alias = substr($alias, 0, -2) . '-' . $suffix; + } else { + $alias .= '-2'; + } + $alias = $this->checkAlias($alias); + } + } + + return $alias; + } + + /** + * @param $key + * @return bool + */ + public function issetField($key) + { + return (array_key_exists($key, $this->default_field) || (array_key_exists($key, $this->tv) && $this->belongsToTemplate($this->tv[$key]))); + } + + /** + * @param bool $reload + * @return $this + */ + protected function get_TV($reload = false) + { + $this->modx->_TVnames = $this->loadFromCache('_TVnames'); + if ($this->modx->_TVnames === false || empty($this->modx->_TVnames) || $reload) { + $this->modx->_TVnames = array(); + $result = $this->query('SELECT `id`,`name`,`default_text`,`type`,`display`,`display_params` FROM ' . $this->makeTable('site_tmplvars')); + while ($row = $this->modx->db->GetRow($result)) { + $this->modx->_TVnames[$row['name']] = array( + 'id' => $row['id'], + 'type' => $row['type'], + 'default' => $row['default_text'], + 'display' => $row['display'], + 'display_params' => $row['display_params'] + ); + } + $this->saveToCache($this->modx->_TVnames, '_TVnames'); + } + $arrayTypes = array('checkbox', 'listbox-multiple'); + $arrayTVs = array(); + foreach ($this->modx->_TVnames as $name => $data) { + $this->tvid[$data['id']] = $name; + $this->tv[$name] = $data['id']; + if (in_array($data['type'], $arrayTypes)) { + $arrayTVs[] = $name; + } + } + if (empty($this->tvaFields)) { + $this->tvaFields = $arrayTVs; + } + $this->loadTVTemplate()->loadTVDefault(array_values($this->tv)); + + return $this; + } + + /** + * @return $this + */ + protected function loadTVTemplate() + { + $this->tvTpl = $this->loadFromCache('_tvTpl'); + if ($this->tvTpl === false) { + $q = $this->query("SELECT `tmplvarid`, `templateid` FROM " . $this->makeTable('site_tmplvar_templates')); + $this->tvTpl = array(); + while ($item = $this->modx->db->getRow($q)) { + $this->tvTpl[$item['templateid']][] = $item['tmplvarid']; + } + $this->saveToCache($this->tvTpl, '_tvTpl'); + } + + return $this; + } + + /** + * @param array $tvId + * @return $this + */ + protected function loadTVDefault(array $tvId = array()) + { + if (is_array($tvId) && ! empty($tvId)) { + $this->tvd = array(); + foreach ($tvId as $id) { + $name = $this->tvid[$id]; + $this->tvd[$name] = $this->modx->_TVnames[$name]; + } + } + + return $this; + } + + /** + * @param $tpl + * @return int + * @throws Exception + */ + public function setTemplate($tpl) + { + if (!is_numeric($tpl) || $tpl != (int)$tpl) { + if (is_scalar($tpl)) { + $sql = "SELECT `id` FROM {$this->makeTable('site_templates')} WHERE `templatename` = '" . $this->escape($tpl) . "'"; + $rs = $this->query($sql); + if (! $rs || $this->modx->db->getRecordCount($rs) <= 0) { + throw new Exception("Template {$tpl} is not exists"); + } + $tpl = $this->modx->db->getValue($rs); + } else { + throw new Exception("Invalid template name: " . print_r($tpl, 1)); + } + } + + return (int)$tpl; + } + + /** + * @return string + */ + protected function getAlias() + { + if ($this->modxConfig('friendly_urls') && $this->modxConfig('automatic_alias') && $this->get('alias') == '') { + $alias = strtr($this->get('pagetitle'), $this->table); + } else { + if ($this->get('alias') != '') { + $alias = $this->get('alias'); + } else { + $alias = ''; + } + } + $alias = $this->modx->stripAlias($alias); + + return $this->checkAlias($alias); + } + + /** + * @param int $parent + * @param string $criteria + * @param string $dir + * @return $this + * + * Пересчет menuindex по полю таблицы site_content + */ + public function updateMenuindex($parent, $criteria = 'id', $dir = 'asc') + { + $dir = strtolower($dir) == 'desc' ? 'desc' : 'asc'; + if (is_integer($parent) && $criteria !== '') { + $this->query("SET @index := 0"); + $this->query("UPDATE {$this->makeTable('site_content')} SET `menuindex` = (@index := @index + 1) WHERE `parent`={$parent} ORDER BY {$criteria} {$dir}"); + } + + return $this; + } + + /** + * Устанавливает значение шаблона согласно системной настройке + * + * @return $this + */ + public function setDefaultTemplate() + { + $parent = $this->get('parent'); + $template = $this->modxConfig('default_template'); + switch ($this->modxConfig('auto_template_logic')) { + case 'sibling': + if (! $parent) { + $site_start = $this->modxConfig('site_start'); + $where = "sc.isfolder=0 AND sc.id!={$site_start}"; + $sibl = $this->modx->getDocumentChildren($parent, 1, 0, 'template', $where, 'menuindex', 'ASC', 1); + if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') { + $template = $sibl[0]['template']; + } + } else { + $sibl = $this->modx->getDocumentChildren($parent, 1, 0, 'template', 'isfolder=0', 'menuindex', + 'ASC', 1); + if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') { + $template = $sibl[0]['template']; + } else { + $sibl = $this->modx->getDocumentChildren($parent, 0, 0, 'template', 'isfolder=0', 'menuindex', + 'ASC', 1); + if (isset($sibl[0]['template']) && $sibl[0]['template'] !== '') { + $template = $sibl[0]['template']; + } + } + } + break; + case 'parent': + if ($parent) { + $_parent = $this->modx->getPageInfo($parent, 0, 'template'); + if (isset($_parent['template'])) { + $template = $_parent['template']; + } + } + break; + } + $this->set('template', $template); + + return $this; + } + + /** + * Декодирует конкретное поле + * @param string $field Имя поля + * @param bool $store обновить распакованное поле + * @return array ассоциативный массив с данными из json строки + */ + public function decodeField($field, $store = false) + { + $out = array(); + if ($this->isDecodableField($field)) { + $data = $this->get($field); + if ($this->isTVarrayField($field)) { + $out = explode('||', $data); + } else { + $out = jsonHelper::jsonDecode($data, array('assoc' => true), true); + } + } + if ($store) { + $this->field[$field] = $out; + $this->markAsDecode($field); + } + + return $out; + } + + /** + * Запаковывает конкретное поле в JSON + * @param string $field Имя поля + * @param bool $store обновить запакованное поле + * @return string|null json строка + */ + public function encodeField($field, $store = false) + { + $out = null; + if ($this->isEncodableField($field)) { + $data = $this->get($field); + if ($this->isTVarrayField($field)) { + $out = is_array($data) ? implode('||', $data) : (string)$data; + } else { + $out = json_encode($data); + } + } + if ($store) { + $this->field[$field] = $out; + $this->markAsEncode($field); + } + + return $out; + } + + /** + * Может ли содержать данное поле json массив + * @param string $field имя поля + * @return boolean + */ + public function isTVarrayField($field) + { + return (is_scalar($field) && in_array($field, $this->tvaFields)); + } + + /** + * Пометить все поля как запакованные + * @return $this + */ + public function markAllEncode() + { + parent::markAllEncode(); + foreach ($this->tvaFields as $field) { + $this->markAsEncode($field); + } + + return $this; + } + + /** + * Пометить все поля как распакованные + * @return $this + */ + public function markAllDecode() + { + parent::markAllDecode(); + foreach ($this->tvaFields as $field) { + $this->markAsDecode($field); + } + + return $this; + } + + /** + * @param int $docId + */ + public function getDocumentGroups($docId = 0) + { + $out = array(); + $doc = $this->switchObject($docId); + if (null !== $doc->getID()) { + $doc_groups = $this->makeTable('document_groups'); + $docgroup_names = $this->makeTable('documentgroup_names'); + + $rs = $this->query("SELECT `dg`.`document_group`, `dgn`.`name` FROM {$doc_groups} as `dg` INNER JOIN {$docgroup_names} as `dgn` ON `dgn`.`id`=`dg`.`document_group` + WHERE `dg`.`document` = " . $doc->getID()); + while ($row = $this->modx->db->getRow($rs)) { + $out[$row['document_group']] = $row['name']; + } + + } + unset($doc); + + return $out; + } + + /** + * @param int $docId + * @param array $groupIds + * @return $this + */ + public function setDocumentGroups($docId = 0, $groupIds = array()) + { + if (!is_array($groupIds)) { + return $this; + } + if ($this->newDoc && $docId == 0) { + $this->groupIds = $groupIds; + } else { + $doc = $this->switchObject($docId); + if ($id = $doc->getID()) { + foreach ($groupIds as $gid) { + $this->query("REPLACE INTO {$this->makeTable('document_groups')} (`document_group`, `document`) VALUES ('{$gid}', '{$id}')"); + } + if (! $this->newDoc) { + $groupIds = empty($groupIds) ? '0' : implode(',', $groupIds); + $this->query("DELETE FROM {$this->makeTable('document_groups')} WHERE `document`={$id} AND `document_group` NOT IN ({$groupIds})"); + } + } + unset($doc); + $this->groupIds = array(); + } + + return $this; + } +} diff --git a/assets/lib/MODxAPI/modUsers.php b/assets/lib/MODxAPI/modUsers.php index 0f22907dd5..64af4797dd 100644 --- a/assets/lib/MODxAPI/modUsers.php +++ b/assets/lib/MODxAPI/modUsers.php @@ -159,7 +159,7 @@ public function close() */ protected function getUserId($id) { $find = $this->findUser($id); - if ($find && !empty($this->userIdCache[$find])) { + if ($find && ! empty($this->userIdCache[$find])) { $id = $this->userIdCache[$find]; } else { $id = null; @@ -179,7 +179,7 @@ public function edit($id) $this->close(); $this->newDoc = false; - if (!$find = $this->findUser($id)) { + if (! $find = $this->findUser($id)) { $this->id = null; } else { $this->set('editedon', time()); @@ -218,7 +218,7 @@ protected function editQuery($find, $id) */ public function set($key, $value) { - if (is_scalar($value) && is_scalar($key) && !empty($key)) { + if (is_scalar($value) && is_scalar($key) && ! empty($key)) { switch ($key) { case 'password': $this->givenPassword = $value; @@ -269,7 +269,7 @@ public function save($fire_events = false, $clearCache = false) return false; } - if ($this->isChanged('username') && !$this->checkUnique('web_users', 'username')) { + if ($this->isChanged('username') && ! $this->checkUnique('web_users', 'username')) { $this->log['UniqueUsername'] = 'username not unique
' . print_r(
                 $this->get('username'),
                 true
@@ -278,7 +278,7 @@ public function save($fire_events = false, $clearCache = false)
             return false;
         }
 
-        if ($this->isChanged('username') && !$this->checkUnique('web_user_attributes', 'email', 'internalKey')) {
+        if ($this->isChanged('username') && ! $this->checkUnique('web_user_attributes', 'email', 'internalKey')) {
             $this->log['UniqueEmail'] = 'Email not unique 
' . print_r($this->get('email'), true) . '
'; return false; @@ -293,7 +293,7 @@ public function save($fire_events = false, $clearCache = false) $this->Uset($key, 'user'); unset($fld[$key]); } - if (!empty($this->set['user'])) { + if (! empty($this->set['user'])) { if ($this->newDoc) { $SQL = "INSERT into {$this->makeTable('web_users')} SET " . implode(', ', $this->set['user']); } else { @@ -313,7 +313,7 @@ public function save($fire_events = false, $clearCache = false) unset($fld['id']); foreach ($fld as $key => $value) { - if ($value == '' || !$this->isChanged($key)) { + if ($value == '' || ! $this->isChanged($key)) { continue; } $result = $this->query("SELECT `setting_value` FROM {$this->makeTable('web_user_settings')} WHERE `webuser` = '{$this->id}' AND `setting_name` = '{$key}'"); @@ -323,7 +323,7 @@ public function save($fire_events = false, $clearCache = false) $this->query("INSERT into {$this->makeTable('web_user_settings')} SET `webuser` = {$this->id},`setting_name` = '{$key}',`setting_value` = '{$value}';"); } } - if (!$this->newDoc && $this->givenPassword) { + if (! $this->newDoc && $this->givenPassword) { $this->invokeEvent('OnWebChangePassword', array( 'userObj' => $this, 'userid' => $this->id, @@ -334,7 +334,7 @@ public function save($fire_events = false, $clearCache = false) ), $fire_events); } - if (!empty($this->groupIds)) { + if (! empty($this->groupIds)) { $this->setUserGroups($this->id, $this->groupIds); } @@ -365,7 +365,7 @@ protected function saveQuery(array &$fld) $this->Uset($key, 'attribute'); unset($fld[$key]); } - if (!empty($this->set['attribute'])) { + if (! empty($this->set['attribute'])) { if ($this->newDoc) { $this->set('internalKey', $this->id)->Uset('internalKey', 'attribute'); $SQL = "INSERT into {$this->makeTable('web_user_attributes')} SET " . implode( @@ -467,7 +467,7 @@ public function checkBlock($id = 0) $b = $tmp->get('blocked'); $bu = $tmp->get('blockeduntil'); $ba = $tmp->get('blockedafter'); - $flag = (($b && !$bu && !$ba) || ($bu && $now < $bu) || ($ba && $now > $ba)); + $flag = (($b && ! $bu && ! $ba) || ($bu && $now < $bu) || ($ba && $now > $ba)); unset($tmp); return $flag; @@ -492,7 +492,7 @@ public function testAuth($id, $password, $blocker, $fire_events = false) } $flag = $pluginFlag = false; - if ((null !== $tmp->getID()) && (!$blocker || ($blocker && !$tmp->checkBlock($id))) + if ((null !== $tmp->getID()) && (! $blocker || ($blocker && ! $tmp->checkBlock($id))) ) { $eventResult = $this->getInvokeEventResult('OnWebAuthentication', array( 'userObj' => $this, @@ -508,7 +508,7 @@ public function testAuth($id, $password, $blocker, $fire_events = false) } else { $pluginFlag = (bool)$eventResult; } - if (!$pluginFlag) { + if (! $pluginFlag) { $flag = ($tmp->get('password') == $tmp->getPassword($password)); } } @@ -528,7 +528,7 @@ public function AutoLogin($fulltime = true, $cookieName = 'WebLoginPE', $fire_ev if (isset($_COOKIE[$cookieName])) { $cookie = explode('|', $_COOKIE[$cookieName], 4); if (isset($cookie[0], $cookie[1], $cookie[2]) && strlen($cookie[0]) == 32 && strlen($cookie[1]) == 32) { - if (!$fulltime && isset($cookie[4])) { + if (! $fulltime && isset($cookie[4])) { $fulltime = (int)$cookie[4]; } $this->close(); @@ -538,7 +538,7 @@ public function AutoLogin($fulltime = true, $cookieName = 'WebLoginPE', $fire_ev && null !== $this->getID() && $this->get('password') == $cookie[1] && $this->get('sessionid') == $cookie[2] - && !$this->checkBlock($this->getID()) + && ! $this->checkBlock($this->getID()) ) { $flag = $this->authUser($this->getID(), $fulltime, $cookieName, $fire_events); } @@ -554,7 +554,7 @@ public function AutoLogin($fulltime = true, $cookieName = 'WebLoginPE', $fire_ev */ public function logOut($cookieName = 'WebLoginPE', $fire_events = false) { - if (!$uid = $this->modx->getLoginUserID('web')) { + if (! $uid = $this->modx->getLoginUserID('web')) { return; } $params = array( @@ -598,7 +598,7 @@ protected function SessionHandler($directive, $cookieName, $remember = true) $_SESSION['webUsrConfigSet'] = array(); $_SESSION['webUserGroupNames'] = $this->getUserGroups(); $_SESSION['webDocgroups'] = $this->getDocumentGroups(); - if (!empty($remember)) { + if (! empty($remember)) { $this->setAutoLoginCookie($cookieName, $remember); } } @@ -650,7 +650,7 @@ public function isSecure() */ public function setAutoLoginCookie($cookieName, $remember = true) { - if (!empty($cookieName) && $this->getID() !== null) { + if (! empty($cookieName) && $this->getID() !== null) { $secure = $this->isSecure(); $remember = is_bool($remember) ? $this->getRememberTime() : (int)$remember; $cookieValue = array(md5($this->get('username')), $this->get('password'), $this->get('sessionid'), $remember); @@ -726,7 +726,7 @@ public function setUserGroups($userID = 0, $groupIds = array()) foreach ($groupIds as $gid) { $this->query("REPLACE INTO {$this->makeTable('web_groups')} (`webgroup`, `webuser`) VALUES ('{$gid}', '{$uid}')"); } - if (!$this->newDoc) { + if (! $this->newDoc) { $groupIds = empty($groupIds) ? '0' : implode(',', $groupIds); $this->query("DELETE FROM {$this->makeTable('web_groups')} WHERE `webuser`={$uid} AND `webgroup` NOT IN ({$groupIds})"); } diff --git a/assets/lib/Module/Action.php b/assets/lib/Module/Action.php index f06b6189f9..4a953439cb 100644 --- a/assets/lib/Module/Action.php +++ b/assets/lib/Module/Action.php @@ -95,7 +95,7 @@ protected static function _workValue($callback) self::$TPL = 'ajax/getValue'; $data = Helper::jeditable('data'); $out = array(); - if (!empty($data)) { + if (! empty($data)) { $modObj = self::$classTable; $modObj->edit($data['id']); if ($modObj->getID() !== null && ((is_object($callback) && ($callback instanceof \Closure)) || is_callable($callback))) { diff --git a/assets/lib/Module/Helper.php b/assets/lib/Module/Helper.php index 14d23f85f1..449ab3ffcd 100644 --- a/assets/lib/Module/Helper.php +++ b/assets/lib/Module/Helper.php @@ -70,7 +70,7 @@ public static function jeditable($key = 'id', $post = true) isset($request[$key]) && is_scalar($request[$key]) && preg_match("/^(.*)_(\d+)$/i", $request[$key], $match) ) ? $match : array(); - if (!empty($match)) { + if (! empty($match)) { $data = array( 'key' => $match[1], 'id' => $match[2] @@ -96,7 +96,7 @@ public static function curl($url, $data = '', $post = false, array $header = arr if ($post) { curl_setopt($ch, CURLOPT_POSTFIELDS, $data); } - if (!empty($header)) { + if (! empty($header)) { curl_setopt($ch, CURLOPT_HTTPHEADER, $header); } curl_setopt($ch, CURLOPT_TIMEOUT, 10); diff --git a/assets/lib/Module/Template.php b/assets/lib/Module/Template.php old mode 100755 new mode 100644 index 08ddcd1309..794d19484b --- a/assets/lib/Module/Template.php +++ b/assets/lib/Module/Template.php @@ -7,13 +7,13 @@ abstract class Template { /** - * @var \DocumentParser|null + * @var \DocumentParser */ - protected $_modx = null; + protected $_modx; /** - * @var null|string + * @var string */ - protected $_tplFolder = null; + protected $_tplFolder; /** * @var string */ @@ -47,7 +47,7 @@ abstract class Template * Template constructor. * @param \DocumentParser $modx * @param bool $ajax - * @param null $tplFolder + * @param null|string $tplFolder */ public function __construct(\DocumentParser $modx, $ajax = false, $tplFolder = null) { @@ -166,7 +166,7 @@ public function showBody($TplName, array $tplParams = array()) /** * @param $key * @param array $param - * @param null $default + * @param mixed $default * @return mixed|null */ public static function getParam($key, array $param = array(), $default = null) @@ -177,7 +177,7 @@ public static function getParam($key, array $param = array(), $default = null) /** * @param $action * @param array $data - * @param null $module + * @param null|int|string $module * @param bool $full * @return string */ diff --git a/assets/lib/SimpleTab/controller.abstract.php b/assets/lib/SimpleTab/controller.abstract.php index 544b36a986..691ff37147 100644 --- a/assets/lib/SimpleTab/controller.abstract.php +++ b/assets/lib/SimpleTab/controller.abstract.php @@ -72,7 +72,7 @@ public function remove() $ids = isset($_POST['ids']) ? (string)$_POST['ids'] : ''; $ids = isset($_POST['id']) ? (string)$_POST['id'] : $ids; $out['success'] = false; - if (!empty($ids)) { + if (! empty($ids)) { if ($this->data->deleteAll($ids, $this->rid)) { $out['success'] = true; } @@ -90,7 +90,7 @@ public function place() $ids = isset($_POST['ids']) ? (string)$_POST['ids'] : ''; $dir = isset($_POST['dir']) ? $_POST['dir'] : 'top'; $out['success'] = false; - if (!empty($ids)) { + if (! empty($ids)) { if ($this->data->place($ids, $dir, $this->rid)) { $out['success'] = true; } @@ -125,7 +125,7 @@ public function reorder() */ public function listing() { - if (!$this->rid) { + if (! $this->rid) { $this->isExit = true; return; diff --git a/assets/lib/SimpleTab/plugin.class.php b/assets/lib/SimpleTab/plugin.class.php index 0b9b663881..2379ba7183 100644 --- a/assets/lib/SimpleTab/plugin.class.php +++ b/assets/lib/SimpleTab/plugin.class.php @@ -102,10 +102,9 @@ public function checkPermissions() $templates = isset($this->params['templates']) ? explode(',', $this->params['templates']) : false; $roles = isset($this->params['roles']) ? explode(',', $this->params['roles']) : false; - $tplFlag = ($this->checkTemplate && !$templates || ($templates && !in_array( - $this->params['template'], - $templates - ))); + $tplFlag = ($this->checkTemplate && ( + ! $templates || ($templates && !in_array($this->params['template'],$templates)) + )); $documents = isset($this->params['documents']) ? explode(',', $this->params['documents']) : false; $docFlag = ($this->checkId && $tplFlag) ? !($documents && in_array($this->params['id'], $documents)) : $tplFlag; @@ -121,9 +120,9 @@ public function checkPermissions() */ public function prerender() { - if (!$this->checkTable()) { + if (! $this->checkTable()) { $result = $this->createTable(); - if (!$result) { + if (! $result) { $this->modx->logEvent(0, 3, "Cannot create {$this->table} table.", $this->pluginName); return; @@ -184,7 +183,7 @@ public function getTplPlaceholders() */ public function render() { - if (!$this->checkPermissions()) { + if (! $this->checkPermissions()) { $output = $this->prerender(); if ($output !== false) { $ph = $this->getTplPlaceholders(); @@ -205,7 +204,7 @@ public function render() */ public function renderEmpty() { - if (!$this->checkPermissions()) { + if (! $this->checkPermissions()) { $tpl = MODX_BASE_PATH . $this->emptyTpl; if ($this->fs->checkFile($tpl)) { $output = '[+js+]' . file_get_contents($tpl); @@ -249,9 +248,9 @@ public function registerEvents($events = array(), $eventsType = '6') $eventsTable = $this->modx->getFullTableName('system_eventnames'); foreach ($events as $event) { $result = $this->modx->db->select('`id`', $eventsTable, "`name` = '{$event}'"); - if (!$this->modx->db->getRecordCount($result)) { + if (! $this->modx->db->getRecordCount($result)) { $sql = "INSERT INTO {$eventsTable} VALUES (NULL, '{$event}', '{$eventsType}', '{$this->pluginName} Events')"; - if (!$this->modx->db->query($sql)) { + if (! $this->modx->db->query($sql)) { $this->modx->logEvent(0, 3, "Cannot register {$event} event.", $this->pluginName); } } diff --git a/assets/lib/SimpleTab/table.abstract.php b/assets/lib/SimpleTab/table.abstract.php index dd2d57f45c..7dfe634bf3 100644 --- a/assets/lib/SimpleTab/table.abstract.php +++ b/assets/lib/SimpleTab/table.abstract.php @@ -123,7 +123,7 @@ public function deleteThumb($url, $cache = false) } $dir = $this->fs->takeFileDir($url); $iterator = new \FilesystemIterator($dir); - if (!$iterator->valid()) { + if (! $iterator->valid()) { rmdir($dir); } if ($cache) { diff --git a/assets/lib/class.modxRTEbridge.php b/assets/lib/class.modxRTEbridge.php index 448c5fa28b..5279133f8b 100755 --- a/assets/lib/class.modxRTEbridge.php +++ b/assets/lib/class.modxRTEbridge.php @@ -452,11 +452,11 @@ public function renderConfigRawString() // Get final value of editor-config public function determineValue($key, $conf=NULL) { - if($conf == NULL) { $conf = $this->themeConfig[$key]; }; + if($conf == NULL && isset($this->themeConfig[$key])) { $conf = $this->themeConfig[$key]; }; $value = isset($this->themeConfig[$key]['bridged']) ? $this->themeConfig[$key]['bridged'] : NULL; $value = $value === NULL && isset($this->themeConfig[$key]['force']) ? $this->themeConfig[$key]['force'] : $value; - $value = $value === NULL ? $this->themeConfig[$key]['value'] : $value; + $value = $value === NULL && isset($this->themeConfig[$key]['value']) ? $this->themeConfig[$key]['value'] : $value; if(!in_array($conf['type'], array('boolean','bool'))) { if ($value === '' && $conf['empty'] === false) { // Empty values not allowed @@ -966,7 +966,7 @@ public function getTemplateChunkList() $templatesArr = array(); - if ($modx->getLoginUserType() === 'manager') { + if ($modx->getLoginUserType() === 'manager' || IN_MANAGER_MODE) { $modx->getSettings(); $ids = $modx->config[$this->editorKey.'_template_docs']; @@ -1017,7 +1017,7 @@ public function saveContentProcessor($rid, $ppPluginName, $ppEditableIds='editab { global $modx; - if ($rid > 0 && $modx->getLoginUserType() === 'manager') + if ($rid > 0 && ($modx->getLoginUserType() === 'manager' || IN_MANAGER_MODE)) { if(!isset($_POST['secHash']) || !isset($_SESSION['modxRTEbridge']['secHash'][$rid]) || diff --git a/assets/lib/class.summary.php b/assets/lib/class.summary.php index 9ec665d7bb..0e325690bd 100644 --- a/assets/lib/class.summary.php +++ b/assets/lib/class.summary.php @@ -41,9 +41,9 @@ class SummaryText /** * SummaryText constructor. - * @param $text - * @param $action - * @param null $break + * @param string $text + * @param string $action + * @param null|string $break */ public function __construct($text, $action, $break = null) { @@ -214,7 +214,7 @@ protected function html_substr($posttext, $minimum_length = 200, $length_offset } else { $next_char = ""; } - if (!$quotes_on) { + if (! $quotes_on) { // Check if it's a tag // On a "<" add 3 if it's an opening tag (like ) @@ -354,7 +354,7 @@ private function closeTags($text) if (mb_strstr($tag, ' ', 'UTF-8')) { $tag = mb_substr($tag, 0, strpos($tag, ' '), 'UTF-8'); } - if (!mb_stristr($tag, 'br', 'UTF-8') && !mb_stristr($tag, 'img', 'UTF-8') && !empty($tag)) { + if (! mb_stristr($tag, 'br', 'UTF-8') && ! mb_stristr($tag, 'img', 'UTF-8') && ! empty($tag)) { $endTags .= ''; } } diff --git a/assets/modules/docmanager/tv.ajax.php b/assets/modules/docmanager/tv.ajax.php index b51ce802df..bf3d2f7dbd 100755 --- a/assets/modules/docmanager/tv.ajax.php +++ b/assets/modules/docmanager/tv.ajax.php @@ -93,7 +93,7 @@ function renderFormElement($field_type, $field_id, $default_text, $field_element case "dropdown": // handler for select boxes $field_html .= ''; $index_list = ParseIntputOptions(ProcessTVCommand($field_elements, $field_id)); - while (list($item, $itemvalue) = each($index_list)) { + foreach($index_list as $item => $itemvalue) { list($item, $itemvalue) = (is_array($itemvalue)) ? $itemvalue : explode("==", $itemvalue); if (strlen($itemvalue) == 0) { $itemvalue = $item; @@ -118,7 +118,7 @@ function renderFormElement($field_type, $field_id, $default_text, $field_element $field_value = explode("||", $field_value); $field_html .= ' according to the hint selection state + > input_autoComplt_blurEvtHandle, input_autoComplt_keyEvtHandle : The event handle + > input_autoComplt_inputEvtHandleMobile : The event handle for the mobile mode + [ Public ] + > setHintsFetcher, setListener, config, setStyles, close, enable, disable, destroy : Refe to the Public APIs above + */ + input.autoComplt = {}; + + var + input_autoComplt_delay = _CONST.autoCompltDelay, + input_autoComplt_enabled = true, + input_autoComplt_currentTarget = '', + input_autoComplt_hintsFetcher = null, + input_autoComplt_listenerMap = null, + input_autoComplt_list = new _AutoCompltList(input), + /* + */ + input_autoComplt_startFetcher = function() { + + if (input.value.length > 0 + && input_autoComplt_enabled + && typeof input_autoComplt_hintsFetcher == 'function' + && input_autoComplt_currentTarget !== input.value // If equals, it means we've already been searching for the hints for the same value + ) { + + var fetcherCaller = { + + that: input, + + // Record the autocomplete target for this fetching job + compltTarget: (input_autoComplt_currentTarget = input.value), + + compltTargetMatchCurrentTarget: function() { + // If the user's input has changed during the fetching, this fetching job is useless. + // So only when the user's input doesn't change, we will return true to indicate proceeding further. + return (fetcherCaller.compltTarget === input_autoComplt_currentTarget); + }, + + call: function() { + + if (fetcherCaller.compltTargetMatchCurrentTarget()) { + + input_autoComplt_hintsFetcher.call( + fetcherCaller.that, + fetcherCaller.compltTarget, + fetcherCaller.openHint + ); + } + }, + + openHint: function(hints) { + if (fetcherCaller.compltTargetMatchCurrentTarget()) { + + if (input_autoComplt_list.putHints(hints)) { + input_autoComplt_list.open(); + } else { + fetcherCaller.that.autoComplt.close(); + } + } + } + }; + + setTimeout(fetcherCaller.call, input_autoComplt_delay); + } + }, + /* + */ + input_autoComplt_compltInput = function() { + + if (input_autoComplt_enabled) { + + var hint = input_autoComplt_list.getPicked(); + + if (hint) { + input.value = hint.innerHTML; + } else { + // If no hint is selected, just use the original user input to autocomplete + input.value = input_autoComplt_currentTarget; + } + } + }, + /* + */ + input_autoComplt_blurEvtHandle = function(e) { + + if (input_autoComplt_list.mouseOnList) { + // If the mouse is on the autocomplete list, do not close the list + // and still need to focus on the input. + input.focus(); + input_autoComplt_list.mouseOnList = false; // Assign false for the next detection + } else { + + if (input_autoComplt_list.isOpen()) { + input.autoComplt.close(_CONST.hiddenArg_close_list_n_make_final_selection); + } + } + }, + /* + */ + input_autoComplt_keyEvtHandle = function(e) { + + if (_getAppropriateMode() === _CONST.modeMobile) return; // Let this::input_autoComplt_inputEvtHandleMobile handle + + e = _normalizeEvt(e); + + if (input_autoComplt_enabled) { + if (e.type == 'keydown' + && input_autoComplt_list.isOpen() + && (e.keyCode === _CONST.keyCode.up || e.keyCode === _CONST.keyCode.down) + ) { + // At the case that the hint list is open ans user is walking thru the hints. + // Let's try to autocomplete the input by the selected input. + + var hint = input_autoComplt_list.getPicked(); + + if (e.keyCode === _CONST.keyCode.up) { + + if (!hint) { + // If none is selected, then pick the last hint + input_autoComplt_list.pick(-1); + } else if (hint.previousSibling) { + // If some hint is selected and the previous hint exists, then pick the previous hint + input_autoComplt_list.pick(hint.previousSibling); + } else { + // If some hint is selected but the previous hint doesn't exists, then unpick all + input_autoComplt_list.unpick(); + } + + } else if (e.keyCode === _CONST.keyCode.down) { + + if (!hint) { + // If none is selected, then pick the first hint + input_autoComplt_list.pick(0); + } else if (hint.nextSibling) { + // If some hint is selected and the next hint exists, then pick the next hint + input_autoComplt_list.pick(hint.nextSibling); + } else { + // If some hint is selected but the next hint doesn't exists, then unpick all + input_autoComplt_list.unpick(); + } + + } + + input_autoComplt_list.autoScroll(); + + input_autoComplt_compltInput(); + + } + else if (e.type == 'keyup') { + + var startFetching = false; + + switch (e.keyCode) { + case _CONST.keyCode.up: + case _CONST.keyCode.down: + if (input_autoComplt_list.isOpen()) { + // We have handled this 2 key codes onkeydown, so must do nothing here + } else { + startFetching = true; + } + break; + + case _CONST.keyCode.esc: + if (input_autoComplt_list.isOpen()) { + // When pressing the ESC key, let's resume back to the original user input + input.value = input_autoComplt_currentTarget; + input.autoComplt.close(_CONST.hiddenArg_close_list_n_make_final_selection); + } + break; + + case _CONST.keyCode.enter: + if (input_autoComplt_list.isOpen()) { + // When pressing the enter key, let's try autocomplete + input_autoComplt_compltInput(); + input.autoComplt.close(_CONST.hiddenArg_close_list_n_make_final_selection); + } + break; + + default: + startFetching = true; + break; + } + + if (startFetching) { + if (input.value.length > 0) { + input_autoComplt_startFetcher(); + } else { + input.autoComplt.close(); + } + } + } + } + }, + /* + */ + input_autoComplt_inputEvtHandleMobile = function(e) { + + if (_getAppropriateMode() === _CONST.modePC) return; // Let this::input_autoComplt_keyEvtHandle handle + + if (input.value.length > 0) { + input_autoComplt_startFetcher(); + } else { + input.autoComplt.close(); + } + }, + /* Arg: + name = Refer to _CONST.listenersSupported + */ + input_autoComplt_invokeListener = function(name) { + + if (input_autoComplt_listenerMap != null && typeof input_autoComplt_listenerMap[name] == 'function') { + + input_autoComplt_listenerMap[name].call(input); + } + }; + + input.autoComplt.setHintsFetcher = function(hintsFetcher) { + if (hintsFetcher === null || typeof hintsFetcher == 'function') { + input_autoComplt_hintsFetcher = hintsFetcher; + return true; + } + return false; + }; + + input.autoComplt.setListener = function(name, listener) { + + if ((listener === null || typeof listener == 'function') && _CONST.listenersSupported.indexOf(name) >= 0) { + + if (input_autoComplt_listenerMap == null) input_autoComplt_listenerMap = {}; + + input_autoComplt_listenerMap[name] = listener; + + return true; + } + + return false; + }; + + input.autoComplt.setStyles = function(targetClass, styles) { + + var tStyles, + adjStyleAttrs, + newStyles = false; + + // Let's find out which the target UI part is being set + switch (targetClass) { + case _CONST.autoCompltListClass: + tStyles = input_autoComplt_list.styles.autoCompltList; + adjStyleAttrs = _CONST.adjStyleAttrs.autoCompltList; + break; + + case _CONST.autoCompltHintClass: + tStyles = input_autoComplt_list.styles.autoCompltHint; + adjStyleAttrs = _CONST.adjStyleAttrs.autoCompltHint; + break; + + case _CONST.autoCompltHintSelectedClass: + tStyles = input_autoComplt_list.styles.autoCompltHintSelected; + adjStyleAttrs = _CONST.adjStyleAttrs.autoCompltHintSelected; + break; + } + + if (styles instanceof Object && tStyles && adjStyleAttrs) { + + for (var i = 0; i < adjStyleAttrs.length; i++) { + + if (typeof styles[adjStyleAttrs[i]] == 'string' || typeof styles[adjStyleAttrs[i]] == 'number') { // A simple type checking + if (!newStyles) { + newStyles = {}; + } + newStyles[adjStyleAttrs[i]] = tStyles[adjStyleAttrs[i]] = styles[adjStyleAttrs[i]]; + } + + } + + } + + return newStyles; + }; + + input.autoComplt.config = function(params) { + + var pms = false; + + if (params instanceof Object) { + + var buf; + + // Config the fetching delay timing + // + if (params.delay !== undefined && (buf = Math.floor(params.delay)) > 0) { + + if (!pms) pms = {}; + + input_autoComplt_delay = pms.delay = buf; + } + + // Config the max number of displayed hints + // + if (params.maxHintNum !== undefined && (buf = Math.floor(params.maxHintNum)) > 0) { + + if (!pms) pms = {}; + + input_autoComplt_list.maxHintNum = pms.maxHintNum = buf; + } + } + return pms; + }; + + input.autoComplt.close = function() { + + input_autoComplt_currentTarget = ''; // Closing means no need for autocomplete hint so no autocomplete target either + + input_autoComplt_list.close(); + + if (input_autoComplt_enabled + && input.value !== '' + && arguments[0] === _CONST.hiddenArg_close_list_n_make_final_selection + ) { + + input_autoComplt_invokeListener('select'); + } + }; + + input.autoComplt.enable = function() { + input_autoComplt_enabled = true; + }; + + input.autoComplt.disable = function() { + input_autoComplt_enabled = false; + this.close(); + }; + + input.autoComplt.destroy = function() { + _rmEvent(input, 'blur', input_autoComplt_blurEvtHandle); + _rmEvent(input, 'keyup', input_autoComplt_keyEvtHandle); + _rmEvent(input, 'keydown', input_autoComplt_keyEvtHandle); + this.disable(); + delete input.autoComplt; + }; + + input_autoComplt_list.onMouseSelectionListener = function() { + + input_autoComplt_compltInput(); + + input.autoComplt.close(_CONST.hiddenArg_close_list_n_make_final_selection); + }; + + _addEvt(input, 'blur', input_autoComplt_blurEvtHandle); + _addEvt(input, 'keyup', input_autoComplt_keyEvtHandle); + _addEvt(input, 'keydown', input_autoComplt_keyEvtHandle); + + _addEvt(input, 'input', input_autoComplt_inputEvtHandleMobile); + + if (params instanceof Object) { + input.autoComplt.config(params); + input.autoComplt.setHintsFetcher(params.hintsFetcher); + } + + return input; + } + return null; + } + + }; + + return publicProps; +}()); + +tinymce.PluginManager.add('modxlink', function(editor) { + function createLinkList(callback) + { + return function() { + var linkList = editor.settings.link_list; + + if (typeof linkList == 'string') { + tinymce.util.XHR.send({ + url: linkList, + success: function(text) { + callback(tinymce.util.JSON.parse(text)); + } + }); + } else if (typeof linkList == 'function') { + linkList(callback); + } else { + callback(linkList); + } + }; + } + + function buildListItems(inputList, itemCallback, startItems) + { + function appendItems(values, output) + { + output = output || []; + + tinymce.each(values, function(item) { + var menuItem = {text: item.text || item.title}; + + if (item.menu) { + menuItem.menu = appendItems(item.menu); + } else { + menuItem.value = item.value; + + if (itemCallback) { + itemCallback(menuItem); + } + } + + output.push(menuItem); + }); + + return output; + } + + return appendItems(inputList, startItems || []); + } + + function showDialog(linkList) + { + + if (parent.tree) { + parent.tree.ca = 'disabled'; // Disable Modx-TreeAction, resetted on onOk or OnCancel + checkModxTreeUpdate.call(this); // Watch Modx-Tree for changes and update URL-field + } + ; + + var data = {}, selection = editor.selection, dom = editor.dom, selectedElm, anchorElm, initialText; + var win, onlyText, textListCtrl, linkListCtrl, relListCtrl, targetListCtrl, classListCtrl, linkTitleCtrl, value; + + function linkListChangeHandler(e) + { + var textCtrl = win.find('#text'); + + if (!textCtrl.value() || (e.lastControl && textCtrl.value() == e.lastControl.text())) { + textCtrl.value(e.control.text()); + } + + win.find('#href').value(e.control.value()); + } + + function buildAnchorListControl(url) + { + var anchorList = []; + + tinymce.each(editor.dom.select('a:not([href])'), function(anchor) { + var id = anchor.name || anchor.id; + + if (id) { + anchorList.push({ + text: id, + value: '#' + id, + selected: url.indexOf('#' + id) != -1 + }); + } + }); + + if (anchorList.length) { + anchorList.unshift({text: 'None', value: ''}); + + return { + name: 'anchor', + type: 'listbox', + label: 'Anchors', + values: anchorList, + onselect: linkListChangeHandler + }; + } + } + + function updateText() + { + if (!initialText && data.text.length === 0 && onlyText) { + this.parent().parent().find('#text')[0].value(this.value()); + } + } + + function urlChange(e) + { + var meta = e.meta || {}; + + if (linkListCtrl) { + linkListCtrl.value(editor.convertURL(this.value(), 'href')); + } + + tinymce.each(e.meta, function(value, key) { + win.find('#' + key).value(value); + }); + + if (!meta.text) { + updateText.call(this); + } + } + + function isOnlyTextSelected(anchorElm) + { + var html = selection.getContent(); + + // Partial html and not a fully selected anchor element + if (/]+>[^<]+<\/a>$/.test(html) || html.indexOf('href=') == -1)) { + return false; + } + + if (anchorElm) { + var nodes = anchorElm.childNodes, i; + + if (nodes.length === 0) { + return false; + } + + for (i = nodes.length - 1; i >= 0; i--) { + if (nodes[i].nodeType != 3) { + return false; + } + } + } + + return true; + } + + selectedElm = selection.getNode(); + anchorElm = dom.getParent(selectedElm, 'a[href]'); + onlyText = isOnlyTextSelected(); + + data.text = initialText = anchorElm ? (anchorElm.innerText || anchorElm.textContent) : selection.getContent({format: 'text'}); + data.href = anchorElm ? dom.getAttrib(anchorElm, 'href') : ''; + + if (anchorElm) { + data.target = dom.getAttrib(anchorElm, 'target'); + } else if (editor.settings.default_link_target) { + data.target = editor.settings.default_link_target; + } + + if ((value = dom.getAttrib(anchorElm, 'rel'))) { + data.rel = value; + } + + if ((value = dom.getAttrib(anchorElm, 'class'))) { + data['class'] = value; + } + + if ((value = dom.getAttrib(anchorElm, 'title'))) { + data.title = value; + } + + if (onlyText) { + textListCtrl = { + name: 'text', + type: 'textbox', + size: 40, + label: 'Text to display', + id: 'text-to-display', + onchange: function() { + data.text = this.value(); + } + }; + } + + if (linkList) { + linkListCtrl = { + type: 'listbox', + label: 'Link list', + values: buildListItems( + linkList, + function(item) { + item.value = editor.convertURL(item.value || item.url, 'href'); + }, + [{text: 'None', value: ''}] + ), + onselect: linkListChangeHandler, + value: editor.convertURL(data.href, 'href'), + onPostRender: function() { + linkListCtrl = this; + } + }; + } + + if (editor.settings.target_list !== false) { + if (!editor.settings.target_list) { + editor.settings.target_list = [ + {text: 'None', value: ''}, + {text: 'New window', value: '_blank'} + ]; + } + + targetListCtrl = { + name: 'target', + type: 'listbox', + label: 'Target', + values: buildListItems(editor.settings.target_list) + }; + } + + if (editor.settings.rel_list) { + relListCtrl = { + name: 'rel', + type: 'listbox', + label: 'Rel', + values: buildListItems(editor.settings.rel_list) + }; + } + + if (editor.settings.link_class_list) { + classListCtrl = { + name: 'class', + type: 'listbox', + label: 'Class', + values: buildListItems( + editor.settings.link_class_list, + function(item) { + if (item.value) { + item.textStyle = function() { + return editor.formatter.getCssText({inline: 'a', classes: [item.value]}); + }; + } + } + ) + }; + } + + if (editor.settings.link_title !== false) { + linkTitleCtrl = { + name: 'title', + type: 'textbox', + label: 'Title', + value: data.title + }; + } + + win = editor.windowManager.open({ + title: 'Insert link', + data: data, + body: [ + { + name: 'href', + type: 'FileImagePicker', + filetype: 'file', + size: 40, + autofocus: true, + label: 'Url', + id: 'link-href', + onchange: urlChange, + onkeyup: updateText + }, + { + name: 'search', + type: 'textbox', + label: 'Search in EVO', + id: 'link-search' + }, + textListCtrl, + linkTitleCtrl, + buildAnchorListControl(data.href), + linkListCtrl, + relListCtrl, + targetListCtrl, + classListCtrl + ], + onSubmit: function(e) { + /*eslint dot-notation: 0*/ + var href; + + data = tinymce.extend(data, e.data); + href = data.href; + + // Delay confirm since onSubmit will move focus + function delayedConfirm(message, callback) + { + var rng = editor.selection.getRng(); + + window.setTimeout(function() { + editor.windowManager.confirm(message, function(state) { + editor.selection.setRng(rng); + callback(state); + }); + }, 0); + } + + function insertLink() + { + + // Reset Modx-TreeAction + if (parent.tree) { + parent.tree.ca = ''; + clearTimeout(checkModxTreeUpdateInterval); + } + ; + + var linkAttrs = { + href: href, + target: data.target ? data.target : null, + rel: data.rel ? data.rel : null, + 'class': data['class'] ? data['class'] : null, + title: data.title ? data.title : null + }; + + if (anchorElm) { + editor.focus(); + + if (onlyText && data.text != initialText) { + if ('innerText' in anchorElm) { + anchorElm.innerText = data.text; + } else { + anchorElm.textContent = data.text; + } + } + + dom.setAttribs(anchorElm, linkAttrs); + + selection.select(anchorElm); + editor.undoManager.add(); + } else { + if (onlyText) { + editor.insertContent(dom.createHTML('a', linkAttrs, dom.encode(data.text))); + } else { + editor.execCommand('mceInsertLink', false, linkAttrs); + } + } + } + + if (!href) { + editor.execCommand('unlink'); + return; + } + + // Is email and not //user@domain.com + if (href.indexOf('@') > 0 && href.indexOf('//') == -1 && href.indexOf('mailto:') == -1) { + delayedConfirm( + 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?', + function(state) { + if (state) { + href = 'mailto:' + href; + } + + insertLink(); + } + ); + + return; + } + + // Is not protocol prefixed + if ((editor.settings.link_assume_external_targets && !/^\w+:/i.test(href)) || + (!editor.settings.link_assume_external_targets && /^\s*www\./i.test(href))) { + delayedConfirm( + 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?', + function(state) { + if (state) { + href = 'http://' + href; + } + + insertLink(); + } + ); + + return; + } + + insertLink(); + }, + onClose: function(e) { + // Reset Modx-TreeAction + if (parent.tree) { + parent.tree.ca = ''; + clearTimeout(checkModxTreeUpdateInterval); + } + ; + } + }); + + var input = document.querySelector('#link-search'), _resultDataset = {}; + autoComplt.enable(input, { + // the hintsFetcher is your customized function which searchs the proper autocomplete hints based on the user's input value. + hintsFetcher: function(v, openList) { + _resultDataset = {}; + var xhr = new XMLHttpRequest(), _link = encodeURI(tinymce4_baseUrl + 'tinymce/plugins/modxlink/search.php' + '?q=' + v); + xhr.open('GET', _link); + xhr.onload = function() { + if (xhr.status === 200) { + //alert(xhr.responseText); + var _results = JSON.parse(xhr.responseText), _e = []; + for (var i = 0; i < Object.keys(_results).length; i++) { + _resultDataset[_results[i].pagetitle] = _results[i]; + _e.push(_results[i].pagetitle); + } + openList(_e); + } else { + console.error('ajax error', _link); + } + }; + xhr.send(); + } + }); + input.autoComplt.setListener('select', function(e, r) { + var _a = document.querySelector('#link-href input'), _title = document.querySelector('#text-to-display'); + _a.value = '[~' + _resultDataset[this.value].id + '~]'; + if (_title.value == '') _title.value = _resultDataset[this.value].title; + }); + + } + + editor.addButton('link', { + icon: 'link', + tooltip: 'Insert/edit link', + shortcut: 'Meta+K', + onclick: createLinkList(showDialog), + stateSelector: 'a[href]' + }); + + editor.addButton('unlink', { + icon: 'unlink', + tooltip: 'Remove link', + cmd: 'unlink', + stateSelector: 'a[href]' + }); + + editor.addShortcut('Meta+K', '', createLinkList(showDialog)); + editor.addCommand('mceLink', createLinkList(showDialog)); + + this.showDialog = showDialog; + + editor.addMenuItem('link', { + icon: 'link', + text: 'Insert/edit link', + shortcut: 'Meta+K', + onclick: createLinkList(showDialog), + stateSelector: 'a[href]', + context: 'insert', + prependToContext: true + }); + tinymce.ui.Factory.add('FileImagePicker',tinymce.ui.ComboBox.extend({ + init: function(settings) { + var self = this, editor = tinymce.activeEditor, editorSettings = editor.settings; + var actionCallback, fileBrowserCallback, fileBrowserCallbackTypes; + settings.spellcheck = false; + fileBrowserCallbackTypes = editorSettings.file_picker_types || editorSettings.file_browser_callback_types; + if (fileBrowserCallbackTypes) { + fileBrowserCallbackTypes = Tools.makeMap(fileBrowserCallbackTypes, /[, ]/); + } + + if (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[settings.filetype]) { + fileBrowserCallback = editorSettings.file_picker_callback; + if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[settings.filetype])) { + actionCallback = function() { + var meta = self.fire('beforecall').meta; + + meta = Tools.extend({filetype: settings.filetype}, meta); + + // file_picker_callback(callback, currentValue, metaData) + fileBrowserCallback.call( + editor, + function(value, meta) { + self.value(value).fire('change', {meta: meta}); + }, + self.value(), + meta + ); + }; + } else { + // Legacy callback: file_picker_callback(id, currentValue, filetype, window) + fileBrowserCallback = editorSettings.file_browser_callback; + if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[settings.filetype])) { + actionCallback = function() { + fileBrowserCallback( + self.getEl('inp').id, + self.value(), + self.settings.filetype, + window + ); + }; + } + } + } + + if (actionCallback) { + settings.icon = 'browse'; + settings.onaction = actionCallback; + } + + self._super(settings); + self.off('click').on('click', function(e){ + var elm = e.target, root = self.getEl(); + if (!self.$.contains(root, elm) && elm != root) { + return; + } + + while (elm && elm != root) { + if (elm.id && elm.id.indexOf('-action') != -1) { + if (elm.id === self._id + '-image-action') { + self.settings.filetype = 'image'; + } else { + self.settings.filetype = 'file'; + } + self.fire('action'); + } + elm = elm.parentNode; + } + }); + }, + renderHtml: function() { + var self = this, id = self._id, settings = self.settings, prefix = self.classPrefix; + var value = self.state.get('value') || ''; + var icon, text, openBtnHtml = '', extraAttrs = ''; + if ("spellcheck" in settings) { + extraAttrs += ' spellcheck="' + settings.spellcheck + '"'; + } + + if (settings.maxLength) { + extraAttrs += ' maxlength="' + settings.maxLength + '"'; + } + + if (settings.size) { + extraAttrs += ' size="' + settings.size + '"'; + } + + if (settings.subtype) { + extraAttrs += ' type="' + settings.subtype + '"'; + } + + if (self.disabled()) { + extraAttrs += ' disabled="disabled"'; + } + + openBtnHtml = ( + '
' + + '' + + '' + + '
' + ); + self.classes.add('has-open'); + + return ( + '
' + + '' + + openBtnHtml + + '
' + ); + }, + })); +}); diff --git a/assets/plugins/tinymce4/tinymce/plugins/modxlink/plugin.min.js b/assets/plugins/tinymce4/tinymce/plugins/modxlink/plugin.min.js index 48b0ac0974..fc3ec01083 100755 --- a/assets/plugins/tinymce4/tinymce/plugins/modxlink/plugin.min.js +++ b/assets/plugins/tinymce4/tinymce/plugins/modxlink/plugin.min.js @@ -1,1545 +1 @@ -/** - * modxlink.js - * - * Based on link.js but with resource search added. - * - * By default both pagetitle and alias are searched. - * - * Author: markwillis82 - * Date: 7/7/15 - * update 64j 8/11/17 - */ - -// Handles selection from Modx-Ressource-Tree -if (parent.modx.tree) { - var modxOldRessourceId = parent.modx.tree.itemToChange; - var modxLinkTitle = ''; - var checkModxTreeUpdateInterval = undefined; - var checkModxTreeUpdate = function() { - - checkModxTreeUpdateInterval = setTimeout(checkModxTreeUpdate, 100); - - if (parent.modx.tree.itemToChange != modxOldRessourceId) { - modxOldRessourceId = parent.modx.tree.itemToChange; - modxLinkTitle = parent.modx.tree.selectedObjectName; - - document.getElementById('link-href-inp').value = '[~' + modxOldRessourceId + '~]'; - if (!document.getElementById('text-to-display').value) { - document.getElementById('text-to-display').value = modxLinkTitle; - } - } - }; -} - -/*global tinymce:true */ -var autoComplt = (function() { - /* Properties: - [ Private ] - _CONST = the constants collection - _ui = the obj to build UI - _AutoCompltList = the class dealing with the autocomplete operations - [ Public ] - > Refer to the Public APIs above - Methods: - [ Private ] - > _getIEVersion : Get the IE version - > _getAppropriateMode : Get the mode appropriate for the current user scenario - > _getWindowSize : Get the client window width and height - > _normalizeEvt : Normalize the event obj - > _addEvt : Add an event to one elem, used for cross-browser mitigation - > _rmEvent : remove an event to one elem, used for cross-browser mitigation - > _getComputedStyle : Get the computed style value, used for cross-browser mitigation - [ Public ] - > enable : Refer to the Public APIs above - - */ - 'use strict'; - - var _DBG = 0; // A little debug flag - - if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function(searchElement, fromIndex) { - if (this === undefined || this === null) {throw new TypeError('"this" is null or not defined');} - var length = this.length >>> 0; - fromIndex = +fromIndex || 0; - if (Math.abs(fromIndex) === Infinity) {fromIndex = 0;} - if (fromIndex < 0) { - fromIndex += length; - if (fromIndex < 0) {fromIndex = 0;} - } - for (; fromIndex < length; fromIndex++) {if (this[fromIndex] === searchElement) {return fromIndex;}} - return -1; - }; - } - - var - /* Return: - @ Is IE: the version of IE - @ Not IE: NaN - */ - _getIEVersion = function() { - var rv = -1; // Return value assumes failure. - if (navigator.appName == 'Microsoft Internet Explorer') { - var ua = navigator.userAgent; - var re = new RegExp('MSIE ([0-9]{1,}[\.0-9]{0,})'); - if (re.exec(ua) != null) { - rv = +(RegExp.$1); - } - } - return (rv === -1) ? NaN : rv; - }, - /* Return: - > _CONST.modePC or _CONST.modeMobile - */ - _getAppropriateMode = function() { - - // Judge by the userAgent string - var ua = window.navigator.userAgent.toLowerCase(); - if (ua.search(/mobile|windows phone/) >= 0) return _CONST.modeMobile; - - // Bye the legacy IEs - if (_getIEVersion() <= 9) return _CONST.modePC; - - // Judge by the window width - return (_getWindowSize().windowWidth > _CONST.modeMobileW) ? _CONST.modePC : _CONST.modeMobile; - }, - /* Return: { - windowWidth : the width of the client window in px. If unable to find, then -1. - windowHeight : the height of the client window in px. If unable to find, then -1. - } - */ - _getWindowSize = function() { - - if (window.innerWidth) { - - return { - windowWidth: window.innerWidth, - windowHeight: window.innerHeight - }; - - } else if (document.documentElement.offsetHeight) { - - return { - windowWidth: document.documentElement.offsetWidth, - windowHeight: document.documentElement.offsetHeight - }; - - } else if (document.body.offsetHeight) { - - return { - windowWidth: document.body.offsetWidth, - windowHeight: document.body.offsetHeight - }; - - } else if (document.documentElement.clientHeight) { - - return { - windowWidth: document.documentElement.clientWidth, - windowHeight: document.documentElement.clientHeight - }; - - } else if (document.body.clientHeight) { - - return { - windowWidth: document.body.clientWidth, - windowHeight: document.body.clientHeight - }; - } - - return { - windowWidth: -1, - windowHeight: -1 - }; - }, - _CONST = (function(c) { - - _CONST = c; - - c.modePC = 'modePC'; // Represent the PC mode - - c.modeMobile = 'modeMobile'; // Represent the mobile mode - - c.modeMobileW = 768; // in px. The width used to seperate the PC & mobile mode - - c.autoCompltListClass = 'autoComplt-list'; - - c.autoCompltHintClass = 'autoComplt-hint'; - - c.autoCompltHintSelectedClass = 'autoComplt-hint-selected'; - - c.maxHintNum = (_getAppropriateMode() === _CONST.modePC) ? 10 : 5; // For limited mobile screen, not too many - - c.autoCompltDelay = 250; // in ms - - c.hiddenArg_close_list_n_make_final_selection = 'hiddenArg_close_list_n_make_final_selection'; - - c.listStatus = { - attr: 'data-listStatus', - open: 'open' - }; - - c.keyCode = { - up: 38, - down: 40, - esc: 27, - enter: 13 - }; - - c.defaultStyles = { - - autoCompltList: { - maxHeight: 'none', - border: '1px solid #aaa', - padding: '0', - margin: '0', - zIndex: 99999, - overflowX: 'hidden', - overflowY: 'auto', - display: 'none', - position: 'absolute', - backgroundColor: '#fff' - }, - - autoCompltHint: { - height: '1.5em', - padding: (_getAppropriateMode() === _CONST.modePC) ? '2px 6px 2px 10px' : '6px 6px 6px 10px', // For good touch ux, enlarge for the mobile mode - margin: '6px 0', - overflow: 'hidden', - listStyleType: 'none', - color: '#000', - backgroundColor: '#fff', - cursor: 'default', - fontSize: '1em' - }, - - autoCompltHintSelected: { - color: '#fff', - backgroundColor: '#3399ff' - } - }; - - c.adjStyleAttrs = { - autoCompltList: ['border', 'maxHeight', 'backgroundColor'], - autoCompltHint: ['height', 'padding', 'margin', 'color', 'backgroundColor', 'fontSize'], - autoCompltHintSelected: ['color', 'backgroundColor'] - }; - - // names of listeners supported - c.listenersSupported = [ - 'select' // Called when the user's final hint selection is decided - ]; - - return _CONST; - })({}), - /* Arg: - e = the event obj - Return: - the normalized event obj - */ - _normalizeEvt = function(e) { - - if (!e) e = window.event; - - if (!e.target) e.target = e.srcElement; - - e.stopBubble = function() { - this.cancelBubble = true; - if (this.stopPropagation) { this.stopPropagation(); } - }; - - e.stopDefault = function() { - if (this.preventDefault) { this.preventDefault(); } - this.returnValue = false; - return false; - }; - return e; - }, - /* Arg: - elem = the DOM elem - evt = the event name - eHandle = the event handle - */ - _addEvt = function(elem, evt, eHandle) { - if (elem.addEventListener) { - elem.addEventListener(evt, eHandle); - } else if (elem.attachEvent) { // The IE 8 case - elem.attachEvent('on' + evt, eHandle); - } - }, - /* Arg: Refer to _addEvt - */ - _rmEvent = function(elem, evt, eHandle) { - if (elem.removeEventListener) { - elem.removeEventListener(evt, eHandle); - } else if (elem.detachEvent) { // The IE 8 case - elem.detachEvent('on' + evt, eHandle); - } - }, - /* Arg: - elem = the DOM elem - name = the style name - */ - _getComputedStyle = function(elem, name) { - var v = null; - - if (window.getComputedStyle) { - - v = window.getComputedStyle(elem)[name] || null; - - } else if (elem.currentStyle) { // Hack for IE...Reference from the jQuery - - v = elem.currentStyle && elem.currentStyle[name]; - - var left, - rsLeft, - style = elem.style; - - // Avoid setting v to empty string here - // so we don't default to auto - if (v == null && style && style[name]) { - v = style[name]; - } - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - // but not position css attributes, as those are proportional to the parent element instead - // and we can't measure the parent instead because it might trigger a "stacking dolls" problem - - // Remember the original values - left = style.left; - rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - if (rsLeft) { - elem.runtimeStyle.left = elem.currentStyle.left; - } - style.left = name === 'fontSize' ? '1em' : v; - v = style.pixelLeft + 'px'; - - // Revert the changed values - style.left = left; - if (rsLeft) { - elem.runtimeStyle.left = rsLeft; - } - - } - - return v; - }, - /* Methods: - [ Public ] - > buildElem : Build on elem from the HTML text - > buildHint : Build one autocomplete hint elem - > buildList : Build one autocomplete list - */ - _ui = { - /* Arg: - html = the HTMl text - Return: - the elem built from the input HTML - */ - buildElem: function(html) { - var div = document.createElement('DIV'); - div.innerHTML = html; - return div.firstChild.cloneNode(true); - }, - /* Arg: - hint = the hint text - styles = the obk holding the styles to set. Refer to _CONST.defaultStyles.autoCompltHint for the required styles - Return: - @ OK: the hint ui elem - @ NG: null - */ - buildHint: function(hint, styles) { - if (typeof hint == 'string' && hint) { - hint = this.buildElem('
  • ' + hint + '
  • '); - - hint.style.height = hint.style.lineHeight = styles.autoCompltHint.height; // line-height shall always be equal to the height - hint.style.padding = styles.autoCompltHint.padding; - hint.style.margin = styles.autoCompltHint.margin; - hint.style.overflow = styles.autoCompltHint.overflow; - hint.style.listStyleType = styles.autoCompltHint.listStyleType; - hint.style.color = styles.autoCompltHint.color; - hint.style.backgroundColor = styles.autoCompltHint.backgroundColor; - hint.style.cursor = styles.autoCompltHint.cursor; - hint.style.fontSize = styles.autoCompltHint.fontSize; - - return hint; - } - return null; - }, - /* Arg: - styles = the obk holding the styles to set. Refer to _CONST.defaultStyles.autoCompltList for the required styles - Return: - @ OK: the list ui elem - @ NG: null - */ - buildList: function(styles) { - var list = this.buildElem('
      '); - - list.style.maxHeight = styles.autoCompltList.maxHeight; - list.style.border = styles.autoCompltList.border; - list.style.padding = styles.autoCompltList.padding; - list.style.margin = styles.autoCompltList.margin; - list.style.zIndex = styles.autoCompltList.zIndex; - list.style.overflowX = styles.autoCompltList.overflowX; - list.style.overflowY = styles.autoCompltList.overflowY; - list.style.display = styles.autoCompltList.display; - list.style.position = styles.autoCompltList.position; - list.style.backgroundColor = styles.autoCompltList.backgroundColor; - - return list; - } - }, - /* Properties: - [ Public ] - uiElem = the autocomplete list current being displayed and associated with. - assocInput = the input elem associated with - mouseOnList = A little flag marking the moused is on the top of the autocomplete list - maxHintNum = The max number of hints displayed - styles = the obj holding the style setting of the list and hints. Refer to _CONST.defaultStyles for the required styles. - onMouseSelectionListener = Called when user explicitly selects one hint by mouse clicking. No args passed. - Methods: - [ Public ] - > genList : Build and setup one autocomplete list - > isHint : Check if it is a autocomplete hint elem or not - > putHints : Put hints into the autocomplete list - > clearHints : Clear all hints - > isOpen : Tell if the auotcomplete list is open or not - > open : Open the autocomplete list. NOTICE: before opening, there must at one hint in the list so please call this.putHints first then open. - > close : Close the autocomplete list - > autoScroll : Auto scroll the list according the position and offset of the current selected hint so the current selected hint could show up - > pick : Pick up one hint. NOTICE: this action is to pick up one hint but not to select that hint so it will not change this.assocInput's value. Please use this.getPicked to get the picked hint and extract the hint text and assign this.assocInput's value the hint text - > unpick : Unpick all hints - > getPicked : Get the hint elem picked - */ - _AutoCompltList = function(assocInput) { - - this.uiElem = null; - this.assocInput = assocInput; - this.mouseOnList = false; - this.onMouseSelectionListener = null; - this.maxHintNum = _CONST.maxHintNum; - this.styles = JSON.parse(JSON.stringify(_CONST.defaultStyles)); // Copy the default first - - }; - { - /* - */ - _AutoCompltList.prototype.genList = function() { - if (!this.uiElem) { - - var that = this; - - this.uiElem = _ui.buildList(this.styles); - - // Make hint selected onmouseover - _addEvt(this.uiElem, 'mouseover', function(e) { - e = _normalizeEvt(e); - if (that.isHint(e.target)) { - that.pick(e.target); - that.autoScroll(); - } - }); - - // Make hint not selected onmouseout - _addEvt(this.uiElem, 'mouseout', function(e) { - that.unpick(); - }); - - // Prepare for the hint selection by clicking - _addEvt(this.uiElem, 'mousedown', function(e) { - that.mouseOnList = true; - // One hack for FF. - // Even call focus methos on the input's onblur event, however, still the input losese its focus. - // As a result we have to set a timeout here - setTimeout(function() { - that.assocInput.focus(); - }, 50); - }); - - // pick hint by clicking - _addEvt(this.uiElem, 'mouseup', function(e) { - - e = _normalizeEvt(e); - - if (that.isHint(e.target)) { - - that.pick(e.target); - - if (typeof that.onMouseSelectionListener == 'function') that.onMouseSelectionListener(); - } - }); - - document.body.appendChild(this.uiElem); - } - }; - /* Arg: - el = the elem to check - Return: - @ Ok: true - @ NG: false - */ - _AutoCompltList.prototype.isHint = function(el) { - if (el && typeof el == 'object' && el.nodeType === 1) { - var cls = ' ' + el.className + ' '; - return (cls.indexOf(' ' + _CONST.autoCompltHintClass + ' ') >= 0); - } - return false; - }; - /* Arg: - hints = the array of hint texts - Return: - the number of hints put - */ - _AutoCompltList.prototype.putHints = function(hints) { - var count = 0; - if (hints instanceof Array) { - var i, - j, - hs = []; - - j = Math.min(hints.length, this.maxHintNum); - for (i = 0; i < j; i++) { - hs.push(_ui.buildHint(hints[i], this.styles)); - if (!hs[hs.length - 1]) { - hs.pop(); - } - } - - if (hs.length > 0) { - var buf = document.createDocumentFragment(); - for (i = 0, count = hs.length; i < count; i++) { - buf.appendChild(hs[i]); - } - this.clearHints(); - - this.genList(); // Geneate the list in case there is none - this.uiElem.appendChild(buf); - } - } - return count; - }; - /* - */ - _AutoCompltList.prototype.clearHints = function() { - if (this.uiElem) { - this.uiElem.innerHTML = ''; - } - }; - /* - Return: - @ Ok: true - @ NG: false - */ - _AutoCompltList.prototype.isOpen = function() { - if (this.uiElem) { - return (this.uiElem.getAttribute(_CONST.listStatus.attr) == _CONST.listStatus.open); - } - return false; - }; - /* - */ - _AutoCompltList.prototype.open = function() { - var hints; - - if (this.uiElem - && (hints = this.uiElem.querySelectorAll('.' + _CONST.autoCompltHintClass)) - && hints.length // At lease one hint exists, we would open... - ) { - var i, - buf; - - // Position the list - buf = this.assocInput.getBoundingClientRect(); - this.uiElem.style.top = (document.documentElement && document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) - + buf.bottom + 'px'; - this.uiElem.style.left = buf.left + 'px'; - - // Calculate the list's width - buf = buf.right - buf.left - parseFloat(_getComputedStyle(this.uiElem, 'borderLeftWidth')) - parseFloat(_getComputedStyle(this.uiElem, 'borderRightWidth')); - this.uiElem.style.width = buf + 'px'; - - // Calculate the list's height - for (i = 0, buf = 0; i < hints.length; i++) { - buf += parseFloat(_getComputedStyle(hints[i], 'height')) - + parseFloat(_getComputedStyle(hints[i], 'paddingTop')) - + parseFloat(_getComputedStyle(hints[i], 'paddingBottom')); - - if (hints[i + 1]) { // Compute the margin between the hints - buf += Math.max( - parseFloat(_getComputedStyle(hints[i], 'marginBottom')), parseFloat(_getComputedStyle(hints[i + 1], 'marginTop')) - ); - } - } - buf += parseFloat(_getComputedStyle(hints[0], 'marginTop')) - + parseFloat(_getComputedStyle(hints[hints.length - 1], 'marginBottom')); - this.uiElem.style.height = (buf + 1) + 'px'; // Plus one for a little buffer - - // Open - this.uiElem.setAttribute(_CONST.listStatus.attr, _CONST.listStatus.open); - this.uiElem.style.display = 'block'; - - } - }; - /* - */ - _AutoCompltList.prototype.close = function() { - if (this.uiElem) { - this.mouseOnList = false; - this.uiElem.parentNode.removeChild(this.uiElem); - this.uiElem = null; - } - }; - /* - */ - _AutoCompltList.prototype.autoScroll = function() { - var hint = this.getPicked(); - if (hint) { - var currHint, - offset = 0, - minDisplayH = 0, - hintH = hint.clientHeight, - hintMT = parseFloat(_getComputedStyle(hint, 'marginTop')), - hintMB = parseFloat(_getComputedStyle(hint, 'marginBottom')); - - currHint = hint.previousSibling; - - minDisplayH = hintH + (currHint ? Math.max(hintMT, hintMB) : hintMT); // The min height to display one hint - - while (currHint) { - - offset += hintH; // Add the current hint' hintH - - currHint = currHint.previousSibling; - if (currHint) { - // There is one hint before the current hint so calculate based on the collapsed model - offset += Math.max(hintMT, hintMB); - } else { - // No more previous hint, this is the 1st hint so just take the marign top - offset += hintMT; - } - } - - if (this.uiElem.clientHeight + this.uiElem.scrollTop - offset < minDisplayH - || offset - this.uiElem.scrollTop < minDisplayH - ) { - // Ther is no enough room displaying the current selected hint so adjust the scroll - this.uiElem.scrollTop = offset; - } - } - }; - /* Arg: - candidate = could be - 1) the hint elem or - 2) the index of the hint in the list. Passing in -1 would pick the last hint. Passing in 0 would pick the 1st hint. - */ - _AutoCompltList.prototype.pick = function(candidate) { - - if (this.uiElem) { - - var hint = null; - - if (this.isHint(candidate)) { - - hint = candidate; - - } else if (typeof candidate == 'number' && (candidate >= 0 || candidate === -1)) { - - var hints = this.uiElem.querySelectorAll('.' + _CONST.autoCompltHintClass); - - if (hints.length > 0) { - hint = +candidate; - hint = (hint === -1 || hint > hints.length - 1) ? hints.length - 1 : hint; - hint = hints[hint]; - } - } - - if (hint !== null) { - - this.unpick(); - hint.className += ' ' + _CONST.autoCompltHintSelectedClass; - hint.style.color = this.styles.autoCompltHintSelected.color; - hint.style.backgroundColor = this.styles.autoCompltHintSelected.backgroundColor; - } - } - }; - /* - */ - _AutoCompltList.prototype.unpick = function() { - if (this.uiElem) { - var slct = this.getPicked(); - if (slct) { - slct.className = _CONST.autoCompltHintClass; - slct.style.color = this.styles.autoCompltHint.color; - slct.style.backgroundColor = this.styles.autoCompltHint.backgroundColor; - } - } - }; - /* Return: - @ OK: the selected hint element - @ NG: null - */ - _AutoCompltList.prototype.getPicked = function() { - return !this.uiElem ? null : this.uiElem.querySelector('.' + _CONST.autoCompltHintSelectedClass) || null; - }; - } - - var - publicProps = { - - enable: function(input, params) { - if (input - && typeof input == 'object' - && typeof input.tagName == 'string' - && input.tagName.toLowerCase() == 'input' - && input.type == 'text' - && input.nodeType === 1 - && !input.autoComplt - ) { - - /* Propertise: - [ Private ] - input_autoComplt_delay = the ms delays the work of fetching the autocomplete hints based on the user's input - input_autoComplt_enabled = true to perform the autocomplete function; false not to perform. - input_autoComplt_currentTarget = the current user's input for which the autocomplete is target - input_autoComplt_listenerMap = the map of listeners - input_autoComplt_list = the instance of _AutoCompltList - Methods: - [ Private ] - > input_autoComplt_hintsFetcher : The function fetching the autocomplete hints - > input_autoComplt_startFetcher : Setup and call input_autoComplt_hintsFetcher to fetch the hints - > input_autoComplt_compltInput : Autocomplete the according to the hint selection state - > input_autoComplt_blurEvtHandle, input_autoComplt_keyEvtHandle : The event handle - > input_autoComplt_inputEvtHandleMobile : The event handle for the mobile mode - [ Public ] - > setHintsFetcher, setListener, config, setStyles, close, enable, disable, destroy : Refe to the Public APIs above - */ - input.autoComplt = {}; - - var - input_autoComplt_delay = _CONST.autoCompltDelay, - input_autoComplt_enabled = true, - input_autoComplt_currentTarget = '', - input_autoComplt_hintsFetcher = null, - input_autoComplt_listenerMap = null, - input_autoComplt_list = new _AutoCompltList(input), - /* - */ - input_autoComplt_startFetcher = function() { - - if (input.value.length > 0 - && input_autoComplt_enabled - && typeof input_autoComplt_hintsFetcher == 'function' - && input_autoComplt_currentTarget !== input.value // If equals, it means we've already been searching for the hints for the same value - ) { - - var fetcherCaller = { - - that: input, - - // Record the autocomplete target for this fetching job - compltTarget: (input_autoComplt_currentTarget = input.value), - - compltTargetMatchCurrentTarget: function() { - // If the user's input has changed during the fetching, this fetching job is useless. - // So only when the user's input doesn't change, we will return true to indicate proceeding further. - return (fetcherCaller.compltTarget === input_autoComplt_currentTarget); - }, - - call: function() { - - if (fetcherCaller.compltTargetMatchCurrentTarget()) { - - input_autoComplt_hintsFetcher.call( - fetcherCaller.that, - fetcherCaller.compltTarget, - fetcherCaller.openHint - ); - } - }, - - openHint: function(hints) { - if (fetcherCaller.compltTargetMatchCurrentTarget()) { - - if (input_autoComplt_list.putHints(hints)) { - input_autoComplt_list.open(); - } else { - fetcherCaller.that.autoComplt.close(); - } - } - } - }; - - setTimeout(fetcherCaller.call, input_autoComplt_delay); - } - }, - /* - */ - input_autoComplt_compltInput = function() { - - if (input_autoComplt_enabled) { - - var hint = input_autoComplt_list.getPicked(); - - if (hint) { - input.value = hint.innerHTML; - } else { - // If no hint is selected, just use the original user input to autocomplete - input.value = input_autoComplt_currentTarget; - } - } - }, - /* - */ - input_autoComplt_blurEvtHandle = function(e) { - - if (input_autoComplt_list.mouseOnList) { - // If the mouse is on the autocomplete list, do not close the list - // and still need to focus on the input. - input.focus(); - input_autoComplt_list.mouseOnList = false; // Assign false for the next detection - } else { - - if (input_autoComplt_list.isOpen()) { - input.autoComplt.close(_CONST.hiddenArg_close_list_n_make_final_selection); - } - } - }, - /* - */ - input_autoComplt_keyEvtHandle = function(e) { - - if (_getAppropriateMode() === _CONST.modeMobile) return; // Let this::input_autoComplt_inputEvtHandleMobile handle - - e = _normalizeEvt(e); - - if (input_autoComplt_enabled) { - if (e.type == 'keydown' - && input_autoComplt_list.isOpen() - && (e.keyCode === _CONST.keyCode.up || e.keyCode === _CONST.keyCode.down) - ) { - // At the case that the hint list is open ans user is walking thru the hints. - // Let's try to autocomplete the input by the selected input. - - var hint = input_autoComplt_list.getPicked(); - - if (e.keyCode === _CONST.keyCode.up) { - - if (!hint) { - // If none is selected, then pick the last hint - input_autoComplt_list.pick(-1); - } else if (hint.previousSibling) { - // If some hint is selected and the previous hint exists, then pick the previous hint - input_autoComplt_list.pick(hint.previousSibling); - } else { - // If some hint is selected but the previous hint doesn't exists, then unpick all - input_autoComplt_list.unpick(); - } - - } else if (e.keyCode === _CONST.keyCode.down) { - - if (!hint) { - // If none is selected, then pick the first hint - input_autoComplt_list.pick(0); - } else if (hint.nextSibling) { - // If some hint is selected and the next hint exists, then pick the next hint - input_autoComplt_list.pick(hint.nextSibling); - } else { - // If some hint is selected but the next hint doesn't exists, then unpick all - input_autoComplt_list.unpick(); - } - - } - - input_autoComplt_list.autoScroll(); - - input_autoComplt_compltInput(); - - } - else if (e.type == 'keyup') { - - var startFetching = false; - - switch (e.keyCode) { - case _CONST.keyCode.up: - case _CONST.keyCode.down: - if (input_autoComplt_list.isOpen()) { - // We have handled this 2 key codes onkeydown, so must do nothing here - } else { - startFetching = true; - } - break; - - case _CONST.keyCode.esc: - if (input_autoComplt_list.isOpen()) { - // When pressing the ESC key, let's resume back to the original user input - input.value = input_autoComplt_currentTarget; - input.autoComplt.close(_CONST.hiddenArg_close_list_n_make_final_selection); - } - break; - - case _CONST.keyCode.enter: - if (input_autoComplt_list.isOpen()) { - // When pressing the enter key, let's try autocomplete - input_autoComplt_compltInput(); - input.autoComplt.close(_CONST.hiddenArg_close_list_n_make_final_selection); - } - break; - - default: - startFetching = true; - break; - } - - if (startFetching) { - if (input.value.length > 0) { - input_autoComplt_startFetcher(); - } else { - input.autoComplt.close(); - } - } - } - } - }, - /* - */ - input_autoComplt_inputEvtHandleMobile = function(e) { - - if (_getAppropriateMode() === _CONST.modePC) return; // Let this::input_autoComplt_keyEvtHandle handle - - if (input.value.length > 0) { - input_autoComplt_startFetcher(); - } else { - input.autoComplt.close(); - } - }, - /* Arg: - name = Refer to _CONST.listenersSupported - */ - input_autoComplt_invokeListener = function(name) { - - if (input_autoComplt_listenerMap != null && typeof input_autoComplt_listenerMap[name] == 'function') { - - input_autoComplt_listenerMap[name].call(input); - } - }; - - input.autoComplt.setHintsFetcher = function(hintsFetcher) { - if (hintsFetcher === null || typeof hintsFetcher == 'function') { - input_autoComplt_hintsFetcher = hintsFetcher; - return true; - } - return false; - }; - - input.autoComplt.setListener = function(name, listener) { - - if ((listener === null || typeof listener == 'function') && _CONST.listenersSupported.indexOf(name) >= 0) { - - if (input_autoComplt_listenerMap == null) input_autoComplt_listenerMap = {}; - - input_autoComplt_listenerMap[name] = listener; - - return true; - } - - return false; - }; - - input.autoComplt.setStyles = function(targetClass, styles) { - - var tStyles, - adjStyleAttrs, - newStyles = false; - - // Let's find out which the target UI part is being set - switch (targetClass) { - case _CONST.autoCompltListClass: - tStyles = input_autoComplt_list.styles.autoCompltList; - adjStyleAttrs = _CONST.adjStyleAttrs.autoCompltList; - break; - - case _CONST.autoCompltHintClass: - tStyles = input_autoComplt_list.styles.autoCompltHint; - adjStyleAttrs = _CONST.adjStyleAttrs.autoCompltHint; - break; - - case _CONST.autoCompltHintSelectedClass: - tStyles = input_autoComplt_list.styles.autoCompltHintSelected; - adjStyleAttrs = _CONST.adjStyleAttrs.autoCompltHintSelected; - break; - } - - if (styles instanceof Object && tStyles && adjStyleAttrs) { - - for (var i = 0; i < adjStyleAttrs.length; i++) { - - if (typeof styles[adjStyleAttrs[i]] == 'string' || typeof styles[adjStyleAttrs[i]] == 'number') { // A simple type checking - if (!newStyles) { - newStyles = {}; - } - newStyles[adjStyleAttrs[i]] = tStyles[adjStyleAttrs[i]] = styles[adjStyleAttrs[i]]; - } - - } - - } - - return newStyles; - }; - - input.autoComplt.config = function(params) { - - var pms = false; - - if (params instanceof Object) { - - var buf; - - // Config the fetching delay timing - // - if (params.delay !== undefined && (buf = Math.floor(params.delay)) > 0) { - - if (!pms) pms = {}; - - input_autoComplt_delay = pms.delay = buf; - } - - // Config the max number of displayed hints - // - if (params.maxHintNum !== undefined && (buf = Math.floor(params.maxHintNum)) > 0) { - - if (!pms) pms = {}; - - input_autoComplt_list.maxHintNum = pms.maxHintNum = buf; - } - } - return pms; - }; - - input.autoComplt.close = function() { - - input_autoComplt_currentTarget = ''; // Closing means no need for autocomplete hint so no autocomplete target either - - input_autoComplt_list.close(); - - if (input_autoComplt_enabled - && input.value !== '' - && arguments[0] === _CONST.hiddenArg_close_list_n_make_final_selection - ) { - - input_autoComplt_invokeListener('select'); - } - }; - - input.autoComplt.enable = function() { - input_autoComplt_enabled = true; - }; - - input.autoComplt.disable = function() { - input_autoComplt_enabled = false; - this.close(); - }; - - input.autoComplt.destroy = function() { - _rmEvent(input, 'blur', input_autoComplt_blurEvtHandle); - _rmEvent(input, 'keyup', input_autoComplt_keyEvtHandle); - _rmEvent(input, 'keydown', input_autoComplt_keyEvtHandle); - this.disable(); - delete input.autoComplt; - }; - - input_autoComplt_list.onMouseSelectionListener = function() { - - input_autoComplt_compltInput(); - - input.autoComplt.close(_CONST.hiddenArg_close_list_n_make_final_selection); - }; - - _addEvt(input, 'blur', input_autoComplt_blurEvtHandle); - _addEvt(input, 'keyup', input_autoComplt_keyEvtHandle); - _addEvt(input, 'keydown', input_autoComplt_keyEvtHandle); - - _addEvt(input, 'input', input_autoComplt_inputEvtHandleMobile); - - if (params instanceof Object) { - input.autoComplt.config(params); - input.autoComplt.setHintsFetcher(params.hintsFetcher); - } - - return input; - } - return null; - } - - }; - - return publicProps; -}()); - -tinymce.PluginManager.add('modxlink', function(editor) { - function createLinkList(callback) - { - return function() { - var linkList = editor.settings.link_list; - - if (typeof linkList == 'string') { - tinymce.util.XHR.send({ - url: linkList, - success: function(text) { - callback(tinymce.util.JSON.parse(text)); - } - }); - } else if (typeof linkList == 'function') { - linkList(callback); - } else { - callback(linkList); - } - }; - } - - function buildListItems(inputList, itemCallback, startItems) - { - function appendItems(values, output) - { - output = output || []; - - tinymce.each(values, function(item) { - var menuItem = {text: item.text || item.title}; - - if (item.menu) { - menuItem.menu = appendItems(item.menu); - } else { - menuItem.value = item.value; - - if (itemCallback) { - itemCallback(menuItem); - } - } - - output.push(menuItem); - }); - - return output; - } - - return appendItems(inputList, startItems || []); - } - - function showDialog(linkList) - { - - if (parent.tree) { - parent.tree.ca = 'disabled'; // Disable Modx-TreeAction, resetted on onOk or OnCancel - checkModxTreeUpdate.call(this); // Watch Modx-Tree for changes and update URL-field - } - ; - - var data = {}, selection = editor.selection, dom = editor.dom, selectedElm, anchorElm, initialText; - var win, onlyText, textListCtrl, linkListCtrl, relListCtrl, targetListCtrl, classListCtrl, linkTitleCtrl, value; - - function linkListChangeHandler(e) - { - var textCtrl = win.find('#text'); - - if (!textCtrl.value() || (e.lastControl && textCtrl.value() == e.lastControl.text())) { - textCtrl.value(e.control.text()); - } - - win.find('#href').value(e.control.value()); - } - - function buildAnchorListControl(url) - { - var anchorList = []; - - tinymce.each(editor.dom.select('a:not([href])'), function(anchor) { - var id = anchor.name || anchor.id; - - if (id) { - anchorList.push({ - text: id, - value: '#' + id, - selected: url.indexOf('#' + id) != -1 - }); - } - }); - - if (anchorList.length) { - anchorList.unshift({text: 'None', value: ''}); - - return { - name: 'anchor', - type: 'listbox', - label: 'Anchors', - values: anchorList, - onselect: linkListChangeHandler - }; - } - } - - function updateText() - { - if (!initialText && data.text.length === 0 && onlyText) { - this.parent().parent().find('#text')[0].value(this.value()); - } - } - - function urlChange(e) - { - var meta = e.meta || {}; - - if (linkListCtrl) { - linkListCtrl.value(editor.convertURL(this.value(), 'href')); - } - - tinymce.each(e.meta, function(value, key) { - win.find('#' + key).value(value); - }); - - if (!meta.text) { - updateText.call(this); - } - } - - function isOnlyTextSelected(anchorElm) - { - var html = selection.getContent(); - - // Partial html and not a fully selected anchor element - if (/]+>[^<]+<\/a>$/.test(html) || html.indexOf('href=') == -1)) { - return false; - } - - if (anchorElm) { - var nodes = anchorElm.childNodes, i; - - if (nodes.length === 0) { - return false; - } - - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].nodeType != 3) { - return false; - } - } - } - - return true; - } - - selectedElm = selection.getNode(); - anchorElm = dom.getParent(selectedElm, 'a[href]'); - onlyText = isOnlyTextSelected(); - - data.text = initialText = anchorElm ? (anchorElm.innerText || anchorElm.textContent) : selection.getContent({format: 'text'}); - data.href = anchorElm ? dom.getAttrib(anchorElm, 'href') : ''; - - if (anchorElm) { - data.target = dom.getAttrib(anchorElm, 'target'); - } else if (editor.settings.default_link_target) { - data.target = editor.settings.default_link_target; - } - - if ((value = dom.getAttrib(anchorElm, 'rel'))) { - data.rel = value; - } - - if ((value = dom.getAttrib(anchorElm, 'class'))) { - data['class'] = value; - } - - if ((value = dom.getAttrib(anchorElm, 'title'))) { - data.title = value; - } - - if (onlyText) { - textListCtrl = { - name: 'text', - type: 'textbox', - size: 40, - label: 'Text to display', - id: 'text-to-display', - onchange: function() { - data.text = this.value(); - } - }; - } - - if (linkList) { - linkListCtrl = { - type: 'listbox', - label: 'Link list', - values: buildListItems( - linkList, - function(item) { - item.value = editor.convertURL(item.value || item.url, 'href'); - }, - [{text: 'None', value: ''}] - ), - onselect: linkListChangeHandler, - value: editor.convertURL(data.href, 'href'), - onPostRender: function() { - linkListCtrl = this; - } - }; - } - - if (editor.settings.target_list !== false) { - if (!editor.settings.target_list) { - editor.settings.target_list = [ - {text: 'None', value: ''}, - {text: 'New window', value: '_blank'} - ]; - } - - targetListCtrl = { - name: 'target', - type: 'listbox', - label: 'Target', - values: buildListItems(editor.settings.target_list) - }; - } - - if (editor.settings.rel_list) { - relListCtrl = { - name: 'rel', - type: 'listbox', - label: 'Rel', - values: buildListItems(editor.settings.rel_list) - }; - } - - if (editor.settings.link_class_list) { - classListCtrl = { - name: 'class', - type: 'listbox', - label: 'Class', - values: buildListItems( - editor.settings.link_class_list, - function(item) { - if (item.value) { - item.textStyle = function() { - return editor.formatter.getCssText({inline: 'a', classes: [item.value]}); - }; - } - } - ) - }; - } - - if (editor.settings.link_title !== false) { - linkTitleCtrl = { - name: 'title', - type: 'textbox', - label: 'Title', - value: data.title - }; - } - - win = editor.windowManager.open({ - title: 'Insert link', - data: data, - body: [ - { - name: 'href', - type: 'filepicker', - filetype: 'file', - size: 40, - autofocus: true, - label: 'Url', - id: 'link-href', - onchange: urlChange, - onkeyup: updateText - }, - { - name: 'search', - type: 'textbox', - label: 'Search in EVO', - id: 'link-search' - }, - textListCtrl, - linkTitleCtrl, - buildAnchorListControl(data.href), - linkListCtrl, - relListCtrl, - targetListCtrl, - classListCtrl - ], - onSubmit: function(e) { - /*eslint dot-notation: 0*/ - var href; - - data = tinymce.extend(data, e.data); - href = data.href; - - // Delay confirm since onSubmit will move focus - function delayedConfirm(message, callback) - { - var rng = editor.selection.getRng(); - - window.setTimeout(function() { - editor.windowManager.confirm(message, function(state) { - editor.selection.setRng(rng); - callback(state); - }); - }, 0); - } - - function insertLink() - { - - // Reset Modx-TreeAction - if (parent.tree) { - parent.tree.ca = ''; - clearTimeout(checkModxTreeUpdateInterval); - } - ; - - var linkAttrs = { - href: href, - target: data.target ? data.target : null, - rel: data.rel ? data.rel : null, - 'class': data['class'] ? data['class'] : null, - title: data.title ? data.title : null - }; - - if (anchorElm) { - editor.focus(); - - if (onlyText && data.text != initialText) { - if ('innerText' in anchorElm) { - anchorElm.innerText = data.text; - } else { - anchorElm.textContent = data.text; - } - } - - dom.setAttribs(anchorElm, linkAttrs); - - selection.select(anchorElm); - editor.undoManager.add(); - } else { - if (onlyText) { - editor.insertContent(dom.createHTML('a', linkAttrs, dom.encode(data.text))); - } else { - editor.execCommand('mceInsertLink', false, linkAttrs); - } - } - } - - if (!href) { - editor.execCommand('unlink'); - return; - } - - // Is email and not //user@domain.com - if (href.indexOf('@') > 0 && href.indexOf('//') == -1 && href.indexOf('mailto:') == -1) { - delayedConfirm( - 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?', - function(state) { - if (state) { - href = 'mailto:' + href; - } - - insertLink(); - } - ); - - return; - } - - // Is not protocol prefixed - if ((editor.settings.link_assume_external_targets && !/^\w+:/i.test(href)) || - (!editor.settings.link_assume_external_targets && /^\s*www\./i.test(href))) { - delayedConfirm( - 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?', - function(state) { - if (state) { - href = 'http://' + href; - } - - insertLink(); - } - ); - - return; - } - - insertLink(); - }, - onClose: function(e) { - // Reset Modx-TreeAction - if (parent.tree) { - parent.tree.ca = ''; - clearTimeout(checkModxTreeUpdateInterval); - } - ; - } - }); - - var input = document.querySelector('#link-search'), _resultDataset = {}; - autoComplt.enable(input, { - // the hintsFetcher is your customized function which searchs the proper autocomplete hints based on the user's input value. - hintsFetcher: function(v, openList) { - _resultDataset = {}; - var xhr = new XMLHttpRequest(), _link = encodeURI(tinymce4_baseUrl + 'tinymce/plugins/modxlink/search.php' + '?q=' + v); - xhr.open('GET', _link); - xhr.onload = function() { - if (xhr.status === 200) { - //alert(xhr.responseText); - var _results = JSON.parse(xhr.responseText), _e = []; - for (var i = 0; i < Object.keys(_results).length; i++) { - _resultDataset[_results[i].pagetitle] = _results[i]; - _e.push(_results[i].pagetitle); - } - openList(_e); - } else { - console.error('ajax error', _link); - } - }; - xhr.send(); - } - }); - input.autoComplt.setListener('select', function(e, r) { - var _a = document.querySelector('#link-href input'), _title = document.querySelector('#text-to-display'); - _a.value = '[~' + _resultDataset[this.value].id + '~]'; - if (_title.value == '') _title.value = _resultDataset[this.value].title; - }); - - } - - editor.addButton('link', { - icon: 'link', - tooltip: 'Insert/edit link', - shortcut: 'Meta+K', - onclick: createLinkList(showDialog), - stateSelector: 'a[href]' - }); - - editor.addButton('unlink', { - icon: 'unlink', - tooltip: 'Remove link', - cmd: 'unlink', - stateSelector: 'a[href]' - }); - - editor.addShortcut('Meta+K', '', createLinkList(showDialog)); - editor.addCommand('mceLink', createLinkList(showDialog)); - - this.showDialog = showDialog; - - editor.addMenuItem('link', { - icon: 'link', - text: 'Insert/edit link', - shortcut: 'Meta+K', - onclick: createLinkList(showDialog), - stateSelector: 'a[href]', - context: 'insert', - prependToContext: true - }); -}); \ No newline at end of file +if(typeof parent.modx!=='undefined' && typeof parent.modx.tree!=='undefined')var modxOldRessourceId=parent.modx.tree.itemToChange,modxLinkTitle="",checkModxTreeUpdateInterval=void 0,checkModxTreeUpdate=function(){checkModxTreeUpdateInterval=setTimeout(checkModxTreeUpdate,100),parent.modx.tree.itemToChange!=modxOldRessourceId&&(modxOldRessourceId=parent.modx.tree.itemToChange,modxLinkTitle=parent.modx.tree.selectedObjectName,document.getElementById("link-href-inp").value="[~"+modxOldRessourceId+"~]",document.getElementById("text-to-display").value||(document.getElementById("text-to-display").value=modxLinkTitle))};var autoComplt=function(){"use strict";Array.prototype.indexOf||(Array.prototype.indexOf=function(t,e){if(void 0===this||null===this)throw new TypeError('"this" is null or not defined');var n=this.length>>>0;for(e=+e||0,Math.abs(e)===1/0&&(e=0),e<0&&(e+=n)<0&&(e=0);e=0?o.modeMobile:function(){var t=-1;if("Microsoft Internet Explorer"==navigator.appName){var e=navigator.userAgent;null!=new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})").exec(e)&&(t=+RegExp.$1)}return-1===t?NaN:t}()<=9?o.modePC:n().windowWidth>o.modeMobileW?o.modePC:o.modeMobile},n=function(){return window.innerWidth?{windowWidth:window.innerWidth,windowHeight:window.innerHeight}:document.documentElement.offsetHeight?{windowWidth:document.documentElement.offsetWidth,windowHeight:document.documentElement.offsetHeight}:document.body.offsetHeight?{windowWidth:document.body.offsetWidth,windowHeight:document.body.offsetHeight}:document.documentElement.clientHeight?{windowWidth:document.documentElement.clientWidth,windowHeight:document.documentElement.clientHeight}:document.body.clientHeight?{windowWidth:document.body.clientWidth,windowHeight:document.body.clientHeight}:{windowWidth:-1,windowHeight:-1}},o=(o=t={},t.modePC="modePC",t.modeMobile="modeMobile",t.modeMobileW=768,t.autoCompltListClass="autoComplt-list",t.autoCompltHintClass="autoComplt-hint",t.autoCompltHintSelectedClass="autoComplt-hint-selected",t.maxHintNum=e()===o.modePC?10:5,t.autoCompltDelay=250,t.hiddenArg_close_list_n_make_final_selection="hiddenArg_close_list_n_make_final_selection",t.listStatus={attr:"data-listStatus",open:"open"},t.keyCode={up:38,down:40,esc:27,enter:13},t.defaultStyles={autoCompltList:{maxHeight:"none",border:"1px solid #aaa",padding:"0",margin:"0",zIndex:99999,overflowX:"hidden",overflowY:"auto",display:"none",position:"absolute",backgroundColor:"#fff"},autoCompltHint:{height:"1.5em",padding:e()===o.modePC?"2px 6px 2px 10px":"6px 6px 6px 10px",margin:"6px 0",overflow:"hidden",listStyleType:"none",color:"#000",backgroundColor:"#fff",cursor:"default",fontSize:"1em"},autoCompltHintSelected:{color:"#fff",backgroundColor:"#3399ff"}},t.adjStyleAttrs={autoCompltList:["border","maxHeight","backgroundColor"],autoCompltHint:["height","padding","margin","color","backgroundColor","fontSize"],autoCompltHintSelected:["color","backgroundColor"]},t.listenersSupported=["select"],o),i=function(t){return t||(t=window.event),t.target||(t.target=t.srcElement),t.stopBubble=function(){this.cancelBubble=!0,this.stopPropagation&&this.stopPropagation()},t.stopDefault=function(){return this.preventDefault&&this.preventDefault(),this.returnValue=!1,!1},t},l=function(t,e,n){t.addEventListener?t.addEventListener(e,n):t.attachEvent&&t.attachEvent("on"+e,n)},a=function(t,e,n){t.removeEventListener?t.removeEventListener(e,n):t.detachEvent&&t.detachEvent("on"+e,n)},s=function(t,e){var n=null;if(window.getComputedStyle)n=window.getComputedStyle(t)[e]||null;else if(t.currentStyle){n=t.currentStyle&&t.currentStyle[e];var o,i,l=t.style;null==n&&l&&l[e]&&(n=l[e]),o=l.left,(i=t.runtimeStyle&&t.runtimeStyle.left)&&(t.runtimeStyle.left=t.currentStyle.left),l.left="fontSize"===e?"1em":n,n=l.pixelLeft+"px",l.left=o,i&&(t.runtimeStyle.left=i)}return n},r={buildElem:function(t){var e=document.createElement("DIV");return e.innerHTML=t,e.firstChild.cloneNode(!0)},buildHint:function(t,e){return"string"==typeof t&&t?((t=this.buildElem('
    • '+t+"
    • ")).style.height=t.style.lineHeight=e.autoCompltHint.height,t.style.padding=e.autoCompltHint.padding,t.style.margin=e.autoCompltHint.margin,t.style.overflow=e.autoCompltHint.overflow,t.style.listStyleType=e.autoCompltHint.listStyleType,t.style.color=e.autoCompltHint.color,t.style.backgroundColor=e.autoCompltHint.backgroundColor,t.style.cursor=e.autoCompltHint.cursor,t.style.fontSize=e.autoCompltHint.fontSize,t):null},buildList:function(t){var e=this.buildElem('
        ');return e.style.maxHeight=t.autoCompltList.maxHeight,e.style.border=t.autoCompltList.border,e.style.padding=t.autoCompltList.padding,e.style.margin=t.autoCompltList.margin,e.style.zIndex=t.autoCompltList.zIndex,e.style.overflowX=t.autoCompltList.overflowX,e.style.overflowY=t.autoCompltList.overflowY,e.style.display=t.autoCompltList.display,e.style.position=t.autoCompltList.position,e.style.backgroundColor=t.autoCompltList.backgroundColor,e}},u=function(t){this.uiElem=null,this.assocInput=t,this.mouseOnList=!1,this.onMouseSelectionListener=null,this.maxHintNum=o.maxHintNum,this.styles=JSON.parse(JSON.stringify(o.defaultStyles))};return u.prototype.genList=function(){if(!this.uiElem){var t=this;this.uiElem=r.buildList(this.styles),l(this.uiElem,"mouseover",function(e){e=i(e),t.isHint(e.target)&&(t.pick(e.target),t.autoScroll())}),l(this.uiElem,"mouseout",function(e){t.unpick()}),l(this.uiElem,"mousedown",function(e){t.mouseOnList=!0,setTimeout(function(){t.assocInput.focus()},50)}),l(this.uiElem,"mouseup",function(e){e=i(e),t.isHint(e.target)&&(t.pick(e.target),"function"==typeof t.onMouseSelectionListener&&t.onMouseSelectionListener())}),document.body.appendChild(this.uiElem)}},u.prototype.isHint=function(t){return!(!t||"object"!=typeof t||1!==t.nodeType)&&(" "+t.className+" ").indexOf(" "+o.autoCompltHintClass+" ")>=0},u.prototype.putHints=function(t){var e=0;if(t instanceof Array){var n,o,i=[];for(o=Math.min(t.length,this.maxHintNum),n=0;n0){var l=document.createDocumentFragment();for(n=0,e=i.length;n=0||-1===t)){var n=this.uiElem.querySelectorAll("."+o.autoCompltHintClass);n.length>0&&(e=n[e=-1===(e=+t)||e>n.length-1?n.length-1:e])}null!==e&&(this.unpick(),e.className+=" "+o.autoCompltHintSelectedClass,e.style.color=this.styles.autoCompltHintSelected.color,e.style.backgroundColor=this.styles.autoCompltHintSelected.backgroundColor)}},u.prototype.unpick=function(){if(this.uiElem){var t=this.getPicked();t&&(t.className=o.autoCompltHintClass,t.style.color=this.styles.autoCompltHint.color,t.style.backgroundColor=this.styles.autoCompltHint.backgroundColor)}},u.prototype.getPicked=function(){return this.uiElem&&this.uiElem.querySelector("."+o.autoCompltHintSelectedClass)||null},{enable:function(t,n){if(t&&"object"==typeof t&&"string"==typeof t.tagName&&"input"==t.tagName.toLowerCase()&&"text"==t.type&&1===t.nodeType&&!t.autoComplt){t.autoComplt={};var s=o.autoCompltDelay,r=!0,c="",d=null,m=null,p=new u(t),f=function(){if(t.value.length>0&&r&&"function"==typeof d&&c!==t.value){var e={that:t,compltTarget:c=t.value,compltTargetMatchCurrentTarget:function(){return e.compltTarget===c},call:function(){e.compltTargetMatchCurrentTarget()&&d.call(e.that,e.compltTarget,e.openHint)},openHint:function(t){e.compltTargetMatchCurrentTarget()&&(p.putHints(t)?p.open():e.that.autoComplt.close())}};setTimeout(e.call,s)}},h=function(){if(r){var e=p.getPicked();t.value=e?e.innerHTML:c}},g=function(e){p.mouseOnList?(t.focus(),p.mouseOnList=!1):p.isOpen()&&t.autoComplt.close(o.hiddenArg_close_list_n_make_final_selection)},y=function(n){if(e()!==o.modeMobile&&(n=i(n),r))if("keydown"!=n.type||!p.isOpen()||n.keyCode!==o.keyCode.up&&n.keyCode!==o.keyCode.down){if("keyup"==n.type){var l=!1;switch(n.keyCode){case o.keyCode.up:case o.keyCode.down:p.isOpen()||(l=!0);break;case o.keyCode.esc:p.isOpen()&&(t.value=c,t.autoComplt.close(o.hiddenArg_close_list_n_make_final_selection));break;case o.keyCode.enter:p.isOpen()&&(h(),t.autoComplt.close(o.hiddenArg_close_list_n_make_final_selection));break;default:l=!0}l&&(t.value.length>0?f():t.autoComplt.close())}}else{var a=p.getPicked();n.keyCode===o.keyCode.up?a?a.previousSibling?p.pick(a.previousSibling):p.unpick():p.pick(-1):n.keyCode===o.keyCode.down&&(a?a.nextSibling?p.pick(a.nextSibling):p.unpick():p.pick(0)),p.autoScroll(),h()}};return t.autoComplt.setHintsFetcher=function(t){return(null===t||"function"==typeof t)&&(d=t,!0)},t.autoComplt.setListener=function(t,e){return(null===e||"function"==typeof e)&&o.listenersSupported.indexOf(t)>=0&&(null==m&&(m={}),m[t]=e,!0)},t.autoComplt.setStyles=function(t,e){var n,i,l=!1;switch(t){case o.autoCompltListClass:n=p.styles.autoCompltList,i=o.adjStyleAttrs.autoCompltList;break;case o.autoCompltHintClass:n=p.styles.autoCompltHint,i=o.adjStyleAttrs.autoCompltHint;break;case o.autoCompltHintSelectedClass:n=p.styles.autoCompltHintSelected,i=o.adjStyleAttrs.autoCompltHintSelected}if(e instanceof Object&&n&&i)for(var a=0;a0&&(n||(n={}),s=n.delay=e),void 0!==t.maxHintNum&&(e=Math.floor(t.maxHintNum))>0&&(n||(n={}),p.maxHintNum=n.maxHintNum=e));return n},t.autoComplt.close=function(){var e;c="",p.close(),r&&""!==t.value&&arguments[0]===o.hiddenArg_close_list_n_make_final_selection&&(e="select",null!=m&&"function"==typeof m[e]&&m[e].call(t))},t.autoComplt.enable=function(){r=!0},t.autoComplt.disable=function(){r=!1,this.close()},t.autoComplt.destroy=function(){a(t,"blur",g),a(t,"keyup",y),a(t,"keydown",y),this.disable(),delete t.autoComplt},p.onMouseSelectionListener=function(){h(),t.autoComplt.close(o.hiddenArg_close_list_n_make_final_selection)},l(t,"blur",g),l(t,"keyup",y),l(t,"keydown",y),l(t,"input",function(n){e()!==o.modePC&&(t.value.length>0?f():t.autoComplt.close())}),n instanceof Object&&(t.autoComplt.config(n),t.autoComplt.setHintsFetcher(n.hintsFetcher)),t}return null}}}();tinymce.PluginManager.add("modxlink",function(t){function e(e){return function(){var n=t.settings.link_list;"string"==typeof n?tinymce.util.XHR.send({url:n,success:function(t){e(tinymce.util.JSON.parse(t))}}):"function"==typeof n?n(e):e(n)}}function n(t,e,n){return function t(n,o){return o=o||[],tinymce.each(n,function(n){var i={text:n.text||n.title};n.menu?i.menu=t(n.menu):(i.value=n.value,e&&e(i)),o.push(i)}),o}(t,n||[])}function o(e){parent.tree&&(parent.tree.ca="disabled",checkModxTreeUpdate.call(this));var o,i,l,a,s,r,u,c,d,m,p,f,h={},g=t.selection,y=t.dom;function C(t){var e=a.find("#text");(!e.value()||t.lastControl&&e.value()==t.lastControl.text())&&e.value(t.control.text()),a.find("#href").value(t.control.value())}function v(){!l&&0===h.text.length&&s&&this.parent().parent().find("#text")[0].value(this.value())}o=g.getNode(),i=y.getParent(o,"a[href]"),s=function(t){var e=g.getContent();if(/]+>[^<]+<\/a>$/.test(e)||-1==e.indexOf("href=")))return!1;if(t){var n,o=t.childNodes;if(0===o.length)return!1;for(n=o.length-1;n>=0;n--)if(3!=o[n].nodeType)return!1}return!0}(),h.text=l=i?i.innerText||i.textContent:g.getContent({format:"text"}),h.href=i?y.getAttrib(i,"href"):"",i?h.target=y.getAttrib(i,"target"):t.settings.default_link_target&&(h.target=t.settings.default_link_target),(f=y.getAttrib(i,"rel"))&&(h.rel=f),(f=y.getAttrib(i,"class"))&&(h.class=f),(f=y.getAttrib(i,"title"))&&(h.title=f),s&&(r={name:"text",type:"textbox",size:40,label:"Text to display",id:"text-to-display",onchange:function(){h.text=this.value()}}),e&&(u={type:"listbox",label:"Link list",values:n(e,function(e){e.value=t.convertURL(e.value||e.url,"href")},[{text:"None",value:""}]),onselect:C,value:t.convertURL(h.href,"href"),onPostRender:function(){u=this}}),!1!==t.settings.target_list&&(t.settings.target_list||(t.settings.target_list=[{text:"None",value:""},{text:"New window",value:"_blank"}]),d={name:"target",type:"listbox",label:"Target",values:n(t.settings.target_list)}),t.settings.rel_list&&(c={name:"rel",type:"listbox",label:"Rel",values:n(t.settings.rel_list)}),t.settings.link_class_list&&(m={name:"class",type:"listbox",label:"Class",values:n(t.settings.link_class_list,function(e){e.value&&(e.textStyle=function(){return t.formatter.getCssText({inline:"a",classes:[e.value]})})})}),!1!==t.settings.link_title&&(p={name:"title",type:"textbox",label:"Title",value:h.title}),a=t.windowManager.open({title:"Insert link",data:h,body:[{name:"href",type:"FileImagePicker",filetype:"file",size:40,autofocus:!0,label:"Url",id:"link-href",onchange:function(e){var n=e.meta||{};u&&u.value(t.convertURL(this.value(),"href")),tinymce.each(e.meta,function(t,e){a.find("#"+e).value(t)}),n.text||v.call(this)},onkeyup:v},{name:"search",type:"textbox",label:"Search in EVO",id:"link-search"},r,p,function(e){var n=[];if(tinymce.each(t.dom.select("a:not([href])"),function(t){var o=t.name||t.id;o&&n.push({text:o,value:"#"+o,selected:-1!=e.indexOf("#"+o)})}),n.length)return n.unshift({text:"None",value:""}),{name:"anchor",type:"listbox",label:"Anchors",values:n,onselect:C}}(h.href),u,c,d,m],onSubmit:function(e){var n;function o(e,n){var o=t.selection.getRng();window.setTimeout(function(){t.windowManager.confirm(e,function(e){t.selection.setRng(o),n(e)})},0)}function a(){parent.tree&&(parent.tree.ca="",clearTimeout(checkModxTreeUpdateInterval));var e={href:n,target:h.target?h.target:null,rel:h.rel?h.rel:null,class:h.class?h.class:null,title:h.title?h.title:null};i?(t.focus(),s&&h.text!=l&&("innerText"in i?i.innerText=h.text:i.textContent=h.text),y.setAttribs(i,e),g.select(i),t.undoManager.add()):s?t.insertContent(y.createHTML("a",e,y.encode(h.text))):t.execCommand("mceInsertLink",!1,e)}h=tinymce.extend(h,e.data),(n=h.href)?n.indexOf("@")>0&&-1==n.indexOf("//")&&-1==n.indexOf("mailto:")?o("The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",function(t){t&&(n="mailto:"+n),a()}):t.settings.link_assume_external_targets&&!/^\w+:/i.test(n)||!t.settings.link_assume_external_targets&&/^\s*www\./i.test(n)?o("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?",function(t){t&&(n="http://"+n),a()}):a():t.execCommand("unlink")},onClose:function(t){parent.tree&&(parent.tree.ca="",clearTimeout(checkModxTreeUpdateInterval))}});var x=document.querySelector("#link-search"),b={};autoComplt.enable(x,{hintsFetcher:function(t,e){b={};var n=new XMLHttpRequest,o=encodeURI(tinymce4_baseUrl+"tinymce/plugins/modxlink/search.php?q="+t);n.open("GET",o),n.onload=function(){if(200===n.status){for(var t=JSON.parse(n.responseText),i=[],l=0;l',e.classes.add("has-open"),'
        '+t+"
        "}}))}); diff --git a/assets/plugins/updater/plugin.updater.php b/assets/plugins/updater/plugin.updater.php index 129142abdf..c18a665b84 100755 --- a/assets/plugins/updater/plugin.updater.php +++ b/assets/plugins/updater/plugin.updater.php @@ -23,6 +23,7 @@ $version = isset($version) ? $version : 'evolution-cms/evolution'; $type = isset($type) ? $type : 'tags'; $showButton = isset($showButton) ? $showButton : 'AdminOnly'; +$result = ''; if ($role != 1 && $wdgVisibility == 'AdminOnly') { @@ -207,15 +208,19 @@ switch ($_GET['q']) { case $_SESSION['updatelink']: $currentVersion = $modx->getVersionData(); - $commit = $_GET['sha']; + $commit = isset($_GET['sha']) ? $_GET['sha'] : ''; if ($_SESSION['updateversion'] != $currentVersion['version'] || (isset($commit) && $type == 'commits')) { file_put_contents(MODX_BASE_PATH . 'update.php', 'errors[] = array("ERROR:Download", $e->getMessage()); @@ -257,9 +262,8 @@ function removeFolder($path) return; } - $it = new RecursiveDirectoryIterator($dir); - $files = new RecursiveIteratorIterator($it, - RecursiveIteratorIterator::CHILD_FIRST); + $it = new RecursiveDirectoryIterator($dir); + $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST); foreach ($files as $file) { if ($file->getFilename() === "." || $file->getFilename() === "..") { continue; @@ -273,10 +277,12 @@ function removeFolder($path) rmdir($dir); } -function copyFolder($src, $dest) -{ - $path = realpath($src); - $dest = realpath($dest); +function copyFolder( + $src, + $dest +) { + $path = realpath($src); + $dest = realpath($dest); $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST); foreach ($objects as $name => $object) { @@ -287,13 +293,15 @@ function copyFolder($src, $dest) } if (is_writable($dest . $startsAt) and $object->isFile()) { - copy((string) $name, $dest . $startsAt . DIRECTORY_SEPARATOR . basename($name)); + copy((string)$name, $dest . $startsAt . DIRECTORY_SEPARATOR . basename($name)); } } } -function mmkDir($folder, $perm = 0777) -{ +function mmkDir( + $folder, + $perm = 0777 +) { if (!is_dir($folder)) { mkdir($folder, $perm); } @@ -301,7 +309,7 @@ function mmkDir($folder, $perm = 0777) $version = "' . $version . '"; -downloadFile("https://github.com/".$version."/archive/" . $_GET["version"] . ".zip", "evo.zip"); +downloadFile("https://github.com/" . $version . "/archive/" . $_GET["version"] . ".zip", "evo.zip"); $zip = new ZipArchive; $res = $zip->open(__DIR__ . "/evo.zip"); $zip->extractTo(__DIR__ . "/temp"); @@ -323,23 +331,24 @@ function mmkDir($folder, $perm = 0777) unlink(__DIR__ . "/temp/" . $dir . "/sample-robots.txt"); unlink(__DIR__ . "/temp/" . $dir . "/composer.json"); - -if(is_file(__DIR__ . "/assets/cache/siteManager.php")){ +if (is_file(__DIR__ . "/assets/cache/siteManager.php")) { unlink(__DIR__ . "/temp/" . $dir . "/assets/cache/siteManager.php"); include_once(__DIR__ . "/assets/cache/siteManager.php"); - if(!defined("MGR_DIR")){ define("MGR_DIR","manager"); } - if(MGR_DIR != "manager"){ - mmkDir(__DIR__."/temp/".$dir."/".MGR_DIR); - copyFolder(__DIR__."/temp/".$dir."/manager", __DIR__."/temp/".$dir."/".MGR_DIR); - removeFolder(__DIR__."/temp/".$dir."/manager"); - } + if (!defined("MGR_DIR")) { + define("MGR_DIR", "manager"); + } + if (MGR_DIR != "manager") { + mmkDir(__DIR__ . "/temp/" . $dir . "/" . MGR_DIR); + copyFolder(__DIR__ . "/temp/" . $dir . "/manager", __DIR__ . "/temp/" . $dir . "/" . MGR_DIR); + removeFolder(__DIR__ . "/temp/" . $dir . "/manager"); + } // echo __DIR__."/temp/".$dir."/".MGR_DIR; } -copyFolder(__DIR__."/temp/".$dir, __DIR__."/"); -removeFolder(__DIR__."/temp"); -unlink(__DIR__."/evo.zip"); -unlink(__DIR__."/update.php"); +copyFolder(__DIR__ . "/temp/" . $dir, __DIR__ . "/"); +removeFolder(__DIR__ . "/temp"); +unlink(__DIR__ . "/evo.zip"); +unlink(__DIR__ . "/update.php"); header("Location: ' . constant('MODX_SITE_URL') . 'install/index.php?action=mode");'); if ($result === false){ echo 'Update failed: cannot write to ' . MODX_BASE_PATH . 'update.php'; diff --git a/assets/snippets/DocLister/core/DocLister.abstract.php b/assets/snippets/DocLister/core/DocLister.abstract.php index 2d0aa0459d..09f9bbce9e 100644 --- a/assets/snippets/DocLister/core/DocLister.abstract.php +++ b/assets/snippets/DocLister/core/DocLister.abstract.php @@ -48,14 +48,14 @@ abstract class DocLister * @var DocumentParser * @access protected */ - protected $modx = null; + protected $modx; /** * Шаблонизатор чанков * @var DLTemplate * @access protected */ - protected $DLTemplate = null; + protected $DLTemplate; /** * Массив загруженных экстендеров @@ -133,7 +133,7 @@ abstract class DocLister * @var DLdebug|xNop * @access public */ - public $debug = null; + public $debug; /** * Массив дополнительно подключаемых таблиц с псевдонимами @@ -160,7 +160,8 @@ abstract class DocLister /** @var string имя шаблона обертки для записей */ public $ownerTPL = ''; - public $FS = null; + /** @var \Helpers\FS */ + public $FS; /** @var string результатирующая строка которая была последний раз сгенирирована * вызовами методов DocLister::render и DocLister::getJSON */ @@ -175,16 +176,21 @@ abstract class DocLister protected $alias = ''; /** @var null|paginate_DL_Extender */ - protected $extPaginate = null; + protected $extPaginate; /** @var null|Helpers\Config */ - public $config = null; + public $config; + + /** + * @var cache_DL_Extender + */ + protected $extCache; /** * Конструктор контроллеров DocLister * * @param DocumentParser $modx объект DocumentParser - основной класс MODX - * @param array $cfg массив параметров сниппета + * @param mixed $cfg массив параметров сниппета * @param int $startTime время запуска сниппета * @throws Exception */ @@ -202,7 +208,7 @@ public function __construct($modx, $cfg = array(), $startTime = null) $this->modx = $modx; $this->setDebug(1); - if (!is_array($cfg) || empty($cfg)) { + if (! is_array($cfg) || empty($cfg)) { $cfg = $this->modx->Event->params; } } else { @@ -283,8 +289,7 @@ public function __construct($modx, $cfg = array(), $startTime = null) if ($ext = $this->getCFGDef('templateExtension')) { $DLTemplate->setTemplateExtension($ext); } - $DLTemplate->setTwigTemplateVars(array('DocLister' => $this)); - $this->DLTemplate = $DLTemplate; + $this->DLTemplate = $DLTemplate->setTemplateData(array('DocLister' => $this)); } /** @@ -307,7 +312,7 @@ public function smartSplit($str) break; case ')': $open--; - if ($open == 0) { + if ($open === 0) { $res[] = $cur . ')'; $cur = ''; } else { @@ -319,7 +324,7 @@ public function smartSplit($str) $cur .= $e; break; case ';': - if ($open == 0) { + if ($open === 0) { $res[] = $cur; $cur = ''; } else { @@ -331,11 +336,11 @@ public function smartSplit($str) } } $cur = preg_replace("/(\))$/u", '', $cur); - if ($cur != '') { + if ($cur !== '') { $res[] = $cur; } - return $res; + return array_reverse($res); } /** @@ -420,7 +425,7 @@ public function getTable($name, $alias = '') $this->_table[$name] = $this->modx->getFullTableName($name); } $table = $this->_table[$name]; - if (!empty($alias) && is_scalar($alias)) { + if (! empty($alias) && is_scalar($alias)) { $table .= " as `" . $alias . "`"; } @@ -1001,7 +1006,8 @@ public function renderWrap($data) { $out = $data; $docs = count($this->_docs) - $this->skippedDocs; - if ((($this->getCFGDef("noneWrapOuter", "1") && $docs == 0) || $docs > 0) && !empty($this->ownerTPL)) { + $wrap = $this->getCFGDef('prepareWrap'); + if ((($this->getCFGDef("noneWrapOuter", "1") && $docs == 0) || $docs > 0) && !empty($this->ownerTPL) || !empty($wrap)) { $this->debug->debug("", "renderWrapTPL", 2); $parse = true; $plh = array($this->getCFGDef("sysKey", "dl") . ".wrap" => $data); @@ -1018,7 +1024,7 @@ public function renderWrap($data) 'nameParam' => 'prepareWrap', 'return' => 'placeholders' )); - if (is_bool($params) && $params === false) { + if ($params === false) { $out = $data; $parse = false; } @@ -1635,7 +1641,7 @@ protected function getFilters($filter_string) { $this->debug->debug("getFilters: " . $this->debug->dumpData($filter_string), 'getFilter', 1); // the filter parameter tells us, which filters can be used in this query - $filter_string = trim($filter_string, ' ;'); + $filter_string = ltrim(trim($filter_string, ';')); if (!$filter_string) { return; } @@ -1647,10 +1653,19 @@ protected function getFilters($filter_string) $logic_op_found = true; $subfilters = mb_substr($filter_string, strlen($op) + 1, mb_strlen($filter_string, "UTF-8"), "UTF-8"); $subfilters = $this->smartSplit($subfilters); - foreach ($subfilters as $subfilter) { - $subfilter = $this->getFilters(trim($subfilter)); + $lastFilter = ''; + foreach ($subfilters as $filter) { + /** + * С правой стороны не выполняется trim, т.к. там находятся значения. А они могу быть чувствительны к пробелам + */ + $subfilter = $this->getFilters(ltrim($filter) . ltrim($lastFilter)); if (!$subfilter) { - continue; + $lastFilter = explode(';', $filter, 2); + $subfilter = isset($lastFilter[1]) ? $this->getFilters($lastFilter[1]) : ''; + $lastFilter = $lastFilter[0]; + if (!$subfilter) { + continue; + } } if ($subfilter['join']) { $joins[] = $subfilter['join']; @@ -1659,8 +1674,8 @@ protected function getFilters($filter_string) $wheres[] = $subfilter['where']; } } - $output['join'] = !empty($joins) ? implode(' ', $joins) : ''; - $output['where'] = !empty($wheres) ? '(' . implode($sql, $wheres) . ')' : ''; + $output['join'] = !empty($joins) ? implode(' ', array_reverse($joins)) : ''; + $output['where'] = !empty($wheres) ? '(' . implode($sql, array_reverse($wheres)) . ')' : ''; } } @@ -1671,7 +1686,8 @@ protected function getFilters($filter_string) $output = false; } else { $output['join'] = $filter->get_join(); - $output['where'] = stripslashes($filter->get_where()); + $output['where'] = $filter->get_where(); + } } $this->debug->debug('getFilter'); diff --git a/assets/snippets/DocLister/core/controller/onetable.php b/assets/snippets/DocLister/core/controller/onetable.php index c69754ae0e..1c68145753 100644 --- a/assets/snippets/DocLister/core/controller/onetable.php +++ b/assets/snippets/DocLister/core/controller/onetable.php @@ -127,7 +127,7 @@ public function _render($tpl = '') 'data' => $item, 'nameParam' => 'prepare' )); - if (is_bool($item) && $item === false) { + if ($item === false) { $this->skippedDocs++; continue; } @@ -206,7 +206,7 @@ public function getJSON($data, $fields, $array = array()) if ($extPrepare) { $row = $extPrepare->init($this, array('data' => $row)); - if (is_bool($row) && $row === false) { + if ($row === false) { continue; } } @@ -250,7 +250,7 @@ protected function getDocList() $limit = $this->LimitSQL($this->getCFGDef('queryLimit', 0)); $fields = $this->getCFGDef('selectFields', '*'); - $group = $this->getGroupSQL($this->getCFGDef('groupBy', '')); + $group = $this->getGroupSQL($this->getCFGDef('groupBy', $this->getPK())); $sort = $this->SortOrderSQL($this->getPK()); $rs = $this->dbQuery("SELECT {$fields} FROM {$from} {$where} {$group} {$sort} {$limit}"); @@ -318,7 +318,7 @@ protected function getChildrenList() $where = ''; } $fields = $this->getCFGDef('selectFields', '*'); - $group = $this->getGroupSQL($this->getCFGDef('groupBy', '')); + $group = $this->getGroupSQL($this->getCFGDef('groupBy', $this->getPK())); $sort = $this->SortOrderSQL($this->getPK()); $limit = $this->LimitSQL($this->getCFGDef('queryLimit', 0)); if ($sanitarInIDs != "''" || $this->getCFGDef('ignoreEmpty', '0')) { @@ -356,32 +356,30 @@ public function getChildrenCount() $where = array(); } if ($sanitarInIDs != "''") { - if ($sanitarInIDs != "''") { - switch ($this->getCFGDef('idType', 'parents')) { - case 'parents': - switch ($this->getCFGDef('showParent', '0')) { - case '-1': - $tmpWhere = "{$this->getParentField()} IN ({$sanitarInIDs})"; - break; - case 0: - $tmpWhere = "{$this->getParentField()} IN ({$sanitarInIDs}) AND {$this->getPK()} NOT IN({$sanitarInIDs})"; - break; - case 1: - default: - $tmpWhere = "({$this->getParentField()} IN ({$sanitarInIDs}) OR {$this->getPK()} IN({$sanitarInIDs}))"; - break; - } - if (($addDocs = $this->getCFGDef('documents', '')) != '') { - $addDocs = $this->sanitarIn($this->cleanIDs($addDocs)); - $where[] = "((" . $tmpWhere . ") OR {$this->getPK()} IN({$addDocs}))"; - } else { - $where[] = $tmpWhere; - } - break; - case 'documents': - $where[] = "{$this->getPK()} IN({$sanitarInIDs})"; - break; - } + switch ($this->getCFGDef('idType', 'parents')) { + case 'parents': + switch ($this->getCFGDef('showParent', '0')) { + case '-1': + $tmpWhere = "{$this->getParentField()} IN ({$sanitarInIDs})"; + break; + case 0: + $tmpWhere = "{$this->getParentField()} IN ({$sanitarInIDs}) AND {$this->getPK()} NOT IN({$sanitarInIDs})"; + break; + case 1: + default: + $tmpWhere = "({$this->getParentField()} IN ({$sanitarInIDs}) OR {$this->getPK()} IN({$sanitarInIDs}))"; + break; + } + if (($addDocs = $this->getCFGDef('documents', '')) != '') { + $addDocs = $this->sanitarIn($this->cleanIDs($addDocs)); + $where[] = "((" . $tmpWhere . ") OR {$this->getPK()} IN({$addDocs}))"; + } else { + $where[] = $tmpWhere; + } + break; + case 'documents': + $where[] = "{$this->getPK()} IN({$sanitarInIDs})"; + break; } } if (!empty($where)) { @@ -393,7 +391,7 @@ public function getChildrenCount() $group = $this->getGroupSQL($this->getCFGDef('groupBy', $this->getPK())); $maxDocs = $this->getCFGDef('maxDocs', 0); $limit = $maxDocs > 0 ? $this->LimitSQL($this->getCFGDef('maxDocs', 0)) : ''; - $rs = ("SELECT count(*) FROM (SELECT count(*) FROM {$from} {$where} {$group} {$limit}) as `tmp`"); + $rs = $this->dbQuery("SELECT count(*) FROM (SELECT count(*) FROM {$from} {$where} {$group} {$limit}) as `tmp`"); $out = $this->modx->db->getValue($rs); } diff --git a/assets/snippets/DocLister/core/controller/shopkeeper.php b/assets/snippets/DocLister/core/controller/shopkeeper.php index 186639d5f5..97faf3031a 100644 --- a/assets/snippets/DocLister/core/controller/shopkeeper.php +++ b/assets/snippets/DocLister/core/controller/shopkeeper.php @@ -108,7 +108,7 @@ public function _render($tpl = '') 'data' => $item, 'nameParam' => 'prepare' )); - if (is_bool($item) && $item === false) { + if ($item === false) { $this->skippedDocs++; continue; } @@ -199,11 +199,14 @@ public function getChildrenCount() if (trim($where) == 'WHERE') { $where = ''; } - $group = $this->getGroupSQL($this->getCFGDef('groupBy', 'c.id')); + $group = $this->getGroupSQL($this->getCFGDef('groupBy', $this->getPK())); $maxDocs = $this->getCFGDef('maxDocs', 0); $limit = $maxDocs > 0 ? $this->LimitSQL($this->getCFGDef('maxDocs', 0)) : ''; - $rs = $this->dbQuery("SELECT count(*) FROM (SELECT count(*) FROM {$from} {$where} {$group} {$limit}) as `tmp`"); + $subQuery = trim(implode(' ', array( + 'SELECT', 'count(*)', 'FROM', $from, $where, $group, $limit + ))); + $rs = $this->dbQuery("SELECT count(*) FROM ({$subQuery}) as `tmp`"); $out = $this->modx->db->getValue($rs); } @@ -247,7 +250,7 @@ protected function getDocList() $fields = $this->getCFGDef('selectFields', 'c.*'); - $group = $this->getGroupSQL($this->getCFGDef('groupBy', '')); + $group = $this->getGroupSQL($this->getCFGDef('groupBy', $this->getPK())); $sort = $this->SortOrderSQL("c.createdon"); list($tbl_site_content, $sort) = $this->injectSortByTV($tbl_site_content . ' ' . $this->_filters['join'], $sort); @@ -356,7 +359,7 @@ protected function getChildrenList() $where = ''; } $fields = $this->getCFGDef('selectFields', 'c.*'); - $group = $this->getGroupSQL($this->getCFGDef('groupBy', '')); + $group = $this->getGroupSQL($this->getCFGDef('groupBy', $this->getPK())); if ($sanitarInIDs != "''" || $this->getCFGDef('ignoreEmpty', '0')) { $rs = $this->dbQuery("SELECT {$fields} FROM " . $from . " " . $where . " " . $group . " " . diff --git a/assets/snippets/DocLister/core/controller/site_content.php b/assets/snippets/DocLister/core/controller/site_content.php index 5fb521c001..84e257219d 100644 --- a/assets/snippets/DocLister/core/controller/site_content.php +++ b/assets/snippets/DocLister/core/controller/site_content.php @@ -186,7 +186,7 @@ public function _render($tpl = '') 'data' => $item, 'nameParam' => 'prepare' )); - if (is_bool($item) && $item === false) { + if ($item === false) { $this->skippedDocs++; continue; } @@ -289,7 +289,7 @@ public function getJSON($data, $fields, $array = array()) if ($extPrepare) { $row = $extPrepare->init($this, array('data' => $row)); - if (is_bool($row) && $row === false) { + if ($row === false) { continue; } } @@ -372,7 +372,7 @@ public function getChildrenCount() if (trim($where) == 'WHERE') { $where = ''; } - $group = $this->getGroupSQL($this->getCFGDef('groupBy', 'c.id')); + $group = $this->getGroupSQL($this->getCFGDef('groupBy', $this->getPK())); $q_true = $q_true ? $q_true : $group != ''; if ($q_true) { @@ -427,7 +427,7 @@ protected function getDocList() $fields = $this->getCFGDef('selectFields', 'c.*'); - $group = $this->getGroupSQL($this->getCFGDef('groupBy', '')); + $group = $this->getGroupSQL($this->getCFGDef('groupBy', $this->getPK())); $sort = $this->SortOrderSQL("if(c.pub_date=0,c.createdon,c.pub_date)"); list($tbl_site_content, $sort) = $this->injectSortByTV( $tbl_site_content . ' ' . $this->_filters['join'], @@ -551,7 +551,7 @@ protected function getChildrenList() $where = ''; } $fields = $this->getCFGDef('selectFields', 'c.*'); - $group = $this->getGroupSQL($this->getCFGDef('groupBy', '')); + $group = $this->getGroupSQL($this->getCFGDef('groupBy', $this->getPK())); if ($sanitarInIDs != "''" || $this->getCFGDef('ignoreEmpty', '0')) { $rs = $this->dbQuery("SELECT {$fields} FROM " . $from . " " . $where . " " . diff --git a/assets/snippets/DocLister/core/controller/site_content_menu.php b/assets/snippets/DocLister/core/controller/site_content_menu.php index 5b2637890c..53c20a27a3 100644 --- a/assets/snippets/DocLister/core/controller/site_content_menu.php +++ b/assets/snippets/DocLister/core/controller/site_content_menu.php @@ -335,7 +335,7 @@ public function _render($tpl = '') 'data' => $data, 'nameParam' => 'prepare' )); - if (is_bool($data) && $data === false) { + if ($data === false) { continue; } } @@ -635,7 +635,7 @@ public function getJSON($data, $fields, $array = array()) 'data' => $data, 'nameParam' => 'prepare' )); - if (is_bool($data) && $data === false) { + if ($data === false) { continue; } } diff --git a/assets/snippets/DocLister/core/extender/e.extender.inc b/assets/snippets/DocLister/core/extender/e.extender.inc index b49eb2ec97..6b85deac42 100755 --- a/assets/snippets/DocLister/core/extender/e.extender.inc +++ b/assets/snippets/DocLister/core/extender/e.extender.inc @@ -1,42 +1,42 @@ - - */ -class e_DL_Extender extends extDocLister -{ - /** - * @return mixed - */ - protected function run() - { - $out = $this->getCFGDef('data', array()); - if (($eFields = $this->DocLister->getCFGDef('e', 'title')) != '') { - if (is_scalar($eFields)) { - $eFields = explode(",", $eFields); - } - $sanitarTagsFields = array(); - if ($sanitarTags = $this->DocLister->getCFGDef('sanitarTags',0)) { - if (is_numeric($sanitarTags) && is_array($eFields)) { - $sanitarTagsFields = $eFields; - } elseif (is_scalar($sanitarTags)) { - $sanitarTagsFields = explode(",", $sanitarTags); - } - } - if (is_array($eFields)) { - foreach ($eFields as $field) { - $val = APIHelpers::getkey($out, $field, ''); - if (in_array($field, $sanitarTagsFields)) $val = APIHelpers::sanitarTag($val); - $out['e.' . $field] = APIHelpers::e($val); - } - } - } - - return $out; - } -} + + */ +class e_DL_Extender extends extDocLister +{ + /** + * @return mixed + */ + protected function run() + { + $out = $this->getCFGDef('data', array()); + if (($eFields = $this->DocLister->getCFGDef('e', 'title')) != '') { + if (is_scalar($eFields)) { + $eFields = explode(",", $eFields); + } + $sanitarTagsFields = array(); + if ($sanitarTags = $this->DocLister->getCFGDef('sanitarTags',0)) { + if (is_numeric($sanitarTags) && is_array($eFields)) { + $sanitarTagsFields = $eFields; + } elseif (is_scalar($sanitarTags)) { + $sanitarTagsFields = explode(",", $sanitarTags); + } + } + if (is_array($eFields)) { + foreach ($eFields as $field) { + $val = APIHelpers::getkey($out, $field, ''); + if (in_array($field, $sanitarTagsFields)) $val = APIHelpers::sanitarTag($val); + $out['e.' . $field] = APIHelpers::e($val); + } + } + } + + return $out; + } +} diff --git a/assets/snippets/DocLister/core/extender/paginate.extender.inc b/assets/snippets/DocLister/core/extender/paginate.extender.inc index e08761fbe5..b69f8ed436 100755 --- a/assets/snippets/DocLister/core/extender/paginate.extender.inc +++ b/assets/snippets/DocLister/core/extender/paginate.extender.inc @@ -1,318 +1,318 @@ - - * @see http://mis-algoritmos.com/2007/05/27/digg-style-pagination-class - */ -include_once(MODX_BASE_PATH . "assets/snippets/DocLister/lib/DLpaginate.class.php"); -include_once(MODX_BASE_PATH . "assets/snippets/DocLister/lib/DLpaginateReversed.class.php"); - -/** - * Class paginate_DL_Extender - */ -class paginate_DL_Extender extends extDocLister -{ - /** - * @var bool - */ - protected $lang = true; - protected $reverse = false; - protected $count = 0; - /** - * @var array - */ - private $_pages = array(); - - /** - * Call method - * - * @return int total pages - */ - protected function run() - { - if (($paginate = $this->DocLister->getCFGDef('paginate', '')) == '') { - $this->DocLister->config->setConfig(array('start' => 0)); - } - $this->reverse = $this->DocLister->getCFGDef('reversePagination', 0); - $pages = $this->getListPages($paginate, 'total'); - $display = $this->DocLister->getCFGDef('display', 0); - switch ($paginate) { - case 'offset': - $requestName = $this->getRequestName('start'); - $start = (isset($_GET[$requestName]) && intval($_GET[$requestName]) > 1) ? intval($_GET[$requestName]) : 0; - $this->_pages['current'] = ceil($start / $display) + 1; - if ($this->reverse && $this->_pages['current'] > 1) { - $offset = $pages * $display - $this->count; - $start -= $offset; - } - $this->DocLister->config->setConfig(array('start' => $start)); - break; - case 'pages': - default: - $paginate = 'pages'; - $requestName = $this->getRequestName('page'); - if ( - isset($_GET[$requestName]) - && !$this->DocLister->getCFGDef('noRedirect', 0) - ) { - if ((!$this->reverse && (intval($_GET[$requestName]) <= 1 || intval($_GET[$requestName]) > $pages)) || ($this->reverse && (intval($_GET[$requestName]) >= $pages || intval($_GET[$requestName]) < 1))) { - $this->modx->sendRedirect($this->getUrl()); - } - } - if ($this->reverse) { - $start = (isset($_GET[$requestName]) && intval($_GET[$requestName]) <= $pages) ? ($pages - intval($_GET[$requestName])) : 0; - $this->_pages['current'] = $start + 1; - $offset = $pages * $display - $this->count; - if ($this->_pages['current'] > 1) { - $this->DocLister->config->setConfig(array('start' => $start * $display - $offset)); - } else { - $display = $display - $offset; - $this->DocLister->config->setConfig(array('display' => $display)); - } - } else { - $start = (isset($_GET[$requestName]) && intval($_GET[$requestName]) > 1) ? (intval($_GET[$requestName]) - 1) : 0; - $this->_pages['current'] = $start + 1; - $this->DocLister->config->setConfig(array('start' => $start * $display)); - } - - - break; - } - - if ($this->reverse) { - $currentPage = $pages + 1 - $this->currentPage(); - $diff = $currentPage == $this->totalPage() ? 0 : $display * $pages - $this->count; - $from = ($this->currentPage() - 1) * $display + 1 - $diff; - $to = $currentPage == $this->totalPage() ? $display : $from - 1 + $display; - } else { - $currentPage = $this->currentPage(); - $from = ($this->currentPage() - 1) * $display + 1; - $to = $currentPage == $this->totalPage() ? $this->count : $from - 1 + $display; - } - $this->DocLister->toPlaceholders($currentPage, 1, "current"); - $this->DocLister->toPlaceholders($from, 1, "from"); - $this->DocLister->toPlaceholders($to, 1, "to"); - $this->DocLister->toPlaceholders($this->renderPages($paginate), 1, "pages"); - $this->DocLister->toPlaceholders(($this->currentPage() == 1 ? 1 : 0), 1, - "isstart"); //[+isstart+] – is start page - $this->DocLister->toPlaceholders(($this->currentPage() == $pages ? 1 : 0), 1, - "isstop"); //[+isstop+] – is end page - $this->DocLister->toPlaceholders($pages, 1, "totalPages"); // [+totalPages+] - total page. - $limit = $this->DocLister->getCFGDef('maxDocs', 0); - if ($limit > 0 && !$this->reverse) { - switch ($paginate) { - case 'offset': - $offset = $start; - break; - case 'pages': - default: - $offset = $start * $display; - break; - } - if (($offset + $display) > $limit) { - $this->DocLister->config->setConfig(array('display' => $limit - $offset)); - } - } - - return $pages; - } - - /** - * Get information about pagination (current, total or all in array) - * - * @param string $paginate Mode paginate. Empty string if no paginate - * @param string $name What information is interested - * @return string|array information about pagination - * - * @todo Set always placeholder count document. Not only pagination - */ - protected function getListPages($paginate, $name = '') - { - if ($paginate == '') { - $this->_pages['total'] = 1; - } else { - $addTables = $this->DocLister->AddTable; - $tmp = $this->count = (int)$this->DocLister->getChildrenCount(); - $this->DocLister->AddTable = $addTables; - - $display = $this->DocLister->getCFGDef('display', 0); - $this->_pages['total'] = ceil($tmp / $display); - if ($this->currentPage() <= $this->totalPage() || $this->totalPage() == 0 || $this->DocLister->getCFGDef('noRedirect', - 0) - ) { - $this->DocLister->toPlaceholders($tmp, 1, "count"); - } else { - $this->modx->sendRedirect($this->getUrl()); - } - } - - return APIHelpers::getkey($this->_pages, $name, $this->_pages); - } - - /** - * Номер текущей страницы - * @return int - */ - public function currentPage() - { - return (int)APIHelpers::getkey($this->_pages, 'current', 1); - } - - /** - * Общее число страниц - * @return int - */ - public function totalPage() - { - return (int)APIHelpers::getkey($this->_pages, 'total', 1); - } - - /** - * Общее число документов - * @return int - */ - public function totalDocs() - { - return $this->count; - } - - /** - * @param string $mode - * @return string - */ - private function renderPages($mode = '') - { - $currentPage = $this->currentPage(); - $p = $this->reverse ? new DLpaginateReversed : new DLpaginate; - $p->nextT = $this->DocLister->getChunkByParam('TplNextP', '@CODE:
        [%paginate.next%] >'); - $p->prevT = $this->DocLister->getChunkByParam('TplPrevP', '@CODE:< [%paginate.prev%]'); - $p->firstT = $this->DocLister->getChunkByParam('TplFirstP'); - $p->lastT = $this->DocLister->getChunkByParam('TplLastP'); - $p->numberT = $this->DocLister->getChunkByParam('TplPage', - '@CODE:[+num+]'); - $p->currentT = $this->DocLister->getChunkByParam('TplCurrentPage', '@CODE:[+num+]'); - $p->dotsT = $this->DocLister->getChunkByParam('TplDotsPage', '@CODE:...'); - $p->prevI = ''; - $p->nextI = ''; - $p->firstI = ''; - $p->lastI = ''; - if ($this->DocLister->getCFGDef("PrevNextAlwaysShow", 0) == '1') { - $p->nextI = $this->DocLister->getChunkByParam('TplNextI', '@CODE:[%paginate.next%] >'); - $p->prevI = $this->DocLister->getChunkByParam('TplPrevI', '@CODE:< [%paginate.prev%]'); - $p->firstI = $this->DocLister->getChunkByParam('TplFirstI'); - $p->lastI = $this->DocLister->getChunkByParam('TplLastI'); - } - $p->changeClass($this->DocLister->getCFGDef('PaginateClass', $p->className)); - $p->mainTpl = $this->DocLister->getChunkByParam('TplWrapPaginate', - '@CODE:
        [+wrap+]
        '); - $p->Items($this->totalPage()); - $p->limit($this->DocLister->getCFGDef("pageLimit", 1)); //show page count - $p->adjacents($this->DocLister->getCFGDef("pageAdjacents", 4)); - $p->target($this->getUrl()); - $p->currentPage($currentPage); - - switch (true) { - case ($mode == 'offset' && $this->totalPage() > 1): - $display = $this->DocLister->getCFGDef('display', 0); - $offset = $this->reverse ? $this->totalPage() * $display - $this->count : 0; - if ($currentPage == 1) { - $this->DocLister->config->setConfig(array('display'=>$display - $offset)); - } - $p->setMode('offset', array( - 'display' => $display - ))->parameterName($this->getRequestName('start')); - break; - case ($mode == 'pages' && $this->totalPage() > 1): - $p->parameterName($this->getRequestName('page')); - break; - } - if ($this->DocLister->getCFGDef('paginationMeta', 0)) { - $nextPage = $prevPage = 0; - if ($this->reverse) { - $currentPage = $this->totalPage() + 1 - $currentPage; - } - if ($currentPage > 1) { - $prevPage = $currentPage - 1; - } - if ($currentPage < $this->totalPage()) { - $nextPage = $currentPage + 1; - } - if ($nextPage) { - $this->modx->regClientStartupHTMLBlock(''); - } - if ($prevPage) { - $this->modx->regClientStartupHTMLBlock(''); - } - } - - return $p->getOutput(); - } - - /** - * @param string $requestName - * @return array|string - */ - public function getUrl($requestName = '') - { - $url = $this->DocLister->getUrl(); - $params = parse_url($url, PHP_URL_QUERY); - parse_str(html_entity_decode($params), $params); - if ($requestName == '') { - switch ($this->DocLister->getCFGDef('paginate', '')) { - case 'offset': - $requestName = 'start'; - $url = $this->buildUrl($url, $requestName, $params); - break; - case 'pages': - default: - $requestName = 'page'; - $call = $this->DocLister->getCFGDef('makePaginateUrl', ''); - if ((is_object($call) && ($call instanceof Closure)) || is_callable($call)) { - $url = call_user_func($call, compact('url', 'params'), $this->modx, $this->DocLister, $this); - } else { - $url = $this->buildUrl($url, $requestName, $params); - } - break; - } - } - - - return $url; - } - - /** - * @param $url - * @param $requestName - * @param $params - * @return array|string - */ - public function buildUrl($url, $requestName, $params) - { - if ($requestName != '' && is_array($params)) { - $q = http_build_query(array_merge($params, array($this->getRequestName($requestName) => null))); - $url = explode("?", $url, 2); - $url = $url[0]; - if (!empty($q)) { - $url .= "?" . $q; - } - } - - return $url; - } - - /** - * Имя REQUEST переменной в пагинаторе - * - * @param string $name основное имя REQUEST переменной в пагинаторе - * @return string - */ - public function getRequestName($name) - { - $id = $this->DocLister->getCFGDef('id', ''); - - return (($id != '') ? ($id . "_") : "") . $name; - } -} + + * @see http://mis-algoritmos.com/2007/05/27/digg-style-pagination-class + */ +include_once(MODX_BASE_PATH . "assets/snippets/DocLister/lib/DLpaginate.class.php"); +include_once(MODX_BASE_PATH . "assets/snippets/DocLister/lib/DLpaginateReversed.class.php"); + +/** + * Class paginate_DL_Extender + */ +class paginate_DL_Extender extends extDocLister +{ + /** + * @var bool + */ + protected $lang = true; + protected $reverse = false; + protected $count = 0; + /** + * @var array + */ + private $_pages = array(); + + /** + * Call method + * + * @return int total pages + */ + protected function run() + { + if (($paginate = $this->DocLister->getCFGDef('paginate', '')) == '') { + $this->DocLister->config->setConfig(array('start' => 0)); + } + $this->reverse = $this->DocLister->getCFGDef('reversePagination', 0); + $pages = $this->getListPages($paginate, 'total'); + $display = $this->DocLister->getCFGDef('display', 0); + switch ($paginate) { + case 'offset': + $requestName = $this->getRequestName('start'); + $start = (isset($_GET[$requestName]) && intval($_GET[$requestName]) > 1) ? intval($_GET[$requestName]) : 0; + $this->_pages['current'] = ceil($start / $display) + 1; + if ($this->reverse && $this->_pages['current'] > 1) { + $offset = $pages * $display - $this->count; + $start -= $offset; + } + $this->DocLister->config->setConfig(array('start' => $start)); + break; + case 'pages': + default: + $paginate = 'pages'; + $requestName = $this->getRequestName('page'); + if ( + isset($_GET[$requestName]) + && !$this->DocLister->getCFGDef('noRedirect', 0) + ) { + if ((!$this->reverse && (intval($_GET[$requestName]) <= 1 || intval($_GET[$requestName]) > $pages)) || ($this->reverse && (intval($_GET[$requestName]) >= $pages || intval($_GET[$requestName]) < 1))) { + $this->modx->sendRedirect($this->getUrl()); + } + } + if ($this->reverse) { + $start = (isset($_GET[$requestName]) && intval($_GET[$requestName]) <= $pages) ? ($pages - intval($_GET[$requestName])) : 0; + $this->_pages['current'] = $start + 1; + $offset = $pages * $display - $this->count; + if ($this->_pages['current'] > 1) { + $this->DocLister->config->setConfig(array('start' => $start * $display - $offset)); + } else { + $display = $display - $offset; + $this->DocLister->config->setConfig(array('display' => $display)); + } + } else { + $start = (isset($_GET[$requestName]) && intval($_GET[$requestName]) > 1) ? (intval($_GET[$requestName]) - 1) : 0; + $this->_pages['current'] = $start + 1; + $this->DocLister->config->setConfig(array('start' => $start * $display)); + } + + + break; + } + + if ($this->reverse) { + $currentPage = $pages + 1 - $this->currentPage(); + $diff = $currentPage == $this->totalPage() ? 0 : $display * $pages - $this->count; + $from = ($this->currentPage() - 1) * $display + 1 - $diff; + $to = $currentPage == $this->totalPage() ? $display : $from - 1 + $display; + } else { + $currentPage = $this->currentPage(); + $from = ($this->currentPage() - 1) * $display + 1; + $to = $currentPage == $this->totalPage() ? $this->count : $from - 1 + $display; + } + $this->DocLister->toPlaceholders($currentPage, 1, "current"); + $this->DocLister->toPlaceholders($from, 1, "from"); + $this->DocLister->toPlaceholders($to, 1, "to"); + $this->DocLister->toPlaceholders($this->renderPages($paginate), 1, "pages"); + $this->DocLister->toPlaceholders(($this->currentPage() == 1 ? 1 : 0), 1, + "isstart"); //[+isstart+] – is start page + $this->DocLister->toPlaceholders(($this->currentPage() == $pages ? 1 : 0), 1, + "isstop"); //[+isstop+] – is end page + $this->DocLister->toPlaceholders($pages, 1, "totalPages"); // [+totalPages+] - total page. + $limit = $this->DocLister->getCFGDef('maxDocs', 0); + if ($limit > 0 && !$this->reverse) { + switch ($paginate) { + case 'offset': + $offset = $start; + break; + case 'pages': + default: + $offset = $start * $display; + break; + } + if (($offset + $display) > $limit) { + $this->DocLister->config->setConfig(array('display' => $limit - $offset)); + } + } + + return $pages; + } + + /** + * Get information about pagination (current, total or all in array) + * + * @param string $paginate Mode paginate. Empty string if no paginate + * @param string $name What information is interested + * @return string|array information about pagination + * + * @todo Set always placeholder count document. Not only pagination + */ + protected function getListPages($paginate, $name = '') + { + if ($paginate == '') { + $this->_pages['total'] = 1; + } else { + $addTables = $this->DocLister->AddTable; + $tmp = $this->count = (int)$this->DocLister->getChildrenCount(); + $this->DocLister->AddTable = $addTables; + + $display = $this->DocLister->getCFGDef('display', 0); + $this->_pages['total'] = ceil($tmp / $display); + if ($this->currentPage() <= $this->totalPage() || $this->totalPage() == 0 || $this->DocLister->getCFGDef('noRedirect', + 0) + ) { + $this->DocLister->toPlaceholders($tmp, 1, "count"); + } else { + $this->modx->sendRedirect($this->getUrl()); + } + } + + return APIHelpers::getkey($this->_pages, $name, $this->_pages); + } + + /** + * Номер текущей страницы + * @return int + */ + public function currentPage() + { + return (int)APIHelpers::getkey($this->_pages, 'current', 1); + } + + /** + * Общее число страниц + * @return int + */ + public function totalPage() + { + return (int)APIHelpers::getkey($this->_pages, 'total', 1); + } + + /** + * Общее число документов + * @return int + */ + public function totalDocs() + { + return $this->count; + } + + /** + * @param string $mode + * @return string + */ + private function renderPages($mode = '') + { + $currentPage = $this->currentPage(); + $p = $this->reverse ? new DLpaginateReversed : new DLpaginate; + $p->nextT = $this->DocLister->getChunkByParam('TplNextP', '@CODE:[%paginate.next%] >'); + $p->prevT = $this->DocLister->getChunkByParam('TplPrevP', '@CODE:< [%paginate.prev%]'); + $p->firstT = $this->DocLister->getChunkByParam('TplFirstP'); + $p->lastT = $this->DocLister->getChunkByParam('TplLastP'); + $p->numberT = $this->DocLister->getChunkByParam('TplPage', + '@CODE:[+num+]'); + $p->currentT = $this->DocLister->getChunkByParam('TplCurrentPage', '@CODE:[+num+]'); + $p->dotsT = $this->DocLister->getChunkByParam('TplDotsPage', '@CODE:...'); + $p->prevI = ''; + $p->nextI = ''; + $p->firstI = ''; + $p->lastI = ''; + if ($this->DocLister->getCFGDef("PrevNextAlwaysShow", 0) == '1') { + $p->nextI = $this->DocLister->getChunkByParam('TplNextI', '@CODE:[%paginate.next%] >'); + $p->prevI = $this->DocLister->getChunkByParam('TplPrevI', '@CODE:< [%paginate.prev%]'); + $p->firstI = $this->DocLister->getChunkByParam('TplFirstI'); + $p->lastI = $this->DocLister->getChunkByParam('TplLastI'); + } + $p->changeClass($this->DocLister->getCFGDef('PaginateClass', $p->className)); + $p->mainTpl = $this->DocLister->getChunkByParam('TplWrapPaginate', + '@CODE:
        [+wrap+]
        '); + $p->Items($this->totalPage()); + $p->limit($this->DocLister->getCFGDef("pageLimit", 1)); //show page count + $p->adjacents($this->DocLister->getCFGDef("pageAdjacents", 4)); + $p->target($this->getUrl()); + $p->currentPage($currentPage); + + switch (true) { + case ($mode == 'offset' && $this->totalPage() > 1): + $display = $this->DocLister->getCFGDef('display', 0); + $offset = $this->reverse ? $this->totalPage() * $display - $this->count : 0; + if ($currentPage == 1) { + $this->DocLister->config->setConfig(array('display'=>$display - $offset)); + } + $p->setMode('offset', array( + 'display' => $display + ))->parameterName($this->getRequestName('start')); + break; + case ($mode == 'pages' && $this->totalPage() > 1): + $p->parameterName($this->getRequestName('page')); + break; + } + if ($this->DocLister->getCFGDef('paginationMeta', 0)) { + $nextPage = $prevPage = 0; + if ($this->reverse) { + $currentPage = $this->totalPage() + 1 - $currentPage; + } + if ($currentPage > 1) { + $prevPage = $currentPage - 1; + } + if ($currentPage < $this->totalPage()) { + $nextPage = $currentPage + 1; + } + if ($nextPage) { + $this->modx->regClientStartupHTMLBlock(''); + } + if ($prevPage) { + $this->modx->regClientStartupHTMLBlock(''); + } + } + + return $p->getOutput(); + } + + /** + * @param string $requestName + * @return array|string + */ + public function getUrl($requestName = '') + { + $url = $this->DocLister->getUrl(); + $params = parse_url($url, PHP_URL_QUERY); + parse_str(html_entity_decode($params), $params); + if ($requestName == '') { + switch ($this->DocLister->getCFGDef('paginate', '')) { + case 'offset': + $requestName = 'start'; + $url = $this->buildUrl($url, $requestName, $params); + break; + case 'pages': + default: + $requestName = 'page'; + $call = $this->DocLister->getCFGDef('makePaginateUrl', ''); + if ((is_object($call) && ($call instanceof Closure)) || is_callable($call)) { + $url = call_user_func($call, compact('url', 'params'), $this->modx, $this->DocLister, $this); + } else { + $url = $this->buildUrl($url, $requestName, $params); + } + break; + } + } + + + return $url; + } + + /** + * @param $url + * @param $requestName + * @param $params + * @return array|string + */ + public function buildUrl($url, $requestName, $params) + { + if ($requestName != '' && is_array($params)) { + $q = http_build_query(array_merge($params, array($this->getRequestName($requestName) => null))); + $url = explode("?", $url, 2); + $url = $url[0]; + if (!empty($q)) { + $url .= "?" . $q; + } + } + + return $url; + } + + /** + * Имя REQUEST переменной в пагинаторе + * + * @param string $name основное имя REQUEST переменной в пагинаторе + * @return string + */ + public function getRequestName($name) + { + $id = $this->DocLister->getCFGDef('id', ''); + + return (($id != '') ? ($id . "_") : "") . $name; + } +} diff --git a/assets/snippets/DocLister/core/extender/prepare.extender.inc b/assets/snippets/DocLister/core/extender/prepare.extender.inc index 3c3c6a1e60..272907cc9e 100644 --- a/assets/snippets/DocLister/core/extender/prepare.extender.inc +++ b/assets/snippets/DocLister/core/extender/prepare.extender.inc @@ -42,15 +42,18 @@ class prepare_DL_Extender extends extDocLister if (($prepare = $this->DocLister->getCFGDef($nameParam, '')) != '') { $params = $this->getParams($out); if (is_scalar($prepare)) { - $names = explode(",", $prepare); - foreach ($names as $item) { + $prepare = array_map('trim', explode(',', $prepare)); + } else if (!is_array($prepare) || is_callable($prepare)) { + $prepare = [$prepare]; + } + + if (!empty($prepare)) { + foreach ($prepare as $item) { $params['data'] = $this->callPrepare($item, $params); if ($params['data'] === false) { break; } } - } else { - $params['data'] = $this->callPrepare($prepare, $params); } $out = $params['data']; } @@ -98,7 +101,7 @@ class prepare_DL_Extender extends extDocLister case is_array($data): $out = $data; break; - case ($data === '' || (is_bool($data) && $data === false)): + case ($data === '' || $data === false): $out = false; break; case is_string($data): diff --git a/assets/snippets/DocLister/core/extender/summary.extender.inc b/assets/snippets/DocLister/core/extender/summary.extender.inc index 218c3e43aa..f31c97fe38 100755 --- a/assets/snippets/DocLister/core/extender/summary.extender.inc +++ b/assets/snippets/DocLister/core/extender/summary.extender.inc @@ -1,27 +1,27 @@ - - */ -class summary_DL_Extender extends extDocLister -{ - - /** - * @return mixed - */ - protected function run() - { - if (!empty($this->_cfg['action']) && !empty($this->_cfg['content'])) { - include_once(MODX_BASE_PATH . 'assets/lib/class.summary.php'); - $summary = new SummaryText($this->_cfg['content'], $this->_cfg['action'], - $this->getCFGDef('breakSummary', null)); - $summary->setCut($this->getCFGDef('cutSummary', '')); - $this->_cfg['content'] = $summary->run($this->getCFGDef('dotSummary', 0)); - } - - return $this->_cfg['content']; - } + + */ +class summary_DL_Extender extends extDocLister +{ + + /** + * @return mixed + */ + protected function run() + { + if (!empty($this->_cfg['action']) && !empty($this->_cfg['content'])) { + include_once(MODX_BASE_PATH . 'assets/lib/class.summary.php'); + $summary = new SummaryText($this->_cfg['content'], $this->_cfg['action'], + $this->getCFGDef('breakSummary', null)); + $summary->setCut($this->getCFGDef('cutSummary', '')); + $this->_cfg['content'] = $summary->run($this->getCFGDef('dotSummary', 0)); + } + + return $this->_cfg['content']; + } } \ No newline at end of file diff --git a/assets/snippets/DocLister/core/filter/private.filter.php b/assets/snippets/DocLister/core/filter/private.filter.php index ef1e3ed786..1063530f28 100644 --- a/assets/snippets/DocLister/core/filter/private.filter.php +++ b/assets/snippets/DocLister/core/filter/private.filter.php @@ -23,7 +23,7 @@ public function __construct() * @param string $filter * @return bool */ - public function parseFilter($filter) + protected function parseFilter($filter) { return true; } diff --git a/assets/snippets/DocLister/core/filter/tv.filter.php b/assets/snippets/DocLister/core/filter/tv.filter.php index 767264621b..51437877c5 100644 --- a/assets/snippets/DocLister/core/filter/tv.filter.php +++ b/assets/snippets/DocLister/core/filter/tv.filter.php @@ -54,8 +54,8 @@ protected function parseFilter($filter) $this->tv_id = $tmp[0]; } if (!$this->tv_id) { - $tvid = $this->modx->db->query("SELECT id FROM " . $this->DocLister->getTable('site_tmplvars') . " WHERE `name` = '" . $this->modx->db->escape($this->field) . "'"); - $this->tv_id = intval($this->modx->db->getValue($tvid)); + $tvid = $this->DocLister->dbQuery("SELECT id FROM " . $this->DocLister->getTable('site_tmplvars') . " WHERE `name` = '" . $this->modx->db->escape($this->field) . "'"); + $this->tv_id = (int)$this->modx->db->getValue($tvid); } if (!$this->tv_id) { diff --git a/assets/snippets/DocLister/core/filterDocLister.abstract.php b/assets/snippets/DocLister/core/filterDocLister.abstract.php index f185157716..01a3231cdb 100644 --- a/assets/snippets/DocLister/core/filterDocLister.abstract.php +++ b/assets/snippets/DocLister/core/filterDocLister.abstract.php @@ -142,7 +142,13 @@ protected function build_sql_where($table_alias, $field, $operator, $value) case '!=': case 'no': case 'isnot': - $output .= " != '" . $this->modx->db->escape($value) . "'"; + $output = '(' . $output . " != '" . $this->modx->db->escape($value) . "' OR " . $output . ' IS NULL)'; + break; + case 'isnull': + $output .= ' IS NULL'; + break; + case 'isnotnull': + $output .= ' IS NOT NULL'; break; case '>': case 'gt': @@ -191,7 +197,9 @@ protected function build_sql_where($table_alias, $field, $operator, $value) * искомый $word = " когда". С trim найдем "...мне некогда..." и "...тут когда-то..."; * Без trim будт обнаружено только "...тут когда-то..." */ - $word_arr[] = $this->DocLister->LikeEscape($output, $word); + if (($likeWord = $this->DocLister->LikeEscape($output, $word)) !== '') { + $word_arr[] = $likeWord; + } } if (!empty($word_arr)) { $output = '(' . implode(' OR ', $word_arr) . ')'; @@ -199,11 +207,25 @@ protected function build_sql_where($table_alias, $field, $operator, $value) $output = ''; } break; + case 'containsAll': + $words = explode($this->DocLister->getCFGDef('filter_delimiter', ','), $value); + $word_arr = array(); + foreach ($words as $word) { + if (($likeWord = $this->DocLister->LikeEscape($output, $word)) !== '') { + $word_arr[] = $likeWord; + } + } + if (!empty($word_arr)) { + $output = '(' . implode(' AND ', $word_arr) . ')'; + } else { + $output = ''; + } + break; case 'in': $output .= ' IN(' . $this->DocLister->sanitarIn($value, ',', true) . ')'; break; case 'notin': - $output .= ' NOT IN(' . $this->DocLister->sanitarIn($value, ',', true) . ')'; + $output = '(' . $output . ' NOT IN(' . $this->DocLister->sanitarIn($value, ',', true) . ') OR ' . $output . ' IS NULL)'; break; default: $output = ''; diff --git a/assets/snippets/DocLister/lib/DLTemplate.class.php b/assets/snippets/DocLister/lib/DLTemplate.class.php index dfc3565181..94bad4b098 100644 --- a/assets/snippets/DocLister/lib/DLTemplate.class.php +++ b/assets/snippets/DocLister/lib/DLTemplate.class.php @@ -26,13 +26,14 @@ class DLTemplate /** * @var null|Twig_Environment twig object */ - protected $twig = null; + protected $twig; protected $twigEnabled = false; + protected $bladeEnabled = false; - protected $twigTemplateVars = array(); + protected $templateData = array(); - public $phx = null; + public $phx; /** * gets the instance via lazy initialization (created on first usage) @@ -76,19 +77,24 @@ private function __wakeup() { } + public function getTemplatePath() + { + return $this->templatePath; + } + /** * Задает относительный путь к папке с шаблонами * - * @param $path + * @param string $path + * @param bool $supRoot * @return $this */ - public function setTemplatePath($path) + public function setTemplatePath($path, $supRoot = false) { $path = trim($path); - $path = preg_replace(array( - '/\.*[\/|\\\]/i', - '/[\/|\\\]+/i' - ), array('/', '/'), $path); + if ($supRoot === false) { + $path = $this->cleanPath($path); + } if (!empty($path)) { $this->templatePath = $path; @@ -97,6 +103,20 @@ public function setTemplatePath($path) return $this; } + /** + * @param string $path + * @return string + */ + protected function cleanPath($path) + { + return preg_replace(array('/\.*[\/|\\\]/i', '/[\/|\\\]+/i'), array('/', '/'), $path); + } + + public function getTemplateExtension() + { + return $this->templateExtension; + } + /** * Задает расширение файла с шаблоном * @@ -105,7 +125,8 @@ public function setTemplatePath($path) */ public function setTemplateExtension($ext) { - $ext = trim($ext, ". \t\n\r\0\x0B"); + $ext = $this->cleanPath(trim($ext, ". \t\n\r\0\x0B")); + if (!empty($ext)) { $this->templateExtension = $ext; } @@ -114,20 +135,32 @@ public function setTemplateExtension($ext) } /** - * Additional data for twig templates + * Additional data for external templates * * @param array $data * @return $this */ - public function setTwigTemplateVars($data = array()) + public function setTemplateData($data = array()) { if (is_array($data)) { - $this->twigTemplateVars = $data; + $this->templateData = $data; } return $this; } + /** + * @param array $data + * @return array + */ + public function getTemplateData($data = array()) + { + $plh = $this->templateData; + $plh['data'] = $data; + $plh['modx'] = $this->modx; + return $plh; + } + /** * Сохранение данных в массив плейсхолдеров * @@ -158,7 +191,9 @@ public function toPlaceholders($data, $set = 0, $key = 'contentPlaceholder', $pr public function getChunk($name) { $tpl = ''; + $ext = null; $this->twigEnabled = substr($name, 0, 3) == '@T_'; + $this->bladeEnabled = substr($name, 0, 3) == '@B_';//(0 === strpos($name, '@B_')); if ($name != '' && !isset($this->modx->chunkCache[$name])) { $mode = (preg_match( '/^((@[A-Z_]+)[:]{0,1})(.*)/Asu', @@ -168,31 +203,24 @@ public function getChunk($name) $subTmp = (isset($tmp[3])) ? trim($tmp[3]) : null; if ($this->twigEnabled) { $mode = '@' . substr($mode, 3); + } elseif ($this->bladeEnabled) { + $mode = '@' . substr($mode, 3); + $ext = $this->getTemplateExtension(); + $this->setTemplateExtension('blade.php'); } switch ($mode) { case '@FILE': if ($subTmp != '') { $real = realpath(MODX_BASE_PATH . $this->templatePath); - $path = realpath(MODX_BASE_PATH . $this->templatePath . preg_replace(array( - '/\.*[\/|\\\]/i', - '/[\/|\\\]+/i' - ), array('/', '/'), $subTmp) . '.' . $this->templateExtension); - $fname = explode(".", $path); - if ($real == substr( - $path, - 0, - strlen($real) - ) && end($fname) == $this->templateExtension && file_exists($path) + $path = realpath(MODX_BASE_PATH . $this->templatePath . $this->cleanPath($subTmp) . '.' . $this->templateExtension); + if (basename($path, '.' . $this->templateExtension) !== '' && + 0 === strpos($path, $real) && + file_exists($path) ) { $tpl = file_get_contents($path); } } break; - case '@CHUNK': - if ($subTmp != '') { - $tpl = $this->modx->getChunk($subTmp); - } - break; case '@INLINE': case '@TPL': case '@CODE': @@ -237,13 +265,41 @@ public function getChunk($name) case '@TEMPLATE': $tpl = $this->getTemplate($subTmp); break; + case '@CHUNK': + $tpl = $this->getBaseChunk($subTmp); + break; default: - $tpl = $this->modx->getChunk($name); + $tpl = $this->getBaseChunk($name); } $this->modx->chunkCache[$name] = $tpl; } else { - if ($name != '') { - $tpl = $this->modx->getChunk($name); + $tpl = $this->getBaseChunk($name); + } + + if($ext !== null) { + $this->setTemplateExtension($ext); + } + return $tpl; + } + + protected function getBaseChunk($name) + { + if (empty($name)) { + return null; + } + + if (isset ($this->modx->chunkCache[$name])) { + $tpl = $this->modx->chunkCache[$name]; + } else { + $table = $this->modx->getFullTableName('site_htmlsnippets'); + $query = $this->modx->db->query( + "SELECT `snippet` FROM " . $table . " WHERE `name`='" . $this->modx->db->escape($name) . "' AND `disabled`=0" + ); + if ($this->modx->db->getRecordCount($query) == 1) { + $row = $this->modx->db->getRow($query); + $tpl = $row['snippet']; + } else { + $tpl = null; } } @@ -331,13 +387,14 @@ public function getTemplate($id) public function parseChunk($name, $data = array(), $parseDocumentSource = false, $disablePHx = false) { $out = $this->getChunk($name); - if ($this->twigEnabled && ($out != '') && ($twig = $this->getTwig($name, $out))) { - $plh = $this->twigTemplateVars; - $plh['data'] = $data; - $plh['modx'] = $this->modx; - $out = $twig->render(md5($name), $plh); - } else { - if (is_array($data) && ($out != '')) { + switch (true) { + case $this->twigEnabled && $out !== '' && ($twig = $this->getTwig($name, $out)): + $out = $twig->render(md5($name), $this->getTemplateData($data)); + break; + case $this->bladeEnabled && $out !== '' && ($blade = $this->getBlade($name, $out)): + $out = $blade->with($this->getTemplateData($data))->render(); + break; + case is_array($data) && ($out != ''): if (preg_match("/\[\+[A-Z0-9\.\_\-]+\+\]/is", $out)) { $item = $this->renameKeyArr($data, '[', ']', '+'); $out = str_replace(array_keys($item), array_values($item), $out); @@ -349,9 +406,8 @@ public function parseChunk($name, $data = array(), $parseDocumentSource = false, $this->phx->placeholders = array(); $this->setPHxPlaceholders($data); $out = $this->phx->Parse($out); - $out = $this->cleanPHx($out); } - } + break; } if ($parseDocumentSource) { $out = $this->parseDocumentSource($out); @@ -405,6 +461,34 @@ protected function getTwig($name, $tpl) return $twig; } + /** + * Return clone of blade + * + * @param string $name + * @param string $tpl + * @return Illuminate\View\Factory + */ + protected function getBlade($name, $tpl) + { + $out = null; + try { + /** + * Illuminate\View\Factory $blade + */ + $blade = $this->modx->blade; + $cache = md5($name). '-'. sha1($tpl); + $path = MODX_BASE_PATH . '/assets/cache/blade/' . $cache . '.blade.php'; + if (! file_exists($path)) { + file_put_contents($path, $tpl); + } + $out = $blade->make('cache::' . $cache); + } catch (\Exception $exception) { + $this->modx->messageQuit($exception->getMessage()); + } + + return $out; + } + /** * * @param string $string diff --git a/assets/snippets/DocLister/lib/DLphx.class.php b/assets/snippets/DocLister/lib/DLphx.class.php index cc9099dcfb..1a0b96c11c 100644 --- a/assets/snippets/DocLister/lib/DLphx.class.php +++ b/assets/snippets/DocLister/lib/DLphx.class.php @@ -1,828 +1,829 @@ - array(), - 'ui' => array(), - 'mo' => array() - ); - public $safetags = array( - array('~(?modx = $modx; - $this->user["mgrid"] = isset($_SESSION['mgrInternalKey']) ? intval($_SESSION['mgrInternalKey']) : 0; - $this->user["usrid"] = isset($_SESSION['webInternalKey']) ? intval($_SESSION['webInternalKey']) : 0; - $this->user["id"] = ($this->user["usrid"] > 0) ? (-$this->user["usrid"]) : $this->user["mgrid"]; - - $this->debug = (bool)$debug; - - $this->maxPasses = ($maxpass != '') ? $maxpass : 50; - - $this->modx->setPlaceholder("phx", "&_PHX_INTERNAL_&"); - if (function_exists('mb_internal_encoding')) { - mb_internal_encoding($this->modx->config['modx_charset']); - } - } - - // Plugin event hook for MODx - public function OnParseDocument() - { - // Get document output from MODx - $template = $this->modx->documentOutput; - // To the parse cave .. let's go! *insert batman tune here* - $template = $this->Parse($template); - // Set processed document output in MODx - $this->modx->documentOutput = $template; - } - - // Parser: Preparation, cleaning and checkup - - /** - * @param string $template - * @return mixed|string - */ - public function Parse($template = '') - { - // If we already reached max passes don't get at it again. - if ($this->curPass == $this->maxPasses) { - return $template; - } - // Set template pre-process hash - $st = md5($template); - // Replace non-call characters in the template: [, ] - $template = preg_replace($this->safetags[0], $this->safetags[1], $template); - // To the parse mobile.. let's go! *insert batman tune here* - $template = $this->ParseValues($template); - // clean up unused placeholders that have modifiers attached (MODx can't clean them) - preg_match_all('~(?:=`[^`@]*?)(\[\+([^:\+\[\]]+)([^\[\]]*?)\+\])~s', $template, $matches); - if ($matches[0]) { - $template = str_replace($matches[1], '', $template); - $this->Log("Cleaning unsolved tags: \n" . implode("\n", $matches[2])); - } - // Restore non-call characters in the template: [, ] - $template = str_replace($this->safetags[1], $this->safetags[2], $template); - // Set template post-process hash - $et = md5($template); - // If template has changed, parse it once more... - if ($st != $et) { - $template = $this->Parse($template); - } - // Write an event log if debugging is enabled and there is something to log - if ($this->debug && $this->debugLog) { - $this->modx->logEvent($this->curPass, 1, $this->createEventLog(), $this->name . ' ' . $this->version); - $this->debugLog = false; - } - - // Return the processed template - return $template; - } - - // Parser: Tag detection and replacements - - /** - * @param string $template - * @return mixed|string - */ - public function ParseValues($template = '') - { - $this->curPass = $this->curPass + 1; - $st = md5($template); - - $this->LogPass(); - // MODX Chunks - if (preg_match_all('~(?Log('MODX Chunks -> Merging all chunk tags'); - $count = count($matches[0]); - $var_search = array(); - $var_replace = array(); - for ($i = 0; $i < $count; $i++) { - $var_search[] = $matches[0][$i]; - $input = $matches[1][$i]; - $this->Log('MODX Chunk: ' . $input); - $input = $this->modx->mergeChunkContent('{{' . $input . '}}'); - $var_replace[] = $this->Filter($input, $matches[2][$i]); - } - $template = str_replace($var_search, $var_replace, $template); - } - - // MODx Snippets - //if ( preg_match_all('~\[(\[|!)([^\[]*?)(!|\])\]~s',$template, $matches)) { - if (preg_match_all('~(?Log("MODx Snippet -> " . $snippet); - - // Let MODx evaluate snippet - $replace = $this->modx->evalSnippets("[[" . $snippet . "]]"); - $this->LogSnippet($replace); - - // Replace values - $var_search[] = $matches[0][$i]; - $var_replace[] = $replace; - } - $template = str_replace($var_search, $var_replace, $template); - } - - // PHx / MODx Tags - if (preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?)(\1|\))\]~s', $template, $matches)) { - //$matches[0] // Complete string that's need to be replaced - //$matches[1] // Type - //$matches[2] // The placeholder(s) - //$matches[3] // The modifiers - //$matches[4] // Type (end character) - - $count = count($matches[0]); - $var_search = array(); - $var_replace = array(); - for ($i = 0; $i < $count; $i++) { - $input = $matches[2][$i]; - $modifiers = $matches[3][$i]; - $var_search[] = $matches[0][$i]; - switch ($matches[1][$i]) { - // Document / Template Variable eXtended - case "*": - $this->Log("MODx TV/DV: " . $input); - $input = $this->modx->mergeDocumentContent("[*" . $input . "*]"); - $replace = $this->Filter($input, $modifiers); - break; - // MODx Setting eXtended - case "(": - $this->Log("MODx Setting variable: " . $input); - $input = $this->modx->mergeSettingsContent("[(" . $input . ")]"); - $replace = $this->Filter($input, $modifiers); - break; - // MODx Placeholder eXtended - default: - $this->Log("MODx / PHx placeholder variable: " . $input); - // Check if placeholder is set - if (!array_key_exists($input, $this->placeholders) && !array_key_exists( - $input, - $this->modx->placeholders - ) - ) { - // not set so try again later. - $input = ''; - } else { - // is set, get value and run filter - $input = $this->getPHxVariable($input); - } - $replace = $this->Filter($input, $modifiers); - break; - } - $var_replace[] = $replace; - } - $template = str_replace($var_search, $var_replace, $template); - } - $et = md5($template); // Post-process template hash - - // Log an event if this was the maximum pass - if ($this->curPass == $this->maxPasses) { - $this->Log("Max passes reached. infinite loop protection so exiting.\n If you need the extra passes set the max passes to the highest count of nested tags in your template."); - } - // If this pass is not at maximum passes and the template hash is not the same, get at it again. - if (($this->curPass < $this->maxPasses) && ($st != $et)) { - $template = $this->ParseValues($template); - } - - return $template; - } - - // Parser: modifier detection and eXtended processing if needed - - /** - * @param $input - * @param $modifiers - * @return mixed|null|string - */ - public function Filter($input, $modifiers) - { - $output = $input; - $this->Log(" |--- Input = '" . $output . "'"); - if (preg_match_all('~:([^:=]+)(?:=`(.*?)`(?=:[^:=]+|$))?~s', $modifiers, $matches)) { - $modifier_cmd = $matches[1]; // modifier command - $modifier_value = $matches[2]; // modifier value - $count = count($modifier_cmd); - $condition = array(); - for ($i = 0; $i < $count; $i++) { - $output = trim($output); - $this->Log(" |--- Modifier = '" . $modifier_cmd[$i] . "'"); - if ($modifier_value[$i] != '') { - $this->Log(" |--- Options = '" . $modifier_value[$i] . "'"); - } - switch ($modifier_cmd[$i]) { - ##### Conditional Modifiers - case "input": - case "if": - $output = $modifier_value[$i]; - break; - case "equals": - case "is": - case "eq": - $condition[] = intval(($output == $modifier_value[$i])); - break; - case "empty": - $condition[] = intval(empty($output)); - break; - case "notequals": - case "isnot": - case "isnt": - case "ne": - $condition[] = intval(($output != $modifier_value[$i])); - break; - case "isgreaterthan": - case "isgt": - case "eg": - $condition[] = intval(($output >= $modifier_value[$i])); - break; - case "islowerthan": - case "islt": - case "el": - $condition[] = intval(($output <= $modifier_value[$i])); - break; - case "greaterthan": - case "gt": - $condition[] = intval(($output > $modifier_value[$i])); - break; - case "lowerthan": - case "lt": - $condition[] = intval(($output < $modifier_value[$i])); - break; - case "isinrole": - case "ir": - case "memberof": - case "mo": // Is Member Of (same as inrole but this one can be stringed as a conditional) - if ($output == "&_PHX_INTERNAL_&") { - $output = $this->user["id"]; - } - $grps = ($this->strlen($modifier_value[$i]) > 0) ? explode(",", $modifier_value[$i]) : array(); - $condition[] = intval($this->isMemberOfWebGroupByUserId($output, $grps)); - break; - case "or": - $condition[] = "||"; - break; - case "and": - $condition[] = "&&"; - break; - case "show": - $conditional = implode(' ', $condition); - $isvalid = intval($this->runCode($conditional)); - if (!$isvalid) { - $output = null; - } - break; - case "then": - $conditional = implode(' ', $condition); - $isvalid = intval($this->runCode($conditional)); - if ($isvalid) { - $output = $modifier_value[$i]; - } else { - $output = null; - } - break; - case "else": - $conditional = implode(' ', $condition); - $isvalid = intval($this->runCode($conditional)); - if (!$isvalid) { - $output = $modifier_value[$i]; - } - break; - case "select": - $raw = explode("&", $modifier_value[$i]); - $map = array(); - $count = count($raw); - for ($m = 0; $m < $count; $m++) { - $mi = explode("=", $raw[$m]); - $map[$mi[0]] = $mi[1]; - } - $output = $map[$output]; - break; - ##### End of Conditional Modifiers - - ##### String Modifiers - case "default": - $output = ($output === '') ? $modifier_value[0] : $output; - break; - case "lcase": - case "strtolower": - $output = $this->strtolower($output); - break; - case "ucase": - case "strtoupper": - $output = $this->strtoupper($output); - break; - case "ucfirst": - $output = $this->ucfirst($output); - break; - case "lcfirst": - $output = $this->lcfirst($output); - break; - case "ucwords": - $output = $this->ucwords($output); - break; - case "htmlent": - case "htmlentities": - $output = htmlentities($output, ENT_QUOTES, $this->modx->config['modx_charset']); - break; - case "html_entity_decode": - $output = html_entity_decode($output, ENT_QUOTES, $this->modx->config['modx_charset']); - break; - case "esc": - $output = preg_replace("/&(#[0-9]+|[a-z]+);/i", "&$1;", APIHelpers::e($output)); - $output = str_replace(array("[", "]", "`"), array("[", "]", "`"), $output); - break; - case "strip": - $output = preg_replace("~([\n\r\t\s]+)~", " ", $output); - break; - case "notags": - case "strip_tags": - $output = strip_tags($output); - break; - case "length": - case "len": - case "strlen": - $output = $this->strlen($output); - break; - case "reverse": - case "strrev": - $output = $this->strrev($output); - break; - case "wordwrap": // default: 70 - $wrapat = intval($modifier_value[$i]) ? intval($modifier_value[$i]) : 70; - $output = preg_replace_callback("@(\b\w+\b)@", function ($m) use ($wrapat) { - return wordwrap($m[1], $wrapat, ' ', 1); - }, $output); - break; - case "limit": // default: 100 - $limit = intval($modifier_value[$i]) ? intval($modifier_value[$i]) : 100; - $output = $this->substr($output, 0, $limit); - break; - case "str_shuffle": - case "shuffle": - $output = $this->str_shuffle($output); - break; - case "str_word_count": - case "word_count": - case "wordcount": - $output = $this->str_word_count($output); - break; - - ##### Special functions - case "math": - $filter = preg_replace("~([a-zA-Z\n\r\t\s])~", "", $modifier_value[$i]); - $filter = str_replace("?", $output, $filter); - $output = eval("return " . $filter . ";"); - break; - case "isnotempty": - if (!empty($output)) { - $output = $modifier_value[$i]; - } - break; - case "isempty": - case "ifempty": - if (empty($output)) { - $output = $modifier_value[$i]; - } - break; - case "nl2br": - $output = nl2br($output); - break; - case "date": - $output = strftime($modifier_value[$i], (int)$output); - break; - case "set": - $c = $i + 1; - if ($count > $c && $modifier_cmd[$c] == "value") { - $output = preg_replace("~([^a-zA-Z0-9])~", "", $modifier_value[$i]); - } - break; - case "value": - if ($i > 0 && $modifier_cmd[$i - 1] == "set") { - $this->modx->SetPlaceholder("phx." . $output, $modifier_value[$i]); - } - $output = null; - break; - case "md5": - $output = md5($output); - break; - case "userinfo": - if ($output == "&_PHX_INTERNAL_&") { - $output = $this->user["id"]; - } - $output = $this->ModUser($output, $modifier_value[$i]); - break; - case "inrole": // deprecated - if ($output == "&_PHX_INTERNAL_&") { - $output = $this->user["id"]; - } - $grps = ($this->strlen($modifier_value[$i]) > 0) ? explode(",", $modifier_value[$i]) : array(); - $output = intval($this->isMemberOfWebGroupByUserId($output, $grps)); - break; - - // If we haven't yet found the modifier, let's look elsewhere - default: - $snippet = ''; - // modified by Anton Kuzmin (23.06.2010) // - $snippetName = 'phx:' . $modifier_cmd[$i]; - if (isset($this->modx->snippetCache[$snippetName])) { - $snippet = $this->modx->snippetCache[$snippetName]; - } else { -// not in cache so let's check the db - $sql = "SELECT snippet FROM " . $this->modx->getFullTableName("site_snippets") . " WHERE " . $this->modx->getFullTableName("site_snippets") . ".name='" . $this->modx->db->escape($snippetName) . "';"; - $result = $this->modx->db->query($sql); - if ($this->modx->db->getRecordCount($result) == 1) { - $row = $this->modx->db->getRow($result); - $snippet = $this->modx->snippetCache[$row['name']] = $row['snippet']; - $this->Log(" |--- DB -> Custom Modifier"); - } else { - if ($this->modx->db->getRecordCount($result) == 0) { -// If snippet not found, look in the modifiers folder - $filename = $this->modx->config['rb_base_dir'] . 'plugins/phx/modifiers/' . $modifier_cmd[$i] . '.phx.php'; - if (@file_exists($filename)) { - $file_contents = @file_get_contents($filename); - $file_contents = str_replace('<' . '?php', '', $file_contents); - $file_contents = str_replace('?' . '>', '', $file_contents); - $file_contents = str_replace('modx->snippetCache[$snippetName] = $file_contents; - $this->modx->snippetCache[$snippetName . 'Props'] = ''; - $this->Log(" |--- File ($filename) -> Custom Modifier"); - } else { - $this->Log(" |--- PHX Error: {$modifier_cmd[$i]} could not be found"); - } - } - } - } - if (!empty($snippet)) { - $output = $this->modx->runSnippet($snippetName, array( - 'input' => $output, - 'output' => $output, - 'options' => $modifier_value[$i] - )); - } else { - $output = ''; - } - break; - } - if (count($condition)) { - $this->Log(" |--- Condition = '" . $condition[count($condition) - 1] . "'"); - } - $this->Log(" |--- Output = '" . $output . "'"); - } - } - - return $output; - } - - /** - * @param string $code - * @return mixed - */ - private function runCode($code) - { - return eval("return (" . $code . ");"); - } - - // Event logging (debug) - - /** - * @return string - */ - public function createEventLog() - { - $out = ''; - if (!empty($this->console)) { - $console = implode("\n", $this->console); - $this->console = array(); - - $out = '
        ' . $console . '
        '; - } - - return $out; - } - - // Returns a cleaned string escaping the HTML and special MODx characters - - /** - * @param $string - * @return array|mixed|string - */ - public function LogClean($string) - { - $string = preg_replace("/&(#[0-9]+|[a-z]+);/i", "&$1;", $string); - $string = APIHelpers::sanitarTag($string); - - return $string; - } - - // Simple log entry - - /** - * @param $string - */ - public function Log($string) - { - if ($this->debug) { - $this->debugLog = true; - $this->console[] = (count($this->console) + 1 - $this->curPass) . " [" . strftime( - "%H:%M:%S", - time() - ) . "] " . $this->LogClean($string); - } - } - - // Log snippet output - - /** - * @param $string - */ - public function LogSnippet($string) - { - if ($this->debug) { - $this->debugLog = true; - $this->console[] = (count($this->console) + 1 - $this->curPass) . " [" . strftime( - "%H:%M:%S", - time() - ) . "] " . " |--- Returns:
        " . $this->LogClean($string) . "
        "; - } - } - - // Log pass - public function LogPass() - { - $this->console[] = "
        Pass " . $this->curPass . "
        "; - } - - // Log pass - - /** - * @param $string - */ - public function LogSource($string) - { - $this->console[] = "
        Source:
        " . $this->LogClean($string); - } - - // Returns the specified field from the user record - // positive userid = manager, negative integer = webuser - -/** - * @param $userid - * @param $field - * @return mixed - */ - public function ModUser($userid, $field) - { - if (!array_key_exists($userid, $this->cache["ui"])) { - if (intval($userid) < 0) { - $user = $this->modx->getWebUserInfo(-($userid)); - } else { - $user = $this->modx->getUserInfo($userid); - } - $this->cache["ui"][$userid] = $user; - } else { - $user = $this->cache["ui"][$userid]; - } - - return $user[$field]; - } - - // Returns true if the user id is in one the specified webgroups - - /** - * @param int $userid - * @param array $groupNames - * @return bool - */ - public function isMemberOfWebGroupByUserId($userid = 0, $groupNames = array()) - { - $userid = (int)$userid; - // if $groupNames is not an array return false - if (!is_array($groupNames)) { - return false; - } - - // if the user id is a negative number make it positive - if (intval($userid) < 0) { - $userid = -($userid); - } - - // Creates an array with all webgroups the user id is in - if (!array_key_exists($userid, $this->cache["mo"])) { - $tbl = $this->modx->getFullTableName("webgroup_names"); - $tbl2 = $this->modx->getFullTableName("web_groups"); - $sql = "SELECT `wgn`.`name` FROM {$tbl} `wgn` INNER JOIN {$tbl2} `wg` ON `wg`.`webgroup`=`wgn`.`id` AND `wg`.`webuser`={$userid}"; - $this->cache["mo"][$userid] = $grpNames = $this->modx->db->getColumn("name", $sql); - } else { - $grpNames = $this->cache["mo"][$userid]; - } - // Check if a supplied group matches a webgroup from the array we just created - foreach ($groupNames as $k => $v) { - if (in_array(trim($v), $grpNames)) { - return true; - } - } - - // If we get here the above logic did not find a match, so return false - return false; - } - - // Returns the value of a PHx/MODx placeholder. - - /** - * @param $name - * @return mixed|string - */ - public function getPHxVariable($name) - { - // Check if this variable is created by PHx - if (array_key_exists($name, $this->placeholders)) { - // Return the value from PHx - return $this->placeholders[$name]; - } else { - // Return the value from MODx - return $this->modx->getPlaceholder($name); - } - } - - // Sets a placeholder variable which can only be access by PHx - - /** - * @param $name - * @param $value - */ - public function setPHxVariable($name, $value) - { - if ($name != "phx") { - $this->placeholders[$name] = $value; - } - } - - //mbstring - - /** - * @param $str - * @param $s - * @param null $l - * @return string - */ - public function substr($str, $s, $l = null) - { - if (function_exists('mb_substr')) { - return mb_substr($str, $s, $l); - } - - return substr($str, $s, $l); - } - - /** - * @param $str - * @return int - */ - public function strlen($str) - { - if (function_exists('mb_strlen')) { - return mb_strlen($str); - } - - return strlen($str); - } - - /** - * @param $str - * @return string - */ - public function strtolower($str) - { - if (function_exists('mb_strtolower')) { - return mb_strtolower($str); - } - - return strtolower($str); - } - - /** - * @param $str - * @return string - */ - public function strtoupper($str) - { - if (function_exists('mb_strtoupper')) { - return mb_strtoupper($str); - } - - return strtoupper($str); - } - - /** - * @param $str - * @return string - */ - public function ucfirst($str) - { - if (function_exists('mb_strtoupper') && function_exists('mb_substr') && function_exists('mb_strlen')) { - return mb_strtoupper(mb_substr($str, 0, 1)) . mb_substr($str, 1, mb_strlen($str)); - } - - return ucfirst($str); - } - - /** - * @param $str - * @return string - */ - public function lcfirst($str) - { - if (function_exists('mb_strtolower') && function_exists('mb_substr') && function_exists('mb_strlen')) { - return mb_strtolower(mb_substr($str, 0, 1)) . mb_substr($str, 1, mb_strlen($str)); - } - - return lcfirst($str); - } - - /** - * @param $str - * @return string - */ - public function ucwords($str) - { - if (function_exists('mb_convert_case')) { - return mb_convert_case($str, MB_CASE_TITLE); - } - - return ucwords($str); - } - - /** - * @param $str - * @return string - */ - public function strrev($str) - { - preg_match_all('/./us', $str, $ar); - - return implode(array_reverse($ar[0])); - } - - /** - * @param $str - * @return string - */ - public function str_shuffle($str) - { - preg_match_all('/./us', $str, $ar); - shuffle($ar[0]); - - return implode($ar[0]); - } - - /** - * @param $str - * @return int - */ - public function str_word_count($str) - { - return count(preg_split('~[^\p{L}\p{N}\']+~u', $str)); - } -} + array(), + 'ui' => array(), + 'mo' => array() + ); + public $safetags = array( + array('~(?modx = $modx; + $this->user["mgrid"] = isset($_SESSION['mgrInternalKey']) ? intval($_SESSION['mgrInternalKey']) : 0; + $this->user["usrid"] = isset($_SESSION['webInternalKey']) ? intval($_SESSION['webInternalKey']) : 0; + $this->user["id"] = ($this->user["usrid"] > 0) ? (-$this->user["usrid"]) : $this->user["mgrid"]; + + $this->debug = (bool)$debug; + + $this->maxPasses = ($maxpass != '') ? $maxpass : 50; + + $this->modx->setPlaceholder("phx", "&_PHX_INTERNAL_&"); + if (function_exists('mb_internal_encoding')) { + mb_internal_encoding($this->modx->config['modx_charset']); + } + } + + // Plugin event hook for MODx + public function OnParseDocument() + { + // Get document output from MODx + $template = $this->modx->documentOutput; + // To the parse cave .. let's go! *insert batman tune here* + $template = $this->Parse($template); + // Set processed document output in MODx + $this->modx->documentOutput = $template; + } + + // Parser: Preparation, cleaning and checkup + + /** + * @param string $template + * @return mixed|string + */ + public function Parse($template = '') + { + // If we already reached max passes don't get at it again. + if ($this->curPass == $this->maxPasses) { + return $template; + } + // Set template pre-process hash + $st = md5($template); + // Replace non-call characters in the template: [, ] + $template = preg_replace($this->safetags[0], $this->safetags[1], $template); + // To the parse mobile.. let's go! *insert batman tune here* + $template = $this->ParseValues($template); + // clean up unused placeholders that have modifiers attached (MODx can't clean them) + preg_match_all('~(?:=`[^`@]*?)(\[\+([^:\+\[\]]+)([^\[\]]*?)\+\])~s', $template, $matches); + if ($matches[0]) { + $template = str_replace($matches[1], '', $template); + $this->Log("Cleaning unsolved tags: \n" . implode("\n", $matches[2])); + } + // Restore non-call characters in the template: [, ] + $template = str_replace($this->safetags[1], $this->safetags[2], $template); + // Set template post-process hash + $et = md5($template); + // If template has changed, parse it once more... + if ($st != $et) { + $template = $this->Parse($template); + } + // Write an event log if debugging is enabled and there is something to log + if ($this->debug && $this->debugLog) { + $this->modx->logEvent($this->curPass, 1, $this->createEventLog(), $this->name . ' ' . $this->version); + $this->debugLog = false; + } + + // Return the processed template + return $template; + } + + // Parser: Tag detection and replacements + + /** + * @param string $template + * @return mixed|string + */ + public function ParseValues($template = '') + { + $this->curPass = $this->curPass + 1; + $st = md5($template); + + $this->LogPass(); + // MODX Chunks + if (preg_match_all('~(?Log('MODX Chunks -> Merging all chunk tags'); + $count = count($matches[0]); + $var_search = array(); + $var_replace = array(); + for ($i = 0; $i < $count; $i++) { + $var_search[] = $matches[0][$i]; + $input = $matches[1][$i]; + $this->Log('MODX Chunk: ' . $input); + $input = $this->modx->mergeChunkContent('{{' . $input . '}}'); + $var_replace[] = $this->Filter($input, $matches[2][$i]); + } + $template = str_replace($var_search, $var_replace, $template); + } + + // MODx Snippets + //if ( preg_match_all('~\[(\[|!)([^\[]*?)(!|\])\]~s',$template, $matches)) { + if (preg_match_all('~(?Log("MODx Snippet -> " . $snippet); + + // Let MODx evaluate snippet + $replace = $this->modx->evalSnippets("[[" . $snippet . "]]"); + $this->LogSnippet($replace); + + // Replace values + $var_search[] = $matches[0][$i]; + $var_replace[] = $replace; + } + $template = str_replace($var_search, $var_replace, $template); + } + + // PHx / MODx Tags + if (preg_match_all('~\[(\+|\*|\()([^:\+\[\]]+)([^\[\]]*?)(\1|\))\]~s', $template, $matches)) { + //$matches[0] // Complete string that's need to be replaced + //$matches[1] // Type + //$matches[2] // The placeholder(s) + //$matches[3] // The modifiers + //$matches[4] // Type (end character) + + $count = count($matches[0]); + $var_search = array(); + $var_replace = array(); + for ($i = 0; $i < $count; $i++) { + $input = $matches[2][$i]; + $modifiers = $matches[3][$i]; + if(empty($modifiers)) continue; + $var_search[] = $matches[0][$i]; + switch ($matches[1][$i]) { + // Document / Template Variable eXtended + case "*": + $this->Log("MODx TV/DV: " . $input); + $input = $this->modx->mergeDocumentContent("[*" . $input . "*]"); + $replace = $this->Filter($input, $modifiers); + break; + // MODx Setting eXtended + case "(": + $this->Log("MODx Setting variable: " . $input); + $input = $this->modx->mergeSettingsContent("[(" . $input . ")]"); + $replace = $this->Filter($input, $modifiers); + break; + // MODx Placeholder eXtended + default: + $this->Log("MODx / PHx placeholder variable: " . $input); + // Check if placeholder is set + if (!array_key_exists($input, $this->placeholders) && !array_key_exists( + $input, + $this->modx->placeholders + ) + ) { + // not set so try again later. + $input = ''; + } else { + // is set, get value and run filter + $input = $this->getPHxVariable($input); + } + $replace = $this->Filter($input, $modifiers); + break; + } + $var_replace[] = $replace; + } + $template = str_replace($var_search, $var_replace, $template); + } + $et = md5($template); // Post-process template hash + + // Log an event if this was the maximum pass + if ($this->curPass == $this->maxPasses) { + $this->Log("Max passes reached. infinite loop protection so exiting.\n If you need the extra passes set the max passes to the highest count of nested tags in your template."); + } + // If this pass is not at maximum passes and the template hash is not the same, get at it again. + if (($this->curPass < $this->maxPasses) && ($st != $et)) { + $template = $this->ParseValues($template); + } + + return $template; + } + + // Parser: modifier detection and eXtended processing if needed + + /** + * @param $input + * @param $modifiers + * @return mixed|null|string + */ + public function Filter($input, $modifiers) + { + $output = $input; + $this->Log(" |--- Input = '" . $output . "'"); + if (preg_match_all('~:([^:=]+)(?:=`(.*?)`(?=:[^:=]+|$))?~s', $modifiers, $matches)) { + $modifier_cmd = $matches[1]; // modifier command + $modifier_value = $matches[2]; // modifier value + $count = count($modifier_cmd); + $condition = array(); + for ($i = 0; $i < $count; $i++) { + $output = trim($output); + $this->Log(" |--- Modifier = '" . $modifier_cmd[$i] . "'"); + if ($modifier_value[$i] != '') { + $this->Log(" |--- Options = '" . $modifier_value[$i] . "'"); + } + switch ($modifier_cmd[$i]) { + ##### Conditional Modifiers + case "input": + case "if": + $output = $modifier_value[$i]; + break; + case "equals": + case "is": + case "eq": + $condition[] = intval(($output == $modifier_value[$i])); + break; + case "empty": + $condition[] = intval(empty($output)); + break; + case "notequals": + case "isnot": + case "isnt": + case "ne": + $condition[] = intval(($output != $modifier_value[$i])); + break; + case "isgreaterthan": + case "isgt": + case "eg": + $condition[] = intval(($output >= $modifier_value[$i])); + break; + case "islowerthan": + case "islt": + case "el": + $condition[] = intval(($output <= $modifier_value[$i])); + break; + case "greaterthan": + case "gt": + $condition[] = intval(($output > $modifier_value[$i])); + break; + case "lowerthan": + case "lt": + $condition[] = intval(($output < $modifier_value[$i])); + break; + case "isinrole": + case "ir": + case "memberof": + case "mo": // Is Member Of (same as inrole but this one can be stringed as a conditional) + if ($output == "&_PHX_INTERNAL_&") { + $output = $this->user["id"]; + } + $grps = ($this->strlen($modifier_value[$i]) > 0) ? explode(",", $modifier_value[$i]) : array(); + $condition[] = intval($this->isMemberOfWebGroupByUserId($output, $grps)); + break; + case "or": + $condition[] = "||"; + break; + case "and": + $condition[] = "&&"; + break; + case "show": + $conditional = implode(' ', $condition); + $isvalid = intval($this->runCode($conditional)); + if (!$isvalid) { + $output = null; + } + break; + case "then": + $conditional = implode(' ', $condition); + $isvalid = intval($this->runCode($conditional)); + if ($isvalid) { + $output = $modifier_value[$i]; + } else { + $output = null; + } + break; + case "else": + $conditional = implode(' ', $condition); + $isvalid = intval($this->runCode($conditional)); + if (!$isvalid) { + $output = $modifier_value[$i]; + } + break; + case "select": + $raw = explode("&", $modifier_value[$i]); + $map = array(); + $count = count($raw); + for ($m = 0; $m < $count; $m++) { + $mi = explode("=", $raw[$m]); + $map[$mi[0]] = $mi[1]; + } + $output = $map[$output]; + break; + ##### End of Conditional Modifiers + + ##### String Modifiers + case "default": + $output = ($output === '') ? $modifier_value[0] : $output; + break; + case "lcase": + case "strtolower": + $output = $this->strtolower($output); + break; + case "ucase": + case "strtoupper": + $output = $this->strtoupper($output); + break; + case "ucfirst": + $output = $this->ucfirst($output); + break; + case "lcfirst": + $output = $this->lcfirst($output); + break; + case "ucwords": + $output = $this->ucwords($output); + break; + case "htmlent": + case "htmlentities": + $output = htmlentities($output, ENT_QUOTES, $this->modx->config['modx_charset']); + break; + case "html_entity_decode": + $output = html_entity_decode($output, ENT_QUOTES, $this->modx->config['modx_charset']); + break; + case "esc": + $output = preg_replace("/&(#[0-9]+|[a-z]+);/i", "&$1;", APIHelpers::e($output)); + $output = str_replace(array("[", "]", "`"), array("[", "]", "`"), $output); + break; + case "strip": + $output = preg_replace("~([\n\r\t\s]+)~", " ", $output); + break; + case "notags": + case "strip_tags": + $output = strip_tags($output); + break; + case "length": + case "len": + case "strlen": + $output = $this->strlen($output); + break; + case "reverse": + case "strrev": + $output = $this->strrev($output); + break; + case "wordwrap": // default: 70 + $wrapat = intval($modifier_value[$i]) ? intval($modifier_value[$i]) : 70; + $output = preg_replace_callback("@(\b\w+\b)@", function ($m) use ($wrapat) { + return wordwrap($m[1], $wrapat, ' ', 1); + }, $output); + break; + case "limit": // default: 100 + $limit = intval($modifier_value[$i]) ? intval($modifier_value[$i]) : 100; + $output = $this->substr($output, 0, $limit); + break; + case "str_shuffle": + case "shuffle": + $output = $this->str_shuffle($output); + break; + case "str_word_count": + case "word_count": + case "wordcount": + $output = $this->str_word_count($output); + break; + + ##### Special functions + case "math": + $filter = preg_replace("~([a-zA-Z\n\r\t\s])~", "", $modifier_value[$i]); + $filter = str_replace("?", $output, $filter); + $output = eval("return " . $filter . ";"); + break; + case "isnotempty": + if (!empty($output)) { + $output = $modifier_value[$i]; + } + break; + case "isempty": + case "ifempty": + if (empty($output)) { + $output = $modifier_value[$i]; + } + break; + case "nl2br": + $output = nl2br($output); + break; + case "date": + $output = strftime($modifier_value[$i], (int)$output); + break; + case "set": + $c = $i + 1; + if ($count > $c && $modifier_cmd[$c] == "value") { + $output = preg_replace("~([^a-zA-Z0-9])~", "", $modifier_value[$i]); + } + break; + case "value": + if ($i > 0 && $modifier_cmd[$i - 1] == "set") { + $this->modx->SetPlaceholder("phx." . $output, $modifier_value[$i]); + } + $output = null; + break; + case "md5": + $output = md5($output); + break; + case "userinfo": + if ($output == "&_PHX_INTERNAL_&") { + $output = $this->user["id"]; + } + $output = $this->ModUser($output, $modifier_value[$i]); + break; + case "inrole": // deprecated + if ($output == "&_PHX_INTERNAL_&") { + $output = $this->user["id"]; + } + $grps = ($this->strlen($modifier_value[$i]) > 0) ? explode(",", $modifier_value[$i]) : array(); + $output = intval($this->isMemberOfWebGroupByUserId($output, $grps)); + break; + + // If we haven't yet found the modifier, let's look elsewhere + default: + $snippet = ''; + // modified by Anton Kuzmin (23.06.2010) // + $snippetName = 'phx:' . $modifier_cmd[$i]; + if (isset($this->modx->snippetCache[$snippetName])) { + $snippet = $this->modx->snippetCache[$snippetName]; + } else { +// not in cache so let's check the db + $sql = "SELECT snippet FROM " . $this->modx->getFullTableName("site_snippets") . " WHERE " . $this->modx->getFullTableName("site_snippets") . ".name='" . $this->modx->db->escape($snippetName) . "';"; + $result = $this->modx->db->query($sql); + if ($this->modx->db->getRecordCount($result) == 1) { + $row = $this->modx->db->getRow($result); + $snippet = $this->modx->snippetCache[$row['name']] = $row['snippet']; + $this->Log(" |--- DB -> Custom Modifier"); + } else { + if ($this->modx->db->getRecordCount($result) == 0) { +// If snippet not found, look in the modifiers folder + $filename = $this->modx->config['rb_base_dir'] . 'plugins/phx/modifiers/' . $modifier_cmd[$i] . '.phx.php'; + if (@file_exists($filename)) { + $file_contents = @file_get_contents($filename); + $file_contents = str_replace('<' . '?php', '', $file_contents); + $file_contents = str_replace('?' . '>', '', $file_contents); + $file_contents = str_replace('modx->snippetCache[$snippetName] = $file_contents; + $this->modx->snippetCache[$snippetName . 'Props'] = ''; + $this->Log(" |--- File ($filename) -> Custom Modifier"); + } else { + $this->Log(" |--- PHX Error: {$modifier_cmd[$i]} could not be found"); + } + } + } + } + if (!empty($snippet)) { + $output = $this->modx->runSnippet($snippetName, array( + 'input' => $output, + 'output' => $output, + 'options' => $modifier_value[$i] + )); + } else { + $output = ''; + } + break; + } + if (count($condition)) { + $this->Log(" |--- Condition = '" . $condition[count($condition) - 1] . "'"); + } + $this->Log(" |--- Output = '" . $output . "'"); + } + } + + return $output; + } + + /** + * @param string $code + * @return mixed + */ + private function runCode($code) + { + return eval("return (" . $code . ");"); + } + + // Event logging (debug) + + /** + * @return string + */ + public function createEventLog() + { + $out = ''; + if (!empty($this->console)) { + $console = implode("\n", $this->console); + $this->console = array(); + + $out = '
        ' . $console . '
        '; + } + + return $out; + } + + // Returns a cleaned string escaping the HTML and special MODx characters + + /** + * @param $string + * @return array|mixed|string + */ + public function LogClean($string) + { + $string = preg_replace("/&(#[0-9]+|[a-z]+);/i", "&$1;", $string); + $string = APIHelpers::sanitarTag($string); + + return $string; + } + + // Simple log entry + + /** + * @param $string + */ + public function Log($string) + { + if ($this->debug) { + $this->debugLog = true; + $this->console[] = (count($this->console) + 1 - $this->curPass) . " [" . strftime( + "%H:%M:%S", + time() + ) . "] " . $this->LogClean($string); + } + } + + // Log snippet output + + /** + * @param $string + */ + public function LogSnippet($string) + { + if ($this->debug) { + $this->debugLog = true; + $this->console[] = (count($this->console) + 1 - $this->curPass) . " [" . strftime( + "%H:%M:%S", + time() + ) . "] " . " |--- Returns:
        " . $this->LogClean($string) . "
        "; + } + } + + // Log pass + public function LogPass() + { + $this->console[] = "
        Pass " . $this->curPass . "
        "; + } + + // Log pass + + /** + * @param $string + */ + public function LogSource($string) + { + $this->console[] = "
        Source:
        " . $this->LogClean($string); + } + + // Returns the specified field from the user record + // positive userid = manager, negative integer = webuser + +/** + * @param $userid + * @param $field + * @return mixed + */ + public function ModUser($userid, $field) + { + if (!array_key_exists($userid, $this->cache["ui"])) { + if (intval($userid) < 0) { + $user = $this->modx->getWebUserInfo(-($userid)); + } else { + $user = $this->modx->getUserInfo($userid); + } + $this->cache["ui"][$userid] = $user; + } else { + $user = $this->cache["ui"][$userid]; + } + + return $user[$field]; + } + + // Returns true if the user id is in one the specified webgroups + + /** + * @param int $userid + * @param array $groupNames + * @return bool + */ + public function isMemberOfWebGroupByUserId($userid = 0, $groupNames = array()) + { + $userid = (int)$userid; + // if $groupNames is not an array return false + if (!is_array($groupNames)) { + return false; + } + + // if the user id is a negative number make it positive + if (intval($userid) < 0) { + $userid = -($userid); + } + + // Creates an array with all webgroups the user id is in + if (!array_key_exists($userid, $this->cache["mo"])) { + $tbl = $this->modx->getFullTableName("webgroup_names"); + $tbl2 = $this->modx->getFullTableName("web_groups"); + $sql = "SELECT `wgn`.`name` FROM {$tbl} `wgn` INNER JOIN {$tbl2} `wg` ON `wg`.`webgroup`=`wgn`.`id` AND `wg`.`webuser`={$userid}"; + $this->cache["mo"][$userid] = $grpNames = $this->modx->db->getColumn("name", $sql); + } else { + $grpNames = $this->cache["mo"][$userid]; + } + // Check if a supplied group matches a webgroup from the array we just created + foreach ($groupNames as $k => $v) { + if (in_array(trim($v), $grpNames)) { + return true; + } + } + + // If we get here the above logic did not find a match, so return false + return false; + } + + // Returns the value of a PHx/MODx placeholder. + + /** + * @param $name + * @return mixed|string + */ + public function getPHxVariable($name) + { + // Check if this variable is created by PHx + if (array_key_exists($name, $this->placeholders)) { + // Return the value from PHx + return $this->placeholders[$name]; + } else { + // Return the value from MODx + return $this->modx->getPlaceholder($name); + } + } + + // Sets a placeholder variable which can only be access by PHx + + /** + * @param $name + * @param $value + */ + public function setPHxVariable($name, $value) + { + if ($name != "phx") { + $this->placeholders[$name] = $value; + } + } + + //mbstring + + /** + * @param $str + * @param $s + * @param null $l + * @return string + */ + public function substr($str, $s, $l = null) + { + if (function_exists('mb_substr')) { + return mb_substr($str, $s, $l); + } + + return substr($str, $s, $l); + } + + /** + * @param $str + * @return int + */ + public function strlen($str) + { + if (function_exists('mb_strlen')) { + return mb_strlen($str); + } + + return strlen($str); + } + + /** + * @param $str + * @return string + */ + public function strtolower($str) + { + if (function_exists('mb_strtolower')) { + return mb_strtolower($str); + } + + return strtolower($str); + } + + /** + * @param $str + * @return string + */ + public function strtoupper($str) + { + if (function_exists('mb_strtoupper')) { + return mb_strtoupper($str); + } + + return strtoupper($str); + } + + /** + * @param $str + * @return string + */ + public function ucfirst($str) + { + if (function_exists('mb_strtoupper') && function_exists('mb_substr') && function_exists('mb_strlen')) { + return mb_strtoupper(mb_substr($str, 0, 1)) . mb_substr($str, 1, mb_strlen($str)); + } + + return ucfirst($str); + } + + /** + * @param $str + * @return string + */ + public function lcfirst($str) + { + if (function_exists('mb_strtolower') && function_exists('mb_substr') && function_exists('mb_strlen')) { + return mb_strtolower(mb_substr($str, 0, 1)) . mb_substr($str, 1, mb_strlen($str)); + } + + return lcfirst($str); + } + + /** + * @param $str + * @return string + */ + public function ucwords($str) + { + if (function_exists('mb_convert_case')) { + return mb_convert_case($str, MB_CASE_TITLE); + } + + return ucwords($str); + } + + /** + * @param $str + * @return string + */ + public function strrev($str) + { + preg_match_all('/./us', $str, $ar); + + return implode(array_reverse($ar[0])); + } + + /** + * @param $str + * @return string + */ + public function str_shuffle($str) + { + preg_match_all('/./us', $str, $ar); + shuffle($ar[0]); + + return implode($ar[0]); + } + + /** + * @param $str + * @return int + */ + public function str_word_count($str) + { + return count(preg_split('~[^\p{L}\p{N}\']+~u', $str)); + } +} diff --git a/assets/snippets/DocLister/snippet.DLBuildMenu.php b/assets/snippets/DocLister/snippet.DLBuildMenu.php deleted file mode 100755 index 2027976b14..0000000000 --- a/assets/snippets/DocLister/snippet.DLBuildMenu.php +++ /dev/null @@ -1,104 +0,0 @@ -event->params; -if ( ! is_array($p)) { - $p = array(); -} - -if ( isset( $p['config'] ) ) { - require_once MODX_BASE_PATH . 'assets/lib/Helpers/Config.php'; - - $helper = new \Helpers\Config( $p ); - $helper->setPath( '/assets/snippets/DocLister/' ); - $helper->loadConfig( $p['config'] ); - - $p = array_merge( $helper->getConfig(), $p ); -} - -/** Текущий уровень вложенности */ -$p['currentDepth'] = $currentDepth = \APIhelpers::getkey($p, 'currentDepth', 1); - - -/** Основной шаблон обертка */ -$p['TplMainOwner'] = \APIhelpers::getkey($p, 'TplMainOwner', - '@CODE:' -); - -/** Шаблон обертка для вложенных уровней */ -$p['TplSubOwner'] = \APIhelpers::getkey($p, 'TplSubOwner', - '@CODE:' -); - -/** - * TplOwnerN Шаблон обертка для N уровня вложенности - * TplMainOwner Основной шабон обертка - * TplSubOwner Шаблон обертка для вложенных уровней - */ -$currentOwnerTpl = \APIhelpers::getkey($p, 'TplOwner' . $currentDepth); -if (empty($currentOwnerTpl)) { - $currentOwnerTpl = \APIhelpers::getkey($p, (($currentDepth == 1) ? 'TplMainOwner' : 'TplSubOwner')); -} - - -/** Основной шаблон для каждого пункта меню всех уровней */ -$p['TplOneItem'] = $currentTpl = \APIhelpers::getkey($p, 'TplOneItem', - '@CODE:' -); - -/** - * TplDepthN Шаблон пункта меню вложенности N - * TplNoChildrenDepthN Шаблон пункта меню вложенности N без дочерних элементов - * noChildrenRowTPL Общий шаблон пункта меню без дочерних элементов - */ -$currentTpl = \APIhelpers::getkey($p, 'TplDepth' . $currentDepth, $currentTpl); -$currentNoChildrenTpl = \APIhelpers::getkey($p, 'TplNoChildrenDepth' . $currentDepth); -if (empty($currentNoChildrenTpl)) { - $currentNoChildrenTpl = \APIhelpers::getkey($p, 'noChildrenRowTPL', $currentTpl); -} - - -/** Условия выборки документов для всех уровней */ -$p['addWhereList'] = $currentWhere = \APIhelpers::getkey($p, 'addWhereList', 'c.hidemenu = 0'); -/** addWhereListN Условия выборки документов N уровня */ -$currentWhere = \APIhelpers::getkey($p, 'addWhereList' . $currentDepth, $currentWhere); - -$p['orderBy'] = $currentOrderBy = \APIhelpers::getkey($p, 'orderBy', 'menuindex ASC, id ASC'); -/** orderByN Условия сортировки документов N уровня */ -$currentOrderBy = \APIhelpers::getkey($p, 'orderBy' . $currentDepth, $currentOrderBy); - - -$p['tvList'] = $currentTvList = \APIhelpers::getkey($p, 'tvList'); -$currentTvList = \APIhelpers::getkey($p, 'tvList' . $currentDepth, $currentTvList); -/** - * Получение prepare сниппетов из параметров BeforePrepare и AfterPrepare - * для совмещения с обязательным вызовом DLFixedPrepare::buildMenu метода - */ -$prepare = \APIhelpers::getkey($p, 'BeforePrepare', ''); -$prepare = explode(",", $prepare); -$prepare[] = 'DLFixedPrepare::buildMenu'; -$prepare[] = \APIhelpers::getkey($p, 'AfterPrepare', ''); -$p['prepare'] = trim(implode(",", $prepare), ','); - -return $modx->runSnippet('DocLister', array_merge(array( - 'idType' => 'parents', - 'parents' => \APIhelpers::getkey($p, 'parents', 0), - ), $p, array( - 'params' => $p, - 'tpl' => $currentTpl, - 'ownerTPL' => $currentOwnerTpl, - 'mainRowTpl' => $currentTpl, - 'noChildrenRowTPL' => $currentNoChildrenTpl, - 'noneWrapOuter' => '0', - 'addWhereList' => $currentWhere, - 'orderBy' => $currentOrderBy - )) -); diff --git a/assets/snippets/DocLister/snippet.DLglossary.php b/assets/snippets/DocLister/snippet.DLGlossary.php similarity index 100% rename from assets/snippets/DocLister/snippet.DLglossary.php rename to assets/snippets/DocLister/snippet.DLGlossary.php diff --git a/assets/snippets/DocLister/snippet.DLValuelist.php b/assets/snippets/DocLister/snippet.DLValuelist.php new file mode 100644 index 0000000000..80c45d3ff4 --- /dev/null +++ b/assets/snippets/DocLister/snippet.DLValuelist.php @@ -0,0 +1,49 @@ +event->params; +if (! is_array($p)) { + $p = array(); +} + +$titleField = APIhelpers::getkey($p, 'titleField', 'pagetitle'); +$valueField = APIhelpers::getkey($p, 'valueField', 'id'); + +$p = array_merge( + array( + 'idType' => 'parents', + 'valueField' => $valueField, + 'titleField' => $titleField, + 'api' => implode(",", array($titleField, $valueField)), + 'controller' => 'site_content', + 'debug' => '0' + ), + $p +); + +$json = $modx->runSnippet("DocLister", $p); +$json = jsonHelper::jsonDecode($json, array('assoc' => true)); +$out = array(); + +$nopTitle = APIhelpers::getkey($p, 'addNopTitle'); +if ($nopTitle) { + $nopValue = APIhelpers::getkey($p, 'addNopValue'); + $out[] = $nopTitle . '==' . $nopValue; +} + +foreach ($json as $el) { + $out[] = APIhelpers::getkey($el, $titleField) . '==' . APIhelpers::getkey($el, $valueField); +} +if (APIhelpers::getkey($p, 'debug')) { + $key = APIhelpers::getkey($p, 'sysKey', 'dl') . '.debug'; + $debugStack = $modx->getPlaceholder($key); + if (! empty($debugStack)) { + $modx->logEvent(0, 1, $debugStack, 'DocLister [DLValueList]'); + } +} + +return implode("||", $out); diff --git a/assets/snippets/FormLister/__autoload.php b/assets/snippets/FormLister/__autoload.php index 3195891a4f..a294bdc059 100755 --- a/assets/snippets/FormLister/__autoload.php +++ b/assets/snippets/FormLister/__autoload.php @@ -19,6 +19,7 @@ function autoloade366e6fef0b0abb40d30844d932018e7($class) { 'FormLister\\DeleteContent' => '/core/controller/DeleteContent.php', 'FormLister\\DeleteUser' => '/core/controller/DeleteUser.php', 'FormLister\\FileValidator' => '/lib/FileValidator.php', + 'FormLister\\Filters' => '/lib/Filters.php', 'FormLister\\Form' => '/core/controller/Form.php', 'FormLister\\Login' => '/core/controller/Login.php', 'FormLister\\MailChimp' => '/core/controller/MailChimp.php', diff --git a/assets/snippets/FormLister/core/FormLister.abstract.php b/assets/snippets/FormLister/core/FormLister.abstract.php index 8d491bbc4a..a1aced992e 100644 --- a/assets/snippets/FormLister/core/FormLister.abstract.php +++ b/assets/snippets/FormLister/core/FormLister.abstract.php @@ -105,7 +105,7 @@ abstract class Core * @param \DocumentParser $modx * @param array $cfg */ - public function __construct(\DocumentParser $modx, $cfg = array()) + public function __construct (\DocumentParser $modx, $cfg = array()) { $this->modx = $modx; $this->config = new Config(); @@ -122,7 +122,7 @@ public function __construct(\DocumentParser $modx, $cfg = array()) } $this->lexicon = new Lexicon($modx, array( 'langDir' => 'assets/snippets/FormLister/core/lang/', - 'lang' => $this->getCFGDef('lang', $this->modx->config['manager_language']) + 'lang' => $this->getCFGDef('lang', $this->modx->getConfig('manager_language')) )); $this->DLTemplate = \DLTemplate::getInstance($modx); $this->DLTemplate->setTemplatePath($this->getCFGDef('templatePath')); @@ -148,11 +148,11 @@ public function __construct(\DocumentParser $modx, $cfg = array()) * Установка шаблона формы * Загрузка капчи */ - public function initForm() + public function initForm () { $lexicon = $this->getCFGDef('lexicon'); $langDir = $this->getCFGDef('langDir', 'assets/snippets/FormLister/core/lang/'); - $lang = $this->getCFGDef('lang', $this->modx->config['manager_language']); + $lang = $this->getCFGDef('lang', $this->modx->getConfig('manager_language')); if ($lexicon) { $_lexicon = $this->config->loadArray($lexicon); if (isset($_lexicon[0])) { @@ -173,10 +173,11 @@ public function initForm() $this->emptyFormControls = array_merge( $this->emptyFormControls, $this->config->loadArray($this->getCFGDef('emptyFormControls'), - '' - )); - $this->setRequestParams(); - $this->setExternalFields($this->getCFGDef('defaultsSources', 'array')); + '' + )); + $this->setRequestParams() + ->setExternalFields($this->getCFGDef('defaultsSources', 'array')) + ->sanitizeForm(); $this->renderTpl = $this->getCFGDef('formTpl'); //Шаблон по умолчанию $this->initCaptcha(); $this->runPrepare('prepare'); @@ -190,7 +191,7 @@ public function initForm() * @param string $arrayParam название параметра с данными * @return $this */ - public function setExternalFields($sources = 'array', $arrayParam = 'defaults') + public function setExternalFields ($sources = 'array', $arrayParam = 'defaults') { $keepDefaults = $this->getCFGDef('keepDefaults', 0); $submitted = $this->isSubmitted(); @@ -333,7 +334,7 @@ public function setExternalFields($sources = 'array', $arrayParam = 'defaults') /** * Сохранение массива $_REQUEST */ - public function setRequestParams() + public function setRequestParams () { $this->removeGpc($this->_rq); $this->setFields($this->_rq); @@ -356,7 +357,7 @@ public function setRequestParams() * @param array $forbiddenFields * @return array */ - public function filterFields($fields = array(), $allowedFields = array(), $forbiddenFields = array()) + public function filterFields ($fields = array(), $allowedFields = array(), $forbiddenFields = array()) { $out = array(); foreach ($fields as $key => $value) { @@ -375,9 +376,10 @@ public function filterFields($fields = array(), $allowedFields = array(), $forbi /** * @return bool */ - public function isSubmitted() + public function isSubmitted () { - $out = $this->formid && ($this->getField('formid') === $this->formid); + $enableSubmit = !$this->getCFGDef('disableSubmit', 0); + $out = $this->formid && ($this->getField('formid') === $this->formid) && $enableSubmit; return $out; } @@ -389,7 +391,7 @@ public function isSubmitted() * @param mixed $def значение по умолчанию, если в конфиге нет искомого параметра * @return mixed значение из конфига */ - public function getCFGDef($name, $def = null) + public function getCFGDef ($name, $def = null) { return $this->config->getCFGDef($name, $def); } @@ -402,7 +404,7 @@ public function getCFGDef($name, $def = null) * * @return string */ - public function render() + public function render () { if ($this->isSubmitted()) { $this->validateForm(); @@ -423,7 +425,7 @@ public function render() * @param bool $convertArraysToStrings * @return array */ - public function prerenderForm($convertArraysToStrings = false) + public function prerenderForm ($convertArraysToStrings = false) { if (empty($this->plhCache) || !$convertArraysToStrings) { $this->plhCache = array_merge( @@ -445,7 +447,7 @@ public function prerenderForm($convertArraysToStrings = false) * * @return null|string */ - public function renderForm() + public function renderForm () { $api = (int)$this->getCFGDef('api', 0); $data = $this->getFormData(); @@ -458,7 +460,8 @@ public function renderForm() if ($api == 1) { $out = $data; } else { - $plh = $this->getCFGDef('skipPrerender', 0) ? $this->getFormData('fields') : $this->prerenderForm($this->getFormStatus()); + $plh = $this->getCFGDef('skipPrerender', + 0) ? $this->getFormData('fields') : $this->prerenderForm($this->getFormStatus()); $this->log('Render output', array('template' => $this->renderTpl, 'data' => $plh)); $form = $this->parseChunk($this->renderTpl, $plh); if (!$api) { @@ -483,7 +486,7 @@ public function renderForm() * @param string $prefix добавляет префикс к имени поля * @return $this */ - public function setFields($fields = array(), $prefix = '') + public function setFields ($fields = array(), $prefix = '') { foreach ($fields as $key => $value) { if (is_int($key)) { @@ -498,11 +501,39 @@ public function setFields($fields = array(), $prefix = '') return $this; } + /** + * Обработка значений по предопределенным правилам + * @return $this + */ + public function sanitizeForm () + { + $filterer = $this->getCFGDef('filterer', '\FormLister\Filters'); + $filterer = $this->loadModel($filterer, '', array()); + $filterSet = $this->config->loadArray($this->getCFGDef('filters', ''), ''); + foreach ($filterSet as $field => $filters) { + $value = $this->getField($field); + if (!is_array($filters)) { + $filters = array($filters); + } + foreach ($filters as $filter) { + if (method_exists($filterer, $filter)) { + $value = call_user_func( + array($filterer, $filter), + $value + ); + } + } + $this->setField($field, $value); + } + + return $this; + } + /** * Возвращает результат проверки формы * @return bool */ - public function validateForm() + public function validateForm () { $validator = $this->getCFGDef('validator', '\FormLister\Validator'); $validator = $this->loadModel($validator, '', array()); @@ -528,7 +559,7 @@ public function validateForm() * @param array $fields * @return bool|array */ - public function validate($validator, $rules, $fields) + public function validate ($validator, $rules, $fields) { if (empty($rules) || is_null($validator)) { return true; @@ -604,7 +635,7 @@ public function validate($validator, $rules, $fields) * @param string $section * @return array */ - public function getFormData($section = '') + public function getFormData ($section = '') { if ($section && isset($this->formData[$section])) { $out = $this->formData[$section]; @@ -620,7 +651,7 @@ public function getFormData($section = '') * @param bool $status * @return $this */ - public function setFormStatus($status) + public function setFormStatus ($status) { $this->formData['status'] = (bool)$status; @@ -631,7 +662,7 @@ public function setFormStatus($status) * Возращвет статус формы * @return bool */ - public function getFormStatus() + public function getFormStatus () { return $this->formData['status']; } @@ -642,18 +673,28 @@ public function getFormStatus() * @param mixed $default * @return mixed */ - public function getField($field, $default = '') + public function getField ($field, $default = '') { return \APIhelpers::getkey($this->formData['fields'], $field, $default); } + /** + * Проверяет существование поля в formData + * @param string $field + * @return bool + */ + public function fieldExists ($field) + { + return is_scalar($field) && isset($this->formData['fields'][$field]); + } + /** * Сохраняет значение поля в formData * @param string $field имя поля * @param $value * @return $this */ - public function setField($field, $value) + public function setField ($field, $value) { if ($value !== '' || $this->getCFGDef('allowEmptyFields', 1)) { $this->formData['fields'][$field] = $value; @@ -668,7 +709,7 @@ public function setField($field, $value) * @param $value * @return $this */ - public function setPlaceholder($placeholder, $value) + public function setPlaceholder ($placeholder, $value) { $this->placeholders[$placeholder] = $value; $this->plhCache = array(); @@ -680,7 +721,7 @@ public function setPlaceholder($placeholder, $value) * @param $placeholder * @return mixed */ - public function getPlaceholder($placeholder) + public function getPlaceholder ($placeholder) { return \APIhelpers::getkey($this->placeholders, $placeholder); } @@ -690,10 +731,11 @@ public function getPlaceholder($placeholder) * @param string $field * @return $this */ - public function unsetField($field) + public function unsetField ($field) { if (isset($this->formData['fields'][$field])) { unset($this->formData['fields'][$field]); + $this->plhCache = array(); } return $this; @@ -706,7 +748,7 @@ public function unsetField($field) * @param string $message сообщение об ошибке * @return $this */ - public function addError($field, $type, $message) + public function addError ($field, $type, $message) { if ($this->lexicon->isReady()) { $message = $this->lexicon->parseLang($message); @@ -721,13 +763,14 @@ public function addError($field, $type, $message) * @param string $message * @return $this */ - public function addMessage($message = '') + public function addMessage ($message = '') { if ($message) { if ($this->lexicon->isReady()) { $message = $this->lexicon->parseLang($message); } $this->formData['messages'][] = $message; + $this->plhCache = array(); } return $this; @@ -740,7 +783,7 @@ public function addMessage($message = '') * @param bool $split преобразование массивов в строки * @return array */ - public function fieldsToPlaceholders($fields = array(), $suffix = '', $split = false) + public function fieldsToPlaceholders ($fields = array(), $suffix = '', $split = false) { $plh = array(); if (is_array($fields)) { @@ -788,7 +831,7 @@ public function fieldsToPlaceholders($fields = array(), $suffix = '', $split = f * Готовит сообщения об ошибках для вывода в шаблон * @return array */ - public function errorsToPlaceholders() + public function errorsToPlaceholders () { $plh = array(); foreach ($this->getFormData('errors') as $field => $error) { @@ -812,7 +855,7 @@ public function errorsToPlaceholders() * Обработка чекбоксов, селектов, радио-кнопок перед выводом в шаблон * @return array */ - public function controlsToPlaceholders() + public function controlsToPlaceholders () { $plh = array(); $formControls = $this->config->loadArray($this->getCFGDef('formControls')); @@ -839,7 +882,7 @@ public function controlsToPlaceholders() * @param string $param * @return array|mixed|\xNop */ - public function getValidationRules($param = 'rules') + public function getValidationRules ($param = 'rules') { $rules = $this->getCFGDef($param); if (empty($rules)) { @@ -859,7 +902,7 @@ public function getValidationRules($param = 'rules') * Готовит сообщения из formData для вывода в шаблон * @return string */ - public function renderMessages() + public function renderMessages () { $out = ''; $wrapper = $this->getCFGDef('messagesTpl', '@CODE:
        [+messages+]
        '); @@ -910,7 +953,7 @@ public function renderMessages() * @param string $splitter * @return string */ - public function renderMessagesGroup($messages, $wrapper, $splitter) + public function renderMessagesGroup ($messages, $wrapper, $splitter) { $out = ''; if (is_array($messages) && !empty($messages)) { @@ -928,17 +971,22 @@ public function renderMessagesGroup($messages, $wrapper, $splitter) * @param bool $parseDocumentSource * @return string */ - public function parseChunk($name, $data, $parseDocumentSource = false) + public function parseChunk ($name, $data, $parseDocumentSource = false) { $parseDocumentSource = $parseDocumentSource || $this->getCFGDef('parseDocumentSource', 0); $rewriteUrls = $this->getCFGDef('rewriteUrls', 1); - $this->DLTemplate->setTwigTemplateVars(array( - 'FormLister' => $this, - 'errors' => $this->getFormData('errors'), - 'messages' => $this->getFormData('messages'), - 'plh' => $this->placeholders - ) + $templateData = array( + 'FormLister' => $this, + 'errors' => $this->getFormData('errors'), + 'messages' => $this->getFormData('messages'), + 'plh' => $this->placeholders ); + /* TODO remove in further versions*/ + if (method_exists($this->DLTemplate, 'setTwigTemplateVars')) { + $this->DLTemplate->setTwigTemplateVars($templateData); + } else { + $this->DLTemplate->setTemplateData($templateData); + } $out = $this->DLTemplate->parseChunk($name, $data, $parseDocumentSource); if ($this->lexicon->isReady()) { $out = $this->lexicon->parseLang($out); @@ -959,7 +1007,7 @@ public function parseChunk($name, $data, $parseDocumentSource = false) /** * Загружает класс капчи */ - public function initCaptcha() + public function initCaptcha () { if ($captcha = $this->getCFGDef('captcha')) { $captcha = preg_replace('/[^a-zA-Z]/', '', $captcha); @@ -990,7 +1038,7 @@ public function initCaptcha() /** * @return \DocumentParser|null */ - public function getMODX() + public function getMODX () { return $this->modx; } @@ -998,7 +1046,7 @@ public function getMODX() /** * @return mixed|string */ - public function getFormId() + public function getFormId () { return $this->formid; } @@ -1006,7 +1054,7 @@ public function getFormId() /** * @return bool */ - public function isValid() + public function isValid () { $this->setValid(!count($this->getFormData('errors'))); @@ -1018,7 +1066,7 @@ public function isValid() * @param string $paramName * @return $this */ - public function runPrepare($paramName = 'prepare') + public function runPrepare ($paramName = 'prepare') { if (($prepare = $this->getCFGDef($paramName)) != '') { $names = $this->config->loadArray($prepare); @@ -1041,7 +1089,7 @@ public function runPrepare($paramName = 'prepare') * @param array $params * @return $this */ - public function callPrepare($name, $params = array()) + public function callPrepare ($name, $params = array()) { if (!empty($name)) { if ((is_object($name) && ($name instanceof \Closure)) || is_callable($name)) { @@ -1062,7 +1110,7 @@ public function callPrepare($name, $params = array()) * @param string $param имя параметра с id документа для редиректа * @param array $_query */ - public function redirect($param = 'redirectTo', $_query = array()) + public function redirect ($param = 'redirectTo', $_query = array()) { if ($redirect = $this->getCFGDef($param, 0)) { $redirect = $this->config->loadArray($redirect); @@ -1080,7 +1128,7 @@ public function redirect($param = 'redirectTo', $_query = array()) if (isset($redirect['header'])) { $header = $redirect['header']; } - $page = isset($redirect['page']) ? $redirect['page'] : $this->modx->config['site_start']; + $page = isset($redirect['page']) ? $redirect['page'] : $this->modx->getConfig('site_start'); } if (is_numeric($page)) { $redirect = $this->modx->makeUrl($page, '', $query, 'full'); @@ -1097,10 +1145,13 @@ public function redirect($param = 'redirectTo', $_query = array()) * @param $url * @param $header */ - public function sendRedirect($url, $header = 'HTTP/1.1 307 Temporary Redirect') + public function sendRedirect ($url, $header = 'HTTP/1.1 307 Temporary Redirect') { if (!$this->getCFGDef('api', 0)) { $header = $header ? $header : 'HTTP/1.1 307 Temporary Redirect'; + if (!is_null($this->debug)) { + $this->debug->saveLog(); + } $this->modx->sendRedirect($url, 0, 'REDIRECT_HEADER', $header); } } @@ -1110,13 +1161,13 @@ public function sendRedirect($url, $header = 'HTTP/1.1 307 Temporary Redirect') * * @return mixed */ - abstract public function process(); + abstract public function process (); /** * @param boolean $valid * @return Core */ - public function setValid($valid) + public function setValid ($valid) { $this->valid &= $valid; @@ -1127,7 +1178,7 @@ public function setValid($valid) * @param array $files * @return Core */ - public function setFiles($files) + public function setFiles ($files) { if (is_array($files)) { $this->formData['files'] = $files; @@ -1141,7 +1192,7 @@ public function setFiles($files) * @param array $data * @return Core */ - public function log($message, $data = array()) + public function log ($message, $data = array()) { if (!is_null($this->debug)) { $this->debug->log($message, $data); @@ -1155,7 +1206,7 @@ public function log($message, $data = array()) * @param string $path * @return object */ - public function loadModel($model, $path = '', $init = '') + public function loadModel ($model, $path = '', $init = '') { $out = null; if (!class_exists($model) && $path && $this->fs->checkFile($path)) { @@ -1177,7 +1228,7 @@ public function loadModel($model, $path = '', $init = '') * @param bool $flag * @return array */ - public function filesToArray(array $_files, array $allowed, $flag = true) + public function filesToArray (array $_files, array $allowed, $flag = true) { $files = array(); foreach ($_files as $name => $file) { @@ -1213,7 +1264,7 @@ public function filesToArray(array $_files, array $allowed, $flag = true) * @param string $field * @return array */ - public function getErrorMessage($field) + public function getErrorMessage ($field) { $out = array(); if (!empty($field) && isset($this->formData['errors'][$field]) && is_array($this->formData['errors'][$field])) { @@ -1226,7 +1277,7 @@ public function getErrorMessage($field) /** * @return string */ - protected function setGpcSeed() + protected function setGpcSeed () { $this->gpc_seed = 'sanitize_seed_' . base_convert(md5(realpath(MODX_MANAGER_PATH . 'includes/protect.inc.php')), 16, 36); @@ -1241,7 +1292,7 @@ protected function setGpcSeed() * @param int $count * @return mixed */ - protected function removeGpc(&$target, $count = 0) + protected function removeGpc (&$target, $count = 0) { $removeFields = $this->getRemoveGpcFields(); foreach ($target as $key => $value) { @@ -1269,7 +1320,7 @@ protected function removeGpc(&$target, $count = 0) /** * @return array */ - public function getRemoveGpcFields() + public function getRemoveGpcFields () { $out = $this->gpc_fields; if (($removeGpc = $this->getCFGDef('removeGpc', 0)) && empty($out)) { diff --git a/assets/snippets/FormLister/core/controller/Form.php b/assets/snippets/FormLister/core/controller/Form.php index ab296be2bb..00dc42c3da 100644 --- a/assets/snippets/FormLister/core/controller/Form.php +++ b/assets/snippets/FormLister/core/controller/Form.php @@ -37,8 +37,8 @@ public function __construct(\DocumentParser $modx, array $cfg = array()) $this->mailConfig = array( 'isHtml' => $this->getCFGDef('isHtml', 1), 'to' => $this->getCFGDef('to'), - 'from' => $this->getCFGDef('from', $this->modx->config['emailsender']), - 'fromName' => $this->getCFGDef('fromName', $this->modx->config['site_name']), + 'from' => $this->getCFGDef('from', $this->modx->getConfig('emailsender')), + 'fromName' => $this->getCFGDef('fromName', $this->modx->getConfig('site_name')), 'subject' => $this->getCFGDef('subject'), 'replyTo' => $this->getCFGDef('replyTo'), 'cc' => $this->getCFGDef('cc'), @@ -175,7 +175,7 @@ public function validateForm() */ public function renderReport($tplParam = 'reportTpl') { - $tpl = $this->getCFGDef($tplParam); + $tpl = $this->getCFGDef($tplParam, 'reportTpl'); if (empty($tpl) && $tplParam == 'reportTpl') { $tpl = '@CODE:'; foreach ($this->getFormData('fields') as $key => $value) { @@ -306,27 +306,24 @@ public function sendReport() public function sendAutosender() { $to = $this->getCFGDef('autosender'); - if (empty($to)) { - $out = true; - } else { - $config = $this->getMailSendConfig($to, 'autosenderFromName', 'autoSubject'); - $asConfig = $this->config->loadArray($this->getCFGDef('autoMailConfig')); - if (!empty($asConfig) && is_array($asConfig)) { - $asConfig = $this->parseMailerParams($asConfig); - $config = array_merge($config, $asConfig); - } - $mailer = new Mailer($this->modx, $config); - $report = $this->renderReport('automessageTpl'); - $out = $mailer->send($report); - $this->log( - 'Mail autosender report', - array( - 'report' => $report, - 'mailer_config' => $mailer->config, - 'result' => $out - ) - ); + + $config = $this->getMailSendConfig($to, 'autosenderFromName', 'autoSubject'); + $asConfig = $this->config->loadArray($this->getCFGDef('autoMailConfig')); + if (!empty($asConfig) && is_array($asConfig)) { + $asConfig = $this->parseMailerParams($asConfig); + $config = array_merge($config, $asConfig); } + $mailer = new Mailer($this->modx, $config); + $report = $this->renderReport('automessageTpl'); + $out = empty($to) ? true : $mailer->send($report); + $this->log( + 'Mail autosender report', + array( + 'report' => $report, + 'mailer_config' => $mailer->config, + 'result' => $out + ) + ); return $out; } @@ -338,30 +335,27 @@ public function sendAutosender() public function sendCCSender() { $to = $this->getField($this->getCFGDef('ccSenderField', 'email')); - if (empty($to)) { - $out = true; - } else { - if ($this->getCFGDef('ccSender', 0)) { - $config = $this->getMailSendConfig($to, 'ccSenderFromName', 'ccSubject'); - $ccConfig = $this->config->loadArray($this->getCFGDef('ccMailConfig')); - if (!empty($ccConfig) && is_array($ccConfig)) { - $ccConfig = $this->parseMailerParams($ccConfig); - $config = array_merge($config, $ccConfig); - } - $mailer = new Mailer($this->modx, $config); - $report = $this->renderReport('ccSenderTpl'); - $out = $mailer->send($report); - $this->log( - 'Mail CC report', - array( - 'report' => $report, - 'mailer_config' => $mailer->config, - 'result' => $out - ) - ); - } else { - $out = true; + + if ($this->getCFGDef('ccSender', 0)) { + $config = $this->getMailSendConfig($to, 'ccSenderFromName', 'ccSubject'); + $ccConfig = $this->config->loadArray($this->getCFGDef('ccMailConfig')); + if (!empty($ccConfig) && is_array($ccConfig)) { + $ccConfig = $this->parseMailerParams($ccConfig); + $config = array_merge($config, $ccConfig); } + $mailer = new Mailer($this->modx, $config); + $report = $this->renderReport('ccSenderTpl'); + $out = empty($to) ? true : $mailer->send($report); + $this->log( + 'Mail CC report', + array( + 'report' => $report, + 'mailer_config' => $mailer->config, + 'result' => $out + ) + ); + } else { + $out = true; } return $out; @@ -448,7 +442,7 @@ public function getMailSendConfig($to, $fromParam, $subjectParam = 'subject') array( 'subject' => $subject, 'to' => $to, - 'fromName' => $this->getCFGDef($fromParam, $this->modx->config['site_name']) + 'fromName' => $this->getCFGDef($fromParam, $this->modx->getConfig('site_name')) ) ); $out = $this->parseMailerParams($out); diff --git a/assets/snippets/FormLister/core/controller/Login.php b/assets/snippets/FormLister/core/controller/Login.php index 9b991d7d05..1a46203f63 100644 --- a/assets/snippets/FormLister/core/controller/Login.php +++ b/assets/snippets/FormLister/core/controller/Login.php @@ -27,7 +27,7 @@ public function __construct(\DocumentParser $modx, $cfg = array()) if (0 === strpos($requestUri, MODX_BASE_URL)) { $requestUri = substr($requestUri, strlen(MODX_BASE_URL)); } - $this->requestUri = $this->modx->config['site_url'] . $requestUri; + $this->requestUri = $this->modx->getConfig('site_url') . $requestUri; $this->context = $this->getCFGDef('context', 'web'); $lang = $this->lexicon->loadLang('login'); if ($lang) { @@ -93,8 +93,8 @@ public function process() $loginCookie = $this->getCFGDef('cookieName', 'WebLoginPE'); $this->user->authUser($login, $remember, $loginCookie, true); $this->setFormStatus(true); - if (isset($this->modx->documentIdentifier) && $this->modx->documentIdentifier == $this->modx->config['unauthorized_page']) { - $uaPage = $this->modx->makeUrl($this->modx->config['unauthorized_page'], "", "", "full"); + if (isset($this->modx->documentIdentifier) && $this->modx->documentIdentifier == $this->modx->getConfig('unauthorized_page')) { + $uaPage = $this->modx->makeUrl($this->modx->getConfig('unauthorized_page'), "", "", "full"); $requested = explode('?', $this->requestUri); if (array_shift($requested) != $uaPage) { $this->setField('redirectTo', $this->requestUri); diff --git a/assets/snippets/FormLister/core/controller/Register.php b/assets/snippets/FormLister/core/controller/Register.php index 00e387ba22..7f2a0cd8a3 100644 --- a/assets/snippets/FormLister/core/controller/Register.php +++ b/assets/snippets/FormLister/core/controller/Register.php @@ -152,7 +152,7 @@ public function process() $uidName => $result, 'hash' => $hash )); - $url = $this->getCFGDef('activateTo', $this->modx->config['site_start']); + $url = $this->getCFGDef('activateTo', $this->modx->getConfig('site_start')); $this->setField( 'activate.url', $this->modx->makeUrl($url, '', $query, 'full') diff --git a/assets/snippets/FormLister/core/controller/Reminder.php b/assets/snippets/FormLister/core/controller/Reminder.php old mode 100755 new mode 100644 index 796ca44f8c..37a64a9405 --- a/assets/snippets/FormLister/core/controller/Reminder.php +++ b/assets/snippets/FormLister/core/controller/Reminder.php @@ -136,7 +136,7 @@ public function process() $uid = $this->getField($this->userField); if ($hash = $this->getUserHash($uid)) { $this->setFields($this->user->toArray()); - $url = $this->getCFGDef('resetTo', isset($this->modx->documentIdentifier) && $this->modx->documentIdentifier > 0 ? $this->modx->documentIdentifier : $this->config['site_start']); + $url = $this->getCFGDef('resetTo', isset($this->modx->documentIdentifier) && $this->modx->documentIdentifier > 0 ? $this->modx->documentIdentifier : $this->modx->getConfig('site_start')); $uidName = $this->getCFGDef('uidName', $this->uidField); $this->setField('reset.url', $this->modx->makeUrl($url, "", http_build_query(array($uidName => $this->getField($this->uidField), diff --git a/assets/snippets/FormLister/docs/en/010_Controllers.md b/assets/snippets/FormLister/docs/en/010_Controllers.md deleted file mode 100755 index dac73a6705..0000000000 --- a/assets/snippets/FormLister/docs/en/010_Controllers.md +++ /dev/null @@ -1,50 +0,0 @@ -## Controllers -Controller is the class extending \FormLister\Core base class, which perfoms: - -- loading classes to validate data and generate captcha; -- processing form data (form data here is the value of formData property, not only of $_REQUEST array); -- processing form template and success template. - -The way it works: - -1. Data are loaded from form. -2. Data are loaded from external sources. -3. Snippets are called to process data. -4. Data validation if it's received from form; -3. Snippets are called to process data again. -6. Final processing - if data came from form and passed validation successfully. -7. Output. - -Final processing is done by controller's process() method. Result flag has to be set with setFormStatus() method after successful processing, then fill renderTpl property with template to output processing results. - -These are some base controllers, feel free to extend them: - -### Form -Sends e-mail using form data. - -### Login -Authorizes users. - -### Register -Creates users and sends needed notifications. - -### Activate -Processes a special link to confirm user registration or sends it via e-mail. - -### DeleteUser -Allows users to delete their profiles. It requests password to confirm. - -### Profile -Allows users to edit their profiles. - -### Reminder -Helps users to remind their passwords. - -### Content -Allows to create and edit resources with MODxAPI classes. - -### DeleteContent -Allows users to delete resources they created. - -### MailChimp -Adds users to MailChimp mailing lists. It's provided as example of \FormLister\Core class extension. diff --git a/assets/snippets/FormLister/docs/en/020_Parameters.md b/assets/snippets/FormLister/docs/en/020_Parameters.md deleted file mode 100755 index c48d8988f2..0000000000 --- a/assets/snippets/FormLister/docs/en/020_Parameters.md +++ /dev/null @@ -1,298 +0,0 @@ -## General parameters - -These parameters are processed by FormLister core class. Controllers can change parameters purposes. - -## Settings -### controller -Sets the class to process data. - -Possible values - php-file name without extension which contains controller class. - -Default value - Form. - -### dir -Folder where controller class is located. - -Default value - assets/snippets/FormLister/core/controller/ - -### formid -The name of the form, required parameter. - -Form needs to have a hidden field named "formid" and its value has to be the same as parameter value. The form means to be sent, if there is a key named "formid" in the $_REQUEST array and its value is equal to the parameter value. - -### formMethod -Possible values - post, get or request. - -Default value - post. - -### config -Loads parameters from json file. - -Possible values - filename:folder, several values are separated by the semicolon. - -#### Example -myparams:core - loads parameters from assets/snippets/FormLister/config/core/myparams.json file; -myparams - loads parameters from assets/snippets/FormLister/config/custom/myparams.json file; myparams:/assets/myfolder - loads parameters from assets/myfolder/myparams.json file. - -Default value - none. - -### api -The way of output. - -Possible values: - -- 0: html only; -- 1: json array with form data; -- 2: json array with form data and html. - -### apiFormat -Output format. - -Possible value - json or array. - -Defaut value - json. - -### debug -Enables debug mode. Debug data is sent to MODX events log. - -Possible values - 0, 1. - -Default value - 0. - -### saveObject -Saves FormLister object to placeholder, so other snippets can use it. The object is saved only if form processing is finished successfully. - -Possible values - placeholder name. - -Default value - none. - -### removeGpc -Restores data sanitized by MODX as it contains {{, [[ and so on. MODX tags will be sanitized in output. - -Default value - 0, 1 or field names comma separated. - -Default value - 0. - -## Data sources -### defaultsSources -Allows to load data from external sources, to pre-fill form fields, for example. External data are loaded only before initial form output and ignored after form is sent. This behaviour can be changed with "keepDefaults" parameter. - -Possible values: sources, semicolon separated. The order of loading data matches the sources order in parameter. - -The source can be set as "name:key:prefix". Prefix is added to field name, if set - for example, config.site_name. - -Possible sources: - -- array: json or php array, its values are defined by the parameter named "defaults"; -- param:parameter name:prefix - the same as the "array" source but you can specify any snippet parameter, not only "defaults"; -- session:array key:prefix - loads data from $_SESSION[array key]; -- plh:keys, comma separated:prefix - loads data from $modx->placeholders property; -- aplh:placeholder name:prefix - loads data from an array stored in placeholder; -- config:prefix- loads data from MODX configuration; -- cookie:keys, comma separated:префикс - loads data from the $_COOKIE array; -- MODxAPI class name:key:prefix - a key is the argument of edit() method, the class has to be loaded before snippet call; -- document:prefix - loads current document data from modResource model. It needs no key; -- user:key:prefix - load authorized user data from modUsers model. User type is provided by key value (web or mgr). - -Default value - array. - -### defaults -Data for the "array" source. - -Possible values: json or php array. - -### keepDefaults -Allows to load external data after the form is sent. If fields list is specified, then only these fields will be loaded. - -Possible values: 1, 0; field names, comma separated. - -Default value - 0. - -### allowEmptyFields -Allows to set fields with empty values. - -Possible values - 0 or 1. - -Default value - 1. - -## Form Controls -### formControls -The list of fields hold by form controls (selects, checkboxes, radio buttons). It needs to determine their state. - -Possible values - field names, comma separated. - -Default value - none. - -### emptyFormControls -This parameter allows to solve the problem of unchecked checkboxes, as they are excluded from fields array during form submission: if there's no needed element in the $_REQUEST array, then it's set according to this parameter. The problem is actual mostly for MODxAPI classes usage, because MODxAPI requires to list changed fields in fromArray() method. But it's possible to use it in common forms to set the value of unchecked checkbox in templates. - -Possible values - an array: -``` -&emptyFormControls=`{ - "mycheckbox" : "No", - "published" : 0 -}` -``` - -## Data Processing -### prepare, prepareProcess, prepareAfterProcess -It's similar to the "prepare" parameter of DocLister. - -Snippets defined in the "prepare" parameter are run after form data loaded, "prepareProcess" - after validation is passed successfully, "prepareAfterProcess" - after form processing is finished. Controller object is available in prepare-snippets via $FormLister variable, while $data array contains the values of form fields. Additional $name variable allows to determine the parameter initiated snippet call; so you can use one snippet for all cases. Use controller methods (setField, setFields etc.) to change form data in prepare-snippets. - -Possible values - snippet names, anonymous functions, static methods of loaded classes. - -Default value - none. - -## Validation -### validator -Class name to validate data. Is has to be loaded before snippet call. - -Default value - \FormLister\Validator. - -### rules -Validation rules array. - -Default value - none. - -## Templates -### formTpl -Form template. It needs to have the required field named "formid" with the same value as "formid" parameter's one. - -Possible values - template name, according to DocLister templating rules. - -Default value - none. - -### arraySplitter - -The separator to convert arrays to strings. - -Default value - semicolon. - -### {field}.arraySplitter -The separator to convert arrays to strings, but for particular {field}. Example: groups.arraySplitter - the separator for the field named "groups". - -If not set, then the "arraySplitter" parameter is used. - -### errorTpl -Template for validation messages. - -Possible values - template name, according to DocLister templating rules. - -Default value: -``` -@CODE:
        [+message+]
        -``` - -### requiredClass, errorClass -Class name for empty required fields and wrong filled fields. - -Default value - required and error accordingly. - -### {field}.requiredClass, {field}.errorClass -Allows to set classes mentioned above for particular fields. - -If not set, then "requiredClass", "errorClass" parameters are used. - -### messagesTpl -Template for controller messages. It outputs message groups (messages, required, error). - -Possible values - template name, according to DocLister templating rules. - -Default value: -``` -@CODE:
        [+messages+]
        -``` - -### messagesOuterTpl -Wrapper template for controller message groups. - -Possible values - template name, according to DocLister templating rules. - -Default value - -``` -@CODE: [+messages+] -``` - -### messagesRequiredOuterTpl -Wrapper template for the "required" message group. - -Possible values - template name, according to DocLister templating rules. - -Default value: -``` -@CODE: [+messages+] -``` - -### messagesErrorOuterTpl -Wrapper template for the "error" message group. - -Possible values - template name, according to DocLister templating rules. - -Default value: -``` -@CODE: [+messages+] -``` - -### messagesSplitter, messagesRequiredSplitter, messagesErrorSplitter -Messages separator in groups. - -Possible values - string. - -Default value: -``` -
        -``` - -### removeEmptyPlaceholders -Removes placeholders without values from templates. - -Possible values - 0 or 1. - -Default value - 1. - -### parseDocumentSource -Enables MODX-parser for output post-processing. - -Possible values - 0 or 1. - -Default value - 0. - -### rewriteUrls -Allows to parse links in templates if the "parseDocumentSource" parameter is off. - -Possible values - 0 or 1. - -Default value - 0. - -### skipPrerender -Allows to skip some form fields processing (sanitizing values, converting arrays to strings, error messages rendering). Set to 1, if you do not use MODX templates. - -Possible values - 0 or 1. - -Default value - 0. - -### templatePath, templateExtension -Sets template files folder and template files extension. These parameters are needed to use with EvoTwig plugin. - -Default value - none. - -## Redirect after finish -### redirectTo -Target page id to redirect if form is processed successfully. There's no redirect in api-mode, but absolute url for target page is saved in form data as "redirectTo" field. - -Instead of target page id, you can specify an array with additional options: -``` -&redirectTo=`{ - "page":10, - "query":{ - "foo":"bar" - }, - "header":"HTTP/1.1 307 Temporary Redirect" -}` -``` -The "page" key is the target page id, the "query" array contains get-parameters to pass, the "header" key can be used to set redirect header. - -Possible values - number or array. - -Default value - none. diff --git a/assets/snippets/FormLister/docs/en/030_Data_Validation.md b/assets/snippets/FormLister/docs/en/030_Data_Validation.md deleted file mode 100755 index eee9c95664..0000000000 --- a/assets/snippets/FormLister/docs/en/030_Data_Validation.md +++ /dev/null @@ -1,132 +0,0 @@ -## Data validation - -Validator applies validation rules to field values one by one, if error occures then the record is added to form errors array and further form procession is interrupted. - -Validation is passed successfully if there are no records in form errors array. - -### Validation rules -Validation rules are described as an array. Field name is the array key, and array value contains the rules array. Validation rule is the method of validator class. The key of rules array is the rule name (the name of validation method), its value is either error message string, or an array with rule description. This array contains needed values in the key named "params" and an error message in the key named "message". - -Use exclamation mark for rule denial: "!numeric" - the field passes validation if its value is not numeric. - -If you need to validate only not empty fields, then set exclamation mark before field name to ignore rules if the field is empty. - -``` -{ - "field 1": { - "rule 1" : "error message", - "rule 2" : "error message" - }, - "field 2": { - "rule 1" : "error message", - "rule 2" : { - "params" : value, - "message" : "error message" - } - }, - "!field 3":{ - "rule 1" : "error message" - } -} -``` -\FormLister\Validator base class has the following rules: - -- required: field value is not empty; -- date: field value is a date in defined format; -- min: field value length is greater or equal to defined; -- max: field value length is less or equal to defined; -- greater: field value is greater than defined; -- less: field value is less than defined; -- between: field value is in the range; -- equals: field value is equals to defined; -- in: field value is in defined array; -- alpha: field value contains only letters; -- numeric: field value contains only digits; -- alphaNumeric: field value contains only letters and digits; -- slug: field value is an url slug; -- decimal: field value is a decimal number; -- phone: field value is a phone number; -- matches: field value matches regular expression; -- url: field value is an url; -- email: field value is an e-mail address; -- length: field value length is equal to defined; -- minLength: field value length is greater or equal to defined; -- maxLength: field value length is less or equal to defined; -- lengthBetween: field value length is in the range; -- minCount: array size is greater than defined; -- maxCount: array size is less than defined; -- countBetween: array size is in the range. - -If several values are needed for the rule, then pass them as an array: -``` -&rules=`{ - "field" : { - "lengthBetween" : { - "params" : [10,20], - "message" : "Длина должна быть от 10 до 20" - } - } -}` -``` - -If the rule requires an array (the "in" rule and other), then you should specify this array in the following way: -``` -&rules=`{ - "field" : { - "in" : { - "params" : [ [10,20,30] ], - "message" : "field value should be equal to 10, 20 or 30" - } - } -}` -``` - -It needs to pass an array to validator method as single argument. - -It's possible to use anonymous functions or static methods of loaded classes: -``` -&rules=`{ - "myfield":{ - "required":"Required field", - "custom":{ - "function":"\\Namespace\\Classname::myCustomRule", - "params":[10,20,30], - "message":"Custom check failed" - } - } -}` -``` - -Validation method should accept controller object as the first argument, field value as the second argument, parameters from the "params" key of the rule description as other arguments: -``` -public static function myCustomRule($fl,$value,$a,$b,$c) { - $result = $fl->getField('field1') == $a && $fl->getField('field2') == $b && $value == $c; - return $result; -} -``` -The rule above will be passed if the field1 value is 10, the field2 value is 20, and the value of the the field which the rule is applied to is equal to 30. - -Validator method returns true if the rule is passed, false or error message if not (so it's possible not to use the "message" key for custom rules). - -Example contains the "сustom" rule name, but it can be any if it's not in validator class. So you can use several custom rules. - -### Validation results -Error data are stored as an array and can be obtained with getFormData('errors') method call: -``` -{ - "field 1": { - "failed rule" : "error message" - }, - "field 2": { - "failed rule" : "error message" - } -} -``` -This array is filled with addError(field name, rule name, error message) method. So, it's possible to affect final result adding records to this array manually. You can also call setValid(false) method to decline failed validation. - -Each field validation result can be output in template with [+field name.error+] placeholder. Total results can be output with [+form.messages+] placholder set by messagesTpl parameter. You can use the following placeholders on its part: - -- [+required+] - messages about empty required fields; -- [+errors+] - messages about wrong filled fields. - -Use getErrorMessage(field name) method to get validation error messages for any field. diff --git a/assets/snippets/FormLister/docs/en/035_Captcha_Usage.md b/assets/snippets/FormLister/docs/en/035_Captcha_Usage.md deleted file mode 100755 index 8286070dc7..0000000000 --- a/assets/snippets/FormLister/docs/en/035_Captcha_Usage.md +++ /dev/null @@ -1,43 +0,0 @@ -## Captcha usage - -FormLister can use modified MODX captcha and Google Recaptcha by default. - -Set the "captcha" parameter value with the name of captcha files folder (located at assets/snippets/FormLister/lib/captcha/) to enable it: -``` -&captcha=`modxCaptcha` -``` - -The parameter named "captchaParams" contains an array of captcha settings. For example: -``` -&captchaParams=`{ -"width":200, -"height":120 -}` -``` - -The field name to get captcha value from user is defined by the "captchaField" parameter ("vericode" by default). Validation rule for this field is created automatically. - -To output captcha in form template use [+captcha+] placeholder. - -### modxCaptcha - -Settings: -* width and height - width and height of a captcha image (100 and 60 by default); -* inline - output format. If it's 1, then [+captcha+] placeholder contains an image in base64-format. If it's 0, then placeholder contains the link to connector.php file, which generates captcha image. Default value - 1; -* connectorDir - path to the folder containing connector.php file, if "inline" parameter is set to 0. Default value - assets/snippets/FormLister/lib/captcha/modxCaptcha/; -* errorEmptyCode - error message, if user doesn't enter captcha. -* errorCodeFailed - error message, if user enters wrong value. - -### reCaptcha - -Uses Google reCAPTCHA V2. Include the following script in page tempalate to use it: -``` - -``` - -The value of "captchaField" parameter should be set to "g-recaptcha-response" (see [documentation](https://developers.google.com/recaptcha/docs/verify)). - -Settings: -* secretKey, siteKey - keys to access reCAPTCHA api; -* size, theme, badge, callback, expired_callback, tabIndex, type - see. [documentation](https://developers.google.com/recaptcha/docs/display#render_param); -* errorCodeFailed - error message if captcha validation failed. diff --git a/assets/snippets/FormLister/docs/en/040_Data_Output.md b/assets/snippets/FormLister/docs/en/040_Data_Output.md deleted file mode 100755 index 4a98a8198c..0000000000 --- a/assets/snippets/FormLister/docs/en/040_Data_Output.md +++ /dev/null @@ -1,59 +0,0 @@ -## Data output - -Data are sanitized, arrays are converted to strings to be output in templates. Special placeholders are set for form controls. "Field name" below is the raw field name, without brackets for array fields. - -Raw field value (or placeholder): -[+field name+] - -Sanitized field value (array fields are converted to strings): -``` -[+field name.value+] -``` -Example: -``` -[+comment.value+] //The value of a field named "comment". It may be a scalar value of the real input or textarea or any other form element, but it can be set with PHP as well. -``` - -Setting checkbox: -``` -[+c.field name.field value+] -``` -Example: -``` -[+c.agree.Yes+] //It outputs "checked" if a single checkbox named "agree" contains "Yes" value. -[+c.district.West+] //Same but for one checkbox from an array of two checkboxes named "district[]" -[+c.district.East+] //Same but for one checkbox from an array of two checkboxes named "district[]" -``` - - -Setting select or radio-button: -``` -[+s.field name.field value+] -``` -Example: -``` -[+s.country.Russia+] //It outputs "selected" if a single option of select named "country" is selected and its value is "Russia". See example for checkboxes if you need to use select with multiple options available to choose. -``` - -Class for empty required field: -[+field name.requiredСlass+] - -Class for wrong filled field: -[+field value.errorClass+] - -Alternative classes output: -[+field value.class+] -[+field value.classnames+] - -Validation error message: -[+field name.error+] - -Controller messages output: -[+form.messages+] - -There are 3 possible types of messages in the [+form.messages+] placeholder: failed the "required" rule fields, wrong filled fields, any messages set by addMessage() method. The last ones are output by default, see the "messagesTpl" parameter description. - -Lexicon entries: -[%lexicon keys%] - -If EvoTwig plugin is used then template variables are available: FormLister (controller object), errors (formData['errors'] array), messages (formData['messages'] array), data (formData['fields'] array). diff --git a/assets/snippets/FormLister/docs/en/050_Mail_Sending.md b/assets/snippets/FormLister/docs/en/050_Mail_Sending.md deleted file mode 100755 index e1109d7714..0000000000 --- a/assets/snippets/FormLister/docs/en/050_Mail_Sending.md +++ /dev/null @@ -1,239 +0,0 @@ -## Sending e-mail - -Form controller allows to send form data via e-mail. - -## Mailer parameters -### parseMailerParams -Allows to use form data in mail sending parameters (&to=\`[+user.email.value+]\` etc.). - -Possible values - 1, 0. - -Default value - 0. - -### isHtml -Allows to send e-mail in html format. - -Possible values - 1, 0. - -Default value - 1. - -### to -Receiver's address. If it's not set then the mail is not sent, but form procession is finished successfully. - -Possible values - e-mail address. - -Default value - none. - -### from -Sender's address. - -Possible values - e-mail address. - -Default value - the "emailsender" configuration parameter value. - -### fromName -Sender's name. - -Possible values - string. - -Default value - the "site_name" configuration parameter value. - -### replyTo -ReplyTo header. - -Possible values - e-mail address. - -Default value - none. - -### cc -Cс header. - -Possible values - e-mail address. - -Default value - none. - -### bcc -Bcc header. - -Possible values - e-mail address. - -Default value - none. - -### noemail -If it's set, then the mail isn't sent, but supposed to be sent successfully. - -Possible values - 1, 0. - -Default value - 0. - -### ignoreMailerResult -If it's set, the mail is sent and supposed to be sent successfully. - -Possible values - 1, 0. - -Default value - 0. - -### subject, ccSubject, autoSubject -Letter subject. - -Possible values - string. - -Default value - none. - -### subjectTpl, ccSubjectTpl, autoSubjectTpl -Letter subject template. - -Possible values - template name, according to DocLister templating rules. - -Default value - the "subject" parameter value ("ccSubject", "autoSubject"). - -### autosender -Address to send additional letter. - -Possible values - e-mail address. - -Default value - none. - -### autosenderFromName -The name of the additional letter sender. - -Possible values - string. - -Default value - the "site_name" configuration parameter value. - -### ccSender -If it's set then the receiver's address is defined by the value of form field. - -Possible values - 1, 0. - -Default value - 0. - -### ccSenderField -Field name containing e-mail address. - -Possible values - field name. - -Default value - email. - -### ccSenderFromName -Sender's name for the mail sent to the form field defined address. - -Possible values - string. - -Default value - none. - -## ccMailConfig -Allows to redefine mail sending parameters for the letters to the address taken from the form field ((isHtml, from, fromName, subject, replyTo, cc, bcc, noemail)). - -Possible values - json or php array. - -Default value - none. - -## autoMailConfig -Allows to redefine mail sending parameters for the additional letters (isHtml, from, fromName, subject, replyTo, cc, bcc, noemail). - -Possible values - json or php array. - -Default value - none. - -## Submit protection -### protectSubmit -Prevents submission of the form with the same data again. - -Possible values - 1, 0 or fields list to check if the form is unique. Required fields are used by default. - -Default value - 1. - -### submitLimit -Prevents sending mail too often. - -Possible values - number of seconds between form submits. - -Default value - 60. - -## Templates -### reportTpl -The main template of the letter. - -Possible values - template name, according to DocLister templating rules. - -Default value - the list of fields and their values. - -### automessageTpl -Template of the additional letter. - -Possible values - template name, according to DocLister templating rules. - -Default value - none. - -### ccSenderTpl -Template of the letter sent to the user defined address. - -Possible values - template name, according to DocLister templating rules. - -Default value - none. - -### successTpl -Success message template. - -Possible values - template name, according to DocLister templating rules. - -Default value - none. - -## Sending files -### attachments -Field names to store files. Single file fields (name="field" type="file") and multiple file fields as simple arrays (name="field[]" type="file" multiple) are supported. - -Default value - none. - -### attachFiles -Allows to send any files. - -Possible values - array: -``` -&attachFiles=`{ -"field ":{ - "filepath":"assets/images/logo.png", - "filename":"logo.png" -}, -"field 2":[ - { - "filepath":"assets/images/file1.jpg", - "filename":"report.jpg" - }, - { - "filepath":"assets/images/file2.jpg", - "filename":"report2.jpg" - } -] -}` -``` -### deleteAttachments -Allows to delete attachment files if the mail is sent successfully. - -Possible values - 0 or 1. - -Default value - 0. - -### fileValidator -Class name to validate files. This class has to be loaded before snippet call. - -Default value - \FormLister\FileValidator - -### fileRules -Validation rules (see "Data validation" chapter). Default validator has the following rules: - -- required: files are loaded successfully; -- optional: returns true even if files were not submitted (it makes file field not required); -- allowed: file extension is in defined array; -- images: file extension is jpg, jpeg, gif, png, bmp; -- minSize: file size in kilobytes is greater than defined; -- maxSize: file size in kilobytes is less than defined; -- sizeBetween: file size in kilobytes is in the range; -- minCount: files count is greater than defined; -- maxCount: files count is less than defined; -- countBetween: files count is in the range; - -There's no sense to use the "!field name" construction in file validation rules, because the value of the file field can not be empty, so use the "optional" rule instead. - -There's the [+attachments.value+] placeholder available in reportTpl template, it contains the list of attached files. To output particular file field use the [+field name.value+] placeholder. Files are sent only in letters with reportTpl template. diff --git a/assets/snippets/FormLister/docs/en/060_Authorizing_Users.md b/assets/snippets/FormLister/docs/en/060_Authorizing_Users.md deleted file mode 100755 index 1ce2b3791a..0000000000 --- a/assets/snippets/FormLister/docs/en/060_Authorizing_Users.md +++ /dev/null @@ -1,132 +0,0 @@ -## Authorizing users - -Login controller authorizes registered users using special MODxAPI class to manage them. Users are identified by their names or e-mails (username and email database fields), but it's possible to use alternative ways with "OnWebAuthentication" event. Plugin named "userHelper" performs some related operations: it counts login attempts, registers last login time, checks auto login cookie, blocks users after some unsuccessful tries, logs out users. - -## Controller parameters - -### model -Class to manage users. - -Possible values - class name. - -Default value - \modUsers - -### modelPath -Path to the class to manage users. - -Possible values - relative file path. - -Default value - assets/lib/MODxAPI/modUsers.php - -### loginField -Field to identify user. - -Possible values - field name. - -Default value - username. - -### passwordField -Password field. - -Possible values - field name. - -Default value - password. - -### rememberField -Field to remember user. If the field value is equal to true, then a special auto login cookie will be set after successful authorization. Cookie name and its lifetime is defined by the "cookieName" and "cookieLifetime" parameters. - -It's possible to set the "rememberme" field in the "defaults" parameter, to enable it by default: -``` -&defaults=`{"rememberme":1}` -``` - -Possible values - field name. - -Default value - rememberme. - -### checkActivation -Enables check for the profile activation (see "Activating user profiles"). - -Possible values - 0 or 1. - -Default value - 1. - -### context -Authorization context. - -Possible values - mgr or web. - -Default value - web. - -### cookieName -Cookie name to store auto login parameters. - -Default value - WebLoginPE. - -### cookieLifetime -Autologin cookie life time. - -Possible values - the number of seconds since last login. - -Default value - 157680000 (5 years). - -### redirectTo -Redirects user after successful authorization. - -Possible values - target page id or array. - -Default value - none. - -### exitTo -Redirects already authorized user. - -Possible values - target page id or array. - -Default value - none. - -### successTpl -Success message template. User data can be used there. - -Possible values - template name, according to DocLister templating rules. - -Default value - lexicon entry with the key [%login.default_successTpl%] - -### skipTpl -Outputs message if user is already authorized. - -Possible values - template name, according to DocLister templating rules. - -Default value - lexicon entry with the key [%login.default_skipTpl%] - -## userHelper plugin parameters -### logoutKey -GET-parameter name to catch for user logout request. For example, http://sitename.ru/page.html?logout. - -Default value - logout. - -### cookieName -Cookie name to store autologin parameters. - -Default value - WebLoginPE. - -### cookieLifetime -Autologin cookie life time. - -Possible values - number of seconds since last login. - -Default value - 157680000 (5 years). - -### maxFails -Number of unsuccessful login attempts before the block. - -Possible values - number greater than 0. - -Default value - 3. - -### blockTime -Time to block. - -Possible values - number of seconds since last login attempt. - -Default value - 3600 (1 hour). - diff --git a/assets/snippets/FormLister/docs/en/070_Registering_Users.md b/assets/snippets/FormLister/docs/en/070_Registering_Users.md deleted file mode 100755 index 45eda88ac2..0000000000 --- a/assets/snippets/FormLister/docs/en/070_Registering_Users.md +++ /dev/null @@ -1,138 +0,0 @@ -## Регистрация пользователей - -Register controller allows to register users, add them to user groups and send notifications. It extends Form controller, so you can use all its parameters to send letters during registration. - -Field names should be the same as [modUsers](http://docs.evolution-cms.com/Extras/Snippets/DocLister/MODxAPI) model's ones. - -If there's no "username" field in the form, then its value will be the value of the "email" field. So it's possible to register users only by e-mail. - -If there's no "password" field, then its value will be created automatically. So, the registration adds up to specify e-mail only. - -If there's the "repeatPassword" field in the form and validation rules are set for the "password" and "repeatPassword" fields, then the "equals" rule will be corrected to check if the "password" field matches the "repeatPassword" field: -: -``` -"repeatPassword":{ - "required":"Enter password one more time", - "equals":{ - "params" : "This key is not needed because it will be set by Register controller", - "message":"Passwords don't match" - } -} -``` - -Registration need to check if the "username" and "email" fields are unique. Controller provides rules needed: -``` -&rules=`{ - "username":{ - "required":"Enter user name", - "alphaNumeric":"Only letters and digits are allowed", - "custom":{ - "function":"\\FormLister\\Register::uniqueUsername", - "message":"You cannot use this name" - } - }, - "email":{ - "required":"Enter e-mail", - "email":"Wrong e-mail", - "custom":{ - "function":"\\FormLister\\Register::uniqueEmail", - "message":"You cannot use this e-mail" - } - } -}` -``` -All model fields for the new record are available in templates. Additional field "user.password" with given password is set. - -## Parameters -### model -Class to manage users. - -Possible values - class name. - -Default value - \modUsers - -### modelPath -Path to the class to manage users. - -Possible values - relative file path. - -Default value - assets/lib/MODxAPI/modUsers.php - -### allowedFields -Fields allowed to process, other fields are ignored. The "username", "email" and "password" fields are enabled always. - -If not set, then all fields are allowed. - -Possible value - field names, comma separated. - -Default value - none. - -### forbiddenFields -Fields forbidden to process. The "username", "email" and "password" fields will be removed from the list of forbidden fields. - -Possible value - field names, comma separated. - -Default value - none. - -### userGroups -Adds registered user to user group. - -Possible values - group names, comma separated (or an array). - -Default value - none. - -### checkActivation -Enables the check for user profile activation (see "Activating user profiles"). The "activate.url" field will be set, which contains link to a page with FormLister call to activate user profile. - -Possible values - 1 or 0. - -Default value - 0. - -### activateTo -If profile activation check is enabled, then you have to specify the id of the page with FormLister call to activate user profile. - -Possible values - page id. - -Default value - the value of $modx->config['site_start']. - -### preparePostProcess -Allows to process data after saving new user. - -Possible values - snippet names, anonymous functions, static methods of loaded classes. - -Default value - none. - -### redirectTo -Redirects user after successful registration. - -Possible values - target page id or array. - -Default value - none. - -### exitTo -Redirects authorized user. - -Possible values - target page id or array. - -Default value - none. - -### skipTpl -Outputs message if user is authorized. - -Possible values - template name, according to DocLister templating rules. - -Default value - register lexicon entry with the key [%register.default_skipTpl%]. - -### successTpl -Success message template. - -Possible values - template name, according to DocLister templating rules. - -Default value - register lexicon entry with the key [%register.default_successTpl%] - -### passwordLength -Password length (if the password needs to be created automatically). - -Possible values - number of characters greater than 6. - -Default value - 6. diff --git a/assets/snippets/FormLister/docs/en/075_Activating_User_Profiles.md b/assets/snippets/FormLister/docs/en/075_Activating_User_Profiles.md deleted file mode 100755 index 38558536c9..0000000000 --- a/assets/snippets/FormLister/docs/en/075_Activating_User_Profiles.md +++ /dev/null @@ -1,77 +0,0 @@ -## Activating user profiles - -Activate controller activates user profile, so it's possible to request registration confirmation by following the special link in the letter sent after the registration. - -If the user hasn't received this letter, then he can request this letter again. - -User profile assumes to be inactivated if the "logincount" field value is -1. - -Snippet calls to register and authorize users should have the "checkActivation" parameter enabled. - -If user creates password himself during registration, then this password needs to be requested to send a letter with the activation link. Or the new password will be created, because if user hasn't received the letter containing generated password after registration, then he cannot know this password - -All model fields are available in templates. Additional field "user.password" with raw password value is set as well as the "activate.url" field with activation link. - -## Parameters -### model -Class to manage users. - -Possible values - class name. - -Default value - \modUsers - -### modelPath -Path to the class to manage users. - -Possible values - relative file path. - -Default value - assets/lib/MODxAPI/modUsers.php - -### redirectTo -Redirects user after successful activation. - -Possible values - target page id or array. - -Default value - none. - -### exitTo -Redirects authorized user. - -Possible values - target page id or array. - -Default value - none. - -### skipTpl -Outputs message if user is authorized. - -Possible values - template name, according to DocLister templating rules. - -Default value - activate lexicon entry with the key [%activate.default_skipTpl%]. - -### reportTpl -Letter template containing profile activation data. - -Possible values - template name, according to DocLister templating rules. - -Default value - none. - -### successTpl -Message template if e-mail with activation data is sent successfully. - -Possible values - template name, according to DocLister templating rules. - -Default value - activate lexicon entry with the key [%activate.default_successTpl%] - -### activateSuccessTpl -Message template if activation is finished successfully. - -Possible values - template name, according to DocLister templating rules. - -Default value - activate lexicon entry with the key [+activate.default_activateSuccessTpl+] - -### passwordLength -Password length. - -Possible values - number of characters greater than 6. - -Default value - 6. diff --git a/assets/snippets/FormLister/docs/en/080_Editing_User_Profiles.md b/assets/snippets/FormLister/docs/en/080_Editing_User_Profiles.md deleted file mode 100755 index f5f3be6df3..0000000000 --- a/assets/snippets/FormLister/docs/en/080_Editing_User_Profiles.md +++ /dev/null @@ -1,98 +0,0 @@ -## Editing user profile - -Profile controller allow authorized users to change their profiles, as well as passwords. - -E-mail should be checked for uniqueness with controller's special rule: -``` -&rules=`{ - "email":{ - "required":"Enter e-mail", - "email":"Wrong e-mail", - "custom":{ - "function":"\\FormLister\\Profile::uniqueEmail", - "message":"You cannot use this e-mail" - } - } -}` -``` -The same for the "username" field: -``` -&rules=`{ - "username":{ - "required":"Enter user name", - "alphaNumeric":"Only letters and digits are allowed", - "custom":{ - "function":"\\FormLister\\Profile::uniqueUsername", - "message":"You cannot use this name" - } - } -}` -``` - -If the "password" field is empty, then the password will stay unchanged.If the password is changed then user needs to be authorized again. The new password is stored in the "user.password" field. - -## Parameters -### model -Class to manage users. - -Possible values - class name. - -Default value - \modUsers - -### modelPath -Path to the class to manage users. - -Possible values - relative file path. - -Default value - assets/lib/MODxAPI/modUsers.php - -### allowedFields -Fields allowed to process, other fields are ignored. If password is changed, then the "password" field will be added to the list. If no value is set to the "username" field then, it this field be set with the "e-mail" field value. The "username" will be allowed in this case. - -If not set, then all fields are allowed. - -Possible value - field names, comma separated. - -Default value - none. - -### forbiddenFields -Fields forbidden to process. The "password" and "username" fields are processed the same way as for the "allowedFields" parameter. - -Possible value - field names, comma separated. - -Default value - none. - -### preparePostProcess -Allows to process data after saving user data. - -Possible values - snippet names, anonymous functions, static methods of loaded classes. - -Default value - none. - -### redirectTo -Redirects user after successful profile update. - -Possible values - target page id or array. - -Default value - none. - -### exitTo -Redirects non authorized user. - -Possible values - target page id or array. - -Default value - none. - -### skipTpl -Outputs message if user is not authorized. - -Possible values - template name, according to DocLister templating rules. - -Default value - profile lexicon entry with the key [%profile.default_skipTpl%]. - -### successTpl -Success message template. - -Possible values - template name, according to DocLister templating rules. - -Default value - none. diff --git a/assets/snippets/FormLister/docs/en/085_Deleting_Users_Profiles.md b/assets/snippets/FormLister/docs/en/085_Deleting_Users_Profiles.md deleted file mode 100755 index bfe4041476..0000000000 --- a/assets/snippets/FormLister/docs/en/085_Deleting_Users_Profiles.md +++ /dev/null @@ -1,50 +0,0 @@ -## Удаление профиля пользователя - -Контроллер DeleteUser позволяет авторизованным пользователям удалять свои профили. Для подтверждения действия пользователю необходимо ввести свой пароль. - -Расширяет Form. - -В шаблонах доступны поля модели для удаляемой записи. - -## Параметры -### model -Класс для работы с пользователями. - -Возможные значения - имя класса. - -Значение по умолчанию - \modUsers - -### modelPath -Путь к файлу класса для работы с пользователями. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modUsers.php - -### redirectTo -Перенаправляет пользователя на указанную страницу после сохранения профиля. - -Возможные значения - id целевой страницы. - -Значение по умолчанию - пусто. - -### exitTo -Перенаправляет неавторизованного пользователя на указанную страницу. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### skipTpl -Шаблон сообщения для неавторизованного пользователя. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона deleteUser с ключом [+deleteUser.default_skipTpl+] - -### successTpl -Шаблон сообщения об успешном удалении профиля. Если не задан, то генерируется сообщение об успешном сохранении формы. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. diff --git a/assets/snippets/FormLister/docs/en/090_Reminding_Passwords.md b/assets/snippets/FormLister/docs/en/090_Reminding_Passwords.md deleted file mode 100755 index e9b507dd4f..0000000000 --- a/assets/snippets/FormLister/docs/en/090_Reminding_Passwords.md +++ /dev/null @@ -1,143 +0,0 @@ -## Восстановление паролей пользователями - -Контроллер Reminder позволяет web-пользователям восстанавливать забытые пароли. Расширяет контроллер Form. - -Восстановление паролей происходит по следующей схеме: - -- пользователь вводит в форме свой идентификатор (им может быть имя пользователя или email); -- пользователь получает письмо, в котором содержится ссылка для восстановления; -- при переходе по ссылке пользователь получает возможность ввести новый пароль либо пароль будет сгенерирован автоматически; -- пользователю отправляется письмо с новым паролем и показыается сообщение (в сообщении можно также вывести новый пароль). - -Параметр to перезаписывается значением email пользователя. Обязательно должен быть задан параметр resetTo. - -## Параметры -### model -Класс для работы с пользователями. - -Возможные значения - имя класса. - -Значение по умолчанию - \modUsers - -### modelPath -Путь к файлу класса для работы с пользователями. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modUsers.php - -### hashField -Имя поля для хранения хэша данных пользователя. - -Значение по умолчанию - hash. - -### userField -Имя поля для хранения идентификатора пользователя (имя пользователя или email). - -Значение по умолчанию - email. - -### uidField -Имя поля, которое используется для идентификации пользователя при переходе по ссылке. - -Значение по умолчанию - id. - -### exitTo -Перенаправляет авторизованного пользователя на указанную страницу. - -Возможные значения - id целевой страницы. - -Значение по умолчанию - пусто. - -### resetTo -Страница, на которую будет указывать ссылка для восстановления паролей. Обязательный параметр. - -Возможные значения - id целевой страницы. - -Значение по умолчанию - id документа, в котором вызван контроллер. - -### redirectTo -Перенаправляет на указанную страницу после успешного восстановления пароля. - -Возможные значения - id целевой страницы. - -Значение по умолчанию - пусто. - -### skipTpl -Шаблон сообщения для авторизованного пользователя. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Reminder с ключом [+reminder.default_skipTpl+]. - -### formTpl -Шаблон формы для ввода идентификатора пользователя. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. - -### resetTpl -Шаблон формы для ввода нового пароля. Если параметр не задан, то пароль будет сгенерирован автоматически. - -Поля для ввода паролей должны называться password и repeatPassword. В форме должны также присутствовать скрытые поля с именами из параметров uidField и hashField. Значение для поля hashField задается через плейсхолдер [+user.hash+]. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. - -### successTpl -Шаблон сообщения об успешной отправке письма со ссылкой для восстановления пароля. В шаблоне можно выводить плейсхолдеры с данными пользователя (username, email и т.д.). - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Reminder с ключом [+reminder.default_successTpl+]. - -### resetSuccessTpl -Шаблон сообщения об успешном восстановлении пароля. В шаблоне можно выводить плейсхолдеры с данными пользователя (username, email и т.д.), а также новый пароль (newpassword). - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Reminder с ключом [+reminder.default_resetSuccessTpl+]. - -### reportTpl -Шаблон письма со ссылкой для восстановления пароля. В шаблоне можно выводить плейсхолдеры с данными пользователя (username, email и т.д.), а также новый пароль (newpassword). Ссылка для восстановлени пароля в письме задается через плейсхолдер [+reset.url+] - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Reminder с ключом [+reminder.default_reportTpl+].. - -### resetReportTpl -Шаблон письма об успешном восстановлении пароля. В шаблоне можно выводить плейсхолдеры с данными пользователя (username, email и т.д.), а также новый пароль (newpassword). Если не задан, то письмо пользователю отправляться не будет. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. - -### rules -Правила валидации для формы идентификации пользователя. - -Возможные значения - см. раздел "Валидация данных". - -Значение по умолчанию - пусто. - -### resetRules -Правила валидации для формы установки нового пароля. Если заданы правила валидации для полей password и repeatPassword, то при наличии для поля repeatPassword правила equals, оно будет автоматически скорректировано для проверки равенства значений полей password и repeatPassword: -``` -"repeatPassword":{ - "required":"Введите пароль еще раз", - "equals":{ - "params" : "Этот ключ в описании правила можно не задавать, он будет сформирован контроллером автоматически", - "message":"Пароли не совпадают" - } -} -``` -Возможные значения - см. раздел "Валидация данных". - -Значение по умолчанию - пусто. - -### passwordLength -Длина пароля (если создается автоматически). - -Возможные значения - число символов больше 6. - -Значение по умолчанию - 6. diff --git a/assets/snippets/FormLister/docs/en/100_Creating_And_Editing_User_Documents.md b/assets/snippets/FormLister/docs/en/100_Creating_And_Editing_User_Documents.md deleted file mode 100755 index d383e93f47..0000000000 --- a/assets/snippets/FormLister/docs/en/100_Creating_And_Editing_User_Documents.md +++ /dev/null @@ -1,166 +0,0 @@ -## Создание и редактирование документов пользователями - -Контроллер Content позволяет web-пользователям создавать и редактировать записи в таблицах MODxAPI. Расширяет контроллер Form, что позволяет отправлять письма после создания записи. При редактировании записей отправка почты отключена, при необходимости ее можно реализовать с помощью плагинов на событие сохранения (OnDocFormSave и т.п.). - -Данные формы передаются в объект MODxAPI как есть, соответственно разработчику нужно заботиться об их корректности самостоятельно. - -При редактировании записей можно запретить изменение отдельных полей, используя параметр keepDefaults. - -При создании новой записи вызывается событие OnMakeDocUrl, в которое передается id записи и массив data со значениями полей записи. Это позволяет вернуть ссылку на созданную запись, она будет доступна через плейсхолдер [+content.url+]. Ссылку можно использовать в письме c уведомлением о создании новой записи. - -Также можно использовать данные авторизованного пользователя, доступны через плейсхолдеры [+user.fullname+], [+user.email+] и т.д. - -## Параметры -### model -Класс MODxAPI. - -Возможные значения - имя класса MODxAPI. - -Значение по умолчанию - \modResource. - -### modelPath -Путь к файлу класса, если класс не загружается заранее. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modResource.php. - -### userModel -Класс для работы с пользователями. - -Возможные значения - имя класса. - -Значение по умолчанию - \modUsers - -### userModelPath -Путь к файлу класса для работы с пользователями. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modUsers.php - -### onlyUsers -Разрешить добавление записей только для зарегистрированных пользователей. - -Возможные значения - 0, 1. - -Значение по умолчанию - 1. - -### userGroups -Группы пользователей, которым разрешено добавлять или изменять записи. - -Возможные значения - список групп через точку с запятой. - -Значение по умолчанию - пусто (разрешены любые группы). - -### onlyOwners -Разрешает редактирование записей только их авторами. Автор определяется по полю, указанному в параметре ownerField. - -Возможные значения - 0, 1. - -Значение по умолчанию - 1. - -### ownerField -Имя поля, определяющего владельца записи. Если работать с документами modResource, то это будет имя tv-параметра (в Evo не предусмотрено создание записей веб-пользователями). - -Возможные значения - имя поля. - -Значение по умолчанию - aid. - -### idField -Имя ключа массива $_REQUEST, по которому определяется id редактируемой записи. Если ключ не задан, то контроллер вызывается в режиме создания записей. Информацию о режиме контроллера можно получить с помощью метода getMode. - -В форме редактирования нужно предусмотреть скрытое поле с именем параметра, в котором будет сохраняться id записи. - -Значение по умолчанию - id. - -### contentFields -Задает сопоставление полей MODxAPI и полей формы. Можно не задавать, если имена полей совпадают. Если параметр не задан, то ограничить список передаваемых в модель полей можно с помощью параметров allowedFields и forbiddenFields. - -Возможные значения - массив вида: -``` -&contentFields=`{ - "поле MODxAPI":"поле формы", - "поле MODxAPI":"поле формы" -} -` -``` -Значение по умолчанию - пусто. - -### clearCache -Очищать кэш после сохранения записи. - -Возможные значения - 0, 1. - -Значение по умолчанию - 0. - -### redirectTo -Перенаправляет пользователя на указанную страницу после сохранения новой записи. В режиме редактирования не используется. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### editAfterCreate -Переправляет пользователя на страницу для редактирования созданной записи. Страница указывается в параметре redirectTo. - -Возможные значения - 1 или 0. - -Значение по умолчанию - 0. - -### editTpl -Шаблон формы для редактирования документа. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - значение параметра formTpl. - -### badOwnerTpl -Шаблон сообщения о том, что пользователь не является автором документа. Только режим редактирования. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Content с ключом [+edit.default_badOwnerTpl+]. - -### badGroupTpl, badGroupEditTpl -Шаблон сообщения о том, что пользователь не входит в группу пользователей которым разрешено создавать и редактировать документы. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Content с ключом -[+create.default_badGroupTpl+] или [+edit.default_badGroupTpl+]. - -### badRecordTpl -Шаблон сообщения о том, что пользователь не может редактировать запись: например, запись не существует. Только режим редактирования. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Content с ключом [+edit.default_badRecordTpl+]. - -### exitTo -Перенаправляет неавторизованного пользователя на указанную страницу. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### skipTpl, skipEditTpl -Шаблон сообщения для неавторизованного пользователя. Для режима редактирования - skipEditTpl. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Content с ключом [+create.default_skipTpl+] (edit.default_skipEditTpl). - -### successTpl -Шаблон сообщения об успешном сохранении новой записи. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Content с ключом [+create.default_successTpl+] - -### editSuccessTpl -Шаблон сообщения об успешном обновлении записи. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. diff --git a/assets/snippets/FormLister/docs/en/105_Deleting_User_Documents.md b/assets/snippets/FormLister/docs/en/105_Deleting_User_Documents.md deleted file mode 100755 index a83245f789..0000000000 --- a/assets/snippets/FormLister/docs/en/105_Deleting_User_Documents.md +++ /dev/null @@ -1,97 +0,0 @@ -## Deleting user documents - -DeleteContent controller allows authorized users to delete documents they created. - -It extends Form controller. - -Model fields are available in templates with the "user" prefix (user.fullname, user.email etc.). - -## Parameters -### model -MODxAPI class to manage documents or other type of records. - -Possible values - MODxAPI class name. - -Default value - \modResource. - -### modelPath -Path to the MODxAPI class. - -Possible values - relative file path. - -Default value - assets/lib/MODxAPI/modResource.php. - -### userModel -Class to manage users. - -Possible values - class name. - -Default value - \modUsers - -### userModelPath -Path to the class to manage users. - -Possible values - relative file path. - -Default value - assets/lib/MODxAPI/modUsers.php - -### ownerField -Field name to get the record owner. For the modResource class it can be the name of a tv-parameter (because web users can not create documents in Evo). - -Possible values - field name. - -Default value - aid. - -### idField -$_REQUEST array key to get the id of the record to be deleted. - -Default value - id. - -### redirectTo -Redirects user after successful operation. - -Possible values - target page id or array. - -Default value - none. - -### badOwnerTpl -Outputs message if user is not the record owner. - -Possible values - template name, according to DocLister templating rules. - -Default value - deleteContent lexicon entry with the key [%deleteContent.default_badOwnerTpl%]. - -### badRecordTpl -Outputs message if user can not delete record (it doesn't exists, for example). - -Possible values - template name, according to DocLister templating rules. - -Default value - deleteContent lexicon entry with the key [%deleteContent.default_badRecordTpl%]. - -### skipTpl -Outputs message if user is not authorized. - -Possible values - template name, according to DocLister templating rules. - -Default value - deleteContent lexicon entry with the key [%deleteContent.default_skipTpl%]. - -### successTpl -Success message template. - -Possible values - template name, according to DocLister templating rules. - -Default value - deleteContent lexicon entry with the key [%deleteContent.default_successTpl%] - -### exitTo -Redirects non authorized user. - -Possible values - target page id or array. - -Default value - none. - -### badRecordTo -Redirects if record can not be deleted. - -Possible values - target page id or array. - -Default value - none. diff --git a/assets/snippets/FormLister/docs/en/110_Lexicons.md b/assets/snippets/FormLister/docs/en/110_Lexicons.md deleted file mode 100644 index 254a30e29d..0000000000 --- a/assets/snippets/FormLister/docs/en/110_Lexicons.md +++ /dev/null @@ -1,32 +0,0 @@ -## Lexicons - -To use lexicons you should create a file named "lexicon name.inc.php" in a folder named as full language name (russian-UTF8, english etc.): -``` - -``` -Parameters to load lexicons are: - -* langDir - lexicon folder path; -* lang - lexicon language (the "manager_language" configuration parameter value by default); -* lexicon - lexicon names, comma separated. Or specify an array of values right here: -``` -&lexicon=`{ - "english":{ - "test":"Test lexicon value", - "foo":"Another lexicon value", - "bar":"And one more value" - }, - "russian-UTF8":{ - "test":"Проверка", - "foo":"Еще проверка", - "bar":"И еще" - } -}` -``` - -After that you can use the [%key%] placeholders to output lexicon entries. EvoBabel lexicons are supported as well. diff --git "a/assets/snippets/FormLister/docs/examples/ru/001_\320\237\321\200\320\276\321\201\321\202\320\260\321\217_\321\204\320\276\321\200\320\274\320\260.md" "b/assets/snippets/FormLister/docs/examples/ru/001_\320\237\321\200\320\276\321\201\321\202\320\260\321\217_\321\204\320\276\321\200\320\274\320\260.md" deleted file mode 100755 index 55bbb1ca87..0000000000 --- "a/assets/snippets/FormLister/docs/examples/ru/001_\320\237\321\200\320\276\321\201\321\202\320\260\321\217_\321\204\320\276\321\200\320\274\320\260.md" +++ /dev/null @@ -1,91 +0,0 @@ -## Простая форма -``` -[!FormLister? -&formid=`basic` -&rules=` -{ - "name":{ - "required":"Обязательно введите имя", - "matches":{ - "params":"\/^[\\pL\\s\\-']++$\/uD", - "message":"Введите имя правильно" - } - }, - "email":{ - "required":"Обязательно введите email", - "email":"Введите email правильно" - }, - "phone":{ - "required":"Обязательно введите номер телефона", - "phone":"Введите номер правильно" - }, - "message":{ - "required":"Обязательно введите сообщение", - "minLength":{ - "params":10, - "message":"Сообщение должно быть не менее 10 символов" - } - } -}` -&formTpl=`@CODE: -
        -
        -
        -
        - -
        - -
        - - [+name.error+] -
        -
        -
        - -
        - - [+email.error+] -
        -
        -
        - -
        - - [+phone.error+] -
        -
        - -
        - -
        - - [+message.error+] -
        -
        - [+form.messages+] -
        -
        - -
        -
        -
        -
        -
        -
        ` -&to=`test@test.com` -&ccSender=`1` -&ccSenderField=`email` -&ccSenderTpl=`@CODE:Спасибо за обращение, [+name.value+]` -&reportTpl=`@CODE: -

        Имя: [+name.value+]

        -

        Телефон: [+phone.value+]

        -

        Email: [+email.value+]

        -

        Сообщение: [+message:strip_tags:nl2br+]

        -` -&errorClass=` has-error` -&requiredClass=` has-warning` -&subject=`Новое сообщение` -&messagesOuterTpl=`@CODE:` -&errorTpl=`@CODE:[+message+]` -!] -``` diff --git "a/assets/snippets/FormLister/docs/examples/ru/002_\320\255\320\273\320\265\320\274\320\265\320\275\321\202\321\213_\321\203\320\277\321\200\320\260\320\262\320\273\320\265\320\275\320\270\321\217.md" "b/assets/snippets/FormLister/docs/examples/ru/002_\320\255\320\273\320\265\320\274\320\265\320\275\321\202\321\213_\321\203\320\277\321\200\320\260\320\262\320\273\320\265\320\275\320\270\321\217.md" deleted file mode 100755 index f3df8d9e89..0000000000 --- "a/assets/snippets/FormLister/docs/examples/ru/002_\320\255\320\273\320\265\320\274\320\265\320\275\321\202\321\213_\321\203\320\277\321\200\320\260\320\262\320\273\320\265\320\275\320\270\321\217.md" +++ /dev/null @@ -1,140 +0,0 @@ -## Форма с элементами управления -``` -[!FormLister? -&formid=`advanced` -&rules=`{ -"name":{ - "required":"Обязательно введите имя" -}, -"email":{ - "required":"Обязательно введите email" -}, -"phone":{ - "required":"Обязательно введите номер телефона", - "phone":"Введите номер правильно" -}, -"message":{ - "required":"Обращение не может быть пустым", - "minLength":{ - "params":100, - "message":"Должно быть не менее 100 символов" - } -}, -"agree":{ - "required":"Вы не можете отправить обращение, если не согласны с правилами" -}, -"products":{ - "minCount":{ - "params": 2, - "message": "Выберите минимум 2 продукта" - } -} -}` -&defaults=`{ -"topic":"Жалоба" -}` -&formControls=`topic,agree,department,products` -&formTpl=`@CODE: -
        -
        -
        -
        - -
        - - - [+name.error+] -
        -
        -
        -
        - - - [+email.error+] -
        -
        -
        -
        - - - [+phone.error+] -
        -
        -
        -
        - - -
        -
        - -
        -
        - - -
        -
        - -
        - -
        -
        - -
        -
        - -
        - [+products.error+] -
        -
        - - - [+message.error+] -
        -
        - - [+agree.error+] -
        - [+form.messages+] -
        - -
        -
        -
        -
        -
        ` -&to=`test@test.com` -&subjectTpl=`@CODE: [+topic.value+] в [+department.value+]` -&reportTpl=`@CODE: -

        Имя: [+name.value+]

        -

        Телефон: [+phone.value+]

        -

        Email: [+email.value+]

        -

        Продукты: [+products.value+]

        -

        Сообщение: [+message:strip_tags:nl2br+]

        -` -&errorClass=` has-error` -&requiredClass=` has-warning` -&subject=`Новое сообщение` -&messagesOuterTpl=`@CODE:` -&errorTpl=`@CODE:[+message+]` -!] -``` diff --git "a/assets/snippets/FormLister/docs/examples/ru/003_\320\236\321\202\320\277\321\200\320\260\320\262\320\272\320\260_\321\204\320\260\320\271\320\273\320\276\320\262.md" "b/assets/snippets/FormLister/docs/examples/ru/003_\320\236\321\202\320\277\321\200\320\260\320\262\320\272\320\260_\321\204\320\260\320\271\320\273\320\276\320\262.md" deleted file mode 100755 index 006527c2f8..0000000000 --- "a/assets/snippets/FormLister/docs/examples/ru/003_\320\236\321\202\320\277\321\200\320\260\320\262\320\272\320\260_\321\204\320\260\320\271\320\273\320\276\320\262.md" +++ /dev/null @@ -1,118 +0,0 @@ -## Отправка файлов -``` -[!FormLister? -&formid=`basic` -&rules=`{ -"name":{ - "required":"Обязательно введите имя" -}, -"email":{ - "required":"Обязательно введите email", - "email":"Введите email правильно" -}, -"message":{ - "required":"Обязательно введите сообщение" -} -}` -&attachments=`first,second` -&attachFiles=`{"userfile":{"filepath":"assets/images/logo.png","filename":"logo.png"}}` -&fileRules=`{ -"first":{ - "required":"Приложите документ", - "allowed":{ - "params": [ ["doc","docx","pdf"] ], - "message": "Разрешены только документы Word и Pdf" - }, - "maxSize" : { - "params": 100, - "message": "Размер файла не должен превышать 100 кб" - } -}, -"second":{ - "required":"Приложите 2 картинки", - "maxSize" : { - "params": 1024, - "message": "Размер файла не должен превышать 1 мб" - }, - "allowed": { - "params": [ ["jpg","jpeg","png","gif"] ], - "message" : "Разрешены только картинки" - }, - "maxCount":{ - "params" : 4, - "message" : "Не больше 4 картинок" - }, - "minCount":{ - "params" : 2, - "message" : "Не меньше 2 картинок" - } -} -}` -&formTpl=`@CODE: -
        -
        -
        -
        - -
        - -
        - - [+name.error+] -
        -
        -
        - -
        - - [+email.error+] -
        -
        -
        - -
        - - [+message.error+] -
        -
        -
        - -
        - - [+first.error+] -
        -
        -
        - -
        - - [+second.error+] -
        -
        - [+form.messages+] -
        -
        - -
        -
        -
        -
        -
        -
        ` -&to=`test@test.com` -&reportTpl=`@CODE: -

        Имя: [+name.value+]

        -

        Email: [+email.value+]

        -

        Сообщение: [+message:strip_tags:nl2br+]

        -

        Документы:[+first.value+]

        -

        Картинки:[+second.value+]

        -

        Доп.:[+userfile.value+] -

        Вложения: [+attachments.value+]

        -` -&errorClass=` has-error` -&requiredClass=` has-warning` -&subject=`Новое сообщение` -&messagesOuterTpl=`@CODE:` -&errorTpl=`@CODE:[+message+]` -!] -``` diff --git "a/assets/snippets/FormLister/docs/examples/ru/004_\320\244\320\276\321\200\320\274\320\260_\321\201_\320\272\320\260\320\277\321\207\320\265\320\271.md" "b/assets/snippets/FormLister/docs/examples/ru/004_\320\244\320\276\321\200\320\274\320\260_\321\201_\320\272\320\260\320\277\321\207\320\265\320\271.md" deleted file mode 100755 index ccebc32acb..0000000000 --- "a/assets/snippets/FormLister/docs/examples/ru/004_\320\244\320\276\321\200\320\274\320\260_\321\201_\320\272\320\260\320\277\321\207\320\265\320\271.md" +++ /dev/null @@ -1,85 +0,0 @@ -## Форма с капчей -``` -[!FormLister? -&formid=`basic` -&rules=`{ -"name":{ - "required":"Обязательно введите имя" -}, -"email":{ - "required":"Обязательно введите email", - "email":"Введите email правильно" -}, -"phone":{ - "required":"Обязательно введите номер телефона", - "phone":"Введите номер правильно" -}, -"message":{ - "required":"Обязательно введите сообщение", - "minLength":{ - "params":100, - "message":"Сообщение должно быть не менее 100 символов" - } -} -}` -&captcha=`modxCaptcha` -&formTpl=`@CODE: -
        -
        -
        -
        - -
        - -
        - - [+name.error+] -
        -
        -
        - -
        - - [+email.error+] -
        -
        -
        - -
        - - [+phone.error+] -
        -
        - -
        - -
        - - [+message.error+] -
        -
        - [+form.messages+] -
        - -
        -
        Введите число
        - - [+vericode.error+] -
        -
        -
        -
        - -
        -
        -
        -
        -
        -
        ` -&errorClass=` has-error` -&requiredClass=` has-warning` -&subject=`Новое сообщение` -&messagesOuterTpl=`@CODE:` -&errorTpl=`@CODE:[+message+]` -!] -``` diff --git "a/assets/snippets/FormLister/docs/examples/ru/005_\320\222\321\213\320\262\320\276\320\264_\321\201\320\276\320\276\320\261\321\211\320\265\320\275\320\270\320\271.md" "b/assets/snippets/FormLister/docs/examples/ru/005_\320\222\321\213\320\262\320\276\320\264_\321\201\320\276\320\276\320\261\321\211\320\265\320\275\320\270\320\271.md" deleted file mode 100755 index 82c029975c..0000000000 --- "a/assets/snippets/FormLister/docs/examples/ru/005_\320\222\321\213\320\262\320\276\320\264_\321\201\320\276\320\276\320\261\321\211\320\265\320\275\320\270\320\271.md" +++ /dev/null @@ -1,74 +0,0 @@ -## Вывод сообщений -``` -[!FormLister? -&formid=`basic` -&rules=`{ -"name":{ - "required":"Обязательно введите имя" -}, -"email":{ - "required":"Обязательно введите email", - "email":"Введите email правильно" -}, -"phone":{ - "required":"Обязательно введите номер телефона", - "phone":"Введите номер телефона правильно" -}, -"message":{ - "required":"Обязательно введите сообщение", - "minLength":{ - "params":100, - "message":"Сообщение должно быть не менее 100 символов" - } -} -}` -&formTpl=`@CODE: -
        -
        -
        -
        - -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        - -
        - -
        - -
        -
        - [+form.messages+] -
        -
        - -
        -
        -
        -
        -
        -
        ` -&messagesTpl=`@CODE:
        [+required+][+errors+][+messages+]
        ` -&messagesRequiredOuterTpl=`@CODE:
        Вы не заполнили обязательные поля
        [+messages+]
        ` -&messagesErrorOuterTpl=`@CODE:
        Некоторые поля заполнены неверно
        [+messages+]
        ` -&messagesOuterTpl=`@CODE:
        [+messages+]
        ` -&errorClass=` has-error` -&requiredClass=` has-warning` -&errorTpl=`@CODE:[+message+]` -!] -``` diff --git "a/assets/snippets/FormLister/docs/examples/ru/006_\320\224\320\262\320\260_\320\275\320\260\320\261\320\276\321\200\320\260_\320\277\320\276\320\273\320\265\320\271.md" "b/assets/snippets/FormLister/docs/examples/ru/006_\320\224\320\262\320\260_\320\275\320\260\320\261\320\276\321\200\320\260_\320\277\320\276\320\273\320\265\320\271.md" deleted file mode 100755 index 73a7ab6387..0000000000 --- "a/assets/snippets/FormLister/docs/examples/ru/006_\320\224\320\262\320\260_\320\275\320\260\320\261\320\276\321\200\320\260_\320\277\320\276\320\273\320\265\320\271.md" +++ /dev/null @@ -1,148 +0,0 @@ -## Два набора полей -В зависимости от значения поля type используются разные правила валидации и шаблоны письма. - -### Вызов FormLister -``` -[!FormLister? -&formid=`basic` -&rules=`{ -"name":{ - "required":"Обязательно введите имя" -}, -"email":{ - "required":"Обязательно введите email", - "email":"Введите email правильно" -}, -"phone":{ - "required":"Обязательно введите номер телефона", - "phone":"Введите номер правильно" -} -}` -&entRules=`{ -"entname":{ - "required":"Обязательно введите имя" -}, -"entemail":{ - "required":"Обязательно введите email", - "email":"Введите email правильно" -}, -"entphone":{ - "required":"Обязательно введите номер телефона", - "phone":"Введите номер правильно" -}, -"entaddress":{ - "required":"Обязательно введите адрес" -} -}` -&formControls=`type` -&defaults=`{"type":"Физическое лицо"}` -&formTpl=`@CODE: -
        -
        -
        -
        - -
        - - -
        -

        Заполняется только физлицами

        -
        - - - - [+name.error+] - -
        -
        -
        -
        - - - - [+email.error+] - -
        -
        -
        -
        - - - - [+phone.error+] - -
        -
        -
        -

        Заполняется только юрлицами

        -
        - - - [+entname.error+] - -
        -
        -
        -
        - - - [+entemail.error+] -
        -
        -
        -
        - - - [+entphone.error+] -
        -
        -
        -
        - - - [+entaddress.error+] - -
        - [+form.messages+] -
        - -
        -
        -
        -
        -
        ` -&to=`test@test.com` -&subjectTpl=`@CODE:[+type.value+]` -&reportTpl=`@CODE: -

        Имя: [+name.value+]

        -

        Телефон: [+phone.value+]

        -

        Email: [+email.value+]

        -` -&reportEntTpl=`@CODE: -

        Название предприятия: [+entname.value+]

        -

        Телефон: [+entphone.value+]

        -

        Email: [+entemail.value+]

        -

        Юридический адрес: [+entaddress.value+]

        -` -&prepare=`typeSelector` -&errorClass=` has-error` -&requiredClass=` has-warning` -&messagesOuterTpl=`@CODE:` -&errorTpl=`@CODE:[+message+]` -!] -``` -### Prepare-сниппет typeSelector -``` -if ($FormLister->getField('type') == 'Юридическое лицо') { - $FormLister->config->setConfig(array( - 'rules'=>$FormLister->getCFGDef('entRules'), - 'reportTpl'=>$FormLister->getCFGDef('reportEntTpl') - )); -} else { - $FormLister->setField('type','Физическое лицо'); -} -``` diff --git "a/assets/snippets/FormLister/docs/examples/ru/007_\320\220\320\262\321\202\320\276\321\200\320\270\320\267\320\260\321\206\320\270\321\217.md" "b/assets/snippets/FormLister/docs/examples/ru/007_\320\220\320\262\321\202\320\276\321\200\320\270\320\267\320\260\321\206\320\270\321\217.md" deleted file mode 100755 index 00010188b8..0000000000 --- "a/assets/snippets/FormLister/docs/examples/ru/007_\320\220\320\262\321\202\320\276\321\200\320\270\320\267\320\260\321\206\320\270\321\217.md" +++ /dev/null @@ -1,48 +0,0 @@ -## Авторизация -``` -[!FormLister? -&formid=`login` -&controller=`Login` -&loginField=`email` -&rules=`{ -"email":{ - "required":"Обязательно введите email", - "email":"Введите email правильно" -}, -"password":{ - "required":"Обязательно введите пароль" -} -}` -&formTpl=`@CODE: -
        -
        -
        -
        - -
        - - - [+email.error+] -
        -
        - - - [+password.error+] -
        - [+form.messages+] -
        - -
        - -
        -
        -
        -
        ` -&messagesOuterTpl=`@CODE:` -&skipTpl=`@CODE:
        Вы уже авторизованы.
        ` -&successTpl=`@CODE:
        Привет, [+fullname+]!
        ` -&errorTpl=`@CODE:[+message+]` -&errorClass=` has-error` -&requiredClass=` has-warning` -!] -``` diff --git "a/assets/snippets/FormLister/docs/examples/ru/008_\320\240\320\265\320\263\320\270\321\201\321\202\321\200\320\260\321\206\320\270\321\217.md" "b/assets/snippets/FormLister/docs/examples/ru/008_\320\240\320\265\320\263\320\270\321\201\321\202\321\200\320\260\321\206\320\270\321\217.md" deleted file mode 100755 index 4561108910..0000000000 --- "a/assets/snippets/FormLister/docs/examples/ru/008_\320\240\320\265\320\263\320\270\321\201\321\202\321\200\320\260\321\206\320\270\321\217.md" +++ /dev/null @@ -1,98 +0,0 @@ -## Регистрация пользователей - -При регистрации пользователь добавляется в группу opt. Отправляется два письма - менеджеру и пользователю. Пользователь должен подтвердить регистрацию, перейдя по ссылке из письма (см. Активация учетных записей). - -``` -[!FormLister? -&formid=`register` -&controller=`Register` -&userGroups=`opt` -&checkActivation=`1` -&activateTo=`1514` -&rules=`{ -"fullname":{ - "required":"Обязательно введите имя" -}, -"email":{ - "required":"Обязательно введите email", - "email":"Введите email правильно" -}, -"password":{ - "required":"Обязательно введите пароль", - "minLength":{ - "params":6, - "message":"В пароле должно быть больше 6 символов" - } -}, -"repeatPassword":{ - "required":"Повторите пароль", - "equals":{ - "message":"Пароли не совпадают" - } -}, -"agree":{ - "required":"Для регистрации вы должны принять правила" -} -}` -&allowedFields=`fullname` -&formControls=`agree` -&formTpl=`@CODE: -
        -
        -
        -
        - -
        - - - [+fullname.error+] -
        -
        - - - [+email.error+] -
        -
        -
        -
        - - - [+password.error+] -
        -
        -
        -
        - - - [+repeatPassword.error+] -
        -
        -
        -
        - - [+agree.error+] -
        - [+form.messages+] -
        - -
        -
        -
        -
        -
        ` -&to=`info@sitename.ru` -&reportTpl=`@CODE:Новый пользователь [+fullname.value+] ([+id.value+])` -&ccSender=`1` -&ccSenderField=`email` -&ccSenderTpl=`@CODE:Привет [+fullname.value+]. Для активации учетной записи нужно перейти по ссылке [+activate.url+]` -&subject=`Регистрация на сайте [(site_name)]` -&messagesOuterTpl=`@CODE:` -&successTpl=`@CODE:
        Поздравляем с успешной регистрацией, [+fullname.value+]! После активации вы можете авторизоваться на сайте. Если вы не получили письмо для активации учетной записи, запросите его еще раз.
        ` -&errorTpl=`@CODE:[+message+]` -&errorClass=` has-error` -&requiredClass=` has-warning` -!] -``` diff --git "a/assets/snippets/FormLister/docs/examples/ru/009_\320\220\320\272\321\202\320\270\320\262\320\260\321\206\320\270\321\217_\321\203\321\207\320\265\321\202\320\275\320\276\320\271_\320\267\320\260\320\277\320\270\321\201\320\270.md" "b/assets/snippets/FormLister/docs/examples/ru/009_\320\220\320\272\321\202\320\270\320\262\320\260\321\206\320\270\321\217_\321\203\321\207\320\265\321\202\320\275\320\276\320\271_\320\267\320\260\320\277\320\270\321\201\320\270.md" deleted file mode 100644 index 4b5d85558c..0000000000 --- "a/assets/snippets/FormLister/docs/examples/ru/009_\320\220\320\272\321\202\320\270\320\262\320\260\321\206\320\270\321\217_\321\203\321\207\320\265\321\202\320\275\320\276\320\271_\320\267\320\260\320\277\320\270\321\201\320\270.md" +++ /dev/null @@ -1,42 +0,0 @@ -## Активация учетной записи -``` -[!FormLister? -&controller=`Activate` -&formid=`activate` -&protectSubmit=`0` -&rules=`{ -"email":{ - "required":"Обязательно введите email", - "email":"Введите email правильно" -} -}` -&formTpl=`@CODE: -
        -
        -
        -
        - -
        - - - [+email.error+] -
        - [+form.messages+] -
        - -
        -
        -
        -
        -
        ` -&messagesOuterTpl=`@CODE:` -&successTpl=`@CODE:
        На указанный вами при регистрации email отправлено письмо с дальнейшими инструкциями!
        ` -&subject=`Активация учетной записи` -&reportTpl=`@CODE:

        Для активации учетной записи перейдите по ссылке [+activate.url+]

        ` -&activateReportTpl=`@CODE:

        Здравствуйте, [+fullname.value+]!

        Ваша учетная запись успешно активирована.

        ` -&activateSuccessTpl=`@CODE:
        Ваша учетная запись успешно активирована!
        ` -&errorTpl=`@CODE:[+message+]` -&errorClass=` has-error` -&requiredClass=` has-warning` -!] -``` diff --git "a/assets/snippets/FormLister/docs/examples/ru/010_\320\222\320\276\321\201\321\201\321\202\320\260\320\275\320\276\320\262\320\273\320\265\320\275\320\270\320\265_\320\277\320\260\321\200\320\276\320\273\320\265\320\271.md" "b/assets/snippets/FormLister/docs/examples/ru/010_\320\222\320\276\321\201\321\201\321\202\320\260\320\275\320\276\320\262\320\273\320\265\320\275\320\270\320\265_\320\277\320\260\321\200\320\276\320\273\320\265\320\271.md" deleted file mode 100644 index 27d4a54f14..0000000000 --- "a/assets/snippets/FormLister/docs/examples/ru/010_\320\222\320\276\321\201\321\201\321\202\320\260\320\275\320\276\320\262\320\273\320\265\320\275\320\270\320\265_\320\277\320\260\321\200\320\276\320\273\320\265\320\271.md" +++ /dev/null @@ -1,131 +0,0 @@ -## Восстановление паролей -### Вариант 1 -Пароль генерируется автоматически и отправляется в письме. -``` -[!FormLister? -&controller=`Reminder` -&formid=`remind` -&rules=`{ -"email":{ - "required":"Обязательно введите email", - "email":"Введите email правильно" -} -}` -&formTpl=`@CODE: -
        -
        -
        -
        - -
        - - - [+email.error+] -
        - [+form.messages+] -
        - -
        -
        -
        -
        -
        ` -&messagesOuterTpl=`@CODE:` -&successTpl=`@CODE:
        На указанный вами при регистрации email отправлено письмо с дальнейшими инструкциями!
        ` -&subject=`Восстановление пароля` -&resetTo=`38` -&reportTpl=`@CODE:

        Для восстановления пароля перейдите по ссылке [+reset.url+]

        ` -&resetReportTpl=`@CODE:

        Здравствуйте, [+fullname.value+]!

        Ваш новый пароль: [+newpassword+]

        ` -&resetSuccessTpl=`@CODE:
        На указанный вами при регистрации email отправлено письмо с новым паролем!
        ` -&errorTpl=`@CODE:[+message+]` -&errorClass=` has-error` -&requiredClass=` has-warning` -!] -``` - -### Вариант 2 -Пользователь вводит новый пароль. -``` -[!FormLister? -&controller=`Reminder` -&formid=`remind` -&rules=`{ -"email":{ - "required":"Обязательно введите email", - "email":"Введите email правильно" -} -}` -&resetRules=`{ -"password":{ - "required":"Обязательно введите пароль", - "minLength":{ - "params":6, - "message":"В пароле должно быть больше 6 символов" - } -}, -"repeatPassword":{ - "required":"Повторите пароль", - "equals":{ - "message":"Пароли не совпадают" - } -} -}` -&formTpl=`@CODE: -
        -
        -
        -
        - -
        - - - [+email.error+] -
        - [+form.messages+] -
        - -
        -
        -
        -
        -
        ` -&resetTpl=`@CODE: -
        -
        -
        -
        - - - -
        - - - [+password.error+] -
        -
        - - - [+repeatPassword.error+] -
        - [+form.messages+] -
        - -
        -
        -
        -
        -
        -` -&uidName=`uid` -&messagesOuterTpl=`@CODE:` -&successTpl=`@CODE:
        На указанный вами при регистрации email отправлено письмо с дальнейшими инструкциями!
        ` -&subject=`Восстановление пароля` -&reportTpl=`@CODE:

        Для восстановления пароля перейдите по ссылке [+reset.url+]

        ` -&resetReportTpl=`@CODE:

        Здравствуйте, [+fullname.value+]!

        Ваш новый пароль: [+newpassword+]

        ` -&resetSuccessTpl=`@CODE:Готово!` -&resetTo=`12` -&errorTpl=`@CODE:[+message+]` -&errorClass=` has-error` -&requiredClass=` has-warning` -!] -``` diff --git a/assets/snippets/FormLister/docs/history.md b/assets/snippets/FormLister/docs/history.md deleted file mode 100644 index 1981c3009f..0000000000 --- a/assets/snippets/FormLister/docs/history.md +++ /dev/null @@ -1,199 +0,0 @@ -## History -### 1.7.19 -* [Refactor] Имя пользователя и E-mail не приводятся в нижний регистр (Login, Register, Profile). -* [Refactor] Не выводятся пустые обертки для сообщений формы (Core). -* [Enhancement] Вывод логов моделей MODxAPI при отладке (Content, Register, Profile). -* [Enhancement] Spanish, Italian lexicons. -* [Fix] Опечатка в методе renderMessages() (Core). -* [Fix] Неправильно задавался параметр size для ReCaptcha. - -### 1.7.18 -* [Enhancement] Dutch, Polish, English-Britain, German lexicons. -* [Refactor] Экранирование значений массива до преобразования массива в строку в методе fieldsToPlaceholders - -### 1.7.17 -* [Refactor] Мультибайтовые функции. - -### 1.7.16 -* [Fix] Ошибка с полями username и email при их отсутствии (Profile). -* [Enhancement] В метод getField можно передать значение по умолчанию (Core). -* [Refactor] Оптимизация обработки чанков (Core). - -### 1.7.15 -* [Enhancement] Отдельные настройки почты для писем ccSender и automessage в параметрах ccMailConfig и autoMailConfig (Form). -* [Refactor] Проверка типа входящих данных (Validator). -* [Refactor] Изменен метод renderForm (Core). -* [Enhancement] Параметр apiFormat для формата вывода данных (json или просто массив) (Core). -* [Fix] В валидаторе файлов неправильно обрабатывалась ситуация, когда файлы отправляются одним массивом из нескольких полей (Form). -* [Enhancement] Разлогинивание удаленных и заблокированных пользователей (userHelper). - -### 1.7.14 -* [Refactor] Упрощение параметра parseMailerParams. - -### 1.7.13 -* [Enhancement] Параметр parseMailerParams для обработки плейсхолдеров в параметрах отправки почты, по умолчанию отключен (Form). -* [Fix] Некорректная загрузка пользовательских лексиконов из файлов (Core, Lexicon). -* [Fix] Параметр debug со значением 0 не отключал отладку (Core). - -### 1.7.12 -* [Enhancement] Возможность указывать имя параметра с id пользователя в ссылках (Reminder, Activate). -* [Refactor] Имя пользователя и E-mail принудительно приводятся в нижний регистр (Login, Register, Profile). -* [Fix] Неверное значение по умолчанию параметра resetTo (Reminder). -* [Fix] Неверное значение по умолчанию параметра activateTo (Activate). -* [Fix] Ошибка при расчете хэша для активации учетной записи (Register, Activate). - -### 1.7.11 -* [Fix] Предупреждения в PHP 7 (Core). -* [Enhancement] Вывод сообщений в лог при проблемах с параметрами rules, fileRules и contentFields (Core, Content). -* [Refactor] Обработка языковых плейсхолдеров в сообщениях (Core). -* [Enhancement] Из prepare-сниппетов можно возвращать массив значений полей, который будет передан в метод setFields (Core). - -### 1.7.10 -* [Enhancement] Возможность использовать плейсхолдеры с данными пользователя в шаблоне skipTpl (Login, Activate, Register, Reminder). -* [Fix] Неверное определение страницы для редиректа (Login). - -### 1.7.9 -* [Fix] Исправления ошибок. - -### 1.7.8 -* [Refactor] Переименованы файлы документации. -* [Refactor] Параметр removeEmptyPlaceholders по умолчанию включен (Core). -* [Refactor] Параметр rewriteUrls по умолчанию включен (Core). -* [Refactor] Плейсхолдеры ошибок [+field.error+] не устанавливаются, если нет сообщения об ошибке (Core). -* [Enhancement] Плейсхолдеры [+field.class+] (включает class="") и [+field.classname+] (не включает class="") (Core). -* [Refactor] Параметр lexicon может содержать или имена файлов (без расширения) через запятую или массив с языковыми строками (Lexicon). - -### 1.7.7 -* [Enhancement] Возможность указывать разный subject для разных типов писем (Form). - -### 1.7.6 -* [Fix] Исправления ошибок. - -### 1.7.5 -* [Fix] $this->modx вместо $modx в сниппете. - -### 1.7.4 -* [Fix] Ошибка в лексиконе (Form). -* [Refactor] Версии PHP ниже 5.6 не поддерживаются (Core). - -### 1.7.3 -* [Refactor] Подключать __autoload.php, если не задан другой загрузчик. -* [Fix] Ошибка в обработке параметра редиректа (Core). - -### 1.7.2 -* [Enhancement] Параметр &context в контроллере Login для поддержки модели modManagers (Login). -* [Fix] Ошибка в обработке параметра редиректа (Core). - -### 1.7.1 -* [Enhancement] Сниппет записывает в лог, если не задан параметр formid или не удалось загрузить класс контроллера. -* [Refactor] Плагин userHelper по умолчанию отключен. -* [Refactor] По умолчанию загружается лексикон english. -* [Fix] Ошибка в формате даты для лексикона english/form. - -### 1.7.0 -* [Refactor] Изменен метод loadModel, добавлена возможность указывать параметры, передаваемые в конструктор модели (Core). -* [Fix] Ошибка в лексиконе контроллера DeleteContent. -* [Fix] Создание записей анонимными пользователями если &onlyUsers=`0` (Content). -* [Refactor] Убраны include/require, для загрузки классов подключается файл assets/snippets/FormLister/__autoload.php. Модели MODxAPI загружаются этим же загрузчиком. -* [Refactor] Создание записи в логе, если не удалось сохранить данные (Content). -* [Refactor] Изменена обработка поля для запоминания авторизации: теперь время для автологина задается в параметре cookieLifetime (по умолчанию 5 лет, в секундах), а не значением поля (Login). -* [Refactor] Имя куки для автологина можно задать с помощью параметра cookieName, по умолчанию WebLoginPE (Login). -* [Refactor] В контроллере Login сначала проверяется, активирована ли учетная запись, а потом уже возможность авторизации (Login). -* [Enhancement] Блокировка пользователей после определенного числа неудачных попыток авторизации в плагине userHelper. - -### 1.6.2 -* [Fix] Неверное объявление метода в классах капчи. - -### 1.6.1 -* [Refactor] Переделан автологин в плагине userHelper. - -### 1.6.0 -* [Enhancement] Параметр rewriteUrls для обработки ссылок в шаблонах. Игнорируется, если задан параметр parseDocumentSource (Core). -* [Enhancement] Если страница с вызовом контроллера Login указана в конфигурации, как страница "Доступ запрещен", то после успешной авторизации будет произведен редирект на запрашиваемую страницу (Login). -* [Enhancement] Новый параметр ignoreMailerResult (Form). -* [Fix] Неправильная проверка уникальности username в контроллере Profile. -* [Refactor] Для добавления пользователей в группы используется метод из modUsers (Register). -* [Refactor] Введенный пользователем пароль сохраняется в поле user.password (Register). -* [Refactor] Контроллеры Register, Profile и Content загружают данные из моделей после успешного выполнения; после этого можно выполнить сниппеты из параметра preparePostProcess. Сделано это потому что плагины на сохранение или сами модели могут менять данные. -* [Enhancement] Восстановление данных, испорченных в protect.inc.php. Если параметр removeGpc равен 1, то очищены будут все входящие поля. Можно указать в параметре имена полей через запятую. При выводе обработанных полей будут экранироваться тэги MODX (Core). -* [Refactor] В prepare-сниппеты передается переменная name с названием параметра в котором задан сниппет. Можно использовать один сниппет для всех случаев (Core). -* [Enhancement] Контроллер DeleteUser для удаления пользователей c запросом пароля. -* [Enhancement] Контроллер DeleteContent для удаления записей MODxAPI. -* [Enhancement] Контроллер Activate для активации учетных записей. -* [Enhancement] Контроллеры Register и Login могут работать с активацией учетных записей. -* [Enhancement] Вывод параметров data-badge и data-callback для рекапчи (ReCaptchaWrapper). -* [Enhancement] Параметр deleteAttachments для удаления файлов после отправки письма (Form). -* [Enhancement] Сохранение имен файлов в поля формы (Form). -* [Enhancement] Отправка файлов не из формы. Список файлов задается массивом в параметре attachFiles: {"field":{"filepath":"assets/images/logo.png","filename":"logo.png"}} (Form). -* [Refactor] Можно не задавать параметр contentFields, в этом случае в модель будут переданы поля формы (Content). -* [Refactor] Корректная обработка полей lastlogin и thislogin в плагине userHelper. -* [Fix] Неверно выбирался шаблон при восстановлении паролей (Reminder). -* [Enhancement] Дополнительная обработка чанков парсером MODX c помощью параметра parseDocumentSource (Core). -* [Enhancement] Возможность вырезать необработанные плейсхолдеры из чанков с помощью параметра removeEmptyPlaceholders (Core). -* [Enhancement] Параметр removeEmptyPlaceholders для удаления необработанных плейсхолдеров из чанков (возможные значения 0,1; по умолчанию - 0) (Core). -* [Fix] Из-за неправильной обработки параметра defaultsSources не загружались поля в контроллере Profile (Core). -* [Fix] Метод filterFields не учитывал значение параметра allowEmptyFields (Core). - -### 1.5.1 -Исправления ошибок. - -###1.5.0 -* [Refactor] Переделана загрузка внешних параметров с учетом того, что не все источники могут содержать массив: добавлен источник aplh для загрузки массива значений из плейсхолдера MODX, в источнике cookie можно указать несколько имен кук через запятую. Добавлен источник user для загрузки данных авторизованного веб-пользователя (user:web) или менеджера (user:mgr) (Core). Добавлен источник document для загрузки данных текущего или указанного документа. -* [Refactor] Валидация капчи вынесена в класс капчи (Core). -* [Refactor] Параметры капчи задаются массивом, там же указываются сообщения об ошибках (Core). -* [Refactor] Валидация капчи происходит в классе капчи. (Core). -* [Enhancement] reCaptcha2. -* [Enhancement] smsCaptcha. -* [Enhancement] Поддержка Twig: в шаблон передаются переменные FormLister, data, errors, messages. Добавлен метод getErrorMessage для получения в шаблоне сообщений об ошибках для указанного поля (Core). -* [Enhancement] Параметры редиректа можно задавать в виде массива с ключами page (id страницы), query (массив параметров запроса) и header (заголовок) (Core). -* [Enhancement] Если задан параметр redirectTo и параметр editAfterCreate равен 1, то в параметры редиректа будет добавлен идентификатор созданного документа (Core, Content). -* [Fix] Плагин userHelper теперь перенаправляет пользователя на текущую страницу без ?logout в ссылке. -* [Fix] Сопоставление имен полей формы и модели в параметре contentFields неправильно работало в режиме редактирования, если имена различались (Content). -* [Refactor] Пользовательские функции валидации могут вместо false возвращать сообщение об ошибке (Core). - -### 1.4.1 -* [Refactor] Больше рандома в modxCaptcha. - -### 1.4.0 -* [Refactor] Класс modxCaptchaWrapper больше не привязан к FormLister (Core, modxCaptchaWrapper). -* [Enhancement] Убрано принудительное отключение параметров submitLimit и protectSubmit (Content). -* [Refactor] Изменен алгоритм загрузки пользовательских лексиконов. Теперь в параметре lexicon можно указывать как имя файла, так и сразу массив c языковыми записями (Core, Lexicon). -* [Refactor] Загрузка полей отправленной формы происходит не из $_REQUEST, а согласно параметру formMethod (значение по умолчанию - 'post') (Core). -* [Enhancement] Метод loadArray можно использовать для обработки строк с разделителем (по умолчанию - ',') (Config). -* [Enhancement] Если значение параметра submitLimit меньше 60, то оно не пересчитывается в минуты (Form). - -### 1.3.0 -* [Enhancement] Поддержка события OnBeforeWebLogin. В плагине можно реализовать процедуру авторизации независимую от модели; установку полей и шаблона сообщения об успешной авторизации нужно также производить в плагине. Плагин должен вернуть true в случае успешной авторизации, иначе будет выполнена авторизация методами модели (Login). - -### 1.2.1 -* [Refactor] Метод isArray теперь protected (FileValidator). - -### 1.2.0 -* [Refactor] Переделан пропуск полей при преобразовании в плейсхолдеры. Теперь плейсхолдеры отделены от полей формы, для работы с ними следует использовать методы setPlaceholder и getPlaceholder. Выводятся через [+placeholder+]. -* [Bug] Сниппеты, указанные в prepareProcess, выполнялись независимо от результатов валидации. -* [Refactor] Изменена логика обработки правил валидации. Теперь все правила, которых нет в валидаторе, обрабатываются как custom. Это позволяет применять сразу несколько таких правил. -* [Enhancement] Возможность применять правила валидации только для заполненных полей. -* [Refactor] Информация о файлах размещается в массиве formData c помощью метода setFiles (Core, Form). -* [Refactor] Объект FS теперь публичный. -* [Refactor] Контроллер Profile наследуется от Form, а не от Core. - -### 1.1.0 -* [Refactor] Метод filesToArray перемещен в Core. -* [Enhancement] Возможность загрузки произвольных моделей в контроллерах, которые используют MODxAPI. Новые параметры - model и modelPath. -* [Refactor] Метод для загрузки моделей MODxAPI. -* [Enhancement] Возможность загружать произвольные модели MODxAPI в контроллерах. -* [Enhancement] Новое правило валидации - date, проверяет является ли значение поля датой в указанном формате (Validator). -* [Enhancement] Возможность пропускать поля при преобразовании в плейсхолдеры (Core). - -### 1.0.2 -* [Enhancement] Убрано значение по умолчанию свойства allowedFields в контроллерах Register и Profile. - -### 1.0.1 -* [Enhancement] Новое правило валидации файлов - optional, аналог правила required но выполняется также, если файл не загружен пользователем (FileValidator). -* [Enhancement] Правила валидации файлов allowed, minSize, sizeBetween считаются выполненными, если файл не загружен пользователем (код ошибки 4). Решает проблему с файловыми полями, для которых не задано правило required (FileValidator). -* [Bug] К письму прикреплялись не загруженные пользователем файлы, теперь прикрепляются только успешно загруженные (код ошибки 0) (Form). -* [Fix] Параметры из файлов перезаписывали параметры сниппета (Core). -* [Bug] Конфиг из файла не добавлялся в общий массив настроек (Helpers/Config). - -### 1.0.0 -Public release. diff --git "a/assets/snippets/FormLister/docs/ru/010_\320\232\320\276\320\275\321\202\321\200\320\276\320\273\320\273\320\265\321\200\321\213.md" "b/assets/snippets/FormLister/docs/ru/010_\320\232\320\276\320\275\321\202\321\200\320\276\320\273\320\273\320\265\321\200\321\213.md" deleted file mode 100755 index e566b9dae2..0000000000 --- "a/assets/snippets/FormLister/docs/ru/010_\320\232\320\276\320\275\321\202\321\200\320\276\320\273\320\273\320\265\321\200\321\213.md" +++ /dev/null @@ -1,50 +0,0 @@ -## Контроллеры -Контроллер представляет собой класс, унаследованный от базового класса \FormLister\Core, который реализует: - -- загрузку классов для валидации и генерации капчи; -- работу с данными (под данными здесь и далее подразумеваются значения свойства formData, то есть не только значения массива $_REQUEST); -- работу с шаблоном формы и шаблоном успешной обработки. - -Схема работы: - -1. Загрузка данных из формы -2. Загрузка данных из внешних источников -3. Вызов сниппетов для обработки данных. -4. Валидация данных - если получены данные из формы; -3. Вызов сниппетов для обработки данных. -6. Итоговая обработка - если получены данные из формы и пройдена валидация. -7. Вывод. - -Итоговая обработка формы происходит в методе process() контроллера. После успешной обработки необходимо установить флаг результа обработки формы с помощью метода setFormStatus(), а также и указать в свойстве renderTpl шаблон для вывода информации с результатами обработки. - -Ниже перечислены базовые контроллеры. - -### Контроллер Form -Отправляет письма с данными формы. - -### Контроллер Login -Авторизует пользователя в контексте web. - -### Контроллер Register -Создает web-пользователя и отправляет соответствующие письма. - -### Контроллер Activate -Обрабатывает ссылку из письма с подтверждением регистрации или отправляет такое письмо. - -### Контроллер DeleteUser -Позволяет пользователям удалять свои учетные записи. Для подтверждения запрашивает пароль. - -### Контроллер Profile -Предназначен для редактирования данных web-пользователя. - -### Контроллер Reminder -Предназначен для восстановления паролей web-пользователями. - -### Контроллер Content -Позволяет создавать и изменять записи с помощью классов MODxAPI. - -### Контроллер DeleteContent -Позволяет пользователям удалять созданные ими записи. - -### Контроллер MailChimp -Добавляет пользователей в список рассылки сервиса MailChimp. Добавлен как пример расширения базового класса \FormLister\Core. diff --git "a/assets/snippets/FormLister/docs/ru/020_\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213.md" "b/assets/snippets/FormLister/docs/ru/020_\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213.md" deleted file mode 100755 index 19d7add816..0000000000 --- "a/assets/snippets/FormLister/docs/ru/020_\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213.md" +++ /dev/null @@ -1,298 +0,0 @@ -## Общие параметры - -Эти параметры обрабатываются базовым классом FormLister. В контроллерах некоторые общие параметры могут иметь другое назначение. - -## Настройки -### controller -Задает класс для обработки данных. - -Возможные значения - имя php-файла с классом без расширения. - -Значение по умолчанию - Form. - -### dir -Папка в которой находится класс контроллера. - -Значение по умолчанию - assets/snippets/FormLister/core/controller/ - -### formid -Имя формы, обязательный параметр. - -В шаблоне формы обязательно должно быть скрытое поле с именем formid и значением, указанным в параметре. Форма считается отправленной, если в массиве $_REQUEST присутствует ключ с именем параметра, а его значение соответствует значению параметра. - -### formMethod -Возможные значения - post, get или request. - -Значение по умолчанию - post. - -### config -Загрузка параметров в формате json из файла. - -Возможные значения - имяфайла:папка, несколько значений разделяются точкой с запятой. - -#### Пример -myparams:core - загрузить параметры из файла assets/snippets/FormLister/config/core/myparams.json; myparams - загрузить параметры из файла assets/snippets/FormLister/config/custom/myparams.json; myparams:/assets/myfolder - загрузить параметры из файла assets/myfolder/myparams.json. - -Значение по умолчанию - пусто. - -### api -Определяет, в каком виде будут выводиться данные. - -Возможные значения: - -- 0: только html; -- 1: json-массив с данными формы; -- 2: json-массив с данными формы и html. - -### apiFormat -Формат вывода данных для api-режимов. - -Возможные значения - json, array. - -Значение по умолчанию - json. - -### debug -Режим отладки. Вывод записывается в лог MODX. - -Возможные значения - 0, 1. - -Значение по умолчанию - 0. - -### saveObject -Сохраняет объект класса FormLister в плейсхолдер, который можно использовать в других сниппетах. Объект сохраняется только при успешной обработке формы. - -Возможные значения - имя плейсхолдера. - -Значение по умолчанию - пусто. - -### removeGpc -Убирает экранирование данных, которое выполняет MODX для символов {{, [[ и т.д. При этом экранируются тэги MODX при выводе. - -Возножные значения - 0, 1 или имена полей через запятую. - -Значение по умолчанию - 0. - -## Источники данных -### defaultsSources -Позволяет загружать дополнительные данные из внешних источников, например, для предварительного заполнения полей формы. По умолчанию внешние данные загружаются только при начальном выводе формы и не загружаются после отправки формы Это поведение может быть изменено с помощью параметра keepDefaults. - -Возможные значения: список источников, разделенных точкой с запятой. Загрузка данных производится в том порядке, в котором они указаны в списке. - -Источник может задаваться в формате "имя:ключ:префикс". Префикс, если указан, добавляется c точкой к имени поля - например, config.site_name. - -Возможные значения: - -- array: json или php-массив, значения задаются параметром defaults; -- param:имя параметра:префикс - значения задаются значением параметра из вызова сниппета (аналогично array, только значение задается не параметром defaults, а произвольным, также можно указать префикс); -- session:ключ массива:префикс - значения загружаются из массива $_SESSION; -- plh:ключи через запятую:префикс - загружаются значения из массива $modx->placeholders; -- aplh:имя плейсхолдера:префикс - загружаются значения из плейсхолдера, содержащего массив; -- config:префикс - загружаются значения из конфигурации MODX; -- cookie:ключи через запятую:префикс - загружаются значения из массива $_COOKIE; -- имя класса MODxAPI:ключ:префикс - ключ является аргументом метода edit(), класс должен быть заранее загружен; -- document:префикс - загружает данные из модели modResource для документа, в котором вызван сниппет. Ключ не указывается; -- user:ключ:префикс - загружает данные из модели modUsers для авторизованного пользователя. Тип пользователя уточняется в ключе (web или mgr). - -Значение по умолчанию - array. - -### defaults -Данные для источника array. - -Возможные значения: массив значений по умолчанию, в формате json или php. - -### keepDefaults -Позволяет повторно загружать данные из внешних источников после отправки формы. Если в параметре указан список полей, то загружены будут только указанные поля. - -Возможные значения: 1, 0, имена полей, разделенные запятой. - -Значение по умолчанию - 0. - -### allowEmptyFields -Разрешает задавать поля с пустыми значениями. - -Возможные значения - 0 или 1. - -Значение по умолчанию - 1. - -## Элементы управления -### formControls -Список полей с управляющими элементами формы (списки, чекбоксы, радио-кнопки). Необходимо для отслеживания состояния элементов. - -Возможные значения - имена полей, разделенные запятой. - -Значение по умолчанию - пусто. - -### emptyFormControls - -Этот параметр позволяет решить проблему неотмеченных чекбоксов, которые не включаются в массив полей при отправке формы: если в $_REQUEST отсутствует нужный элемент, то он создается согласно данному параметру. Необходимость в таком параметре возникла в связи с тем, что MODxAPI требует явно указывать изменяемые поля в методе fromArray(). Но можно использовать и в обычных формах, чтобы подставить в шаблон значение неотмеченного чекбокса. - -Возможные значения - массив: -``` -&emptyFormControls=`{ - "mycheckbox" : "Нет", - "published" : 0 -}` -``` - -## Обработка данных -### prepare, prepareProcess, prepareAfterProcess -Аналогично параметру prepare в DocLister. - -Сниппеты из параметра prepare выполняются после загрузки данных в форму, сниппеты из параметра prepareProcess - после прохождения валидации, сниппеты из параметра prepareAfterProcess - после успешного выполнения обработки. В сниппетах через переменную $FormLister доступен объект контроллера, а через массив $data - значения полей формы. Также доступна переменная $name, которая задержит имя параметра из которого взят сниппет (prepare, prepareProcess и т.д.); это позволяет использовать один и тот же сниппет для разных случаев. Для изменения данных следует использовать в prepare-сниппетах методы контроллера (setField, setFields и т.д.) - -Возможные значения - имена сниппетов, анонимные функции, статические методы загруженных классов. - -Значение по умолчанию - пусто. - -## Валидация -### validator -Имя класса для валидации данных. Класс должен быть предварительно загружен. - -Значение по умолчанию - \FormLister\Validator. - -### rules -Массив с правилами валидации. - -Значение по умолчанию - пусто. - -## Шаблоны -### formTpl -Шаблон формы. В шаблоне формы обязательно должно быть поле с именем formid и значением, указанным в параметре formid. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. - -### arraySplitter - -Разделитель для преобразования массивов в строку. - -Значение по умолчанию - точка с запятой. - -### {field}.arraySplitter -Разделитель для преобразования массивов в строку, но для отдельного поля {field}. Например: groups.arraySplitter - разделитель для массива из поля groups. - -Если не задано, то используется значение параметра arraySplitter. - -### errorTpl -Шаблон для вывода сообщений валидатора. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию: -``` -@CODE:
        [+message+]
        -``` - -### requiredClass, errorClass -Имена классов для обозначения незаполненных (required) и неверно заполенных (error) полей. - -Значение по умолчанию - required и error соответственно. - -### {field}.requiredClass, {field}.errorClass -Позволяет задавать указанные выше классы для конкретных полей. - -По умолчанию используются значения параметров requiredClass и errorClass. - -### messagesTpl -Шаблон сообщений обработчика формы. В шаблоне выводятся группы сообщений (messages, required, error). - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию: -``` -@CODE:
        [+messages+]
        -``` - -### messagesOuterTpl -Шаблон-обертка для группы произвольных сообщений. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - -``` -@CODE: [+messages+] -``` - -### messagesRequiredOuterTpl -Шаблон-обертка для группы сообщений о незаполненных полях. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию: -``` -@CODE: [+messages+] -``` - -### messagesErrorOuterTpl -Шаблон-обертка для группы сообщений о неверно заполненных полях. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию: -``` -@CODE: [+messages+] -``` - -### messagesSplitter, messagesRequiredSplitter, messagesErrorSplitter -Разделитель сообщений в группе. - -Возможные значения - произвольная строка. - -Значение по умолчанию: -``` -
        -``` - -### removeEmptyPlaceholders -Удаляет из шаблонов незаполненные прейслхолдеры. - -Возможные значения - 0 или 1. - -Значение по умолчанию - 1. - -### parseDocumentSource -Обрабатывает чанки MODX-парсером. - -Возможные значения - 0 или 1. - -Значение по умолчанию - 0. - -### rewriteUrls -Если параметр parseDocumentSource отключен, то парсит ссылки в шаблонах. - -Возможные значения - 0 или 1. - -Значение по умолчанию - 0. - -### skipPrerender -Позволяет отключить предварительную обработку полей формы (экранирование значений, преобразование массивов в строки, установка сообщений об ошибках). Можно включить, если для вывода не используется парсер MODX. - -Возможные значения - 0 или 1. - -Значение по умолчанию - 0. - -### templatePath, templateExtension -Путь к папке с файлами шаблонов и расширение файлов шаблонов. Эти параметры необходимо задавать при использовании плагина EvoTwig. - -Значение по умолчанию - пусто. - -## Перенаправление после обработки -### redirectTo -Id страницы, на которую нужно выполнить перенаправление после успешной обработки формы. В api-режиме перенаправление не выполняется, но в массиве данных формы сохраняется абсолютная ссылка на целевую страницу (поле "redirectTo"). - -Вместо числа можно указывать массив: -``` -&redirectTo=`{ - "page":10, - "query":{ - "foo":"bar" - }, - "header":"HTTP/1.1 307 Temporary Redirect" -}` -``` -Ключ page задает id станицы, в массиве query можно передать дополнительные get-параметры, значением ключа header может быть текст заголовка для перенаправления. - -Возможные значения - число или массив. - -Значение по умолчанию - пусто. diff --git "a/assets/snippets/FormLister/docs/ru/030_\320\222\320\260\320\273\320\270\320\264\320\260\321\206\320\270\321\217_\320\264\320\260\320\275\320\275\321\213\321\205.md" "b/assets/snippets/FormLister/docs/ru/030_\320\222\320\260\320\273\320\270\320\264\320\260\321\206\320\270\321\217_\320\264\320\260\320\275\320\275\321\213\321\205.md" deleted file mode 100755 index 9efb7da81d..0000000000 --- "a/assets/snippets/FormLister/docs/ru/030_\320\222\320\260\320\273\320\270\320\264\320\260\321\206\320\270\321\217_\320\264\320\260\320\275\320\275\321\213\321\205.md" +++ /dev/null @@ -1,132 +0,0 @@ -## Валидация данных - -При валидации данных валидатор последовательно применяет к значению поля заданные правила, при возникновении ошибки в массив данных об ошибках добавляется запись и дальнейшая обработка формы прекращается. - -Валидация считается пройденной, если в массиве данных об ошибках отсутствуют записи. - -### Правила валидации -Список правил задается в виде массива. Ключом является имя поля, а значением - массив правил валидации. Правило валидации является методом класса-валидатора. В массиве правил ключом является имя правила (название метода валидации), значением может быть либо строка с сообщением об ошибке валидации правила, или же массив с описанием. В этом массиве в ключе params задаются необходимые для валидации значения, а в ключе message задается строка с сообщением об ошибке. - -Можно также использовать отрицание правил, если добавить перед именем правила восклицательный знак: "!numeric" - поле пройдет валидацию, если его значение не является числом. - -Если нужно реализовать проверку только заполненных полей, то перед именем поля в списке правил нужно добавить восклицательный знак. В этом случае если значение поля пустое, правила будут проигнорированы. - -``` -{ - "имя поля 1": { - "правило 1" : "сообщение об ошибке", - "правило 2" : "сообщение об ошибке" - }, - "имя поля 2": { - "правило 1" : "сообщение об ошибке", - "правило 2" : { - "params" : значение, - "message" : "сообщение об ошибке" - } - }, - "!имя поля 3":{ - "правило 1" : "сообщение об ошибке" - } -} -``` -Стандартным классом валидации (\FormLister\Validator) предусмотрены правила: - -- required: поле заполнено; -- date: значение поля является датой в заданном формате; -- min: значение поля больше заданного или равно ему; -- max: значение поля меньше заданного или равно ему; -- greater: значение поля строго меньше заданного; -- less: значение поля строго больше заданного; -- between: значение поля входит в диапазон; -- equals: значение поля равно заданному; -- in: значение поля входит в заданный массив значений; -- alpha: значение поля содержит только буквы; -- numeric: значение поля содержит только цифры; -- alphaNumeric: значение поля содержит только буквы и цифры; -- slug: значение поля является частью url; -- decimal: значение поля является десятичным числом; -- phone: значение поля является номером телефона; -- matches: значение поля удовлетворяет регулярному выражению; -- url: значение поля является ссылкой; -- email: значение поля является email-адресом; -- length: длина значения поля равна заданному; -- minLength: длина значения поля больше заданного или равна ему; -- maxLength: длина значения поля меньше заданного или равна ему; -- lengthBetween: длина значения поля входит в диапазон; -- minCount: размер массива больше заданного; -- maxCount: размер массива меньше заданного; -- countBetween: размер массива входит в диапазон. - -Если требуется задать два значения для правила, то их следует задавать как массив: -``` -&rules=`{ - "field" : { - "lengthBetween" : { - "params" : [10,20], - "message" : "Длина должна быть от 10 до 20" - } - } -}` -``` - -Для правила in (и других правил, использующих массив) массив значений следует задавать следующим образом: -``` -&rules=`{ - "field" : { - "in" : { - "params" : [ [10,20,30] ], - "message" : "Значение поля field должно быть равно 10, 20 или 30" - } - } -}` -``` - -Это нужно, чтобы массив был передан в функцию одним аргументом. - -Предусмотрена также возможность использовать для валидации функции или статические методы загруженного класса: -``` -&rules=`{ - "myfield":{ - "required":"Required field", - "custom":{ - "function":"\\Namespace\\Classname::myCustomRule", - "params":[10,20,30], - "message":"Custom check failed" - } - } -}` -``` - -Метод должен принимать первым аргументом экземпляр контроллера из которого вызывается правило, вторым аргументом - значение проверяемого поля, далее - параметры передаваемые в ключе описания params: -``` -public static function myCustomRule($fl,$value,$a,$b,$c) { - $result = $fl->getField('field1') == $a && $fl->getField('field2') == $b && $value == $c; - return $result; -} -``` -В примере правило будет пройдено, если значение поля field1 = 10, значение поля field2 = 20, а значение поля, к которму применяется правило, = 30. - -Метод должен вернуть true, false или текст сообщения об ошибке (в этом случае можно не указывать message в списке правил). - -В примере используется название правила "сustom", но можно использовать любое название правила, которого нет в классе валидации. Таким образом можно использовать несколько правил данного типа. - -### Результаты валидации -Данные об ошибках хранятся в виде массива и могут быть получены вызовом метода getFormData('errors'): -``` -{ - "имя поля 1": { - "имя нарушенного правила" : "сообщение об ошибке" - }, - "имя поля 2": { - "имя нарушенного правила" : "сообщение об ошибке" - } -} -``` -Для добавления данных в этот массив используется метод addError(имя поля, имя правила, сообщение об ошибке). Таким образом, можно влиять на итоговый результат валидации, вручную добавляя записи в этот массив. Можно также объявить валидацию непройденной по умолчанию, вызвав метод setValid(false). - -В шаблонах результаты валидации для каждого поля выводятся с помощью плейсхолдера [+имя поля.error+]. Общий результат может быть выведен в плейсхолдер [+form.messages+], который задается шаблоном messagesTpl. В свою очередь, в этом шаблоне можно использовать плейсхолдеры: - -- [+required+] - сообщения о незаполенных полях; -- [+errors+] - сообщения о неверно заполненных полях. - -Получить сообщения об ошибках для определенного поля можно с помощью метода getErrorMessage(имя поля). diff --git "a/assets/snippets/FormLister/docs/ru/035_\320\230\321\201\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\320\275\320\270\320\265_\320\272\320\260\320\277\321\207\320\270.md" "b/assets/snippets/FormLister/docs/ru/035_\320\230\321\201\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\320\275\320\270\320\265_\320\272\320\260\320\277\321\207\320\270.md" deleted file mode 100755 index 99f61a25bf..0000000000 --- "a/assets/snippets/FormLister/docs/ru/035_\320\230\321\201\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\320\275\320\270\320\265_\320\272\320\260\320\277\321\207\320\270.md" +++ /dev/null @@ -1,175 +0,0 @@ -## Использование капчи - -По умолчанию FormLister может использовать модицифированную капчу MODX и Google Recaptcha. Также в наличии SmsCaptcha - для отправки формы необходимо ввести код, полученный в смс-сообщении (отправку сообщения необходимо реализовывать отдельно). - -Для подключения необходимо указать имя папки с файлами капчи (папки находятся в assets/snippets/FormLister/lib/captcha/) в параметре &captcha. - -В параметре &captchaParams задаются в виде массива настройки капчи. Например: -``` -&captchaParams=`{ -"width":200, -"height":120 -}` -``` - -Имя поля, в которое пользователь вводит значение капчи, задается параметром captchaField (по умолчанию - vericode). Правило валидации для этого поля создается автоматически. - -Капча выводится в шаблоне формы с помощью плейсхолдера [+captcha+]. - -### modxCaptcha - -Модификация стандартной капчи MODX. - -Настройки: -* width и height - ширина и высота картинки с капчей (значение по умолчанию - 100 и 60); -* inline - формат вывода. Если значение параметра равно 1, то в плейсхолдер [+captcha+] выводится картинка в base64-формате. Если 0, то выводится ссылка на файл connector.php, генерирующий картинку. Значение по умолчанию - 1; -* connectorDir - путь к папке с файлом connector.php, если параметр inline равен 0. Значение по умолчанию - assets/snippets/FormLister/lib/captcha/modxCaptcha/; -* errorEmptyCode - текст сообщения об ошибке, если поле со значением капчи не заполнено. Значение по умолчанию - "Введите проверочный код"; -* errorCodeFailed - текст сообщения об ошибке, если введено неверное значение капчи. Значение по умолчанию - "Неверный проверочный код" - -### reCaptcha - -Капча Google reCAPTCHA V2. На странице с формой должен быть подключен скрипт: -``` - -``` - -Значение параметра captchaField должно быть "g-recaptcha-response" (см. [документацию](https://developers.google.com/recaptcha/docs/verify)). - -Настройки: -* secretKey, siteKey - ключи для доступа к api reCAPTCHA; -* size, theme, badge, callback, expired_callback, tabIndex, type - см. [документацию](https://developers.google.com/recaptcha/docs/display#render_param); -* errorCodeFailed - текст сообщения об ошибке, если пользователь не прошел проверку. Значение по умолчанию - "Вы не прошли проверку" - -### smsCaptcha - -Настройки: -* codeLifeTime - срок действия введенного кода, секунд. Если пользователь попытается ввести код до истечения срока, то будет выведено сообщение errorCodeUsed. Значение по умолчанию - 86400 (сутки); -* errorEmptyCode - сообщение об ошибке, если пользователь получил, но не ввел код. Значение по умолчанию - "Введите код авторизации"; -* errorCodeRequired - сообщение об ошибке, если пользователь не запросил код. Значение по умолчанию - "Получите код авторизации"; -* errorCodeFailed - сообщение об ошибке, если пользователь ввел неверный код авторизации. Значение по умолчанию - "Неверный код авторизации"; -* errorCodeExpired - сообщение об ошибке, если пользователь не ввел полученный код в течение заданного времени. Значение по умолчанию - "Код авторизации истек, получите новый"; -* errorCodeUsed - сообщение об ошибке, если пользователь уже вводил код для текущей формы. Значение по умолчанию - "Код авторизации уже использовался". - -Чтобы использовать эту капчу необходимо предварительно создать таблицу в базе данных: -``` -createTable(); -``` - -Для отправки кода необходимо создать отдельную форму и указать в параметре prepareProcess сниппет: - ``` -setValid(false); - $FormLister->addError('phone','phone','Неверный номер телефона'); -} else { - //загружаем класс для работы с таблицей - $sms = $FormLister->loadModel('SmsModel','assets/snippets/FormLister/lib/captcha/smsCaptcha/model.php'); - $flag = false; - //проверяем, есть ли в таблице запись для заданного номера и идентификатора формы - $data = $sms->getData('+'.$rawPhone,$formid); - if ($data->getID()) { - //если есть и код не истек - if ($sms->get('expires') > time()) { - //смотрим, использован ли код - if ($sms->get('active')) { - $FormLister->addMessage('Вы уже использовали код.'); - } else { - $FormLister->addMessage('Код уже был отправлен. Подождите несколько минут прежде чем запросить новый.'); - } - //если код истек, то удаляем запись и разрешаем выдать новый - } else { - $sms->delete($sms->getID()); - $flag = true; - } - } else { - $flag = true; - } - //если можно выдать новый код - if ($flag) { - $code = mt_rand(1000,9999); - - //здесь отправляется смс и результат помещается в переменную $result - /** - * - */ - $result = array('status'=>true); - - //проверяем отправлена ли смс - if (is_array($result) && $result['status']) { - //создаем запись в таблице, время жизни кода - 3 минуты - $result = $sms->create()->fromArray(array( - 'phone'=>('+'.$rawPhone), - 'formid'=>$formid, - 'expires'=>(time() + 60*3), - 'ip'=> \APIhelpers::getUserIP(), - 'code'=>$code - ))->save(); - //если получилось записать, то сохраняем в сессию номер телефона - if ($result) { - $_SESSION[$session_key] = '+'.$rawPhone; - } else { - $FormLister->setValid(false); - $FormLister->addMessage('Не удалось отправить смс'); - } - } else { - //если нельзя выдать код, то запрещаем дальнейшую обработку формы - $FormLister->setValid(false); - } -} -?> -``` - -Полностью вызов FormLister: -``` -[!FormLister? -&formid=`code` -&submitLimit=`0` -&protectSubmit=`0` -&rules=`{ -"phone":{ - "required":"Обязательно введите номер телефона", - "phone":"Введите номер правильно" -} -}` -&prepareProcess=`setSmsCaptcha` -&captcha=`modxCaptcha` -&formTpl=`@CODE: -
        -
        -
        -
        - - -
        - -
        - - [+phone.error+] -
        -
        -[+form.messages+] -
        -
        - -
        -
        - - - [+vericode.error+] -
        -
        -
        -
        ` -&successTpl=`@CODE:Код авторизации отправлен на номер [+phone.value+]. Срок действия кода - 3 минуты.` -!] -``` diff --git "a/assets/snippets/FormLister/docs/ru/040_\320\222\321\213\320\262\320\276\320\264_\320\264\320\260\320\275\320\275\321\213\321\205.md" "b/assets/snippets/FormLister/docs/ru/040_\320\222\321\213\320\262\320\276\320\264_\320\264\320\260\320\275\320\275\321\213\321\205.md" deleted file mode 100755 index 8dc1af8cf9..0000000000 --- "a/assets/snippets/FormLister/docs/ru/040_\320\222\321\213\320\262\320\276\320\264_\320\264\320\260\320\275\320\275\321\213\321\205.md" +++ /dev/null @@ -1,40 +0,0 @@ -## Вывод данных - -Для вывода в шаблоны данные экранируются, а массивы преобразовываются в строки. Кроме этого, для элементов управления устанавливаются специальные плейсхолдеры. - -Вывод неэкранированного значения поля: -[+имя поля+] - -Вывод значения поля: -``` -[+имя поля.value+] -``` - -Установка чекбокса: -``` -[+c.имя поля.значение поля+] -``` - -Установка выпадающего списка или радио-кнопки: -``` -[+s.имя поля.значение поля+] -``` - -Установка класса для незаполненного поля: -[+имя поля.requiredСlass+] - -Установка класса для неверно заполненного поля: -[+имя поля.errorClass+] - -Вывод сообщения об ошибке валидации: -[+имя поля.error+] - -Вывод сообщений обработчика: -[+form.messages+] - -В плейсхолдер [+form.messages+] могут выводиться три типа сообщений: нарушения правила required, нарушения остальных правил, произвольные сообщения, которые задаются методом addMessage. По умолчанию выводятся только последние, см. описание параметра messagesTpl. - -Вывод значений из лексиконов: -[%ключ лексикона%] - -При использовании плагина EvoTwig в шаблонах доступны переменные FormLister (объект контроллера), errors (массив formData['errors']), messages (массив formData['messages']). diff --git "a/assets/snippets/FormLister/docs/ru/050_\320\236\321\202\320\277\321\200\320\260\320\262\320\272\320\260_\320\277\320\270\321\201\320\265\320\274.md" "b/assets/snippets/FormLister/docs/ru/050_\320\236\321\202\320\277\321\200\320\260\320\262\320\272\320\260_\320\277\320\270\321\201\320\265\320\274.md" deleted file mode 100644 index 99b5a33802..0000000000 --- "a/assets/snippets/FormLister/docs/ru/050_\320\236\321\202\320\277\321\200\320\260\320\262\320\272\320\260_\320\277\320\270\321\201\320\265\320\274.md" +++ /dev/null @@ -1,237 +0,0 @@ -## Отправка писем - -Контроллер Form позволяет отправлять данные формы в письме. - -## Параметры отправки почты -### parseMailerParams -Разрешает использовать данные формы в параметрах отправки почты (&to=\`[+user.email.value+]\` и т.п.). - -Возможные значения - 1, 0. - -Значение по умолчанию - 0. - -### isHtml -Разрешает отправлять письмо в формате html. Проверка корректности кода письма возлагается на разработчика. - -Возможные значения - 1, 0. - -Значение по умолчанию - 1. - -### to -Адрес получателя. Если не указан, то письмо не отправляется, но считается успешно отправленным. - -Возможные значения - email-адрес. - -Значение по умолчанию - пусто. - -### from -Возможные значения - email-адрес. - -Значение по умолчанию - параметр конфигурации emailsender. - -### fromName -Имя отправителя. - -Возможное значение - строка. - -Значение по умолчанию - параметр конфигурации site_name. - -### replyTo -Заголовок replyTo. - -Возможные значения - email-адрес. - -Значение по умолчанию - пусто. - -### cc -Заголовок сс. - -Возможные значения - email-адрес. - -Значение по умолчанию - пусто. - -### bcc -Заголовок bcc. - -Возможные значения - email-адрес. - -Значение по умолчанию - пусто. - -### noemail -Если параметр задан, то письмо не отправляется, но считается успешно отправленным. - -Возможные значения - 1, 0. - -Значение по умолчанию - 0. - -### ignoreMailerResult -Если параметр задан, то письмо отправляется, но результат отправки игнорируется. - -Возможные значения - 1, 0. - -Значение по умолчанию - 0. - -### subject, ccSubject, autoSubject -Тема письма. - -Возможные значения - строка. - -Значение по умолчанию - пусто. - -### subjectTpl, ccSubjectTpl, autoSubjectTpl -Шаблон темы письма. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - значение параметра subject (ccSubject, autoSubject). - -### autosender -Адрес на который отправляется дополнительное письмо. - -Возможные значения - email-адрес. - -Значение по умолчанию - пусто. - -### autosenderFromName -Имя отправителя дополнительного письма. - -Возможные значения - строка. - -Значение по умолчанию - параметр конфигурации site_name. - -### ccSender -Если параметр задан, то на адрес указанный в поле формы отправляется письмо. - -Возможные значения - 1, 0. - -Значение по умолчанию - 0. - -### ccSenderField -Имя поля, в котором хранится адрес получателя. - -Возможные значения - имя поля формы. - -Значение по умолчанию - email. - -### ccSenderFromName -Имя отправителя письма на заданный в поле формы адрес. - -Возможные значения - строка. - -Значение по умолчанию - не указано. - -### ccMailConfig -Позволяет переопределить параметры отправки для писем, отправляемых по адресу из формы (isHtml, from, fromName, subject, replyTo, cc, bcc, noemail). - -Возможные значения - json или php массив. - -Значение по умолчанию - не указано. - -### autoMailConfig -Позволяет переопределить параметры отправки для дополнительно отправляемых писем (isHtml, from, fromName, subject, replyTo, cc, bcc, noemail). - -Возможные значения - json или php массив. - -Значение по умолчанию - не указано. - -## Защита от повторной отправки -### protectSubmit -Защита от повторной отправки письма. - -Возможные значения - 1, 0 или список полей, по которым определяется уникальность письма. Если список не задан, то используются поля, обязательные для заполнения. - -Значение по умолчанию - 1. - -### submitLimit -Защита от частой отправки писем. - -Значение - число секунд между повторной отправкой. - -Значение по умолчанию - 60. - -## Шаблоны -### reportTpl -Основной шаблон письма. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - список полей и их значений. - -### automessageTpl -Шаблон дополнительного письма. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. Обязательный параметр, если задан параметр autosender. - -Значение по умолчанию - пусто. - -### ccSenderTpl -Шаблон письма на заданный в поле формы адрес. Обязательный параметр, если задан параметр ccSender. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. - -### successTpl -Шаблон сообщения об успешной отправке писем. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. - -## Отправка файлов -### attachments -Имена полей, в которых хранятся файлы. Поддерживаются только поля с одним файлом (name="field" type="file") и поля с одномерным массивом файлов (name="field[]" type="file" multiple). - -Значение по умолчанию - пусто. - -### attachFiles -Позволяет отправить произвольные файлы. - -Возможные значения - массив: -``` -&attachFiles=`{ -"имя поля1":{ - "filepath":"assets/images/logo.png", - "filename":"logo.png" -}, -"имя поля2":[ - { - "filepath":"assets/images/file1.jpg", - "filename":"отчет.jpg" - }, - { - "filepath":"assets/images/file2.jpg", - "filename":"отчет2.jpg" - } -] -}` -``` -### deleteAttachments -Позволяет удалить файлы вложений после успешной отправки. - -Возможные значения - 0 или 1. - -Значение по умолчанию - 0. - -### fileValidator -Имя класса для валидации файлов. Если задано, то класс должен быть загружен заранее. - -Значение по умолчанию - \FormLister\FileValidator - -### fileRules -Правила валидации (см. раздел "Валидация данных"). Стандартный валидатор поддерживает правила: - -- required: файлы успешно отправлены; -- optional: аналогично required, но выполняется и в том случае, если пользователь не загружал файлы (то есть поле с файлами не является обязательным); -- allowed: расширение файла входит в заданный массив; -- images: расширение файла jpg, jpeg, gif, png, bmp; -- minSize: размер файла в килобайтах больше заданного; -- maxSize: размер файла в килобайтах меньше заданного; -- sizeBetween: размер файла в килобайтах входит в диапазон; -- minCount: количество файлов больше заданного; -- maxCount: количество файлов меньше заданного; -- countBetween: количество файлов входит в диапазон. - -Использовать конструкцию "!имя поля" в правилах валидации файлов нет смысла, так как значение поля с файлом не будет пустым, даже если файл не загружен. Следует использовать правило optional. - -В шаблоне письма reportTpl доступен плейсхолдер [+attachments.value+] со списком всех приложенных к письму файлов. Можно также вывести по отдельности: [+имя поля.value+]. Файлы отправляются только в письме c шаблоном reportTpl. diff --git "a/assets/snippets/FormLister/docs/ru/060_\320\220\320\262\321\202\320\276\321\200\320\270\320\267\320\260\321\206\320\270\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\320\265\320\271.md" "b/assets/snippets/FormLister/docs/ru/060_\320\220\320\262\321\202\320\276\321\200\320\270\320\267\320\260\321\206\320\270\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\320\265\320\271.md" deleted file mode 100755 index 8a1203405e..0000000000 --- "a/assets/snippets/FormLister/docs/ru/060_\320\220\320\262\321\202\320\276\321\200\320\270\320\267\320\260\321\206\320\270\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\320\265\320\271.md" +++ /dev/null @@ -1,204 +0,0 @@ -## Авторизация пользователей - -Авторизация пользователей в `FormLister` осуществляется с использованием контроллера `Login`. - -### Выбор поля для авторизации - -Поле для авторизации задается в параметре `loginField` и должно быть **уникальным** для каждого веб-пользователя. - -Авторизация может осуществляться: -* по **базовым** полям средствами класса `modUsers`: `id`, `username` и `email` -* по любому **другому полю** из учетной записи (с помощью плагина для события `OnWebAuthentication`) - - -Дополнительное использование плагина [userHelper](https://github.com/evolution-cms/evolution/blob/develop/assets/snippets/FormLister/plugin.userHelper.php) позволяет: - -* вести учет количества логинов -* определить время последней авторизации -* реализовать автологин и выход из учетной записи -* блокировать пользователей после определенного количества неудачных попыток авторизации - -Перед использованием плагина `userHelper` убедитесь что он включен: - -![Не забудьте включить userHelper](https://habrastorage.org/web/dbc/1e2/abd/dbc1e2abd8664a548f4eca254187fb60.png) - -## Пример вызова FormLister для авторизации веб-пользователей - -```javascript -[!FormLister? -&formid=`login` -&controller=`Login` -&loginField=`email` -&passwordField=`password` -&rules=`{ - "email":{ - "required":"Обязательно введите email" - } - }, - "password":{ - "required":"Обязательно введите пароль", - "minLength":{ - "params":6, - "message":"В пароле должно быть больше 6 символов" - } - }, -}` -&allowedFields=`email,password` -&formTpl=`@CODE: -
        -
        - -
        - - - [+email.error+] -
        -
        - - - [+password.error+] -
        - [+form.messages+] -
        - -
        -
        -
        -` -&messagesOuterTpl=`@CODE:` -&successTpl=`@CODE:
        Поздравляем с успешной авторизацией, [+fullname.value+]!
        ` -&errorTpl=`@CODE:
        [+message+]
        ` -&requiredClass=` has-error` -&errorClass=` has-error` -&requiredClass=` has-error` -!] -``` - -## Параметры контроллера - -### model -Класс для работы с пользователями. - -Возможные значения - имя класса. - -Значение по умолчанию - \modUsers - -### modelPath -Путь к файлу класса для работы с пользователями. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modUsers.php - -### loginField -Поле, содержащее имя пользователя. - -Возможные значения - имя поля. - -Значение по умолчанию - username. - -### passwordField -Поле, содержащее пароль пользователя. - -Возможные значения - имя поля. - -Значение по умолчанию - password. - -### rememberField -Поле для запоминания пользователя. Если значение поля приводится к true, то при успешной авторизации будет установлена кука с параметрами автологина. Имя куки и ее время жизни задаются параметрами cookieName и cookieLifetime. - -Можно также задать поле rememberme в параметре defaults, чтобы запоминание происходило без участия пользователя: -``` -&defaults=`{"rememberme":1}` -``` - -Возможные значения - имя поля. - -Значение по умолчанию - rememberme. - -### checkActivation -Включает проверку активации учетной записи пользователя (см. "Активация учетных записей"). - -Возможные значения - 0 или 1. - -Значение по умолчанию - 1. - -### context -Контекст авторизации. - -Возможные значения - mgr или web. - -Значение по умолчанию - web. - -### cookieName -Имя куки для хранения параметров автологина. - -Значение по умолчанию - WebLoginPE. - -### cookieLifetime -Время жизни вышеуказанной куки. - -Возможные значения - число секунд с момента последнего логина. - -Значение по умолчанию - 157680000 (5 лет). - -### redirectTo -Перенаправляет пользователя на страницу c указанным id после авторизации. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### exitTo -Перенаправляет уже авторизованного пользователя на указанную страницу. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### successTpl -Шаблон сообщения об успешной авторизации. В шаблоне можно использовать данные пользователя. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Login с ключом [+login.default_successTpl+] - -### skipTpl -Шаблон сообщения о том, что пользователь уже авторизован. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Login с ключом [+login.default_skipTpl+] - -## Параметры плагина userHelper -### logoutKey -Имя GET-параметра для запуска выхода из учетной записи. Если в ссылке на страницу сайта указан параметр с соответствующим именем (например, http://sitename.ru/page.html?logout), будет произведен выход из учетной записи. - -Значение по умолчанию - logout. - -### cookieName -Имя куки для хранения параметров автологина. - -Значение по умолчанию - WebLoginPE. - -### cookieLifetime -Время жизни вышеуказанной куки. - -Возможные значения - число секунд с момента последнего логина. - -Значение по умолчанию - 157680000 (5 лет). - -### maxFails -Количество попыток для ввода учетных данных. - -Возможные значения - число больше 0. - -Значение по умолчанию - 3. - -### blockTime -Время блокировки пользователя. - -Возможные значения - число секунд с момента последнего логина. - -Значение по умолчанию - 3600 (1 час). - diff --git "a/assets/snippets/FormLister/docs/ru/070_\320\240\320\265\320\263\320\270\321\201\321\202\321\200\320\260\321\206\320\270\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\320\265\320\271.md" "b/assets/snippets/FormLister/docs/ru/070_\320\240\320\265\320\263\320\270\321\201\321\202\321\200\320\260\321\206\320\270\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\320\265\320\271.md" deleted file mode 100755 index 97e0de13cd..0000000000 --- "a/assets/snippets/FormLister/docs/ru/070_\320\240\320\265\320\263\320\270\321\201\321\202\321\200\320\260\321\206\320\270\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\320\265\320\271.md" +++ /dev/null @@ -1,142 +0,0 @@ -## Регистрация пользователей - -Контроллер Register позволяет регистрировать пользователей в заданные группы и отправлять уведомления о регистрации. Контроллер является расширением контроллера Form, соответственно можно использовать соответствующие параметры для отправки писем при регистрации. - -Имена полей в форме должны соответствовать полям модели [modUsers](http://docs.evolution-cms.com/Extras/Snippets/DocLister/MODxAPI). - -Если в форме не задано поле username, то ему присваивается значение поля email. Таким образом можно регистрировать пользователей только по email. - -Если в форме не задано поле password, то значение поля генерируется автоматически. То есть регистрацию пользователя можно свести к указанию email. - -При регистрации с паролем, в форме может присутствовать поле repeatPassword. Если заданы правила валидации для полей password и repeatPassword, то при наличии для поля repeatPassword правила equals, оно будет автоматически скорректировано для проверки равенства значений полей password и repeatPassword: -``` -"repeatPassword":{ - "required":"Введите пароль еще раз", - "equals":{ - "params" : "Этот ключ в описании правила можно не задавать, он будет сформирован контроллером автоматически", - "message":"Пароли не совпадают" - } -} -``` - -При регистрации следует проверять уникальность имени пользователя и email. В контроллере предусмотрены соответствующие правила: -``` -&rules=`{ - "username":{ - "required":"Введите имя пользователя", - "alphaNumeric":"Только буквы и цифры", - "custom":{ - "function":"\\FormLister\\Register::uniqueUsername", - "message":"Имя уже занято" - } - }, - "email":{ - "required":"Введите email", - "email":"Неверный email", - "custom":{ - "function":"\\FormLister\\Register::uniqueEmail", - "message":"Этот email уже использует другой пользователь" - } - } -}` -``` -В шаблонах доступны все поля модели для созданной записи. Дополнительно задается поле user.password с незашифрованным паролем. - -## Параметры -### model -Класс для работы с пользователями. - -Возможные значения - имя класса. - -Значение по умолчанию - \modUsers - -### modelPath -Путь к файлу класса для работы с пользователями. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modUsers.php - -### allowedFields -Разрешенные для обработки поля. Поля, не указанные в списке, игнорируются. Поля username, email и password всегда разрешены. - -Если не задано, то разрешены все поля. - -Возможные значения - имена полей формы, разделенные запятой. - -Значение по умолчанию - пусто. - -### forbiddenFields -Запрещенные для обработки поля. Поля, указанные в списке, игнорируются. Поля username, email и password удаляются из списка запрещенных. - -Возможные значения - имена полей формы, разделенные запятой. - -Значение по умолчанию - пусто. - -### userGroups -Добавляет зарегистрированного пользователя в указанные группы. - -Возможные значения - имена групп, разделенные запятой (если имена содержат запятую в названии, то можно задать значение параметра массивом). - -Значение по умолчанию - пусто. - -### checkActivation -Включает проверку активации учетной записи пользователя (см. "Активация учетных записей"). При этом после сохранения записи будет установлено поле activate.url, содержащее ссылку на страницу с вызовом сниппета для активации учетной записи. - -Возможные значения - 1 или 0. - -Значение по умолчанию - 0. - -### activateTo -Если включена проверка активации, то в этом параметре необходимо указать id страницы, на которой вызывается сниппет для активации. - -Возможные значения - id страницы. - -Значение по умолчанию - значение $modx->config['site_start']. - -### uidName -Имя GET-параметра в ссылке для восстановления пароля, который содержит id пользователя. - -Значение по умолчанию - primary key для таблицы с пользователями. - -### preparePostProcess -Позволяет выполнить обработку данных после сохранения. - -Возможные значения - имена сниппетов, анонимные функции, статические методы загруженных классов. - -Значение по умолчанию - пусто. - -### redirectTo -Перенаправляет пользователя на указанную страницу после регистрации. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### exitTo -Перенаправляет уже авторизованного пользователя на указанную страницу. - -Возможные значения - id целевой страницы. - -Значение по умолчанию - пусто. - -### skipTpl -Шаблон сообщения для уже авторизованного пользователя. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Register с ключом [+register.default_skipTpl+] - -### successTpl -Шаблон сообщения об успешной регистрации. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Register с ключом [+register.default_successTpl+] - -### passwordLength -Длина пароля (если создается автоматически). - -Возможные значения - число символов больше 6. - -Значение по умолчанию - 6. diff --git "a/assets/snippets/FormLister/docs/ru/075_\320\220\320\272\321\202\320\270\320\262\320\260\321\206\320\270\321\217_\321\203\321\207\320\265\321\202\320\275\321\213\321\205_\320\267\320\260\320\277\320\270\321\201\320\265\320\271.md" "b/assets/snippets/FormLister/docs/ru/075_\320\220\320\272\321\202\320\270\320\262\320\260\321\206\320\270\321\217_\321\203\321\207\320\265\321\202\320\275\321\213\321\205_\320\267\320\260\320\277\320\270\321\201\320\265\320\271.md" deleted file mode 100755 index ee220f6804..0000000000 --- "a/assets/snippets/FormLister/docs/ru/075_\320\220\320\272\321\202\320\270\320\262\320\260\321\206\320\270\321\217_\321\203\321\207\320\265\321\202\320\275\321\213\321\205_\320\267\320\260\320\277\320\270\321\201\320\265\320\271.md" +++ /dev/null @@ -1,89 +0,0 @@ -## Активация учетных записей - -Контроллер Activate реализует активацию учетных записей. Таким образом появляется возможность требовать у пользователя подтверждение учетной записи путем перехода по специальной ссылке из письма, отправленного при регистрации. - -Если по какой-то причине пользователь не получил письмо, то c помощью контроллера Activate он может запросить его повторную отправку. - -Учетная запись пользователя считается неактивированной если в поле logincount записано -1. - -В вызовах сниппета для регистрации и авторизации пользователей должен присутствовать параметр &checkActivation=`1`. - -Поэтому если при регистрации пользователь указывал пароль самостоятельно, то обязательно нужно запрашивать пароль для отправки письма со ссылкой для активации. Иначе будет генерироваться новый пароль, потому что раз пользователь запрашивает письмо для активации вручную, значит письмо после регистрации он не получил и не знает созданный при регистрации пароль. - -В шаблонах доступны все поля модели для обрабатываемой записи. В шаблоне reportTpl задается поле user.password с незашифрованным паролем и поле activate.url со ссылкой для активации. - -## Параметры -### model -Класс для работы с пользователями. - -Возможные значения - имя класса. - -Значение по умолчанию - \modUsers - -### uidName -Имя GET-параметра в ссылке для активации, который содержит id пользователя. - -Значение по умолчанию - primary key для таблицы с пользователями. - -### modelPath -Путь к файлу класса для работы с пользователями. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modUsers.php - -### redirectTo -Перенаправляет пользователя на указанную страницу после активации. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### exitTo -Перенаправляет авторизованного пользователя на указанную страницу. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### skipTpl -Шаблон сообщения для авторизованного пользователя. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Register с ключом [+register.default_skipTpl+] - -### reportTpl -Шаблон письма с информацией для активации учетной записи. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. - -### reportTpl -Шаблон письма с информацией для активации учетной записи. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. - -### successTpl -Шаблон сообщения об успешной отправке письма с данными для активации. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Activate с ключом [+activate.default_successTpl+] - -### activateSuccessTpl -Шаблон сообщения об успешной активации. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Activate с ключом [+activate.default_activateSuccessTpl+] - -### passwordLength -Длина создаваемого пароля. - -Возможные значения - число символов больше 6. - -Значение по умолчанию - 6. diff --git "a/assets/snippets/FormLister/docs/ru/080_\320\240\320\265\320\264\320\260\320\272\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265_\320\277\321\200\320\276\321\204\320\270\320\273\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217.md" "b/assets/snippets/FormLister/docs/ru/080_\320\240\320\265\320\264\320\260\320\272\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265_\320\277\321\200\320\276\321\204\320\270\320\273\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217.md" deleted file mode 100755 index 1a6d503c7d..0000000000 --- "a/assets/snippets/FormLister/docs/ru/080_\320\240\320\265\320\264\320\260\320\272\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265_\320\277\321\200\320\276\321\204\320\270\320\273\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217.md" +++ /dev/null @@ -1,99 +0,0 @@ -## Редактирование профиля пользователя - -Контроллер Profile позволяет авторизованным пользователям редактировать свои профили, в том числе менять пароль. - -При изменении профиля следует проверять уникальность email. В контроллере предусмотрено соответствующее правило: -``` -&rules=`{ - "email":{ - "required":"Введите email", - "email":"Неверный email", - "custom":{ - "function":"\\FormLister\\Profile::uniqueEmail", - "message":"Этот email уже использует другой пользователь" - } - } -}` -``` -Аналогично с полем username: -``` -&rules=`{ - "username":{ - "required":"Введите имя пользователя", - "alphaNumeric":"Только буквы и цифры", - "custom":{ - "function":"\\FormLister\\Profile::uniqueUsername", - "message":"Имя уже занято" - } - } -}` -``` - -Если поле с паролем пустое, то пароль остается прежний. После изменения пароля пользователь должен авторизоваться с новым паролем. Новый пароль сохраняется в поле user.password. - - -## Параметры -### model -Класс для работы с пользователями. - -Возможные значения - имя класса. - -Значение по умолчанию - \modUsers - -### modelPath -Путь к файлу класса для работы с пользователями. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modUsers.php - -### allowedFields -Разрешенные для обработки поля. Поля, не указанные в списке, игнорируются. Если пользователь меняет пароль, то в разрешенные поля добавляется поле password. Если у пользователей совпадают поля e-mail и username, то при изменении e-mail будет изменено и поле username, если значение этого поля не задано. В этом случае поле username будет добавлено в список разрешенных. - -Если не задано, то разрешены все поля. - -Возможные значения - имена полей формы, разделенные запятой. - -Значение по умолчанию - пусто. - -### forbiddenFields -Запрещенные для обработки поля. Поля, указанные в списке, игнорируются. Поля password и username исключаются из списка по аналогии с allowedFields. - -Возможные значения - имена полей формы, разделенные запятой. - -Значение по умолчанию - пусто. - -### preparePostProcess -Позволяет выполнить обработку данных после сохранения. - -Возможные значения - имена сниппетов, анонимные функции, статические методы загруженных классов. - -Значение по умолчанию - пусто. - -### redirectTo -Перенаправляет пользователя на указанную страницу после сохранения профиля. - -Возможные значения - id целевой страницы. - -Значение по умолчанию - пусто. - -### exitTo -Перенаправляет неавторизованного пользователя на указанную страницу. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### skipTpl -Шаблон сообщения для неавторизованного пользователя. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Profile с ключом [+profile.default_skipTpl+] - -### successTpl -Шаблон сообщения об успешном обновлении профиля. Если не задан, то генерируется сообщение об успешном сохранении формы. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. diff --git "a/assets/snippets/FormLister/docs/ru/085_\320\243\320\264\320\260\320\273\320\265\320\275\320\270\320\265_\320\277\321\200\320\276\321\204\320\270\320\273\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217.md" "b/assets/snippets/FormLister/docs/ru/085_\320\243\320\264\320\260\320\273\320\265\320\275\320\270\320\265_\320\277\321\200\320\276\321\204\320\270\320\273\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217.md" deleted file mode 100755 index bfe4041476..0000000000 --- "a/assets/snippets/FormLister/docs/ru/085_\320\243\320\264\320\260\320\273\320\265\320\275\320\270\320\265_\320\277\321\200\320\276\321\204\320\270\320\273\321\217_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217.md" +++ /dev/null @@ -1,50 +0,0 @@ -## Удаление профиля пользователя - -Контроллер DeleteUser позволяет авторизованным пользователям удалять свои профили. Для подтверждения действия пользователю необходимо ввести свой пароль. - -Расширяет Form. - -В шаблонах доступны поля модели для удаляемой записи. - -## Параметры -### model -Класс для работы с пользователями. - -Возможные значения - имя класса. - -Значение по умолчанию - \modUsers - -### modelPath -Путь к файлу класса для работы с пользователями. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modUsers.php - -### redirectTo -Перенаправляет пользователя на указанную страницу после сохранения профиля. - -Возможные значения - id целевой страницы. - -Значение по умолчанию - пусто. - -### exitTo -Перенаправляет неавторизованного пользователя на указанную страницу. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### skipTpl -Шаблон сообщения для неавторизованного пользователя. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона deleteUser с ключом [+deleteUser.default_skipTpl+] - -### successTpl -Шаблон сообщения об успешном удалении профиля. Если не задан, то генерируется сообщение об успешном сохранении формы. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. diff --git "a/assets/snippets/FormLister/docs/ru/090_\320\222\320\276\321\201\321\201\321\202\320\260\320\275\320\276\320\262\320\273\320\265\320\275\320\270\320\265_\320\277\320\260\321\200\320\276\320\273\320\265\320\271_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217\320\274\320\270.md" "b/assets/snippets/FormLister/docs/ru/090_\320\222\320\276\321\201\321\201\321\202\320\260\320\275\320\276\320\262\320\273\320\265\320\275\320\270\320\265_\320\277\320\260\321\200\320\276\320\273\320\265\320\271_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217\320\274\320\270.md" deleted file mode 100755 index 6a4c13828c..0000000000 --- "a/assets/snippets/FormLister/docs/ru/090_\320\222\320\276\321\201\321\201\321\202\320\260\320\275\320\276\320\262\320\273\320\265\320\275\320\270\320\265_\320\277\320\260\321\200\320\276\320\273\320\265\320\271_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217\320\274\320\270.md" +++ /dev/null @@ -1,148 +0,0 @@ -## Восстановление паролей пользователями - -Контроллер Reminder позволяет web-пользователям восстанавливать забытые пароли. Расширяет контроллер Form. - -Восстановление паролей происходит по следующей схеме: - -- пользователь вводит в форме свой идентификатор (им может быть имя пользователя или email); -- пользователь получает письмо, в котором содержится ссылка для восстановления; -- при переходе по ссылке пользователь получает возможность ввести новый пароль либо пароль будет сгенерирован автоматически; -- пользователю отправляется письмо с новым паролем и показыается сообщение (в сообщении можно также вывести новый пароль). - -Параметр to перезаписывается значением email пользователя. Обязательно должен быть задан параметр resetTo. - -## Параметры -### model -Класс для работы с пользователями. - -Возможные значения - имя класса. - -Значение по умолчанию - \modUsers - -### modelPath -Путь к файлу класса для работы с пользователями. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modUsers.php - -### hashField -Имя поля для хранения хэша данных пользователя. - -Значение по умолчанию - hash. - -### userField -Имя поля для хранения уникального идентификатора пользователя (имя пользователя или email). - -Значение по умолчанию - email. - -### uidField -Имя поля, которое содержит числовой идентификатор пользователя (Primary Key в таблице БД). - -Значение по умолчанию - id. - -### uidName -Имя GET-параметра в ссылке для восстановления пароля, который содержит id пользователя. - -Значение по умолчанию - значение параметра uidField. - -### exitTo -Перенаправляет авторизованного пользователя на указанную страницу. - -Возможные значения - id целевой страницы. - -Значение по умолчанию - пусто. - -### resetTo -Страница, на которую будет указывать ссылка для восстановления паролей. - -Возможные значения - id целевой страницы. - -Значение по умолчанию - id документа, в котором вызван контроллер. - -### redirectTo -Перенаправляет на указанную страницу после успешного восстановления пароля. - -Возможные значения - id целевой страницы. - -Значение по умолчанию - пусто. - -### skipTpl -Шаблон сообщения для авторизованного пользователя. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Reminder с ключом [+reminder.default_skipTpl+]. - -### formTpl -Шаблон формы для ввода идентификатора пользователя. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. - -### resetTpl -Шаблон формы для ввода нового пароля. Если параметр не задан, то пароль будет сгенерирован автоматически. - -Поля для ввода паролей должны называться password и repeatPassword. В форме должны также присутствовать скрытые поля с именами из параметров uidField и hashField. Значение для поля hashField задается через плейсхолдер [+user.hash+], а для поля uidField - [+user.id+]. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. - -### successTpl -Шаблон сообщения об успешной отправке письма со ссылкой для восстановления пароля. В шаблоне можно выводить плейсхолдеры с данными пользователя (username, email и т.д.). - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Reminder с ключом [+reminder.default_successTpl+]. - -### resetSuccessTpl -Шаблон сообщения об успешном восстановлении пароля. В шаблоне можно выводить плейсхолдеры с данными пользователя (username, email и т.д.), а также новый пароль (newpassword). - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Reminder с ключом [+reminder.default_resetSuccessTpl+]. - -### reportTpl -Шаблон письма со ссылкой для восстановления пароля. В шаблоне можно выводить плейсхолдеры с данными пользователя (username, email и т.д.), а также новый пароль (newpassword). Ссылка для восстановлени пароля в письме задается через плейсхолдер [+reset.url+] - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Reminder с ключом [+reminder.default_reportTpl+].. - -### resetReportTpl -Шаблон письма об успешном восстановлении пароля. В шаблоне можно выводить плейсхолдеры с данными пользователя (username, email и т.д.), а также новый пароль (newpassword). Если не задан, то письмо пользователю отправляться не будет. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. - -### rules -Правила валидации для формы идентификации пользователя. - -Возможные значения - см. раздел "Валидация данных". - -Значение по умолчанию - пусто. - -### resetRules -Правила валидации для формы установки нового пароля. Если заданы правила валидации для полей password и repeatPassword, то при наличии для поля repeatPassword правила equals, оно будет автоматически скорректировано для проверки равенства значений полей password и repeatPassword: -``` -"repeatPassword":{ - "required":"Введите пароль еще раз", - "equals":{ - "params" : "Этот ключ в описании правила можно не задавать, он будет сформирован контроллером автоматически", - "message":"Пароли не совпадают" - } -} -``` -Возможные значения - см. раздел "Валидация данных". - -Значение по умолчанию - пусто. - -### passwordLength -Длина пароля (если создается автоматически). - -Возможные значения - число символов больше 6. - -Значение по умолчанию - 6. diff --git "a/assets/snippets/FormLister/docs/ru/100_\320\241\320\276\320\267\320\264\320\260\320\275\320\270\320\265_\320\270_\321\200\320\265\320\264\320\260\320\272\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265_\320\264\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\276\320\262_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217\320\274\320\270.md" "b/assets/snippets/FormLister/docs/ru/100_\320\241\320\276\320\267\320\264\320\260\320\275\320\270\320\265_\320\270_\321\200\320\265\320\264\320\260\320\272\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265_\320\264\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\276\320\262_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217\320\274\320\270.md" deleted file mode 100755 index d383e93f47..0000000000 --- "a/assets/snippets/FormLister/docs/ru/100_\320\241\320\276\320\267\320\264\320\260\320\275\320\270\320\265_\320\270_\321\200\320\265\320\264\320\260\320\272\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265_\320\264\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\276\320\262_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217\320\274\320\270.md" +++ /dev/null @@ -1,166 +0,0 @@ -## Создание и редактирование документов пользователями - -Контроллер Content позволяет web-пользователям создавать и редактировать записи в таблицах MODxAPI. Расширяет контроллер Form, что позволяет отправлять письма после создания записи. При редактировании записей отправка почты отключена, при необходимости ее можно реализовать с помощью плагинов на событие сохранения (OnDocFormSave и т.п.). - -Данные формы передаются в объект MODxAPI как есть, соответственно разработчику нужно заботиться об их корректности самостоятельно. - -При редактировании записей можно запретить изменение отдельных полей, используя параметр keepDefaults. - -При создании новой записи вызывается событие OnMakeDocUrl, в которое передается id записи и массив data со значениями полей записи. Это позволяет вернуть ссылку на созданную запись, она будет доступна через плейсхолдер [+content.url+]. Ссылку можно использовать в письме c уведомлением о создании новой записи. - -Также можно использовать данные авторизованного пользователя, доступны через плейсхолдеры [+user.fullname+], [+user.email+] и т.д. - -## Параметры -### model -Класс MODxAPI. - -Возможные значения - имя класса MODxAPI. - -Значение по умолчанию - \modResource. - -### modelPath -Путь к файлу класса, если класс не загружается заранее. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modResource.php. - -### userModel -Класс для работы с пользователями. - -Возможные значения - имя класса. - -Значение по умолчанию - \modUsers - -### userModelPath -Путь к файлу класса для работы с пользователями. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modUsers.php - -### onlyUsers -Разрешить добавление записей только для зарегистрированных пользователей. - -Возможные значения - 0, 1. - -Значение по умолчанию - 1. - -### userGroups -Группы пользователей, которым разрешено добавлять или изменять записи. - -Возможные значения - список групп через точку с запятой. - -Значение по умолчанию - пусто (разрешены любые группы). - -### onlyOwners -Разрешает редактирование записей только их авторами. Автор определяется по полю, указанному в параметре ownerField. - -Возможные значения - 0, 1. - -Значение по умолчанию - 1. - -### ownerField -Имя поля, определяющего владельца записи. Если работать с документами modResource, то это будет имя tv-параметра (в Evo не предусмотрено создание записей веб-пользователями). - -Возможные значения - имя поля. - -Значение по умолчанию - aid. - -### idField -Имя ключа массива $_REQUEST, по которому определяется id редактируемой записи. Если ключ не задан, то контроллер вызывается в режиме создания записей. Информацию о режиме контроллера можно получить с помощью метода getMode. - -В форме редактирования нужно предусмотреть скрытое поле с именем параметра, в котором будет сохраняться id записи. - -Значение по умолчанию - id. - -### contentFields -Задает сопоставление полей MODxAPI и полей формы. Можно не задавать, если имена полей совпадают. Если параметр не задан, то ограничить список передаваемых в модель полей можно с помощью параметров allowedFields и forbiddenFields. - -Возможные значения - массив вида: -``` -&contentFields=`{ - "поле MODxAPI":"поле формы", - "поле MODxAPI":"поле формы" -} -` -``` -Значение по умолчанию - пусто. - -### clearCache -Очищать кэш после сохранения записи. - -Возможные значения - 0, 1. - -Значение по умолчанию - 0. - -### redirectTo -Перенаправляет пользователя на указанную страницу после сохранения новой записи. В режиме редактирования не используется. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### editAfterCreate -Переправляет пользователя на страницу для редактирования созданной записи. Страница указывается в параметре redirectTo. - -Возможные значения - 1 или 0. - -Значение по умолчанию - 0. - -### editTpl -Шаблон формы для редактирования документа. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - значение параметра formTpl. - -### badOwnerTpl -Шаблон сообщения о том, что пользователь не является автором документа. Только режим редактирования. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Content с ключом [+edit.default_badOwnerTpl+]. - -### badGroupTpl, badGroupEditTpl -Шаблон сообщения о том, что пользователь не входит в группу пользователей которым разрешено создавать и редактировать документы. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Content с ключом -[+create.default_badGroupTpl+] или [+edit.default_badGroupTpl+]. - -### badRecordTpl -Шаблон сообщения о том, что пользователь не может редактировать запись: например, запись не существует. Только режим редактирования. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Content с ключом [+edit.default_badRecordTpl+]. - -### exitTo -Перенаправляет неавторизованного пользователя на указанную страницу. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### skipTpl, skipEditTpl -Шаблон сообщения для неавторизованного пользователя. Для режима редактирования - skipEditTpl. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Content с ключом [+create.default_skipTpl+] (edit.default_skipEditTpl). - -### successTpl -Шаблон сообщения об успешном сохранении новой записи. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона Content с ключом [+create.default_successTpl+] - -### editSuccessTpl -Шаблон сообщения об успешном обновлении записи. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - пусто. diff --git "a/assets/snippets/FormLister/docs/ru/105_\320\243\320\264\320\260\320\273\320\265\320\275\320\270\320\265_\320\264\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\276\320\262_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217\320\274\320\270.md" "b/assets/snippets/FormLister/docs/ru/105_\320\243\320\264\320\260\320\273\320\265\320\275\320\270\320\265_\320\264\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\276\320\262_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217\320\274\320\270.md" deleted file mode 100755 index 7cddeb4ad3..0000000000 --- "a/assets/snippets/FormLister/docs/ru/105_\320\243\320\264\320\260\320\273\320\265\320\275\320\270\320\265_\320\264\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\276\320\262_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217\320\274\320\270.md" +++ /dev/null @@ -1,97 +0,0 @@ -## Удаление профиля пользователя - -Контроллер DeleteContent позволяет авторизованным пользователям удалять созданные ими документы. - -Расширяет Form. - -В шаблонах доступны поля модели для удаляемой записи. Информация о пользователе доступна в полях с префиксом user (user.fullname, user.email и т.д.) - -## Параметры -### model -Класс MODxAPI. - -Возможные значения - имя класса MODxAPI. - -Значение по умолчанию - \modResource. - -### modelPath -Путь к файлу класса, если класс не загружается заранее. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modResource.php. - -### userModel -Класс для работы с пользователями. - -Возможные значения - имя класса. - -Значение по умолчанию - \modUsers - -### userModelPath -Путь к файлу класса для работы с пользователями. - -Возможные значения - относительный путь к файлу. - -Значение по умолчанию - assets/lib/MODxAPI/modUsers.php - -### ownerField -Имя поля, определяющего владельца записи. Если работать с документами modResource, то это будет имя tv-параметра (в Evo не предусмотрено создание записей веб-пользователями). - -Возможные значения - имя поля. - -Значение по умолчанию - aid. - -### idField -Имя ключа массива $_REQUEST, по которому определяется id удаляемой записи. - -Значение по умолчанию - id. - -### redirectTo -Перенаправляет пользователя на указанную страницу после удаления записи. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### badOwnerTpl -Шаблон сообщения о том, что пользователь не является автором документа. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона deleteContent с ключом [+deleteContent.default_badOwnerTpl+]. - -### badRecordTpl -Шаблон сообщения о том, что пользователь не может удалить запись: например, запись не существует. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона deleteContent с ключом [+deleteContent.default_badRecordTpl+]. - -### skipTpl -Шаблон сообщения для неавторизованного пользователя. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона deleteContent с ключом [+deleteContent.default_skipTpl+]. - -### successTpl -Шаблон сообщения об успешном сохранении новой записи. - -Возможные значения - имя шаблона, указанное по правилам задания шаблонов в DocLister. - -Значение по умолчанию - запись из лексикона deleteContent с ключом [+deleteContent.default_successTpl+] - -### exitTo -Перенаправляет неавторизованного пользователя на указанную страницу. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. - -### badRecordTo -Перенаправление, если невозможно удалить запись. - -Возможные значения - id целевой страницы или массив. - -Значение по умолчанию - пусто. diff --git "a/assets/snippets/FormLister/docs/ru/110_\320\233\320\265\320\272\321\201\320\270\320\272\320\276\320\275\321\213.md" "b/assets/snippets/FormLister/docs/ru/110_\320\233\320\265\320\272\321\201\320\270\320\272\320\276\320\275\321\213.md" deleted file mode 100644 index fbb6ee3e31..0000000000 --- "a/assets/snippets/FormLister/docs/ru/110_\320\233\320\265\320\272\321\201\320\270\320\272\320\276\320\275\321\213.md" +++ /dev/null @@ -1,32 +0,0 @@ -## Лексиконы - -Для использования лексиконов необходимо создать папку с полным названием языка (russian-UTF8, english и т.д.), в ней создать файл название_лексикона.inc.php: -``` - -``` -Для загрузки лексиконов при вызове сниппета следует указать параметры: - -* langDir - путь к папке с лексиконами; -* lang - язык лексикона (если не указано, то используется параметр конфигурации manager_language); -* lexicon - название лексикона, можно указать несколько названий через запятую. Также можно задать значения непосредственно в параметре: -``` -&lexicon=`{ - "english":{ - "test":"Test lexicon value", - "foo":"Another lexicon value", - "bar":"And one more value" - }, - "russian-UTF8":{ - "test":"Проверка", - "foo":"Еще проверка", - "bar":"И еще" - } -}` -``` - -После этого в шаблонах можно использовать плейсхолдеры [%ключ%] для подстановки значений из загруженных языковых файлов. Кроме того поддерживаются лексиконы компонента EvoBabel. diff --git a/assets/snippets/FormLister/lib/FileValidator.php b/assets/snippets/FormLister/lib/FileValidator.php index 5576b64ee3..315a459c02 100644 --- a/assets/snippets/FormLister/lib/FileValidator.php +++ b/assets/snippets/FormLister/lib/FileValidator.php @@ -66,7 +66,7 @@ public static function allowed($value, $allowed) if ($file['error'] === 4) { $flag = true; } else { - $ext = strtolower(array_pop(explode('.', $file['name']))); + $ext = strtolower(substr(strrchr($file['name'], '.'), 1)); $flag = in_array($ext, $allowed); if (!$flag) { break; diff --git a/assets/snippets/FormLister/lib/Filters.php b/assets/snippets/FormLister/lib/Filters.php new file mode 100644 index 0000000000..d5b56a7e40 --- /dev/null +++ b/assets/snippets/FormLister/lib/Filters.php @@ -0,0 +1,173 @@ +cfg, 'langDir', 'lang/') : MODX_BASE_PATH . $langDir; if (empty($lang)) { - $lang = \APIhelpers::getkey($this->cfg, 'lang', $this->modx->config['manager_language']); + $lang = \APIhelpers::getkey($this->cfg, 'lang', $this->modx->getConfig('manager_language')); } if (is_scalar($name) && !empty($name)) { @@ -70,7 +70,7 @@ private function loadLangFile($name = 'core', $lang = '', $langDir = '') */ public function fromArray($lang) { - $language = \APIhelpers::getkey($this->cfg, 'lang', $this->modx->config['manager_language']); + $language = \APIhelpers::getkey($this->cfg, 'lang', $this->modx->getConfig('manager_language')); if (is_array($lang) && isset($lang[$language])) { $this->_lang = array_merge($this->_lang, $lang[$language]); } diff --git a/assets/snippets/FormLister/lib/Validator.php b/assets/snippets/FormLister/lib/Validator.php index f865b6feb0..6103622c55 100644 --- a/assets/snippets/FormLister/lib/Validator.php +++ b/assets/snippets/FormLister/lib/Validator.php @@ -113,7 +113,6 @@ public static function alpha($value) */ public static function numeric($value) { - var_dump($value); return (bool) is_scalar($value) && preg_match('#^[0-9]*$#',$value); } diff --git a/assets/snippets/FormLister/lib/captcha/modxCaptcha/connector.php b/assets/snippets/FormLister/lib/captcha/modxCaptcha/connector.php old mode 100755 new mode 100644 index 0348084c1b..f7db012953 --- a/assets/snippets/FormLister/lib/captcha/modxCaptcha/connector.php +++ b/assets/snippets/FormLister/lib/captcha/modxCaptcha/connector.php @@ -6,7 +6,7 @@ if (empty ($modx->config)) { $modx->getSettings(); } -if(strstr($_SERVER['HTTP_REFERER'],$modx->config['site_url']) === false || !isset($_REQUEST['formid'])) throw new Exception('Wrong captcha request'); +if(strstr($_SERVER['HTTP_REFERER'],$modx->getConfig('site_url')) === false || !isset($_REQUEST['formid'])) throw new Exception('Wrong captcha request'); $formid = (string) $_REQUEST['formid']; include_once ('modxCaptcha.php'); $width = isset($_REQUEST['w']) ? (int) $_REQUEST['w'] : 200; diff --git a/assets/snippets/FormLister/lib/captcha/modxCaptcha/modxCaptcha.php b/assets/snippets/FormLister/lib/captcha/modxCaptcha/modxCaptcha.php old mode 100755 new mode 100644 index 186529883a..e2c79eb655 --- a/assets/snippets/FormLister/lib/captcha/modxCaptcha/modxCaptcha.php +++ b/assets/snippets/FormLister/lib/captcha/modxCaptcha/modxCaptcha.php @@ -11,9 +11,9 @@ class ModxCaptcha protected $modx = null; /* path to font directory*/ - protected $dir_font = "ttf/"; + protected $dir_font = "/ttf/"; /* path to background image directory*/ - protected $dir_noise = "noises/"; + protected $dir_noise = "/noises/"; public $word = ""; protected $im = null; protected $im_width = 0; @@ -28,8 +28,8 @@ class ModxCaptcha public function __construct(DocumentParser $modx, $width = 200, $height = 160) { $this->modx = $modx; - $this->dir_font = MODX_MANAGER_PATH . 'includes/' . $this->dir_font; - $this->dir_noise = MODX_MANAGER_PATH . 'includes/' . $this->dir_noise; + $this->dir_font = __DIR__ . $this->dir_font; + $this->dir_noise = __DIR__ . $this->dir_noise; $this->im_width = $width; $this->im_height = $height; $this->word = $this->pickWord(); @@ -64,7 +64,7 @@ public function pickWord() { // set default words $words = "MODX,Access,Better,BitCode,Chunk,Cache,Desc,Design,Excell,Enjoy,URLs,TechView,Gerald,Griff,Humphrey,Holiday,Intel,Integration,Joystick,Join(),Oscope,Genetic,Light,Likeness,Marit,Maaike,Niche,Netherlands,Ordinance,Oscillo,Parser,Phusion,Query,Question,Regalia,Righteous,Snippet,Sentinel,Template,Thespian,Unity,Enterprise,Verily,Veri,Website,WideWeb,Yap,Yellow,Zebra,Zygote"; - $words = $this->modx->config['captcha_words'] ? $this->modx->config['captcha_words'] : $words; + $words = $this->modx->getConfig('captcha_words') ? $this->modx->getConfig('captcha_words') : $words; $words = str_replace(array(' ', ',,'), array('', ','), $words); $arr_words = explode(',', $words); diff --git a/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/index.html b/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/index.html new file mode 100644 index 0000000000..cfb7d0fe18 --- /dev/null +++ b/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/index.html @@ -0,0 +1,2 @@ +

        Unauthorized access

        +You're not allowed to access file folder \ No newline at end of file diff --git a/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise1.jpg b/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise1.jpg new file mode 100644 index 0000000000..59a06d65cd Binary files /dev/null and b/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise1.jpg differ diff --git a/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise2.jpg b/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise2.jpg new file mode 100644 index 0000000000..22c6759d9e Binary files /dev/null and b/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise2.jpg differ diff --git a/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise3.jpg b/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise3.jpg new file mode 100644 index 0000000000..4d26d3ae23 Binary files /dev/null and b/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise3.jpg differ diff --git a/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise4.jpg b/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise4.jpg new file mode 100644 index 0000000000..27d103cf3d Binary files /dev/null and b/assets/snippets/FormLister/lib/captcha/modxCaptcha/noises/noise4.jpg differ diff --git a/assets/snippets/FormLister/lib/captcha/modxCaptcha/ttf/ftb_____.ttf b/assets/snippets/FormLister/lib/captcha/modxCaptcha/ttf/ftb_____.ttf new file mode 100644 index 0000000000..ffe57f8b6d Binary files /dev/null and b/assets/snippets/FormLister/lib/captcha/modxCaptcha/ttf/ftb_____.ttf differ diff --git a/assets/snippets/FormLister/plugin.userHelper.php b/assets/snippets/FormLister/plugin.userHelper.php index 3b646abd79..a94f058fcb 100644 --- a/assets/snippets/FormLister/plugin.userHelper.php +++ b/assets/snippets/FormLister/plugin.userHelper.php @@ -7,7 +7,7 @@ */ $e = $modx->event; include_once(MODX_BASE_PATH . 'assets/lib/MODxAPI/modUsers.php'); -if ($e->name == 'OnWebAuthentication') { +if ($e->name == 'OnWebAuthentication' && isset($userObj)) { /** * @var modUsers $userObj */ @@ -21,7 +21,7 @@ $userObj->save(); } } -if ($e->name == 'OnWebLogin') { +if ($e->name == 'OnWebLogin' && isset($userObj)) { if (!$userObj->get('lastlogin')) { $userObj->set('lastlogin', time()); } else { @@ -38,9 +38,15 @@ if ($e->name == 'OnWebPageInit' || $e->name == 'OnPageNotFound') { $user = new \modUsers($modx); if ($uid = $modx->getLoginUserID('web')) { + if ($trackWebUserActivity == 'Yes') { + $sid = $modx->sid = session_id(); + $pageId = (int)$modx->documentIdentifier; + $q = $modx->db->query("REPLACE INTO {$modx->getFullTableName('active_users')} (`sid`, `internalKey`, `username`, `lasthit`, `action`, `id`) values('{$sid}',-{$uid}, '{$_SESSION['webShortname']}', '{$modx->time}', 998, {$pageId})"); + $modx->updateValidatedUserSession(); + } if (isset($_REQUEST[$logoutKey])) { $user->logOut($cookieName, true); - $page = $modx->config['site_url'] . (isset($_REQUEST['q']) ? $_REQUEST['q'] : ''); + $page = $modx->getConfig('site_url') . (isset($_REQUEST['q']) ? $_REQUEST['q'] : ''); $query = $_GET; unset($query[$logoutKey], $query['q']); if ($query) { diff --git a/assets/snippets/docinfo/snippet.docinfo.php b/assets/snippets/docinfo/snippet.docinfo.php index d843a3ed16..7d6b355d02 100755 --- a/assets/snippets/docinfo/snippet.docinfo.php +++ b/assets/snippets/docinfo/snippet.docinfo.php @@ -3,39 +3,69 @@ * DocInfo * * @category parser - * @version 0.3 + * @version 0.4.1 * @license GNU General Public License (GPL), http://www.gnu.org/copyleft/gpl.html * @param string $field Значение какого поля необходимо достать * @param int $docid ID документа + * @param int $templid ID шаблона документа + * @param int $limit Максимальная глубина вложенности для поиска по шаблону документа * @param int $tv является ли поле TV параметром (0 - нет || 1 - да) * @param int $render Преобразовывать ли значение TV параметра в соответствии с его визуальным компонентом * @return string Значение поля документа или его TV параметра * @author akool, Agel_Nash * - * @TODO getTemplateVarOutput не применяет визуальный компонент к TV параметрам у которых значение совпадает со значением по умолчанию - * + * @TODO getTemplateVarOutput не применяет визуальный компонент к TV параметрам у которых значение совпадает со + * значением по умолчанию + * * @example -* [[DocInfo? &docid=`15` &field=`pagetitle`]] -* [[DocInfo? &docid=`10` &field=`tvname`]] -* [[DocInfo? &docid=`3` &field=`tvname` &render=`1`]] -*/ -if(!defined('MODX_BASE_PATH')){die('What are you doing? Get out of here!');} -$default_field = array('type','contentType','pagetitle','longtitle','description','alias','link_attributes','published','pub_date','unpub_date','parent','isfolder','introtext','content','richtext','template','menuindex','searchable','cacheable','createdon','createdby','editedon','editedby','deleted','deletedon','deletedby','publishedon','publishedby','menutitle','donthit','privateweb','privatemgr','content_dispo','hidemenu','alias_visible'); -$docid = (isset($docid) && (int)$docid>0) ? (int)$docid : $modx->documentIdentifier; + * [[DocInfo? &docid=`15` &field=`pagetitle`]] + * [[DocInfo? &docid=`10` &field=`tvname`]] + * [[DocInfo? &docid=`3` &field=`tvname` &render=`1`]] + * [[DocInfo? &docid=`3` &templid=`2` &field=`tvname` &limit=`2`]] + */ +if (!defined('MODX_BASE_PATH')) { + die('What are you doing? Get out of here!'); +} +$default_field = array( + 'type', 'contentType', 'pagetitle', 'longtitle', 'description', 'alias', 'link_attributes', 'published', 'pub_date', + 'unpub_date', 'parent', 'isfolder', 'introtext', 'content', 'richtext', 'template', 'menuindex', 'searchable', + 'cacheable', 'createdon', 'createdby', 'editedon', 'editedby', 'deleted', 'deletedon', 'deletedby', 'publishedon', + 'publishedby', 'menutitle', 'donthit', 'privateweb', 'privatemgr', 'content_dispo', 'hidemenu', 'alias_visible' +); +$docid = (isset($docid) && (int)$docid > 0) ? (int)$docid : $modx->documentIdentifier; +$templid = isset($templid) ? (int)$templid : null; +$doc = array(); +if ($templid !== null && $templid >= 0) { + $doc['parent'] = $docid; + $limit = (isset($limit) && (int)$limit >= 0) ? (int)$limit : 10; + do { + $doc = $modx->getDocument($doc['parent'], 'id, parent, template'); + if ($doc === false) { + return ''; + } + if ($doc['template'] == (int)$templid) { + $docid = $doc['id']; + } + $limit--; + } while ($doc['template'] != (int)$templid && (int)$doc['parent'] > 0 && $limit >= 0); + if ($doc['template'] != (int)$templid) { + return ''; + } +} $field = (isset($field)) ? $field : 'pagetitle'; -$render = (isset($render)) ? $render : 0; +$render = (isset($render)) ? (bool)$render : false; $output = ''; if (in_array($field, $default_field)) { - $doc = $modx->getPageInfo($docid,'1',$field); + $doc = $modx->getPageInfo($docid, '1', $field); $output = $doc[$field]; -}else{ - if(isset($render) && 1==$render){ +} else { + if (isset($render) && true === $render) { $tv = $modx->getTemplateVarOutput($field, $docid); $output = $tv[$field]; - }else{ - $tv = $modx->getTemplateVar($field,'*',$docid); - $output = ($tv['value']!='') ? $tv['value'] : $tv['defaultText']; + } else { + $tv = $modx->getTemplateVar($field, '*', $docid); + $output = ($tv['value'] != '') ? $tv['value'] : $tv['defaultText']; } } + return $output; -?> \ No newline at end of file diff --git a/assets/snippets/phpthumb/phpthumb.bmp.php b/assets/snippets/phpthumb/phpthumb.bmp.php index 82d9ba3912..241d2ba96f 100755 --- a/assets/snippets/phpthumb/phpthumb.bmp.php +++ b/assets/snippets/phpthumb/phpthumb.bmp.php @@ -20,11 +20,7 @@ class phpthumb_bmp { - function __construct() { - return true; - } - - function phpthumb_bmp2gd(&$BMPdata, $truecolor=true) { + public function phpthumb_bmp2gd(&$BMPdata, $truecolor=true) { $ThisFileInfo = array(); if ($this->getid3_bmp($BMPdata, $ThisFileInfo, true, true)) { $gd = $this->PlotPixelsGD($ThisFileInfo['bmp'], $truecolor); @@ -33,7 +29,7 @@ function phpthumb_bmp2gd(&$BMPdata, $truecolor=true) { return false; } - function phpthumb_bmpfile2gd($filename, $truecolor=true) { + public function phpthumb_bmpfile2gd($filename, $truecolor=true) { if ($fp = @fopen($filename, 'rb')) { $BMPdata = fread($fp, filesize($filename)); fclose($fp); @@ -42,9 +38,9 @@ function phpthumb_bmpfile2gd($filename, $truecolor=true) { return false; } - function GD2BMPstring(&$gd_image) { - $imageX = ImageSX($gd_image); - $imageY = ImageSY($gd_image); + public function GD2BMPstring(&$gd_image) { + $imageX = imagesx($gd_image); + $imageY = imagesy($gd_image); $BMP = ''; for ($y = ($imageY - 1); $y >= 0; $y--) { @@ -83,13 +79,13 @@ function GD2BMPstring(&$gd_image) { return $BITMAPFILEHEADER.$BITMAPINFOHEADER.$BMP; } - function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractData=false) { + public function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractData=false) { - // shortcuts - $ThisFileInfo['bmp']['header']['raw'] = array(); - $thisfile_bmp = &$ThisFileInfo['bmp']; - $thisfile_bmp_header = &$thisfile_bmp['header']; - $thisfile_bmp_header_raw = &$thisfile_bmp_header['raw']; + // shortcuts + $ThisFileInfo['bmp']['header']['raw'] = array(); + $thisfile_bmp = &$ThisFileInfo['bmp']; + $thisfile_bmp_header = &$thisfile_bmp['header']; + $thisfile_bmp_header_raw = &$thisfile_bmp_header['raw']; // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp // all versions @@ -108,7 +104,7 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa $offset += 2; if ($thisfile_bmp_header_raw['identifier'] != 'BM') { - $ThisFileInfo['error'][] = 'Expecting "BM" at offset '.intval(@$ThisFileInfo['avdataoffset']).', found "'.$thisfile_bmp_header_raw['identifier'].'"'; + $ThisFileInfo['error'][] = 'Expecting "BM" at offset '. (int) (@$ThisFileInfo[ 'avdataoffset']) .', found "'. $thisfile_bmp_header_raw[ 'identifier'].'"'; unset($ThisFileInfo['fileformat']); unset($ThisFileInfo['bmp']); return false; @@ -252,9 +248,9 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa // DWORD biClrUsed; // DWORD biClrImportant; - $thisfile_bmp_header_raw['width'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $thisfile_bmp_header_raw['width'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4)); $offset += 4; - $thisfile_bmp_header_raw['height'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $thisfile_bmp_header_raw['height'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4)); $offset += 4; $thisfile_bmp_header_raw['planes'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 2)); $offset += 2; @@ -264,9 +260,9 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa $offset += 4; $thisfile_bmp_header_raw['bmp_data_size'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4)); $offset += 4; - $thisfile_bmp_header_raw['resolution_h'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $thisfile_bmp_header_raw['resolution_h'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4)); $offset += 4; - $thisfile_bmp_header_raw['resolution_v'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $thisfile_bmp_header_raw['resolution_v'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4)); $offset += 4; $thisfile_bmp_header_raw['colors_used'] = $this->LittleEndian2Int(substr($BMPheader, $offset, 4)); $offset += 4; @@ -368,21 +364,21 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa // BYTE rgbGreen; // BYTE rgbRed; // BYTE rgbReserved; - $blue = $this->LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); - $green = $this->LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); - $red = $this->LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); + $blue = $this->LittleEndian2Int($BMPpalette[ $paletteoffset++ ]); + $green = $this->LittleEndian2Int($BMPpalette[ $paletteoffset++ ]); + $red = $this->LittleEndian2Int($BMPpalette[ $paletteoffset++ ]); if (($thisfile_bmp['type_os'] == 'OS/2') && ($thisfile_bmp['type_version'] == 1)) { // no padding byte } else { $paletteoffset++; // padding byte } - $thisfile_bmp['palette'][$i] = (($red << 16) | ($green << 8) | ($blue)); + $thisfile_bmp['palette'][$i] = (($red << 16) | ($green << 8) | $blue); } } } if ($ExtractData) { - $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry + $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundary $BMPpixelData = substr($BMPdata, $thisfile_bmp_header_raw['data_offset'], $thisfile_bmp_header_raw['height'] * $RowByteLength); $overalloffset = $thisfile_bmp_header_raw['data_offset'] + ($thisfile_bmp_header_raw['height'] * $RowByteLength); @@ -481,8 +477,8 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa case 8: $pixelcounter = 0; while ($pixeldataoffset < strlen($BMPpixelData)) { - $firstbyte = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $secondbyte = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $firstbyte = $this->LittleEndian2Int($BMPpixelData[ $pixeldataoffset++ ]); + $secondbyte = $this->LittleEndian2Int($BMPpixelData[ $pixeldataoffset++ ]); if ($firstbyte == 0) { // escaped/absolute mode - the first byte of the pair can be set to zero to @@ -503,8 +499,8 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa // delta - The 2 bytes following the escape contain unsigned values // indicating the horizontal and vertical offsets of the next pixel // from the current position. - $colincrement = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $rowincrement = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $colincrement = $this->LittleEndian2Int($BMPpixelData[ $pixeldataoffset++ ]); + $rowincrement = $this->LittleEndian2Int($BMPpixelData[ $pixeldataoffset++ ]); $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; @@ -516,7 +512,7 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa // number of bytes that follow, each of which contains the color index // of a single pixel. Each run must be aligned on a word boundary. for ($i = 0; $i < $secondbyte; $i++) { - $paletteindex = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $paletteindex = $this->LittleEndian2Int($BMPpixelData[ $pixeldataoffset++ ]); $col = $pixelcounter % $thisfile_bmp_header_raw['width']; $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; @@ -557,8 +553,8 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa case 4: $pixelcounter = 0; while ($pixeldataoffset < strlen($BMPpixelData)) { - $firstbyte = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $secondbyte = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $firstbyte = $this->LittleEndian2Int($BMPpixelData[ $pixeldataoffset++ ]); + $secondbyte = $this->LittleEndian2Int($BMPpixelData[ $pixeldataoffset++ ]); if ($firstbyte == 0) { // escaped/absolute mode - the first byte of the pair can be set to zero to @@ -579,8 +575,8 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa // delta - The 2 bytes following the escape contain unsigned values // indicating the horizontal and vertical offsets of the next pixel // from the current position. - $colincrement = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $rowincrement = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $colincrement = $this->LittleEndian2Int($BMPpixelData[ $pixeldataoffset++ ]); + $rowincrement = $this->LittleEndian2Int($BMPpixelData[ $pixeldataoffset++ ]); $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; @@ -591,9 +587,9 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa // of color indexes that follow. Subsequent bytes contain color indexes in their // high- and low-order 4 bits, one color index for each pixel. In absolute mode, // each run must be aligned on a word boundary. - unset($paletteindexes); - for ($i = 0; $i < ceil($secondbyte / 2); $i++) { - $paletteindexbyte = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $paletteindexes = array(); + for ($i = 0, $iMax = ceil($secondbyte / 2); $i < $iMax; $i++) { + $paletteindexbyte = $this->LittleEndian2Int($BMPpixelData[ $pixeldataoffset++ ]); $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4; $paletteindexes[] = ($paletteindexbyte & 0x0F); } @@ -625,7 +621,7 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa for ($i = 0; $i < $firstbyte; $i++) { $col = $pixelcounter % $thisfile_bmp_header_raw['width']; $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[($i % 2)]]; + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][ $paletteindexes[ $i % 2 ]]; $pixelcounter++; } @@ -665,10 +661,10 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa $pixelvalue = $this->LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8)); $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8; - $red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255)); - $green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255)); - $blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255)); - $thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue)); + $red = (int) round(((($pixelvalue & $thisfile_bmp_header_raw[ 'red_mask']) >> $redshift) / ($thisfile_bmp_header_raw[ 'red_mask'] >> $redshift)) * 255); + $green = (int) round(((($pixelvalue & $thisfile_bmp_header_raw[ 'green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw[ 'green_mask'] >> $greenshift)) * 255); + $blue = (int) round(((($pixelvalue & $thisfile_bmp_header_raw[ 'blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw[ 'blue_mask'] >> $blueshift)) * 255); + $thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | $blue); } while (($pixeldataoffset % 4) != 0) { // lines are padded to nearest DWORD @@ -693,36 +689,36 @@ function getid3_bmp(&$BMPdata, &$ThisFileInfo, $ExtractPalette=false, $ExtractDa return true; } - function IntColor2RGB($color) { + public function IntColor2RGB($color) { $red = ($color & 0x00FF0000) >> 16; $green = ($color & 0x0000FF00) >> 8; $blue = ($color & 0x000000FF); return array($red, $green, $blue); } - function PlotPixelsGD(&$BMPdata, $truecolor=true) { + public function PlotPixelsGD(&$BMPdata, $truecolor=true) { $imagewidth = $BMPdata['header']['raw']['width']; $imageheight = $BMPdata['header']['raw']['height']; if ($truecolor) { - $gd = @ImageCreateTrueColor($imagewidth, $imageheight); + $gd = @imagecreatetruecolor($imagewidth, $imageheight); } else { - $gd = @ImageCreate($imagewidth, $imageheight); + $gd = @imagecreate($imagewidth, $imageheight); if (!empty($BMPdata['palette'])) { // create GD palette from BMP palette foreach ($BMPdata['palette'] as $dummy => $color) { list($r, $g, $b) = $this->IntColor2RGB($color); - ImageColorAllocate($gd, $r, $g, $b); + imagecolorallocate($gd, $r, $g, $b); } } else { // create 216-color websafe palette for ($r = 0x00; $r <= 0xFF; $r += 0x33) { for ($g = 0x00; $g <= 0xFF; $g += 0x33) { for ($b = 0x00; $b <= 0xFF; $b += 0x33) { - ImageColorAllocate($gd, $r, $g, $b); + imagecolorallocate($gd, $r, $g, $b); } } } @@ -740,40 +736,38 @@ function PlotPixelsGD(&$BMPdata, $truecolor=true) { foreach ($colarray as $col => $color) { list($red, $green, $blue) = $this->IntColor2RGB($color); if ($truecolor) { - $pixelcolor = ImageColorAllocate($gd, $red, $green, $blue); + $pixelcolor = imagecolorallocate($gd, $red, $green, $blue); } else { - $pixelcolor = ImageColorClosest($gd, $red, $green, $blue); + $pixelcolor = imagecolorclosest($gd, $red, $green, $blue); } - ImageSetPixel($gd, $col, $row, $pixelcolor); + imagesetpixel($gd, $col, $row, $pixelcolor); } } return $gd; } - function PlotBMP(&$BMPinfo) { + public function PlotBMP(&$BMPinfo) { $starttime = time(); if (!isset($BMPinfo['bmp']['data']) || !is_array($BMPinfo['bmp']['data'])) { echo 'ERROR: no pixel data
        '; return false; } if (!phpthumb_functions::FunctionIsDisabled('set_time_limit')) { - set_time_limit(intval(round($BMPinfo['resolution_x'] * $BMPinfo['resolution_y'] / 10000))); + set_time_limit((int) round($BMPinfo[ 'resolution_x'] * $BMPinfo[ 'resolution_y'] / 10000)); } $im = $this->PlotPixelsGD($BMPinfo['bmp']); if (headers_sent()) { echo 'plotted '.($BMPinfo['resolution_x'] * $BMPinfo['resolution_y']).' pixels in '.(time() - $starttime).' seconds
        '; - ImageDestroy($im); + imagedestroy($im); exit; - } else { - header('Content-Type: image/png'); - ImagePNG($im); - ImageDestroy($im); - return true; } - return false; + header('Content-Type: image/png'); + imagepng($im); + imagedestroy($im); + return true; } - function BMPcompressionWindowsLookup($compressionid) { + public function BMPcompressionWindowsLookup($compressionid) { static $BMPcompressionWindowsLookup = array( 0 => 'BI_RGB', 1 => 'BI_RLE8', @@ -785,7 +779,7 @@ function BMPcompressionWindowsLookup($compressionid) { return (isset($BMPcompressionWindowsLookup[$compressionid]) ? $BMPcompressionWindowsLookup[$compressionid] : 'invalid'); } - function BMPcompressionOS2Lookup($compressionid) { + public function BMPcompressionOS2Lookup($compressionid) { static $BMPcompressionOS2Lookup = array( 0 => 'BI_RGB', 1 => 'BI_RLE8', @@ -799,7 +793,7 @@ function BMPcompressionOS2Lookup($compressionid) { // from getid3.lib.php - function trunc($floatnumber) { + public function trunc($floatnumber) { // truncates a floating-point number at the decimal point // returns int (if possible, otherwise float) if ($floatnumber >= 1) { @@ -815,21 +809,21 @@ function trunc($floatnumber) { return $truncatednumber; } - function LittleEndian2Int($byteword) { + public function LittleEndian2Int($byteword) { $intvalue = 0; $byteword = strrev($byteword); $bytewordlen = strlen($byteword); for ($i = 0; $i < $bytewordlen; $i++) { - $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i)); + $intvalue += ord($byteword{$i}) * pow(256, $bytewordlen - 1 - $i); } return $intvalue; } - function BigEndian2Int($byteword) { + public function BigEndian2Int($byteword) { return $this->LittleEndian2Int(strrev($byteword)); } - function BigEndian2Bin($byteword) { + public function BigEndian2Bin($byteword) { $binvalue = ''; $bytewordlen = strlen($byteword); for ($i = 0; $i < $bytewordlen; $i++) { @@ -838,12 +832,12 @@ function BigEndian2Bin($byteword) { return $binvalue; } - function FixedPoint2_30($rawdata) { + public function FixedPoint2_30($rawdata) { $binarystring = $this->BigEndian2Bin($rawdata); return $this->Bin2Dec(substr($binarystring, 0, 2)) + (float) ($this->Bin2Dec(substr($binarystring, 2, 30)) / 1073741824); } - function Bin2Dec($binstring, $signed=false) { + public function Bin2Dec($binstring, $signed=false) { $signmult = 1; if ($signed) { if ($binstring{0} == '1') { @@ -852,13 +846,13 @@ function Bin2Dec($binstring, $signed=false) { $binstring = substr($binstring, 1); } $decvalue = 0; - for ($i = 0; $i < strlen($binstring); $i++) { - $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i); + for ($i = 0, $iMax = strlen($binstring); $i < $iMax; $i++) { + $decvalue += ((int) $binstring[ strlen($binstring) - $i - 1 ]) * pow(2, $i); } return $this->CastAsInt($decvalue * $signmult); } - function CastAsInt($floatnum) { + public function CastAsInt($floatnum) { // convert to float if not already $floatnum = (float) $floatnum; @@ -874,5 +868,3 @@ function CastAsInt($floatnum) { } } - -?> \ No newline at end of file diff --git a/assets/snippets/phpthumb/phpthumb.class.php b/assets/snippets/phpthumb/phpthumb.class.php index 41f0eb87d8..337b32826c 100755 --- a/assets/snippets/phpthumb/phpthumb.class.php +++ b/assets/snippets/phpthumb/phpthumb.class.php @@ -10,9 +10,9 @@ ////////////////////////////////////////////////////////////// ob_start(); -if (!include_once(dirname(__FILE__) . '/phpthumb.functions.php')) { +if (!include_once __DIR__ .'/phpthumb.functions.php' ) { ob_end_flush(); - die('failed to include_once("'.realpath(dirname(__FILE__).'/phpthumb.functions.php').'")'); + die('failed to include_once("'. __DIR__ .'/phpthumb.functions.php")'); } ob_end_clean(); @@ -21,44 +21,44 @@ class phpthumb { // public: // START PARAMETERS (for object mode and phpThumb.php) // See phpthumb.readme.txt for descriptions of what each of these values are - var $src = null; // SouRCe filename - var $new = null; // NEW image (phpThumb.php only) - var $w = null; // Width - var $h = null; // Height - var $wp = null; // Width (Portrait Images Only) - var $hp = null; // Height (Portrait Images Only) - var $wl = null; // Width (Landscape Images Only) - var $hl = null; // Height (Landscape Images Only) - var $ws = null; // Width (Square Images Only) - var $hs = null; // Height (Square Images Only) - var $f = null; // output image Format - var $q = 75; // jpeg output Quality - var $sx = null; // Source crop top-left X position - var $sy = null; // Source crop top-left Y position - var $sw = null; // Source crop Width - var $sh = null; // Source crop Height - var $zc = null; // Zoom Crop - var $bc = null; // Border Color - var $bg = null; // BackGround color - var $fltr = array(); // FiLTeRs - var $goto = null; // GO TO url after processing - var $err = null; // default ERRor image filename - var $xto = null; // extract eXif Thumbnail Only - var $ra = null; // Rotate by Angle - var $ar = null; // Auto Rotate - var $aoe = null; // Allow Output Enlargement - var $far = null; // Fixed Aspect Ratio - var $iar = null; // Ignore Aspect Ratio - var $maxb = null; // MAXimum Bytes - var $down = null; // DOWNload thumbnail filename - var $md5s = null; // MD5 hash of Source image - var $sfn = 0; // Source Frame Number - var $dpi = 150; // Dots Per Inch for vector source formats - var $sia = null; // Save Image As filename - - var $file = null; // >>>deprecated, DO NOT USE, will be removed in future versions<<< - - var $phpThumbDebug = null; + public $src = null; // SouRCe filename + public $new = null; // NEW image (phpThumb.php only) + public $w = null; // Width + public $h = null; // Height + public $wp = null; // Width (Portrait Images Only) + public $hp = null; // Height (Portrait Images Only) + public $wl = null; // Width (Landscape Images Only) + public $hl = null; // Height (Landscape Images Only) + public $ws = null; // Width (Square Images Only) + public $hs = null; // Height (Square Images Only) + public $f = null; // output image Format + public $q = 75; // jpeg output Quality + public $sx = null; // Source crop top-left X position + public $sy = null; // Source crop top-left Y position + public $sw = null; // Source crop Width + public $sh = null; // Source crop Height + public $zc = null; // Zoom Crop + public $bc = null; // Border Color + public $bg = null; // BackGround color + public $fltr = array(); // FiLTeRs + public $goto = null; // GO TO url after processing + public $err = null; // default ERRor image filename + public $xto = null; // extract eXif Thumbnail Only + public $ra = null; // Rotate by Angle + public $ar = null; // Auto Rotate + public $aoe = null; // Allow Output Enlargement + public $far = null; // Fixed Aspect Ratio + public $iar = null; // Ignore Aspect Ratio + public $maxb = null; // MAXimum Bytes + public $down = null; // DOWNload thumbnail filename + public $md5s = null; // MD5 hash of Source image + public $sfn = 0; // Source Frame Number + public $dpi = 150; // Dots Per Inch for vector source formats + public $sia = null; // Save Image As filename + + public $file = null; // >>>deprecated, DO NOT USE, will be removed in future versions<<< + + public $phpThumbDebug = null; // END PARAMETERS @@ -67,158 +67,181 @@ class phpthumb { // See phpThumb.config.php for descriptions of what each of these settings do // * Directory Configuration - var $config_cache_directory = null; - var $config_cache_directory_depth = 0; - var $config_cache_disable_warning = true; - var $config_cache_source_enabled = false; - var $config_cache_source_directory = null; - var $config_temp_directory = null; - var $config_document_root = null; + public $config_cache_directory = null; + public $config_cache_directory_depth = 0; + public $config_cache_disable_warning = true; + public $config_cache_source_enabled = false; + public $config_cache_source_directory = null; + public $config_temp_directory = null; + public $config_document_root = null; // * Default output configuration: - var $config_output_format = 'jpeg'; - var $config_output_maxwidth = 0; - var $config_output_maxheight = 0; - var $config_output_interlace = true; + public $config_output_format = 'jpeg'; + public $config_output_maxwidth = 0; + public $config_output_maxheight = 0; + public $config_output_interlace = true; // * Error message configuration - var $config_error_image_width = 400; - var $config_error_image_height = 100; - var $config_error_message_image_default = ''; - var $config_error_bgcolor = 'CCCCFF'; - var $config_error_textcolor = 'FF0000'; - var $config_error_fontsize = 1; - var $config_error_die_on_error = false; - var $config_error_silent_die_on_error = false; - var $config_error_die_on_source_failure = true; + public $config_error_image_width = 400; + public $config_error_image_height = 100; + public $config_error_message_image_default = ''; + public $config_error_bgcolor = 'CCCCFF'; + public $config_error_textcolor = 'FF0000'; + public $config_error_fontsize = 1; + public $config_error_die_on_error = false; + public $config_error_silent_die_on_error = false; + public $config_error_die_on_source_failure = true; // * Anti-Hotlink Configuration: - var $config_nohotlink_enabled = true; - var $config_nohotlink_valid_domains = array(); - var $config_nohotlink_erase_image = true; - var $config_nohotlink_text_message = 'Off-server thumbnailing is not allowed'; + public $config_nohotlink_enabled = true; + public $config_nohotlink_valid_domains = array(); + public $config_nohotlink_erase_image = true; + public $config_nohotlink_text_message = 'Off-server thumbnailing is not allowed'; // * Off-server Linking Configuration: - var $config_nooffsitelink_enabled = false; - var $config_nooffsitelink_valid_domains = array(); - var $config_nooffsitelink_require_refer = false; - var $config_nooffsitelink_erase_image = true; - var $config_nooffsitelink_watermark_src = ''; - var $config_nooffsitelink_text_message = 'Off-server linking is not allowed'; + public $config_nooffsitelink_enabled = false; + public $config_nooffsitelink_valid_domains = array(); + public $config_nooffsitelink_require_refer = false; + public $config_nooffsitelink_erase_image = true; + public $config_nooffsitelink_watermark_src = ''; + public $config_nooffsitelink_text_message = 'Off-server linking is not allowed'; // * Border & Background default colors - var $config_border_hexcolor = '000000'; - var $config_background_hexcolor = 'FFFFFF'; + public $config_border_hexcolor = '000000'; + public $config_background_hexcolor = 'FFFFFF'; // * TrueType Fonts - var $config_ttf_directory = './fonts'; + public $config_ttf_directory = './fonts'; - var $config_max_source_pixels = null; - var $config_use_exif_thumbnail_for_speed = false; - var $allow_local_http_src = false; + public $config_max_source_pixels = null; + public $config_use_exif_thumbnail_for_speed = false; + public $config_allow_local_http_src = false; - var $config_imagemagick_path = null; - var $config_prefer_imagemagick = true; - var $config_imagemagick_use_thumbnail = true; + public $config_imagemagick_path = null; + public $config_prefer_imagemagick = true; + public $config_imagemagick_use_thumbnail = true; - var $config_cache_maxage = null; - var $config_cache_maxsize = null; - var $config_cache_maxfiles = null; - var $config_cache_source_filemtime_ignore_local = false; - var $config_cache_source_filemtime_ignore_remote = true; - var $config_cache_default_only_suffix = false; - var $config_cache_force_passthru = true; - var $config_cache_prefix = ''; // default value set in the constructor below + public $config_cache_maxage = null; + public $config_cache_maxsize = null; + public $config_cache_maxfiles = null; + public $config_cache_source_filemtime_ignore_local = false; + public $config_cache_source_filemtime_ignore_remote = true; + public $config_cache_default_only_suffix = false; + public $config_cache_force_passthru = true; + public $config_cache_prefix = ''; // default value set in the constructor below // * MySQL - var $config_mysql_query = null; - var $config_mysql_hostname = null; - var $config_mysql_username = null; - var $config_mysql_password = null; - var $config_mysql_database = null; + public $config_mysql_extension = null; + public $config_mysql_query = null; + public $config_mysql_hostname = null; + public $config_mysql_username = null; + public $config_mysql_password = null; + public $config_mysql_database = null; // * Security - var $config_high_security_enabled = true; - var $config_high_security_password = null; - var $config_high_security_url_separator = '&'; - var $config_disable_debug = true; - var $config_allow_src_above_docroot = false; - var $config_allow_src_above_phpthumb = true; - var $config_auto_allow_symlinks = true; // allow symlink target directories without explicitly whitelisting them - var $config_additional_allowed_dirs = array(); // additional directories to allow source images to be read from + public $config_high_security_enabled = true; + public $config_high_security_password = null; + public $config_high_security_url_separator = '&'; + public $config_disable_debug = true; + public $config_allow_src_above_docroot = false; + public $config_allow_src_above_phpthumb = true; + public $config_auto_allow_symlinks = true; // allow symlink target directories without explicitly whitelisting them + public $config_additional_allowed_dirs = array(); // additional directories to allow source images to be read from + public $config_file_create_mask = 0755; + public $config_dir_create_mask = 0755; // * HTTP fopen - var $config_http_fopen_timeout = 10; - var $config_http_follow_redirect = true; + public $config_http_fopen_timeout = 10; + public $config_http_follow_redirect = true; // * Compatability - var $config_disable_pathinfo_parsing = false; - var $config_disable_imagecopyresampled = false; - var $config_disable_onlycreateable_passthru = false; + public $config_disable_pathinfo_parsing = false; + public $config_disable_imagecopyresampled = false; + public $config_disable_onlycreateable_passthru = false; + public $config_disable_realpath = false; - var $config_http_user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7'; + public $config_http_user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7'; // END CONFIGURATION OPTIONS // public: error messages (read-only; persistant) - var $debugmessages = array(); - var $debugtiming = array(); - var $fatalerror = null; + public $debugmessages = array(); + public $debugtiming = array(); + public $fatalerror = null; // private: (should not be modified directly) - var $thumbnailQuality = 75; - var $thumbnailFormat = null; + public $thumbnailQuality = 75; + public $thumbnailFormat = null; - var $sourceFilename = null; - var $rawImageData = null; - var $IMresizedData = null; - var $outputImageData = null; + public $sourceFilename = null; + public $rawImageData = null; + public $IMresizedData = null; + public $outputImageData = null; - var $useRawIMoutput = false; + public $useRawIMoutput = false; - var $gdimg_output = null; - var $gdimg_source = null; + public $gdimg_output = null; + public $gdimg_source = null; - var $getimagesizeinfo = null; + public $getimagesizeinfo = null; - var $source_width = null; - var $source_height = null; + public $source_width = null; + public $source_height = null; - var $thumbnailCropX = null; - var $thumbnailCropY = null; - var $thumbnailCropW = null; - var $thumbnailCropH = null; + public $thumbnailCropX = null; + public $thumbnailCropY = null; + public $thumbnailCropW = null; + public $thumbnailCropH = null; - var $exif_thumbnail_width = null; - var $exif_thumbnail_height = null; - var $exif_thumbnail_type = null; - var $exif_thumbnail_data = null; - var $exif_raw_data = null; + public $exif_thumbnail_width = null; + public $exif_thumbnail_height = null; + public $exif_thumbnail_type = null; + public $exif_thumbnail_data = null; + public $exif_raw_data = null; - var $thumbnail_width = null; - var $thumbnail_height = null; - var $thumbnail_image_width = null; - var $thumbnail_image_height = null; + public $thumbnail_width = null; + public $thumbnail_height = null; + public $thumbnail_image_width = null; + public $thumbnail_image_height = null; - var $tempFilesToDelete = array(); - var $cache_filename = null; + public $tempFilesToDelete = array(); + public $cache_filename = null; - var $AlphaCapableFormats = array('png', 'ico', 'gif'); - var $is_alpha = false; + public $AlphaCapableFormats = array( 'png', 'ico', 'gif'); + public $is_alpha = false; - var $iswindows = null; - var $issafemode = null; + public $iswindows = null; + public $issafemode = null; + public $php_memory_limit = null; - var $phpthumb_version = '1.7.13-201406261000'; + public $phpthumb_version = '1.7.15-201810050741'; ////////////////////////////////////////////////////////////////////// // public: constructor - function __construct() { + public function __construct() { + $this->phpThumb(); + } + + public function phpThumb() { $this->DebugTimingMessage('phpThumb() constructor', __FILE__, __LINE__); $this->DebugMessage('phpThumb() v'.$this->phpthumb_version, __FILE__, __LINE__); - $this->config_max_source_pixels = round(max(intval(ini_get('memory_limit')), intval(get_cfg_var('memory_limit'))) * 1048576 * 0.20); // 20% of memory_limit + + foreach (array(ini_get('memory_limit'), get_cfg_var('memory_limit')) as $php_config_memory_limit) { + if ('' !== $php_config_memory_limit) { + if (strtoupper($php_config_memory_limit[ strlen($php_config_memory_limit) - 1 ]) == 'G') { // PHP memory limit expressed in Gigabytes + $php_config_memory_limit = (int) substr($php_config_memory_limit, 0, -1) * 1073741824; + } elseif (strtoupper($php_config_memory_limit[ strlen($php_config_memory_limit) - 1 ]) == 'M') { // PHP memory limit expressed in Megabytes + $php_config_memory_limit = (int) substr($php_config_memory_limit, 0, -1) * 1048576; + } + $this->php_memory_limit = max($this->php_memory_limit, $php_config_memory_limit); + } + } + if ($this->php_memory_limit > 0) { // could be "-1" for "no limit" + $this->config_max_source_pixels = round($this->php_memory_limit * 0.20); // 20% of memory_limit + } + $this->iswindows = (bool) (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'); $this->issafemode = (bool) preg_match('#(1|ON)#i', ini_get('safe_mode')); $this->config_document_root = (!empty($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : $this->config_document_root); @@ -226,23 +249,23 @@ function __construct() { $this->purgeTempFiles(); // purge existing temp files if re-initializing object - $php_sapi_name = strtolower(function_exists('php_sapi_name') ? php_sapi_name() : ''); + $php_sapi_name = strtolower(function_exists('php_sapi_name') ? PHP_SAPI : ''); if ($php_sapi_name == 'cli') { $this->config_allow_src_above_docroot = true; } if (!$this->config_disable_debug) { // if debug mode is enabled, force phpThumbDebug output, do not allow normal thumbnails to be generated - $this->phpThumbDebug = (is_null($this->phpThumbDebug) ? 9 : max(1, intval($this->phpThumbDebug))); + $this->phpThumbDebug = (null === $this->phpThumbDebug ? 9 : max(1, (int) $this->phpThumbDebug)); } } - function __destruct() { + public function __destruct() { $this->purgeTempFiles(); } // public: - function purgeTempFiles() { + public function purgeTempFiles() { foreach ($this->tempFilesToDelete as $tempFileToDelete) { if (file_exists($tempFileToDelete)) { $this->DebugMessage('Deleting temp file "'.$tempFileToDelete.'"', __FILE__, __LINE__); @@ -254,12 +277,12 @@ function purgeTempFiles() { } // public: - function setSourceFilename($sourceFilename) { + public function setSourceFilename($sourceFilename) { //$this->resetObject(); //$this->rawImageData = null; $this->sourceFilename = $sourceFilename; $this->src = $sourceFilename; - if (is_null($this->config_output_format)) { + if (null === $this->config_output_format) { $sourceFileExtension = strtolower(substr(strrchr($sourceFilename, '.'), 1)); if (preg_match('#^[a-z]{3,4}$#', $sourceFileExtension)) { $this->config_output_format = $sourceFileExtension; @@ -273,7 +296,7 @@ function setSourceFilename($sourceFilename) { } // public: - function setSourceData($rawImageData, $sourceFilename='') { + public function setSourceData($rawImageData, $sourceFilename='') { //$this->resetObject(); //$this->sourceFilename = null; $this->rawImageData = $rawImageData; @@ -297,14 +320,14 @@ function setSourceData($rawImageData, $sourceFilename='') { } // public: - function setSourceImageResource($gdimg) { + public function setSourceImageResource($gdimg) { //$this->resetObject(); $this->gdimg_source = $gdimg; return true; } // public: - function setParameter($param, $value) { + public function setParameter($param, $value) { if ($param == 'src') { $this->setSourceFilename($this->ResolveFilenameToAbsolute($value)); } elseif (@is_array($this->$param)) { @@ -322,7 +345,7 @@ function setParameter($param, $value) { } // public: - function getParameter($param) { + public function getParameter($param) { //if (property_exists('phpThumb', $param)) { return $this->$param; //} @@ -332,7 +355,7 @@ function getParameter($param) { // public: - function GenerateThumbnail() { + public function GenerateThumbnail() { $this->setOutputFormat(); $this->phpThumbDebug('8a'); @@ -401,8 +424,8 @@ function GenerateThumbnail() { ); $this->DebugMessage('memory_get_usage() after copy-resize = '.(function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__); - ImageDestroy($this->gdimg_source); - $this->DebugMessage('memory_get_usage() after ImageDestroy = '.(function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__); + imagedestroy($this->gdimg_source); + $this->DebugMessage('memory_get_usage() after imagedestroy = '.(function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__); $this->phpThumbDebug('8i'); $this->AntiOffsiteLinking(); @@ -420,7 +443,7 @@ function GenerateThumbnail() { // public: - function RenderOutput() { + public function RenderOutput() { if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) { $this->DebugMessage('RenderOutput() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__); return false; @@ -436,61 +459,84 @@ function RenderOutput() { } $builtin_formats = array(); - if (function_exists('ImageTypes')) { - $imagetypes = ImageTypes(); + if (function_exists('imagetypes')) { + $imagetypes = imagetypes(); $builtin_formats['wbmp'] = (bool) ($imagetypes & IMG_WBMP); $builtin_formats['jpg'] = (bool) ($imagetypes & IMG_JPG); $builtin_formats['gif'] = (bool) ($imagetypes & IMG_GIF); $builtin_formats['png'] = (bool) ($imagetypes & IMG_PNG); } - $this->DebugMessage('RenderOutput() attempting Image'.strtoupper(@$this->thumbnailFormat).'($this->gdimg_output)', __FILE__, __LINE__); + + $this->DebugMessage('imageinterlace($this->gdimg_output, '. (int) $this->config_output_interlace .')', __FILE__, __LINE__); + imageinterlace($this->gdimg_output, (int) $this->config_output_interlace); + + $this->DebugMessage('RenderOutput() attempting image'.strtolower(@$this->thumbnailFormat).'($this->gdimg_output)', __FILE__, __LINE__); ob_start(); switch ($this->thumbnailFormat) { case 'wbmp': - if (!@$builtin_formats['wbmp']) { + if (empty($builtin_formats['wbmp'])) { $this->DebugMessage('GD does not have required built-in support for WBMP output', __FILE__, __LINE__); ob_end_clean(); return false; } - ImageJPEG($this->gdimg_output, null, $this->thumbnailQuality); + imagejpeg($this->gdimg_output, null, $this->thumbnailQuality); $this->outputImageData = ob_get_contents(); break; case 'jpeg': case 'jpg': // should be "jpeg" not "jpg" but just in case... - if (!@$builtin_formats['jpg']) { + if (empty($builtin_formats['jpg'])) { $this->DebugMessage('GD does not have required built-in support for JPEG output', __FILE__, __LINE__); ob_end_clean(); return false; } - ImageJPEG($this->gdimg_output, null, $this->thumbnailQuality); + imagejpeg($this->gdimg_output, null, $this->thumbnailQuality); $this->outputImageData = ob_get_contents(); break; case 'png': - if (!@$builtin_formats['png']) { + if (empty($builtin_formats['png'])) { $this->DebugMessage('GD does not have required built-in support for PNG output', __FILE__, __LINE__); ob_end_clean(); return false; } - ImagePNG($this->gdimg_output); + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.1.2', '>=')) { + // https://github.com/JamesHeinrich/phpThumb/issues/24 + + /* http://php.net/manual/en/function.imagepng.php: + from php source (gd.h): + 2.0.12: Compression level: 0-9 or -1, where 0 is NO COMPRESSION at all, + :: 1 is FASTEST but produces larger files, 9 provides the best + :: compression (smallest files) but takes a long time to compress, and + :: -1 selects the default compiled into the zlib library. + Conclusion: Based on the Zlib manual (http://www.zlib.net/manual.html) the default compression level is set to 6. + */ + if (($this->thumbnailQuality >= -1) && ($this->thumbnailQuality <= 9)) { + $PNGquality = $this->thumbnailQuality; + } else { + $this->DebugMessage('Specified thumbnailQuality "'.$this->thumbnailQuality.'" is outside the accepted range (0-9, or -1). Using 6 as default value.', __FILE__, __LINE__); + $PNGquality = 6; + } + imagepng($this->gdimg_output, null, $PNGquality); + } else { + imagepng($this->gdimg_output); + } $this->outputImageData = ob_get_contents(); break; case 'gif': - if (!@$builtin_formats['gif']) { + if (empty($builtin_formats['gif'])) { $this->DebugMessage('GD does not have required built-in support for GIF output', __FILE__, __LINE__); ob_end_clean(); return false; } - ImageGIF($this->gdimg_output); + imagegif($this->gdimg_output); $this->outputImageData = ob_get_contents(); break; case 'bmp': - $ImageOutFunction = '"builtin BMP output"'; - if (!@include_once(dirname(__FILE__).'/phpthumb.bmp.php')) { - $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__); + if (!@include_once __DIR__ .'/phpthumb.bmp.php' ) { + $this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__); ob_end_clean(); return false; } @@ -500,9 +546,8 @@ function RenderOutput() { break; case 'ico': - $ImageOutFunction = '"builtin ICO output"'; - if (!@include_once(dirname(__FILE__) . '/phpthumb.ico.php')) { - $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__); + if (!@include_once __DIR__ .'/phpthumb.ico.php' ) { + $this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__); ob_end_clean(); return false; } @@ -529,7 +574,7 @@ function RenderOutput() { // public: - function RenderToFile($filename) { + public function RenderToFile($filename) { if (preg_match('#^[a-z0-9]+://#i', $filename)) { $this->DebugMessage('RenderToFile() failed because $filename ('.$filename.') is a URL', __FILE__, __LINE__); return false; @@ -551,6 +596,7 @@ function RenderToFile($filename) { if ($this->RenderOutput()) { if (file_put_contents($renderfilename, $this->outputImageData)) { + @chmod($renderfilename, $this->getParameter('config_file_create_mask')); $this->DebugMessage('RenderToFile('.$renderfilename.') succeeded', __FILE__, __LINE__); return true; } @@ -565,7 +611,7 @@ function RenderToFile($filename) { // public: - function OutputThumbnail() { + public function OutputThumbnail() { $this->purgeTempFiles(); if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) { @@ -574,7 +620,6 @@ function OutputThumbnail() { } if (headers_sent()) { return $this->ErrorImage('OutputThumbnail() failed - headers already sent'); - exit; } $downloadfilename = phpthumb_functions::SanitizeFilename(is_string($this->sia) ? $this->sia : ($this->down ? $this->down : 'phpThumb_generated_thumbnail'.'.'.$this->thumbnailFormat)); @@ -592,8 +637,8 @@ function OutputThumbnail() { } else { - $this->DebugMessage('ImageInterlace($this->gdimg_output, '.intval($this->config_output_interlace).')', __FILE__, __LINE__); - ImageInterlace($this->gdimg_output, intval($this->config_output_interlace)); + $this->DebugMessage('imageinterlace($this->gdimg_output, '. (int) $this->config_output_interlace .')', __FILE__, __LINE__); + imageinterlace($this->gdimg_output, (int) $this->config_output_interlace); switch ($this->thumbnailFormat) { case 'jpeg': header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat)); @@ -609,8 +654,8 @@ function OutputThumbnail() { break; case 'bmp': - if (!@include_once(dirname(__FILE__).'/phpthumb.bmp.php')) { - $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__); + if (!@include_once __DIR__ .'/phpthumb.bmp.php' ) { + $this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__); return false; } $phpthumb_bmp = new phpthumb_bmp(); @@ -630,8 +675,8 @@ function OutputThumbnail() { break; case 'ico': - if (!@include_once(dirname(__FILE__) . '/phpthumb.ico.php')) { - $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__); + if (!@include_once __DIR__ .'/phpthumb.ico.php' ) { + $this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__); return false; } $phpthumb_ico = new phpthumb_ico(); @@ -663,8 +708,8 @@ function OutputThumbnail() { // public: - function CleanUpCacheDirectory() { - $this->DebugMessage('CleanUpCacheDirectory() set to purge ('.(is_null($this->config_cache_maxage) ? 'NULL' : number_format($this->config_cache_maxage / 86400, 1)).' days; '.(is_null($this->config_cache_maxsize) ? 'NULL' : number_format($this->config_cache_maxsize / 1048576, 2)).' MB; '.(is_null($this->config_cache_maxfiles) ? 'NULL' : number_format($this->config_cache_maxfiles)).' files)', __FILE__, __LINE__); + public function CleanUpCacheDirectory() { + $this->DebugMessage('CleanUpCacheDirectory() set to purge ('.(null === $this->config_cache_maxage ? 'NULL' : number_format($this->config_cache_maxage / 86400, 1)).' days; '.(null === $this->config_cache_maxsize ? 'NULL' : number_format($this->config_cache_maxsize / 1048576, 2)).' MB; '.(null === $this->config_cache_maxfiles ? 'NULL' : number_format($this->config_cache_maxfiles)).' files)', __FILE__, __LINE__); if (!is_writable($this->config_cache_directory)) { $this->DebugMessage('CleanUpCacheDirectory() skipped because "'.$this->config_cache_directory.'" is not writable', __FILE__, __LINE__); @@ -795,9 +840,9 @@ function CleanUpCacheDirectory() { $empty_dirs = array(); foreach ($AllFilesInCacheDirectory as $fullfilename) { if (is_dir($fullfilename)) { - $empty_dirs[realpath($fullfilename)] = 1; + $empty_dirs[$this->realPathSafe($fullfilename)] = 1; } else { - unset($empty_dirs[realpath(dirname($fullfilename))]); + unset($empty_dirs[$this->realPathSafe(dirname($fullfilename))]); } } krsort($empty_dirs); @@ -820,7 +865,7 @@ function CleanUpCacheDirectory() { ////////////////////////////////////////////////////////////////////// // private: re-initializator (call between rendering multiple images with one object) - function resetObject() { + public function resetObject() { $class_vars = get_class_vars(get_class($this)); foreach ($class_vars as $key => $value) { // do not clobber debug or config info @@ -834,7 +879,7 @@ function resetObject() { ////////////////////////////////////////////////////////////////////// - function ResolveSource() { + public function ResolveSource() { if (is_resource($this->gdimg_source)) { $this->DebugMessage('ResolveSource() exiting because is_resource($this->gdimg_source)', __FILE__, __LINE__); return true; @@ -873,7 +918,7 @@ function ResolveSource() { } - function setOutputFormat() { + public function setOutputFormat() { static $alreadyCalled = false; if ($this->thumbnailFormat && $alreadyCalled) { return true; @@ -882,18 +927,18 @@ function setOutputFormat() { $AvailableImageOutputFormats = array(); $AvailableImageOutputFormats[] = 'text'; - if (@is_readable(dirname(__FILE__).'/phpthumb.ico.php')) { + if (@is_readable( __DIR__ .'/phpthumb.ico.php')) { $AvailableImageOutputFormats[] = 'ico'; } - if (@is_readable(dirname(__FILE__).'/phpthumb.bmp.php')) { + if (@is_readable( __DIR__ .'/phpthumb.bmp.php')) { $AvailableImageOutputFormats[] = 'bmp'; } $this->thumbnailFormat = 'ico'; // Set default output format based on what image types are available - if (function_exists('ImageTypes')) { - $imagetypes = ImageTypes(); + if (function_exists('imagetypes')) { + $imagetypes = imagetypes(); if ($imagetypes & IMG_WBMP) { $this->thumbnailFormat = 'wbmp'; $AvailableImageOutputFormats[] = 'wbmp'; @@ -911,8 +956,7 @@ function setOutputFormat() { $AvailableImageOutputFormats[] = 'jpeg'; } } else { - //return $this->ErrorImage('ImageTypes() does not exist - GD support might not be enabled?'); - $this->DebugMessage('ImageTypes() does not exist - GD support might not be enabled?', __FILE__, __LINE__); + $this->DebugMessage('imagetypes() does not exist - GD support might not be enabled?', __FILE__, __LINE__); } if ($this->ImageMagickVersion()) { $IMformats = array('jpeg', 'png', 'gif', 'bmp', 'ico', 'wbmp'); @@ -938,7 +982,7 @@ function setOutputFormat() { } elseif ($this->config_output_format) { $this->DebugMessage('$this->thumbnailFormat staying as "'.$this->thumbnailFormat.'" because $this->config_output_format ('.strtolower($this->config_output_format).') is not in $AvailableImageOutputFormats', __FILE__, __LINE__); } - if ($this->f && (phpthumb_functions::CaseInsensitiveInArray($this->f, $AvailableImageOutputFormats))) { + if ($this->f && phpthumb_functions::CaseInsensitiveInArray($this->f, $AvailableImageOutputFormats) ) { // override output format if $this->f is set and that format is available $this->DebugMessage('$this->thumbnailFormat set to $this->f "'.strtolower($this->f).'"', __FILE__, __LINE__); $this->thumbnailFormat = strtolower($this->f); @@ -949,17 +993,17 @@ function setOutputFormat() { // for JPEG images, quality 1 (worst) to 99 (best) // quality < 25 is nasty, with not much size savings - not recommended // problems with 100 - invalid JPEG? - $this->thumbnailQuality = max(1, min(99, ($this->q ? intval($this->q) : 75))); + $this->thumbnailQuality = max(1, min(99, ($this->q ? (int) $this->q : 75))); $this->DebugMessage('$this->thumbnailQuality set to "'.$this->thumbnailQuality.'"', __FILE__, __LINE__); return true; } - function setCacheDirectory() { + public function setCacheDirectory() { // resolve cache directory to absolute pathname $this->DebugMessage('setCacheDirectory() starting with config_cache_directory = "'.$this->config_cache_directory.'"', __FILE__, __LINE__); - if (substr($this->config_cache_directory, 0, 1) == '.') { + if ($this->config_cache_directory[ 0 ] == '.') { if (preg_match('#^(f|ht)tps?\://#i', $this->src)) { if (!$this->config_cache_disable_warning) { $this->ErrorImage('$this->config_cache_directory ('.$this->config_cache_directory.') cannot be used for remote images. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php'); @@ -978,15 +1022,15 @@ function setCacheDirectory() { $this->config_cache_directory = str_replace('/', DIRECTORY_SEPARATOR, $this->config_cache_directory); } if ($this->config_cache_directory) { - $real_cache_path = realpath($this->config_cache_directory); + $real_cache_path = $this->realPathSafe($this->config_cache_directory); if (!$real_cache_path) { - $this->DebugMessage('realpath($this->config_cache_directory) failed for "'.$this->config_cache_directory.'"', __FILE__, __LINE__); + $this->DebugMessage('$this->realPathSafe($this->config_cache_directory) failed for "'.$this->config_cache_directory.'"', __FILE__, __LINE__); if (!is_dir($this->config_cache_directory)) { $this->DebugMessage('!is_dir('.$this->config_cache_directory.')', __FILE__, __LINE__); } } if ($real_cache_path) { - $this->DebugMessage('setting config_cache_directory to realpath('.$this->config_cache_directory.') = "'.$real_cache_path.'"', __FILE__, __LINE__); + $this->DebugMessage('setting config_cache_directory to $this->realPathSafe('.$this->config_cache_directory.') = "'.$real_cache_path.'"', __FILE__, __LINE__); $this->config_cache_directory = $real_cache_path; } } @@ -1011,17 +1055,17 @@ function setCacheDirectory() { /* Takes the array of path segments up to now, and the next segment (maybe a modifier: empty, . or ..) Applies it, adding or removing from $segments as a result. Returns nothing. */ // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961 - function applyPathSegment(&$segments, $segment) { + public function applyPathSegment(&$segments, $segment) { if ($segment == '.') { return; // always remove } if ($segment == '') { $test = array_pop($segments); - if (is_null($test)) { + if (null === $test) { $segments[] = $segment; // keep the first empty block } elseif ($test == '') { $test = array_pop($segments); - if (is_null($test)) { + if (null === $test) { $segments[] = $test; $segments[] = $segment; // keep the second one too } else { // put both back and ignore segment @@ -1034,7 +1078,7 @@ function applyPathSegment(&$segments, $segment) { } else { if ($segment == '..') { $test = array_pop($segments); - if (is_null($test)) { + if (null === $test) { $segments[] = $segment; } elseif ($test == '..') { $segments[] = $test; @@ -1052,7 +1096,7 @@ function applyPathSegment(&$segments, $segment) { /* Takes array of path components, normalizes it: removes empty slots and '.', collapses '..' and folder names. Returns array. */ // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961 - function normalizePath($segments) { + public function normalizePath($segments) { $parts = array(); foreach ($segments as $segment) { $this->applyPathSegment($parts, $segment); @@ -1062,10 +1106,10 @@ function normalizePath($segments) { /* True if the provided path points (without resolving symbolic links) into one of the allowed directories. */ // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961 - function matchPath($path, $allowed_dirs) { + public function matchPath($path, $allowed_dirs) { if (!empty($allowed_dirs)) { foreach ($allowed_dirs as $one_dir) { - if (preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', realpath($one_dir))).'#', $path)) { + if (preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', $this->realPathSafe($one_dir))).'#', $path)) { return true; } } @@ -1075,15 +1119,15 @@ function matchPath($path, $allowed_dirs) { /* True if the provided path points inside one of open_basedirs (or if open_basedirs are disabled) */ // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961 - function isInOpenBasedir($path) { + public function isInOpenBasedir($path) { static $open_basedirs = null; - if (is_null($open_basedirs)) { + if (null === $open_basedirs) { $ini_text = ini_get('open_basedir'); $this->DebugMessage('open_basedir: "'.$ini_text.'"', __FILE__, __LINE__); $open_basedirs = array(); if (strlen($ini_text) > 0) { foreach (preg_split('#[;:]#', $ini_text) as $key => $value) { - $open_basedirs[$key] = realpath($value); + $open_basedirs[$key] = $this->realPathSafe($value); } } } @@ -1092,19 +1136,19 @@ function isInOpenBasedir($path) { /* Resolves all symlinks in $path, checking that each continuous part ends in an allowed zone. Returns null, if any component leads outside of allowed zone. */ // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961 - function resolvePath($path, $allowed_dirs) { + public function resolvePath($path, $allowed_dirs) { $this->DebugMessage('resolvePath: '.$path.' (allowed_dirs: '.print_r($allowed_dirs, true).')', __FILE__, __LINE__); // add base path to the top of the list if (!$this->config_allow_src_above_docroot) { - array_unshift($allowed_dirs, realpath($this->config_document_root)); + array_unshift($allowed_dirs, $this->realPathSafe($this->config_document_root)); } else { if (!$this->config_allow_src_above_phpthumb) { - array_unshift($allowed_dirs, realpath(dirname(__FILE__))); + array_unshift($allowed_dirs, $this->realPathSafe( __DIR__ )); } else { // no checks are needed, offload the work to realpath and forget about it - $this->DebugMessage('resolvePath: checks disabled, returning '.realpath($path), __FILE__, __LINE__); - return realpath($path); + $this->DebugMessage('resolvePath: checks disabled, returning '.$this->realPathSafe($path), __FILE__, __LINE__); + return $this->realPathSafe($path); } } if ($path == '') { @@ -1118,8 +1162,8 @@ function resolvePath($path, $allowed_dirs) { // do not use "cleaner" foreach version of this loop as later code relies on both $segments and $i // http://support.silisoftware.com/phpBB3/viewtopic.php?t=964 $segments = explode(DIRECTORY_SEPARATOR, $path); - for ($i = 0; $i < count($segments); $i++) { - $this->applyPathSegment($parts, $segments[$i]); + for ($i = 0, $iMax = count($segments); $i < $iMax; $i++) { + $this->applyPathSegment($parts, $segments[$i]); $thispart = implode(DIRECTORY_SEPARATOR, $parts); if ($this->isInOpenBasedir($thispart)) { if (is_link($thispart)) { @@ -1162,7 +1206,46 @@ function resolvePath($path, $allowed_dirs) { return $path; } - function ResolveFilenameToAbsolute($filename) { + + public function realPathSafe($filename) { + // http://php.net/manual/en/function.realpath.php -- "Note: The running script must have executable permissions on all directories in the hierarchy, otherwise realpath() will return FALSE" + // realPathSafe() provides a reasonable facsimile of realpath() but does not resolve symbolic links, nor does it check that the file/path actually exists + if (!$this->config_disable_realpath) { + return realpath($filename); + } + + // http://stackoverflow.com/questions/21421569 + $newfilename = preg_replace('#[\\/]+#', DIRECTORY_SEPARATOR, $filename); + if (!preg_match('#^'.DIRECTORY_SEPARATOR.'#', $newfilename)) { + $newfilename = __DIR__ .DIRECTORY_SEPARATOR.$newfilename; + } + do { + $beforeloop = $newfilename; + + // Replace all sequences of more than one / with a single one [[ If you're working on a system that treats // at the start of a path as special, make sure you replace multiple / characters at the start with two of them. This is the only place where POSIX allows (but does not mandate) special handling for multiples, in all other cases, multiple / characters are equivalent to a single one.]] + $newfilename = preg_replace('#'.DIRECTORY_SEPARATOR.'+#', DIRECTORY_SEPARATOR, $newfilename); + + // Replace all occurrences of /./ with / + $newfilename = preg_replace('#'.DIRECTORY_SEPARATOR.'\\.'.DIRECTORY_SEPARATOR.'#', DIRECTORY_SEPARATOR, $newfilename); + + // Remove ./ if at the start + $newfilename = preg_replace('#^\\.'.DIRECTORY_SEPARATOR.'#', '', $newfilename); + + // Remove /. if at the end + $newfilename = preg_replace('#'.DIRECTORY_SEPARATOR.'\\.$#', '', $newfilename); + + // Replace /anything/../ with / + $newfilename = preg_replace('#'.DIRECTORY_SEPARATOR.'[^'.DIRECTORY_SEPARATOR.']+'.DIRECTORY_SEPARATOR.'\\.\\.'.DIRECTORY_SEPARATOR.'#', DIRECTORY_SEPARATOR, $newfilename); + + // Remove /anything/.. if at the end + $newfilename = preg_replace('#'.DIRECTORY_SEPARATOR.'[^'.DIRECTORY_SEPARATOR.']+'.DIRECTORY_SEPARATOR.'\\.\\.$#', '', $newfilename); + + } while ($newfilename != $beforeloop); + return $newfilename; + } + + + public function ResolveFilenameToAbsolute($filename) { if (empty($filename)) { return false; } @@ -1198,11 +1281,11 @@ function ResolveFilenameToAbsolute($filename) { if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray($filename)) { $AbsoluteFilename = $ApacheLookupURIarray['filename']; } else { - $AbsoluteFilename = realpath($filename); + $AbsoluteFilename = $this->realPathSafe($filename); if (@is_readable($AbsoluteFilename)) { - $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.$filename.'", but the correct filename ('.$AbsoluteFilename.') seems to have been resolved with realpath($filename)', __FILE__, __LINE__); + $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.$filename.'", but the correct filename ('.$AbsoluteFilename.') seems to have been resolved with $this->realPathSafe($filename)', __FILE__, __LINE__); } elseif (is_dir(dirname($AbsoluteFilename))) { - $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname($filename).'", but the correct directory ('.dirname($AbsoluteFilename).') seems to have been resolved with realpath(.)', __FILE__, __LINE__); + $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname($filename).'", but the correct directory ('.dirname($AbsoluteFilename).') seems to have been resolved with $this->realPathSafe(.)', __FILE__, __LINE__); } else { return $this->ErrorImage('phpthumb_functions::ApacheLookupURIarray() failed for "'.$filename.'". This has been known to fail on Apache2 - try using the absolute filename for the source image (ex: "/home/user/httpdocs/image.jpg" instead of "/~user/image.jpg")'); } @@ -1224,17 +1307,17 @@ function ResolveFilenameToAbsolute($filename) { } else { // relative to current directory (any OS) - $AbsoluteFilename = dirname(__FILE__).DIRECTORY_SEPARATOR.preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $filename); + $AbsoluteFilename = __DIR__ .DIRECTORY_SEPARATOR.preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $filename); if (substr(dirname(@$_SERVER['PHP_SELF']), 0, 2) == '/~') { if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) { $AbsoluteFilename = $ApacheLookupURIarray['filename'].DIRECTORY_SEPARATOR.$filename; } else { - $AbsoluteFilename = realpath('.').DIRECTORY_SEPARATOR.$filename; + $AbsoluteFilename = $this->realPathSafe('.').DIRECTORY_SEPARATOR.$filename; if (@is_readable($AbsoluteFilename)) { - $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'", but the correct filename ('.$AbsoluteFilename.') seems to have been resolved with realpath(.)/$filename', __FILE__, __LINE__); + $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'", but the correct filename ('.$AbsoluteFilename.') seems to have been resolved with $this->realPathSafe(.)/$filename', __FILE__, __LINE__); } elseif (is_dir(dirname($AbsoluteFilename))) { - $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'", but the correct directory ('.dirname($AbsoluteFilename).') seems to have been resolved with realpath(.)', __FILE__, __LINE__); + $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'", but the correct directory ('.dirname($AbsoluteFilename).') seems to have been resolved with $this->realPathSafe(.)', __FILE__, __LINE__); } else { return $this->ErrorImage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'". This has been known to fail on Apache2 - try using the absolute filename for the source image'); } @@ -1248,41 +1331,41 @@ function ResolveFilenameToAbsolute($filename) { $this->DebugMessage('is_link()==true, changing "'.$AbsoluteFilename.'" to "'.readlink($AbsoluteFilename).'"', __FILE__, __LINE__); $AbsoluteFilename = readlink($AbsoluteFilename); } - if (realpath($AbsoluteFilename)) { - $AbsoluteFilename = realpath($AbsoluteFilename); + if ($this->realPathSafe($AbsoluteFilename)) { + $AbsoluteFilename = $this->realPathSafe($AbsoluteFilename); } */ if ($this->iswindows) { - $AbsoluteFilename = preg_replace('#^'.preg_quote(realpath($this->config_document_root)).'#i', realpath($this->config_document_root), $AbsoluteFilename); + $AbsoluteFilename = preg_replace('#^'.preg_quote($this->realPathSafe($this->config_document_root)).'#i', str_replace('\\', '\\\\', $this->realPathSafe($this->config_document_root)), $AbsoluteFilename); $AbsoluteFilename = str_replace(DIRECTORY_SEPARATOR, '/', $AbsoluteFilename); } - $AbsoluteFilename = $this->resolvePath($AbsoluteFilename, $this->config_additional_allowed_dirs); - if (!$this->config_allow_src_above_docroot && !preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', realpath($this->config_document_root))).'#', $AbsoluteFilename)) { - $this->DebugMessage('!$this->config_allow_src_above_docroot therefore setting "'.$AbsoluteFilename.'" (outside "'.realpath($this->config_document_root).'") to null', __FILE__, __LINE__); + $resolvedAbsoluteFilename = $this->resolvePath($AbsoluteFilename, $this->config_additional_allowed_dirs); + if (!$this->config_allow_src_above_docroot && !preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', $this->realPathSafe($this->config_document_root))).'#', $resolvedAbsoluteFilename)) { + $this->DebugMessage('!$this->config_allow_src_above_docroot therefore setting "'.$AbsoluteFilename.'" (outside "'.$this->realPathSafe($this->config_document_root).'") to null', __FILE__, __LINE__); return false; } - if (!$this->config_allow_src_above_phpthumb && !preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__))).'#', $AbsoluteFilename)) { - $this->DebugMessage('!$this->config_allow_src_above_phpthumb therefore setting "'.$AbsoluteFilename.'" (outside "'.dirname(__FILE__).'") to null', __FILE__, __LINE__); + if (!$this->config_allow_src_above_phpthumb && !preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', __DIR__ )).'#', $resolvedAbsoluteFilename)) { + $this->DebugMessage('!$this->config_allow_src_above_phpthumb therefore setting "'.$AbsoluteFilename.'" (outside "'. __DIR__ .'") to null', __FILE__, __LINE__); return false; } - return $AbsoluteFilename; + return $resolvedAbsoluteFilename; } - function file_exists_ignoreopenbasedir($filename, $cached=true) { + public function file_exists_ignoreopenbasedir($filename, $cached=true) { static $open_basedirs = null; static $file_exists_cache = array(); if (!$cached || !isset($file_exists_cache[$filename])) { - if (is_null($open_basedirs)) { + if (null === $open_basedirs) { $open_basedirs = preg_split('#[;:]#', ini_get('open_basedir')); } if (empty($open_basedirs) || in_array(dirname($filename), $open_basedirs)) { $file_exists_cache[$filename] = file_exists($filename); } elseif ($this->iswindows) { - $ls_filename = trim(phpthumb_functions::SafeExec('dir '.$this->customEscapeshellarg($filename))); - $file_exists_cache[$filename] = !preg_match('#File Not Found#i', $ls_filename); + $ls_filename = trim(phpthumb_functions::SafeExec('dir /b '.phpthumb_functions::escapeshellarg_replacement($filename))); + $file_exists_cache[$filename] = ($ls_filename == basename($filename)); // command dir /b return only filename without path } else { - $ls_filename = trim(phpthumb_functions::SafeExec('ls '.$this->customEscapeshellarg($filename))); + $ls_filename = trim(phpthumb_functions::SafeExec('ls '.phpthumb_functions::escapeshellarg_replacement($filename))); $file_exists_cache[$filename] = ($ls_filename == $filename); } } @@ -1290,9 +1373,9 @@ function file_exists_ignoreopenbasedir($filename, $cached=true) { } - function ImageMagickWhichConvert() { + public function ImageMagickWhichConvert() { static $WhichConvert = null; - if (is_null($WhichConvert)) { + if (null === $WhichConvert) { if ($this->iswindows) { $WhichConvert = false; } else { @@ -1302,6 +1385,7 @@ function ImageMagickWhichConvert() { } else { $WhichConvert = trim(phpthumb_functions::SafeExec('which convert')); @file_put_contents($IMwhichConvertCacheFilename, $WhichConvert); + @chmod($IMwhichConvertCacheFilename, $this->getParameter('config_file_create_mask')); } } } @@ -1309,9 +1393,9 @@ function ImageMagickWhichConvert() { } - function ImageMagickCommandlineBase() { + public function ImageMagickCommandlineBase() { static $commandline = null; - if (is_null($commandline)) { + if (null === $commandline) { if ($this->issafemode) { $commandline = ''; return $commandline; @@ -1322,28 +1406,28 @@ function ImageMagickCommandlineBase() { return $commandline; } - $commandline = (!is_null($this->config_imagemagick_path) ? $this->config_imagemagick_path : ''); + $commandline = (null !== $this->config_imagemagick_path ? $this->config_imagemagick_path : ''); - if ($this->config_imagemagick_path && ($this->config_imagemagick_path != realpath($this->config_imagemagick_path))) { - if (@is_executable(realpath($this->config_imagemagick_path))) { - $this->DebugMessage('Changing $this->config_imagemagick_path ('.$this->config_imagemagick_path.') to realpath($this->config_imagemagick_path) ('.realpath($this->config_imagemagick_path).')', __FILE__, __LINE__); - $this->config_imagemagick_path = realpath($this->config_imagemagick_path); + if ($this->config_imagemagick_path && ($this->config_imagemagick_path != $this->realPathSafe($this->config_imagemagick_path))) { + if (@is_executable($this->realPathSafe($this->config_imagemagick_path))) { + $this->DebugMessage('Changing $this->config_imagemagick_path ('.$this->config_imagemagick_path.') to $this->realPathSafe($this->config_imagemagick_path) ('.$this->realPathSafe($this->config_imagemagick_path).')', __FILE__, __LINE__); + $this->config_imagemagick_path = $this->realPathSafe($this->config_imagemagick_path); } else { - $this->DebugMessage('Leaving $this->config_imagemagick_path as ('.$this->config_imagemagick_path.') because !is_execuatable(realpath($this->config_imagemagick_path)) ('.realpath($this->config_imagemagick_path).')', __FILE__, __LINE__); + $this->DebugMessage('Leaving $this->config_imagemagick_path as ('.$this->config_imagemagick_path.') because !is_execuatable($this->realPathSafe($this->config_imagemagick_path)) ('.$this->realPathSafe($this->config_imagemagick_path).')', __FILE__, __LINE__); } } - $this->DebugMessage(' file_exists('.$this->config_imagemagick_path.') = '.intval( @file_exists($this->config_imagemagick_path)), __FILE__, __LINE__); - $this->DebugMessage('file_exists_ignoreopenbasedir('.$this->config_imagemagick_path.') = '.intval($this->file_exists_ignoreopenbasedir($this->config_imagemagick_path)), __FILE__, __LINE__); - $this->DebugMessage(' is_file('.$this->config_imagemagick_path.') = '.intval( @is_file($this->config_imagemagick_path)), __FILE__, __LINE__); - $this->DebugMessage(' is_executable('.$this->config_imagemagick_path.') = '.intval( @is_executable($this->config_imagemagick_path)), __FILE__, __LINE__); + $this->DebugMessage(' file_exists('.$this->config_imagemagick_path.') = '. (int) (@file_exists($this->config_imagemagick_path)), __FILE__, __LINE__); + $this->DebugMessage('file_exists_ignoreopenbasedir('.$this->config_imagemagick_path.') = '. (int) $this->file_exists_ignoreopenbasedir($this->config_imagemagick_path), __FILE__, __LINE__); + $this->DebugMessage(' is_file('.$this->config_imagemagick_path.') = '. (int) (@is_file($this->config_imagemagick_path)), __FILE__, __LINE__); + $this->DebugMessage(' is_executable('.$this->config_imagemagick_path.') = '. (int) (@is_executable($this->config_imagemagick_path)), __FILE__, __LINE__); if ($this->file_exists_ignoreopenbasedir($this->config_imagemagick_path)) { $this->DebugMessage('using ImageMagick path from $this->config_imagemagick_path ('.$this->config_imagemagick_path.')', __FILE__, __LINE__); if ($this->iswindows) { - $commandline = substr($this->config_imagemagick_path, 0, 2).' && cd '.$this->customEscapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, substr(dirname($this->config_imagemagick_path), 2))).' && '.$this->customEscapeshellarg(basename($this->config_imagemagick_path)); + $commandline = substr($this->config_imagemagick_path, 0, 2).' && cd '.phpthumb_functions::escapeshellarg_replacement(str_replace('/', DIRECTORY_SEPARATOR, substr(dirname($this->config_imagemagick_path), 2))).' && '.phpthumb_functions::escapeshellarg_replacement(basename($this->config_imagemagick_path)); } else { - $commandline = $this->customEscapeshellarg($this->config_imagemagick_path); + $commandline = phpthumb_functions::escapeshellarg_replacement($this->config_imagemagick_path); } } else { @@ -1374,14 +1458,15 @@ function ImageMagickCommandlineBase() { } @file_put_contents($IMcommandlineBaseCacheFilename, $commandline); + @chmod($IMcommandlineBaseCacheFilename, $this->getParameter('config_file_create_mask')); } return $commandline; } - function ImageMagickVersion($returnRAW=false) { + public function ImageMagickVersion($returnRAW=false) { static $versionstring = null; - if (is_null($versionstring)) { + if (null === $versionstring) { $versionstring = array(0=>false, 1=>false); $IMversionCacheFilename = $this->config_cache_directory.DIRECTORY_SEPARATOR.'phpThumbCacheIMversion.txt'; @@ -1394,13 +1479,13 @@ function ImageMagickVersion($returnRAW=false) { } else { $commandline = $this->ImageMagickCommandlineBase(); - $commandline = (!is_null($commandline) ? $commandline : ''); + $commandline = (null !== $commandline ? $commandline : ''); if ($commandline) { $commandline .= ' --version'; $this->DebugMessage('ImageMagick version checked with "'.$commandline.'"', __FILE__, __LINE__); $versionstring[1] = trim(phpthumb_functions::SafeExec($commandline)); - if (preg_match('#^Version: [^0-9]*([ 0-9\\.\\:Q/\\-]+)#i', $versionstring[1], $matches)) { - $versionstring[0] = $matches[1]; + if (preg_match('#^Version: [^\d]*([ 0-9\\.\\:Q/\\-]+)#i', $versionstring[1], $matches)) { + $versionstring[0] = trim($matches[1]); } else { $versionstring[0] = false; $this->DebugMessage('ImageMagick did not return recognized version string ('.$versionstring[1].')', __FILE__, __LINE__); @@ -1409,19 +1494,20 @@ function ImageMagickVersion($returnRAW=false) { } @file_put_contents($IMversionCacheFilename, $versionstring[0]."\n".$versionstring[1]); + @chmod($IMversionCacheFilename, $this->getParameter('config_file_create_mask')); } } - return $versionstring[intval($returnRAW)]; + return $versionstring[ (int) $returnRAW ]; } - function ImageMagickSwitchAvailable($switchname) { + public function ImageMagickSwitchAvailable($switchname) { static $IMoptions = null; - if (is_null($IMoptions)) { + if (null === $IMoptions) { $IMoptions = array(); $commandline = $this->ImageMagickCommandlineBase(); - if (!is_null($commandline)) { + if (null !== $commandline) { $commandline .= ' -help'; $IMhelp_lines = explode("\n", phpthumb_functions::SafeExec($commandline)); foreach ($IMhelp_lines as $line) { @@ -1439,21 +1525,21 @@ function ImageMagickSwitchAvailable($switchname) { break; } } - $this->DebugMessage('ImageMagickSwitchAvailable('.implode(';', $switchname).') = '.intval($allOK).'', __FILE__, __LINE__); + $this->DebugMessage('ImageMagickSwitchAvailable('.implode(';', $switchname).') = '. (int) $allOK .'', __FILE__, __LINE__); } else { $allOK = isset($IMoptions[$switchname]); - $this->DebugMessage('ImageMagickSwitchAvailable('.$switchname.') = '.intval($allOK).'', __FILE__, __LINE__); + $this->DebugMessage('ImageMagickSwitchAvailable('.$switchname.') = '. (int) $allOK .'', __FILE__, __LINE__); } return $allOK; } - function ImageMagickFormatsList() { + public function ImageMagickFormatsList() { static $IMformatsList = null; - if (is_null($IMformatsList)) { + if (null === $IMformatsList) { $IMformatsList = ''; $commandline = $this->ImageMagickCommandlineBase(); - if (!is_null($commandline)) { + if (null !== $commandline) { $commandline = dirname($commandline).DIRECTORY_SEPARATOR.str_replace('convert', 'identify', basename($commandline)); $commandline .= ' -list format'; $IMformatsList = phpthumb_functions::SafeExec($commandline); @@ -1463,9 +1549,9 @@ function ImageMagickFormatsList() { } - function SourceDataToTempFile() { + public function SourceDataToTempFile() { if ($IMtempSourceFilename = $this->phpThumb_tempnam()) { - $IMtempSourceFilename = realpath($IMtempSourceFilename); + $IMtempSourceFilename = $this->realPathSafe($IMtempSourceFilename); ob_start(); $fp_tempfile = fopen($IMtempSourceFilename, 'wb'); $tempfile_open_error = ob_get_contents(); @@ -1473,6 +1559,7 @@ function SourceDataToTempFile() { if ($fp_tempfile) { fwrite($fp_tempfile, $this->rawImageData); fclose($fp_tempfile); + @chmod($IMtempSourceFilename, $this->getParameter('config_file_create_mask')); $this->sourceFilename = $IMtempSourceFilename; $this->DebugMessage('ImageMagickThumbnailToGD() setting $this->sourceFilename to "'.$IMtempSourceFilename.'" from $this->rawImageData ('.strlen($this->rawImageData).' bytes)', __FILE__, __LINE__); } else { @@ -1486,7 +1573,7 @@ function SourceDataToTempFile() { } - function ImageMagickThumbnailToGD() { + public function ImageMagickThumbnailToGD() { // http://www.imagemagick.org/script/command-line-options.php $this->useRawIMoutput = true; @@ -1496,7 +1583,7 @@ function ImageMagickThumbnailToGD() { // $UnAllowedParameters contains options that can only be processed in GD, not ImageMagick // note: 'fltr' *may* need to be processed by GD, but we'll check that in more detail below $UnAllowedParameters = array('xto', 'ar', 'bg', 'bc'); - // 'ra' may be part of this list, if not a multiple of 90� + // 'ra' may be part of this list, if not a multiple of 90 degrees foreach ($UnAllowedParameters as $parameter) { if (isset($this->$parameter)) { $this->DebugMessage('$this->useRawIMoutput=false because "'.$parameter.'" is set', __FILE__, __LINE__); @@ -1506,39 +1593,40 @@ function ImageMagickThumbnailToGD() { } } $this->DebugMessage('$this->useRawIMoutput='.($this->useRawIMoutput ? 'true' : 'false').' after checking $UnAllowedParameters', __FILE__, __LINE__); + $ImageCreateFunction = ''; $outputFormat = $this->thumbnailFormat; if (phpthumb_functions::gd_version()) { if ($this->useRawIMoutput) { switch ($this->thumbnailFormat) { case 'gif': - $ImageCreateFunction = 'ImageCreateFromGIF'; + $ImageCreateFunction = 'imagecreatefromgif'; $this->is_alpha = true; break; case 'png': - $ImageCreateFunction = 'ImageCreateFromPNG'; + $ImageCreateFunction = 'imagecreatefrompng'; $this->is_alpha = true; break; case 'jpg': case 'jpeg': - $ImageCreateFunction = 'ImageCreateFromJPEG'; + $ImageCreateFunction = 'imagecreatefromjpeg'; break; default: $this->DebugMessage('Forcing output to PNG because $this->thumbnailFormat ('.$this->thumbnailFormat.' is not a GD-supported format)', __FILE__, __LINE__); $outputFormat = 'png'; - $ImageCreateFunction = 'ImageCreateFromPNG'; + $ImageCreateFunction = 'imagecreatefrompng'; $this->is_alpha = true; $this->useRawIMoutput = false; break; } if (!function_exists(@$ImageCreateFunction)) { - // ImageMagickThumbnailToGD() depends on ImageCreateFromPNG/ImageCreateFromGIF + // ImageMagickThumbnailToGD() depends on imagecreatefrompng/imagecreatefromgif //$this->DebugMessage('ImageMagickThumbnailToGD() aborting because '.@$ImageCreateFunction.'() is not available', __FILE__, __LINE__); $this->useRawIMoutput = true; //return false; } } else { $outputFormat = 'png'; - $ImageCreateFunction = 'ImageCreateFromPNG'; + $ImageCreateFunction = 'imagecreatefrompng'; $this->is_alpha = true; $this->useRawIMoutput = false; } @@ -1567,8 +1655,9 @@ function ImageMagickThumbnailToGD() { $commandline = $this->ImageMagickCommandlineBase(); if ($commandline) { + $commandline .= ' '.phpthumb_functions::escapeshellarg_replacement(preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $this->sourceFilename).(($outputFormat == 'gif') ? '' : '['. (int) $this->sfn .']')); // [0] means first frame of (GIF) animation, can be ignored if ($IMtempfilename = $this->phpThumb_tempnam()) { - $IMtempfilename = realpath($IMtempfilename); + $IMtempfilename = $this->realPathSafe($IMtempfilename); $IMuseExplicitImageOutputDimensions = false; if ($this->ImageMagickSwitchAvailable('thumbnail') && $this->config_imagemagick_use_thumbnail) { @@ -1577,32 +1666,39 @@ function ImageMagickThumbnailToGD() { $IMresizeParameter = 'resize'; // some (older? around 2002) versions of IM won't accept "-resize 100x" but require "-resize 100x100" - $commandline_test = $this->ImageMagickCommandlineBase().' logo: -resize 1x '.$this->customEscapeshellarg($IMtempfilename).' 2>&1'; + $commandline_test = $this->ImageMagickCommandlineBase().' logo: -resize 1x '.phpthumb_functions::escapeshellarg_replacement($IMtempfilename).' 2>&1'; $IMresult_test = phpthumb_functions::SafeExec($commandline_test); $IMuseExplicitImageOutputDimensions = preg_match('#image dimensions are zero#i', $IMresult_test); - $this->DebugMessage('IMuseExplicitImageOutputDimensions = '.intval($IMuseExplicitImageOutputDimensions), __FILE__, __LINE__); + $this->DebugMessage('IMuseExplicitImageOutputDimensions = '. (int) $IMuseExplicitImageOutputDimensions, __FILE__, __LINE__); if ($fp_im_temp = @fopen($IMtempfilename, 'wb')) { // erase temp image so ImageMagick logo doesn't get output if other processing fails fclose($fp_im_temp); + @chmod($IMtempfilename, $this->getParameter('config_file_create_mask')); } } - if (!is_null($this->dpi) && $this->ImageMagickSwitchAvailable('density')) { - // for raster source formats only (WMF, PDF, etc) - $commandline .= ' -density '.$this->customEscapeshellarg($this->dpi); - } ob_start(); - $getimagesize = GetImageSize($this->sourceFilename); + $getimagesize = getimagesize($this->sourceFilename); $GetImageSizeError = ob_get_contents(); ob_end_clean(); if (is_array($getimagesize)) { - $this->DebugMessage('GetImageSize('.$this->sourceFilename.') SUCCEEDED: '.print_r($getimagesize, true), __FILE__, __LINE__); + $this->DebugMessage('getimagesize('.$this->sourceFilename.') SUCCEEDED: '.print_r($getimagesize, true), __FILE__, __LINE__); } else { - $this->DebugMessage('GetImageSize('.$this->sourceFilename.') FAILED with error "'.$GetImageSizeError.'"', __FILE__, __LINE__); + $this->DebugMessage('getimagesize('.$this->sourceFilename.') FAILED with error "'.$GetImageSizeError.'"', __FILE__, __LINE__); + } + if (null !== $this->dpi && $this->ImageMagickSwitchAvailable('density')) { + // for vector source formats only (WMF, PDF, etc) + if (is_array($getimagesize) && isset($getimagesize[2]) && ($getimagesize[2] == IMAGETYPE_PNG)) { + // explicitly exclude PNG from "-flatten" to make sure transparency is preserved + // https://github.com/JamesHeinrich/phpThumb/issues/65 + } else { + $commandline .= ' -flatten'; + $commandline .= ' -density '.phpthumb_functions::escapeshellarg_replacement($this->dpi); + } } if (is_array($getimagesize)) { - $this->DebugMessage('GetImageSize('.$this->sourceFilename.') returned [w='.$getimagesize[0].';h='.$getimagesize[1].';f='.$getimagesize[2].']', __FILE__, __LINE__); + $this->DebugMessage('getimagesize('.$this->sourceFilename.') returned [w='.$getimagesize[0].';h='.$getimagesize[1].';f='.$getimagesize[2].']', __FILE__, __LINE__); $this->source_width = $getimagesize[0]; $this->source_height = $getimagesize[1]; $this->DebugMessage('source dimensions set to '.$this->source_width.'x'.$this->source_height, __FILE__, __LINE__); @@ -1610,10 +1706,14 @@ function ImageMagickThumbnailToGD() { if (!preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat)) { // not a transparency-capable format - $commandline .= ' -background '.$this->customEscapeshellarg('#'.($this->bg ? $this->bg : 'FFFFFF')); + $commandline .= ' -background '.phpthumb_functions::escapeshellarg_replacement('#'.($this->bg ? $this->bg : 'FFFFFF')); if ($getimagesize[2] == IMAGETYPE_GIF) { $commandline .= ' -flatten'; } + } else { + if ($getimagesize[2] == IMAGETYPE_PNG && !$this->bg) { + $commandline .= ' -background none'; + } } if ($getimagesize[2] == IMAGETYPE_GIF) { $commandline .= ' -coalesce'; // may be needed for animated GIFs @@ -1624,14 +1724,14 @@ function ImageMagickThumbnailToGD() { $borderThickness = 0; if (!empty($this->fltr)) { foreach ($this->fltr as $key => $value) { - if (preg_match('#^bord\|([0-9]+)#', $value, $matches)) { + if (preg_match('#^bord\|([\d]+)#', $value, $matches)) { $borderThickness = $matches[1]; break; } } } - $wAll = intval(max($this->w, $this->wp, $this->wl, $this->ws)) - (2 * $borderThickness); - $hAll = intval(max($this->h, $this->hp, $this->hl, $this->hs)) - (2 * $borderThickness); + $wAll = (int) max($this->w, $this->wp, $this->wl, $this->ws) - (2 * $borderThickness); + $hAll = (int) max($this->h, $this->hp, $this->hl, $this->hs) - (2 * $borderThickness); $imAR = $this->source_width / $this->source_height; $zcAR = (($wAll && $hAll) ? $wAll / $hAll : 1); $side = phpthumb_functions::nonempty_min($this->source_width, $this->source_height, max($wAll, $hAll)); @@ -1639,7 +1739,11 @@ function ImageMagickThumbnailToGD() { $sideY = phpthumb_functions::nonempty_min( $this->source_height, $hAll, round($wAll / $zcAR)); $thumbnailH = round(max($sideY, ($sideY * $zcAR) / $imAR)); - $commandline .= ' -'.$IMresizeParameter.' '.$this->customEscapeshellarg(($IMuseExplicitImageOutputDimensions ? $thumbnailH : '').'x'.$thumbnailH); + if ($this->aoe == 1) { + $commandline .= ' -'.$IMresizeParameter.' "'.$wAll.'x'.$hAll.'^"'; + } else { + $commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement(($IMuseExplicitImageOutputDimensions ? $thumbnailH : '').'x'.$thumbnailH); + } switch (strtoupper($this->zc)) { case 'T': @@ -1674,9 +1778,9 @@ function ImageMagickThumbnailToGD() { } if (($wAll > 0) && ($hAll > 0)) { - $commandline .= ' -crop '.$this->customEscapeshellarg($wAll.'x'.$hAll.'+0+0'); + $commandline .= ' -crop '.phpthumb_functions::escapeshellarg_replacement($wAll.'x'.$hAll.'+0+0'); } else { - $commandline .= ' -crop '.$this->customEscapeshellarg($side.'x'.$side.'+0+0'); + $commandline .= ' -crop '.phpthumb_functions::escapeshellarg_replacement($side.'x'.$side.'+0+0'); } if ($this->ImageMagickSwitchAvailable('repage')) { $commandline .= ' +repage'; @@ -1695,7 +1799,7 @@ function ImageMagickThumbnailToGD() { // makes 1x1 output // http://trainspotted.com/phpThumb/phpThumb.php?src=/content/CNR/47/CNR-4728-LD-L-20110723-898.jpg&w=100&h=100&far=1&f=png&fltr[]=lvl&sx=0.05&sy=0.25&sw=0.92&sh=0.42 // '/usr/bin/convert' -density 150 -thumbnail 100x100 -contrast-stretch '0.1%' '/var/www/vhosts/trainspotted.com/httpdocs/content/CNR/47/CNR-4728-LD-L-20110723-898.jpg[0]' png:'/var/www/vhosts/trainspotted.com/httpdocs/phpThumb/_cache/pThumbIIUlvj' - $commandline .= ' -crop '.$this->customEscapeshellarg($crop_param); + $commandline .= ' -crop '.phpthumb_functions::escapeshellarg_replacement($crop_param); // this is broken for aoe=1, but unsure how to fix. Send advice to info@silisoftware.com if ($this->w || $this->h) { @@ -1714,19 +1818,29 @@ function ImageMagickThumbnailToGD() { $this->w = ceil($this->h * ($this->source_width / $this->source_height)); } } - $commandline .= ' -'.$IMresizeParameter.' '.$this->customEscapeshellarg($this->w.'x'.$this->h); + $commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement($this->w.'x'.$this->h); } } else { - if ($this->iar && (intval($this->w) > 0) && (intval($this->h) > 0)) { + if ($this->iar && ((int) $this->w > 0) && ((int) $this->h > 0)) { + list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra); $nw = ((round($nw) != 0) ? round($nw) : ''); $nh = ((round($nh) != 0) ? round($nh) : ''); - $commandline .= ' -'.$IMresizeParameter.' '.$this->customEscapeshellarg($nw.'x'.$nh.'!'); + $commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement($nw.'x'.$nh.'!'); + + } elseif ($this->far && ((int) $this->w > 0) && ((int) $this->h > 0)) { + + $commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement(phpthumb_functions::nonempty_min($this->w, $getimagesize[0]).'x'.phpthumb_functions::nonempty_min($this->h, $getimagesize[1])); + $commandline .= ' -gravity center'; + $commandline .= ' -background '.phpthumb_functions::escapeshellarg_replacement('#'.$this->bg); + $commandline .= ' -extent '.phpthumb_functions::escapeshellarg_replacement($this->w.'x'.$this->h); + } else { - $this->w = ((($this->aoe || $this->far) && $this->w) ? $this->w : ($this->w ? phpthumb_functions::nonempty_min($this->w, $getimagesize[0]) : '')); - $this->h = ((($this->aoe || $this->far) && $this->h) ? $this->h : ($this->h ? phpthumb_functions::nonempty_min($this->h, $getimagesize[1]) : '')); + + $this->w = (($this->aoe && $this->w) ? $this->w : ($this->w ? phpthumb_functions::nonempty_min($this->w, $getimagesize[0]) : '')); + $this->h = (($this->aoe && $this->h) ? $this->h : ($this->h ? phpthumb_functions::nonempty_min($this->h, $getimagesize[1]) : '')); if ($this->w || $this->h) { if ($IMuseExplicitImageOutputDimensions) { if ($this->w && !$this->h) { @@ -1738,39 +1852,40 @@ function ImageMagickThumbnailToGD() { list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra); $nw = ((round($nw) != 0) ? round($nw) : ''); $nh = ((round($nh) != 0) ? round($nh) : ''); - $commandline .= ' -'.$IMresizeParameter.' '.$this->customEscapeshellarg($nw.'x'.$nh); + $commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement($nw.'x'.$nh); } + } } } } else { - $this->DebugMessage('GetImageSize('.$this->sourceFilename.') failed', __FILE__, __LINE__); + $this->DebugMessage('getimagesize('.$this->sourceFilename.') failed', __FILE__, __LINE__); if ($this->w || $this->h) { - $exactDimensionsBang = (($this->iar && (intval($this->w) > 0) && (intval($this->h) > 0)) ? '!' : ''); + $exactDimensionsBang = (($this->iar && ((int) $this->w > 0) && ((int) $this->h > 0)) ? '!' : ''); if ($IMuseExplicitImageOutputDimensions) { // unknown source aspect ratio, just put large number and hope IM figures it out - $commandline .= ' -'.$IMresizeParameter.' '.$this->customEscapeshellarg(($this->w ? $this->w : '9999').'x'.($this->h ? $this->h : '9999').$exactDimensionsBang); + $commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement(($this->w ? $this->w : '9999').'x'.($this->h ? $this->h : '9999').$exactDimensionsBang); } else { - $commandline .= ' -'.$IMresizeParameter.' '.$this->customEscapeshellarg($this->w.'x'.$this->h.$exactDimensionsBang); + $commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement($this->w.'x'.$this->h.$exactDimensionsBang); } } } if ($this->ra) { - $this->ra = intval($this->ra); + $this->ra = (int) $this->ra; if ($this->ImageMagickSwitchAvailable('rotate')) { if (!preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat) || phpthumb_functions::version_compare_replacement($this->ImageMagickVersion(), '6.3.7', '>=')) { $this->DebugMessage('Using ImageMagick rotate', __FILE__, __LINE__); - $commandline .= ' -rotate '.$this->customEscapeshellarg($this->ra); + $commandline .= ' -rotate '.phpthumb_functions::escapeshellarg_replacement($this->ra); if (($this->ra % 90) != 0) { if (preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat)) { // alpha-capable format $commandline .= ' -background rgba(255,255,255,0)'; } else { - $commandline .= ' -background '.$this->customEscapeshellarg('#'.($this->bg ? $this->bg : 'FFFFFF')); + $commandline .= ' -background '.phpthumb_functions::escapeshellarg_replacement('#'.($this->bg ? $this->bg : 'FFFFFF')); } } $this->ra = 0; @@ -1788,14 +1903,14 @@ function ImageMagickThumbnailToGD() { switch ($command) { case 'brit': if ($this->ImageMagickSwitchAvailable('modulate')) { - $commandline .= ' -modulate '.$this->customEscapeshellarg((100 + intval($parameter)).',100,100'); + $commandline .= ' -modulate '.phpthumb_functions::escapeshellarg_replacement((100 + (int) $parameter).',100,100'); $successfullyProcessedFilters[] = $filterkey; } break; case 'cont': if ($this->ImageMagickSwitchAvailable('contrast')) { - $contDiv10 = round(intval($parameter) / 10); + $contDiv10 = round((int) $parameter / 10); if ($contDiv10 > 0) { $contDiv10 = min($contDiv10, 100); for ($i = 0; $i < $contDiv10; $i++) { @@ -1819,7 +1934,7 @@ function ImageMagickThumbnailToGD() { $commandline .= ' -colorspace GRAY'; $commandline .= ' -modulate 100,0,100'; } else { - $commandline .= ' -modulate '.$this->customEscapeshellarg('100,'.(100 - intval($parameter)).',100'); + $commandline .= ' -modulate '.phpthumb_functions::escapeshellarg_replacement('100,'.(100 - (int) $parameter).',100'); } $successfullyProcessedFilters[] = $filterkey; } @@ -1831,7 +1946,7 @@ function ImageMagickThumbnailToGD() { $commandline .= ' -colorspace GRAY'; $commandline .= ' -modulate 100,0,100'; } else { - $commandline .= ' -modulate '.$this->customEscapeshellarg('100,'.(100 + intval($parameter)).',100'); + $commandline .= ' -modulate '.phpthumb_functions::escapeshellarg_replacement('100,'.(100 + (int) $parameter).',100'); } $successfullyProcessedFilters[] = $filterkey; } @@ -1848,8 +1963,9 @@ function ImageMagickThumbnailToGD() { case 'clr': if ($this->ImageMagickSwitchAvailable(array('fill', 'colorize'))) { @list($amount, $color) = explode('|', $parameter); - $commandline .= ' -fill '.$this->customEscapeshellarg('#'.preg_replace('#[^0-9A-F]#i', '', $color)); - $commandline .= ' -colorize '.$this->customEscapeshellarg(min(max(intval($amount), 0), 100)); + $commandline .= ' -fill '.phpthumb_functions::escapeshellarg_replacement('#'.preg_replace('#[^0-9A-F]#i', '', $color)); + $commandline .= ' -colorize '.phpthumb_functions::escapeshellarg_replacement(min(max((int) $amount, 0), 100)); + $successfullyProcessedFilters[] = $filterkey; } break; @@ -1858,7 +1974,7 @@ function ImageMagickThumbnailToGD() { @list($amount, $color) = explode('|', $parameter); $amount = ($amount ? $amount : 80); if (!$color) { - $commandline .= ' -sepia-tone '.$this->customEscapeshellarg(min(max(intval($amount), 0), 100).'%'); + $commandline .= ' -sepia-tone '.phpthumb_functions::escapeshellarg_replacement(min(max((int) $amount, 0), 100).'%'); $successfullyProcessedFilters[] = $filterkey; } } @@ -1866,10 +1982,10 @@ function ImageMagickThumbnailToGD() { case 'gam': @list($amount) = explode('|', $parameter); - $amount = min(max(floatval($amount), 0.001), 10); + $amount = min(max((float) $amount, 0.001), 10); if (number_format($amount, 3) != '1.000') { if ($this->ImageMagickSwitchAvailable('gamma')) { - $commandline .= ' -gamma '.$this->customEscapeshellarg($amount); + $commandline .= ' -gamma '.phpthumb_functions::escapeshellarg_replacement($amount); $successfullyProcessedFilters[] = $filterkey; } } @@ -1885,7 +2001,7 @@ function ImageMagickThumbnailToGD() { case 'th': @list($amount) = explode('|', $parameter); if ($this->ImageMagickSwitchAvailable(array('threshold', 'dither', 'monochrome'))) { - $commandline .= ' -threshold '.$this->customEscapeshellarg(round(min(max(intval($amount), 0), 255) / 2.55).'%'); + $commandline .= ' -threshold '.phpthumb_functions::escapeshellarg_replacement(round(min(max((int) $amount, 0), 255) / 2.55).'%'); $commandline .= ' -dither'; $commandline .= ' -monochrome'; $successfullyProcessedFilters[] = $filterkey; @@ -1897,7 +2013,7 @@ function ImageMagickThumbnailToGD() { @list($colors, $dither) = explode('|', $parameter); $colors = ($colors ? (int) $colors : 256); $dither = ((strlen($dither) > 0) ? (bool) $dither : true); - $commandline .= ' -colors '.$this->customEscapeshellarg(max($colors, 8)); // ImageMagick will otherwise fail with "cannot quantize to fewer than 8 colors" + $commandline .= ' -colors '.phpthumb_functions::escapeshellarg_replacement(max($colors, 8)); // ImageMagick will otherwise fail with "cannot quantize to fewer than 8 colors" $commandline .= ($dither ? ' -dither' : ' +dither'); $successfullyProcessedFilters[] = $filterkey; } @@ -1918,7 +2034,7 @@ function ImageMagickThumbnailToGD() { case 'edge': if ($this->ImageMagickSwitchAvailable('edge')) { $parameter = (!empty($parameter) ? $parameter : 2); - $commandline .= ' -edge '.$this->customEscapeshellarg(!empty($parameter) ? intval($parameter) : 1); + $commandline .= ' -edge '.phpthumb_functions::escapeshellarg_replacement(!empty($parameter) ? (int) $parameter : 1); $successfullyProcessedFilters[] = $filterkey; } break; @@ -1926,7 +2042,7 @@ function ImageMagickThumbnailToGD() { case 'emb': if ($this->ImageMagickSwitchAvailable(array('emboss', 'negate'))) { $parameter = (!empty($parameter) ? $parameter : 2); - $commandline .= ' -emboss '.$this->customEscapeshellarg(intval($parameter)); + $commandline .= ' -emboss '.phpthumb_functions::escapeshellarg_replacement((int) $parameter); if ($parameter < 2) { $commandline .= ' -negate'; // ImageMagick negates the image for some reason with '-emboss 1'; } @@ -1937,8 +2053,8 @@ function ImageMagickThumbnailToGD() { case 'lvl': @list($band, $method, $threshold) = explode('|', $parameter); $band = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band)) : '*'); - $method = ((strlen($method) > 0) ? intval($method) : 2); - $threshold = ((strlen($threshold) > 0) ? min(max(floatval($threshold), 0), 100) : 0.1); + $method = ((strlen($method) > 0) ? (int) $method : 2); + $threshold = ((strlen($threshold) > 0) ? min(max((float) $threshold, 0), 100) : 0.1); $band = preg_replace('#[^RGBA\\*]#', '', strtoupper($band)); @@ -1963,10 +2079,10 @@ function ImageMagickThumbnailToGD() { case 2: // ImageMagick "contrast-stretch" if ($this->ImageMagickSwitchAvailable('contrast-stretch')) { if ($band != '*') { - $commandline .= ' -channel '.$this->customEscapeshellarg(strtoupper($band)); + $commandline .= ' -channel '.phpthumb_functions::escapeshellarg_replacement(strtoupper($band)); } $threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure - //$commandline .= ' -contrast-stretch '.escapeshellarg($threshold.'%'); + //$commandline .= ' -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); $commandline .= ' -contrast-stretch \''.$threshold.'%\''; if ($band != '*') { $commandline .= ' +channel'; @@ -1977,7 +2093,7 @@ function ImageMagickThumbnailToGD() { case 3: // ImageMagick "normalize" if ($this->ImageMagickSwitchAvailable('normalize')) { if ($band != '*') { - $commandline .= ' -channel '.$this->customEscapeshellarg(strtoupper($band)); + $commandline .= ' -channel '.phpthumb_functions::escapeshellarg_replacement(strtoupper($band)); } $commandline .= ' -normalize'; if ($band != '*') { @@ -1999,11 +2115,11 @@ function ImageMagickThumbnailToGD() { case 'wb': if ($this->ImageMagickSwitchAvailable(array('channel', 'contrast-stretch'))) { @list($threshold) = explode('|', $parameter); - $threshold = (!empty($threshold) ? min(max(floatval($threshold), 0), 100) : 0.1); + $threshold = (!empty($threshold) ? min(max((float) $threshold, 0), 100) : 0.1); $threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure - //$commandline .= ' -channel R -contrast-stretch '.escapeshellarg($threshold.'%'); // doesn't work on Windows because most versions of PHP do not properly - //$commandline .= ' -channel G -contrast-stretch '.escapeshellarg($threshold.'%'); // escape special characters (such as %) and just replace them with spaces - //$commandline .= ' -channel B -contrast-stretch '.escapeshellarg($threshold.'%'); // https://bugs.php.net/bug.php?id=43261 + //$commandline .= ' -channel R -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // doesn't work on Windows because most versions of PHP do not properly + //$commandline .= ' -channel G -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // escape special characters (such as %) and just replace them with spaces + //$commandline .= ' -channel B -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // https://bugs.php.net/bug.php?id=43261 $commandline .= ' -channel R -contrast-stretch \''.$threshold.'%\''; $commandline .= ' -channel G -contrast-stretch \''.$threshold.'%\''; $commandline .= ' -channel B -contrast-stretch \''.$threshold.'%\''; @@ -2015,21 +2131,21 @@ function ImageMagickThumbnailToGD() { case 'blur': if ($this->ImageMagickSwitchAvailable('blur')) { @list($radius) = explode('|', $parameter); - $radius = (!empty($radius) ? min(max(intval($radius), 0), 25) : 1); - $commandline .= ' -blur '.$this->customEscapeshellarg($radius); + $radius = (!empty($radius) ? min(max((int) $radius, 0), 25) : 1); + $commandline .= ' -blur '.phpthumb_functions::escapeshellarg_replacement($radius); $successfullyProcessedFilters[] = $filterkey; } break; case 'gblr': @list($radius) = explode('|', $parameter); - $radius = (!empty($radius) ? min(max(intval($radius), 0), 25) : 1); + $radius = (!empty($radius) ? min(max((int) $radius, 0), 25) : 1); // "-gaussian" changed to "-gaussian-blur" sometime around 2009 if ($this->ImageMagickSwitchAvailable('gaussian-blur')) { - $commandline .= ' -gaussian-blur '.$this->customEscapeshellarg($radius); + $commandline .= ' -gaussian-blur '.phpthumb_functions::escapeshellarg_replacement($radius); $successfullyProcessedFilters[] = $filterkey; } elseif ($this->ImageMagickSwitchAvailable('gaussian')) { - $commandline .= ' -gaussian '.$this->customEscapeshellarg($radius); + $commandline .= ' -gaussian '.phpthumb_functions::escapeshellarg_replacement($radius); $successfullyProcessedFilters[] = $filterkey; } break; @@ -2037,10 +2153,10 @@ function ImageMagickThumbnailToGD() { case 'usm': if ($this->ImageMagickSwitchAvailable('unsharp')) { @list($amount, $radius, $threshold) = explode('|', $parameter); - $amount = ($amount ? min(max(intval($radius), 0), 255) : 80); - $radius = ($radius ? min(max(intval($radius), 0), 10) : 0.5); - $threshold = (strlen($threshold) ? min(max(intval($radius), 0), 50) : 3); - $commandline .= ' -unsharp '.$this->customEscapeshellarg(number_format(($radius * 2) - 1, 2, '.', '').'x1+'.number_format($amount / 100, 2, '.', '').'+'.number_format($threshold / 100, 2, '.', '')); + $amount = ($amount ? min(max((int) $amount, 0), 255) : 80); + $radius = ($radius ? min(max((int) $radius, 0), 10) : 0.5); + $threshold = ('' !== $threshold ? min(max((int) $threshold, 0), 50) : 3); + $commandline .= ' -unsharp '.phpthumb_functions::escapeshellarg_replacement(number_format(($radius * 2) - 1, 2, '.', '').'x1+'.number_format($amount / 100, 2, '.', '').'+'.number_format($threshold / 100, 2, '.', '')); $successfullyProcessedFilters[] = $filterkey; } break; @@ -2049,20 +2165,20 @@ function ImageMagickThumbnailToGD() { if ($this->ImageMagickSwitchAvailable(array('border', 'bordercolor', 'thumbnail', 'crop'))) { if (!$this->zc) { @list($width, $rX, $rY, $color) = explode('|', $parameter); - $width = intval($width); - $rX = intval($rX); - $rY = intval($rY); + $width = (int) $width; + $rX = (int) $rX; + $rY = (int) $rY; if ($width && !$rX && !$rY) { if (!phpthumb_functions::IsHexColor($color)) { $color = ((!empty($this->bc) && phpthumb_functions::IsHexColor($this->bc)) ? $this->bc : '000000'); } - $commandline .= ' -border '.$this->customEscapeshellarg(intval($width)); - $commandline .= ' -bordercolor '.$this->customEscapeshellarg('#'.$color); + $commandline .= ' -border '.phpthumb_functions::escapeshellarg_replacement((int) $width); + $commandline .= ' -bordercolor '.phpthumb_functions::escapeshellarg_replacement('#'.$color); - if (preg_match('# \\-crop "([0-9]+)x([0-9]+)\\+0\\+0" #', $commandline, $matches)) { - $commandline = str_replace(' -crop "'.$matches[1].'x'.$matches[2].'+0+0" ', ' -crop '.$this->customEscapeshellarg(($matches[1] - (2 * $width)).'x'.($matches[2] - (2 * $width)).'+0+0').' ', $commandline); + if (preg_match('# \\-crop "([\d]+)x([\d]+)\\+0\\+0" #', $commandline, $matches)) { + $commandline = str_replace(' -crop "'.$matches[1].'x'.$matches[2].'+0+0" ', ' -crop '.phpthumb_functions::escapeshellarg_replacement(($matches[1] - (2 * $width)).'x'.($matches[2] - (2 * $width)).'+0+0').' ', $commandline); } elseif (preg_match('# \\-'.$IMresizeParameter.' "([0-9]+)x([0-9]+)" #', $commandline, $matches)) { - $commandline = str_replace(' -'.$IMresizeParameter.' "'.$matches[1].'x'.$matches[2].'" ', ' -'.$IMresizeParameter.' '.$this->customEscapeshellarg(($matches[1] - (2 * $width)).'x'.($matches[2] - (2 * $width))).' ', $commandline); + $commandline = str_replace(' -'.$IMresizeParameter.' "'.$matches[1].'x'.$matches[2].'" ', ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement(($matches[1] - (2 * $width)).'x'.($matches[2] - (2 * $width))).' ', $commandline); } $successfullyProcessedFilters[] = $filterkey; } @@ -2136,15 +2252,14 @@ function ImageMagickThumbnailToGD() { if (preg_match('#jpe?g#i', $outputFormat) && $this->q) { if ($this->ImageMagickSwitchAvailable(array('quality', 'interlace'))) { - $commandline .= ' -quality '.$this->customEscapeshellarg($this->thumbnailQuality); + $commandline .= ' -quality '.phpthumb_functions::escapeshellarg_replacement($this->thumbnailQuality); if ($this->config_output_interlace) { // causes weird things with animated GIF... leave for JPEG only $commandline .= ' -interlace line '; // Use Line or Plane to create an interlaced PNG or GIF or progressive JPEG image } } } - $commandline .= ' '.$this->customEscapeshellarg(preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $this->sourceFilename).(($outputFormat == 'gif') ? '' : '['.intval($this->sfn).']')); // [0] means first frame of (GIF) animation, can be ignored - $commandline .= ' '.$outputFormat.':'.$this->customEscapeshellarg($IMtempfilename); + $commandline .= ' '.$outputFormat.':'.phpthumb_functions::escapeshellarg_replacement($IMtempfilename); if (!$this->iswindows) { $commandline .= ' 2>&1'; } @@ -2164,13 +2279,13 @@ function ImageMagickThumbnailToGD() { unset($this->fltr[$filterkey]); } $this->IMresizedData = file_get_contents($IMtempfilename); - $getimagesize_imresized = @GetImageSize($IMtempfilename); - $this->DebugMessage('GetImageSize('.$IMtempfilename.') returned [w='.$getimagesize_imresized[0].';h='.$getimagesize_imresized[1].';f='.$getimagesize_imresized[2].']', __FILE__, __LINE__); + $getimagesize_imresized = @getimagesize($IMtempfilename); + $this->DebugMessage('getimagesize('.$IMtempfilename.') returned [w='.$getimagesize_imresized[0].';h='.$getimagesize_imresized[1].';f='.$getimagesize_imresized[2].']', __FILE__, __LINE__); if (($this->config_max_source_pixels > 0) && (($getimagesize_imresized[0] * $getimagesize_imresized[1]) > $this->config_max_source_pixels)) { $this->DebugMessage('skipping ImageMagickThumbnailToGD::'.$ImageCreateFunction.'() because IM output is too large ('.$getimagesize_imresized[0].'x'.$getimagesize_imresized[0].' = '.($getimagesize_imresized[0] * $getimagesize_imresized[1]).' > '.$this->config_max_source_pixels.')', __FILE__, __LINE__); } elseif (function_exists(@$ImageCreateFunction) && ($this->gdimg_source = @$ImageCreateFunction($IMtempfilename))) { - $this->source_width = ImageSX($this->gdimg_source); - $this->source_height = ImageSY($this->gdimg_source); + $this->source_width = imagesx($this->gdimg_source); + $this->source_height = imagesy($this->gdimg_source); $this->DebugMessage('ImageMagickThumbnailToGD::'.$ImageCreateFunction.'() succeeded, $this->gdimg_source is now ('.$this->source_width.'x'.$this->source_height.')', __FILE__, __LINE__); $this->DebugMessage('ImageMagickThumbnailToGD() returning $this->IMresizedData ('.strlen($this->IMresizedData).' bytes)', __FILE__, __LINE__); } else { @@ -2207,14 +2322,14 @@ function ImageMagickThumbnailToGD() { } - function Rotate() { + public function Rotate() { if ($this->ra || $this->ar) { - if (!function_exists('ImageRotate')) { - $this->DebugMessage('!function_exists(ImageRotate)', __FILE__, __LINE__); + if (!function_exists('imagerotate')) { + $this->DebugMessage('!function_exists(imagerotate)', __FILE__, __LINE__); return false; } - if (!include_once(dirname(__FILE__) . '/phpthumb.filters.php')) { - $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__); + if (!include_once __DIR__ .'/phpthumb.filters.php' ) { + $this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__); return false; } @@ -2226,12 +2341,12 @@ function Rotate() { $rotate_angle = 0; if ($this->ra) { - $rotate_angle = floatval($this->ra); + $rotate_angle = (float) $this->ra; } else { if ($this->ar == 'x') { - if (phpthumb_functions::version_compare_replacement(phpversion(), '4.2.0', '>=')) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.2.0', '>=')) { if ($this->sourceFilename) { if (function_exists('exif_read_data')) { if ($exif_data = @exif_read_data($this->sourceFilename, 'IFD0')) { @@ -2269,7 +2384,7 @@ function Rotate() { return false; } } else { - $this->DebugMessage('Cannot auto-rotate from EXIF data because PHP is less than v4.2.0 ('.phpversion().')', __FILE__, __LINE__); + $this->DebugMessage('Cannot auto-rotate from EXIF data because PHP is less than v4.2.0 ('. PHP_VERSION .')', __FILE__, __LINE__); return false; } } elseif (($this->ar == 'l') && ($this->source_height > $this->source_width)) { @@ -2286,15 +2401,15 @@ function Rotate() { if ($rotate_angle % 90) { $this->is_alpha = true; } - phpthumb_filters::ImprovedImageRotate($this->gdimg_source, $rotate_angle, $this->config_background_hexcolor, $this->bg); - $this->source_width = ImageSX($this->gdimg_source); - $this->source_height = ImageSY($this->gdimg_source); + phpthumb_filters::ImprovedImageRotate($this->gdimg_source, $rotate_angle, $this->config_background_hexcolor, $this->bg, $this); + $this->source_width = imagesx($this->gdimg_source); + $this->source_height = imagesy($this->gdimg_source); } return true; } - function FixedAspectRatio() { + public function FixedAspectRatio() { // optional fixed-dimension images (regardless of aspect ratio) if (!$this->far) { @@ -2334,7 +2449,7 @@ function FixedAspectRatio() { } - function OffsiteDomainIsAllowed($hostname, $allowed_domains) { + public function OffsiteDomainIsAllowed($hostname, $allowed_domains) { static $domain_is_allowed = array(); $hostname = strtolower($hostname); if (!isset($domain_is_allowed[$hostname])) { @@ -2359,9 +2474,9 @@ function OffsiteDomainIsAllowed($hostname, $allowed_domains) { } - function AntiOffsiteLinking() { + public function AntiOffsiteLinking() { // Optional anti-offsite hijacking of the thumbnail script - $allow = true; + $allow = true; if ($allow && $this->config_nooffsitelink_enabled && (@$_SERVER['HTTP_REFERER'] || $this->config_nooffsitelink_require_refer)) { $this->DebugMessage('AntiOffsiteLinking() checking $_SERVER[HTTP_REFERER] "'.@$_SERVER['HTTP_REFERER'].'"', __FILE__, __LINE__); foreach ($this->config_nooffsitelink_valid_domains as $key => $valid_domain) { @@ -2371,9 +2486,7 @@ function AntiOffsiteLinking() { } $parsed_url = phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']); if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nooffsitelink_valid_domains)) { - $allow = false; - $erase = $this->config_nooffsitelink_erase_image; - $message = $this->config_nooffsitelink_text_message; + $allow = false; //$this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__); $this->ErrorImage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')'); } else { @@ -2387,8 +2500,6 @@ function AntiOffsiteLinking() { if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) { // This domain is not allowed $allow = false; - $erase = $this->config_nohotlink_erase_image; - $message = $this->config_nohotlink_text_message; $this->DebugMessage('AntiOffsiteLinking() - "'.$parsed_url['host'].'" is NOT in $this->config_nohotlink_valid_domains ('.implode(';', $this->config_nohotlink_valid_domains).')', __FILE__, __LINE__); } else { $this->DebugMessage('AntiOffsiteLinking() - "'.$parsed_url['host'].'" is in $this->config_nohotlink_valid_domains ('.implode(';', $this->config_nohotlink_valid_domains).')', __FILE__, __LINE__); @@ -2406,17 +2517,17 @@ function AntiOffsiteLinking() { if (!phpthumb_functions::IsHexColor($this->config_error_textcolor)) { return $this->ErrorImage('Invalid hex color string "'.$this->config_error_textcolor.'" for $this->config_error_textcolor'); } - if ($erase) { + if ($this->config_nooffsitelink_erase_image) { - return $this->ErrorImage($message, $this->thumbnail_width, $this->thumbnail_height, $this->config_error_bgcolor, $this->config_error_textcolor, $this->config_error_fontsize); + return $this->ErrorImage($this->config_nooffsitelink_text_message, $this->thumbnail_width, $this->thumbnail_height); } else { $this->config_nooffsitelink_watermark_src = $this->ResolveFilenameToAbsolute($this->config_nooffsitelink_watermark_src); if (is_file($this->config_nooffsitelink_watermark_src)) { - if (!include_once(dirname(__FILE__) . '/phpthumb.filters.php')) { - $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.filters.php" which is required for applying watermark', __FILE__, __LINE__); + if (!include_once __DIR__ .'/phpthumb.filters.php' ) { + $this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.filters.php" which is required for applying watermark', __FILE__, __LINE__); return false; } $watermark_img = $this->ImageCreateFromStringReplacement(file_get_contents($this->config_nooffsitelink_watermark_src)); @@ -2425,21 +2536,21 @@ function AntiOffsiteLinking() { $opacity = 50; $margin = 5; $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $watermark_img, '*', $opacity, $margin); - ImageDestroy($watermark_img); + imagedestroy($watermark_img); unset($phpthumbFilters); } else { - $nohotlink_text_array = explode("\n", wordwrap($message, floor($this->thumbnail_width / ImageFontWidth($this->config_error_fontsize)), "\n")); + $nohotlink_text_array = explode("\n", wordwrap($this->config_nooffsitelink_text_message, floor($this->thumbnail_width / imagefontwidth($this->config_error_fontsize)), "\n")); $nohotlink_text_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_error_textcolor); - $topoffset = round(($this->thumbnail_height - (count($nohotlink_text_array) * ImageFontHeight($this->config_error_fontsize))) / 2); + $topoffset = round(($this->thumbnail_height - (count($nohotlink_text_array) * imagefontheight($this->config_error_fontsize))) / 2); $rowcounter = 0; - $this->DebugMessage('AntiOffsiteLinking() writing '.count($nohotlink_text_array).' lines of text "'.$message.'" (in #'.$this->config_error_textcolor.') on top of image', __FILE__, __LINE__); + $this->DebugMessage('AntiOffsiteLinking() writing '.count($nohotlink_text_array).' lines of text "'.$this->config_nooffsitelink_text_message.'" (in #'.$this->config_error_textcolor.') on top of image', __FILE__, __LINE__); foreach ($nohotlink_text_array as $textline) { - $leftoffset = max(0, round(($this->thumbnail_width - (strlen($textline) * ImageFontWidth($this->config_error_fontsize))) / 2)); - ImageString($this->gdimg_output, $this->config_error_fontsize, $leftoffset, $topoffset + ($rowcounter++ * ImageFontHeight($this->config_error_fontsize)), $textline, $nohotlink_text_color); + $leftoffset = max(0, round(($this->thumbnail_width - (strlen($textline) * imagefontwidth($this->config_error_fontsize))) / 2)); + imagestring($this->gdimg_output, $this->config_error_fontsize, $leftoffset, $topoffset + ($rowcounter++ * imagefontheight($this->config_error_fontsize)), $textline, $nohotlink_text_color); } } @@ -2449,7 +2560,7 @@ function AntiOffsiteLinking() { } - function AlphaChannelFlatten() { + public function AlphaChannelFlatten() { if (!$this->is_alpha) { // image doesn't have alpha transparency, no need to flatten $this->DebugMessage('skipping AlphaChannelFlatten() because !$this->is_alpha', __FILE__, __LINE__); @@ -2465,7 +2576,7 @@ function AlphaChannelFlatten() { case 'gif': // image has alpha transparency, but output as GIF which can handle only single-color transparency - $CurrentImageColorTransparent = ImageColorTransparent($this->gdimg_output); + $CurrentImageColorTransparent = imagecolortransparent($this->gdimg_output); if ($CurrentImageColorTransparent == -1) { // no transparent color defined @@ -2474,53 +2585,53 @@ function AlphaChannelFlatten() { return false; } - if ($img_alpha_mixdown_dither = @ImageCreateTrueColor(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output))) { + if ($img_alpha_mixdown_dither = @imagecreatetruecolor(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) { + $dither_color = array(); for ($i = 0; $i <= 255; $i++) { - $dither_color[$i] = ImageColorAllocate($img_alpha_mixdown_dither, $i, $i, $i); + $dither_color[$i] = imagecolorallocate($img_alpha_mixdown_dither, $i, $i, $i); } // scan through current truecolor image copy alpha channel to temp image as grayscale for ($x = 0; $x < $this->thumbnail_width; $x++) { for ($y = 0; $y < $this->thumbnail_height; $y++) { $PixelColor = phpthumb_functions::GetPixelColor($this->gdimg_output, $x, $y); - ImageSetPixel($img_alpha_mixdown_dither, $x, $y, $dither_color[($PixelColor['alpha'] * 2)]); + imagesetpixel($img_alpha_mixdown_dither, $x, $y, $dither_color[ $PixelColor[ 'alpha'] * 2 ]); } } // dither alpha channel grayscale version down to 2 colors - ImageTrueColorToPalette($img_alpha_mixdown_dither, true, 2); + imagetruecolortopalette($img_alpha_mixdown_dither, true, 2); // reduce color palette to 256-1 colors (leave one palette position for transparent color) - ImageTrueColorToPalette($this->gdimg_output, true, 255); + imagetruecolortopalette($this->gdimg_output, true, 255); // allocate a new color for transparent color index - $TransparentColor = ImageColorAllocate($this->gdimg_output, 1, 254, 253); - ImageColorTransparent($this->gdimg_output, $TransparentColor); + $TransparentColor = imagecolorallocate($this->gdimg_output, 1, 254, 253); + imagecolortransparent($this->gdimg_output, $TransparentColor); // scan through alpha channel image and note pixels with >50% transparency - $TransparentPixels = array(); for ($x = 0; $x < $this->thumbnail_width; $x++) { for ($y = 0; $y < $this->thumbnail_height; $y++) { $AlphaChannelPixel = phpthumb_functions::GetPixelColor($img_alpha_mixdown_dither, $x, $y); if ($AlphaChannelPixel['red'] > 127) { - ImageSetPixel($this->gdimg_output, $x, $y, $TransparentColor); + imagesetpixel($this->gdimg_output, $x, $y, $TransparentColor); } } } - ImageDestroy($img_alpha_mixdown_dither); + imagedestroy($img_alpha_mixdown_dither); $this->DebugMessage('AlphaChannelFlatten() set image to 255+1 colors with transparency for GIF output', __FILE__, __LINE__); return true; } else { - $this->DebugMessage('AlphaChannelFlatten() failed ImageCreate('.ImageSX($this->gdimg_output).', '.ImageSY($this->gdimg_output).')', __FILE__, __LINE__); + $this->DebugMessage('AlphaChannelFlatten() failed imagecreate('.imagesx($this->gdimg_output).', '.imagesy($this->gdimg_output).')', __FILE__, __LINE__); return false; } } else { // a single transparent color already defined, leave as-is - $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'.$this->thumbnailFormat.'") and ImageColorTransparent returned "'.$CurrentImageColorTransparent.'"', __FILE__, __LINE__); + $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'.$this->thumbnailFormat.'") and imagecolortransparent() returned "'.$CurrentImageColorTransparent.'"', __FILE__, __LINE__); return true; } break; @@ -2534,15 +2645,15 @@ function AlphaChannelFlatten() { return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"'); } $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor); - ImageFilledRectangle($gdimg_flatten_temp, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color); - ImageCopy($gdimg_flatten_temp, $this->gdimg_output, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height); + imagefilledrectangle($gdimg_flatten_temp, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color); + imagecopy($gdimg_flatten_temp, $this->gdimg_output, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height); - ImageAlphaBlending($this->gdimg_output, true); - ImageSaveAlpha($this->gdimg_output, false); - ImageColorTransparent($this->gdimg_output, -1); - ImageCopy($this->gdimg_output, $gdimg_flatten_temp, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height); + imagealphablending($this->gdimg_output, true); + imagesavealpha($this->gdimg_output, false); + imagecolortransparent($this->gdimg_output, -1); + imagecopy($this->gdimg_output, $gdimg_flatten_temp, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height); - ImageDestroy($gdimg_flatten_temp); + imagedestroy($gdimg_flatten_temp); return true; } else { @@ -2552,10 +2663,10 @@ function AlphaChannelFlatten() { } - function ApplyFilters() { + public function ApplyFilters() { if ($this->fltr && is_array($this->fltr)) { - if (!include_once(dirname(__FILE__) . '/phpthumb.filters.php')) { - $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__); + if (!include_once __DIR__ .'/phpthumb.filters.php' ) { + $this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__); return false; } $phpthumbFilters = new phpthumb_filters(); @@ -2626,7 +2737,7 @@ function ApplyFilters() { break; case 'flip': // Flip - $phpthumbFilters->Flip($this->gdimg_output, (strpos(strtolower($parameter), 'x') !== false), (strpos(strtolower($parameter), 'y') !== false)); + $phpthumbFilters->Flip($this->gdimg_output, strpos(strtolower($parameter), 'x') !== false, strpos(strtolower($parameter), 'y') !== false); break; case 'edge': // EdgeDetect @@ -2645,8 +2756,8 @@ function ApplyFilters() { case 'lvl': // autoLevels @list($band, $method, $threshold) = explode('|', $parameter, 3); $band = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band)) : '*'); - $method = ((strlen($method) > 0) ? intval($method) : 2); - $threshold = ((strlen($threshold) > 0) ? floatval($threshold) : 0.1); + $method = ((strlen($method) > 0) ? (int) $method : 2); + $threshold = ((strlen($threshold) > 0) ? (float) $threshold : 0.1); $phpthumbFilters->HistogramStretch($this->gdimg_output, $band, $method, $threshold); break; @@ -2668,7 +2779,7 @@ function ApplyFilters() { $alignment = ($alignment ? $alignment : 'BR'); $opacity = ($opacity ? $opacity : 50); $margin_x = ($margin_x ? $margin_x : 5); - $margin_y = $margin_y; // just to note it wasn't forgotten, but let the value always pass unchanged + // $margin_y -- it wasn't forgotten, let the value always pass unchanged $phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y); break; @@ -2702,12 +2813,12 @@ function ApplyFilters() { } while (strlen($buffer) > 0); fclose($fp_mask); if ($gdimg_mask = $this->ImageCreateFromStringReplacement($MaskImageData)) { - if ($invert && phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - ImageFilter($gdimg_mask, IMG_FILTER_NEGATE); + if ($invert && phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + imagefilter($gdimg_mask, IMG_FILTER_NEGATE); } $this->is_alpha = true; $phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output); - ImageDestroy($gdimg_mask); + imagedestroy($gdimg_mask); } else { $this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$mask_filename.'"', __FILE__, __LINE__); } @@ -2716,13 +2827,13 @@ function ApplyFilters() { } break; - case 'elip': // Elipse cropping + case 'elip': // Ellipse cropping if (phpthumb_functions::gd_version() < 2) { - $this->DebugMessage('Skipping Elipse() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__); + $this->DebugMessage('Skipping Ellipse() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__); return false; } $this->is_alpha = true; - $phpthumbFilters->Elipse($this->gdimg_output); + $phpthumbFilters->Ellipse($this->gdimg_output); break; case 'ric': // RoundedImageCorners @@ -2770,48 +2881,48 @@ function ApplyFilters() { } while (strlen($buffer) > 0); fclose($fp_watermark); if ($img_watermark = $this->ImageCreateFromStringReplacement($WatermarkImageData)) { - if ($margin < 1) { - $resized_x = max(1, ImageSX($this->gdimg_output) - round(2 * (ImageSX($this->gdimg_output) * $margin))); - $resized_y = max(1, ImageSY($this->gdimg_output) - round(2 * (ImageSY($this->gdimg_output) * $margin))); + if (($margin > 0) && ($margin < 1)) { + $resized_x = max(1, imagesx($this->gdimg_output) - round(2 * (imagesx($this->gdimg_output) * $margin))); + $resized_y = max(1, imagesy($this->gdimg_output) - round(2 * (imagesy($this->gdimg_output) * $margin))); } else { - $resized_x = max(1, ImageSX($this->gdimg_output) - round(2 * $margin)); - $resized_y = max(1, ImageSY($this->gdimg_output) - round(2 * $margin)); + $resized_x = max(1, imagesx($this->gdimg_output) - round(2 * $margin)); + $resized_y = max(1, imagesy($this->gdimg_output) - round(2 * $margin)); } if ($underlay) { - if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output))) { - ImageAlphaBlending($img_watermark_resized, false); - ImageSaveAlpha($img_watermark_resized, true); - $this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark_resized), ImageSY($img_watermark_resized), ImageSX($img_watermark), ImageSY($img_watermark)); + if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) { + imagealphablending($img_watermark_resized, false); + imagesavealpha($img_watermark_resized, true); + $this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, imagesx($img_watermark_resized), imagesy($img_watermark_resized), imagesx($img_watermark), imagesy($img_watermark)); if ($img_source_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) { - ImageAlphaBlending($img_source_resized, false); - ImageSaveAlpha($img_source_resized, true); - $this->ImageResizeFunction($img_source_resized, $this->gdimg_output, 0, 0, 0, 0, ImageSX($img_source_resized), ImageSY($img_source_resized), ImageSX($this->gdimg_output), ImageSY($this->gdimg_output)); + imagealphablending($img_source_resized, false); + imagesavealpha($img_source_resized, true); + $this->ImageResizeFunction($img_source_resized, $this->gdimg_output, 0, 0, 0, 0, imagesx($img_source_resized), imagesy($img_source_resized), imagesx($this->gdimg_output), imagesy($this->gdimg_output)); $phpthumbFilters->WatermarkOverlay($img_watermark_resized, $img_source_resized, 'C', $opacity, $margin); - ImageCopy($this->gdimg_output, $img_watermark_resized, 0, 0, 0, 0, ImageSX($this->gdimg_output), ImageSY($this->gdimg_output)); + imagecopy($this->gdimg_output, $img_watermark_resized, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output)); } else { $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.$resized_x.', '.$resized_y.')', __FILE__, __LINE__); } - ImageDestroy($img_watermark_resized); + imagedestroy($img_watermark_resized); } else { - $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.ImageSX($this->gdimg_output).', '.ImageSY($this->gdimg_output).')', __FILE__, __LINE__); + $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.imagesx($this->gdimg_output).', '.imagesy($this->gdimg_output).')', __FILE__, __LINE__); } } else { // overlay if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) { - ImageAlphaBlending($img_watermark_resized, false); - ImageSaveAlpha($img_watermark_resized, true); - $this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark_resized), ImageSY($img_watermark_resized), ImageSX($img_watermark), ImageSY($img_watermark)); + imagealphablending($img_watermark_resized, false); + imagesavealpha($img_watermark_resized, true); + $this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, imagesx($img_watermark_resized), imagesy($img_watermark_resized), imagesx($img_watermark), imagesy($img_watermark)); $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark_resized, 'C', $opacity, $margin); - ImageDestroy($img_watermark_resized); + imagedestroy($img_watermark_resized); } else { $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.$resized_x.', '.$resized_y.')', __FILE__, __LINE__); } } - ImageDestroy($img_watermark); + imagedestroy($img_watermark); } else { $this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$filename.'"', __FILE__, __LINE__); @@ -2825,12 +2936,12 @@ function ApplyFilters() { @list($filename, $alignment, $opacity, $margin['x'], $margin['y'], $rotate_angle) = explode('|', $parameter, 6); // $margin can be pixel margin or percent margin if $alignment is text, or max width/height if $alignment is position like "50x75" $alignment = ($alignment ? $alignment : 'BR'); - $opacity = (strlen($opacity) ? intval($opacity) : 50); - $rotate_angle = (strlen($rotate_angle) ? intval($rotate_angle) : 0); + $opacity = ('' !== $opacity ? (int) $opacity : 50); + $rotate_angle = ('' !== $rotate_angle ? (int) $rotate_angle : 0); if (!preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) { $margins = array('x', 'y'); foreach ($margins as $xy) { - $margin[$xy] = (strlen($margin[$xy]) ? $margin[$xy] : 5); + $margin[$xy] = ('' !== $margin[ $xy ] ? $margin[ $xy] : 5); if (($margin[$xy] > 0) && ($margin[$xy] < 1)) { $margin[$xy] = min(0.499, $margin[$xy]); } elseif (($margin[$xy] > -1) && ($margin[$xy] < 0)) { @@ -2843,31 +2954,31 @@ function ApplyFilters() { if (@is_readable($filename)) { if ($img_watermark = $this->ImageCreateFromFilename($filename)) { if ($rotate_angle !== 0) { - $phpthumbFilters->ImprovedImageRotate($img_watermark, $rotate_angle); + $phpthumbFilters->ImprovedImageRotate($img_watermark, $rotate_angle, 'FFFFFF', null, $this); } if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) { - $watermark_max_width = intval($margin['x'] ? $margin['x'] : ImageSX($img_watermark)); - $watermark_max_height = intval($margin['y'] ? $margin['y'] : ImageSY($img_watermark)); - $scale = phpthumb_functions::ScaleToFitInBox(ImageSX($img_watermark), ImageSY($img_watermark), $watermark_max_width, $watermark_max_height, true, true); + $watermark_max_width = (int) ($margin[ 'x'] ? $margin[ 'x'] : imagesx($img_watermark)); + $watermark_max_height = (int) ($margin[ 'y'] ? $margin[ 'y'] : imagesy($img_watermark)); + $scale = phpthumb_functions::ScaleToFitInBox(imagesx($img_watermark), imagesy($img_watermark), $watermark_max_width, $watermark_max_height, true, true); $this->DebugMessage('Scaling watermark by a factor of '.number_format($scale, 4), __FILE__, __LINE__); if (($scale > 1) || ($scale < 1)) { - if ($img_watermark2 = phpthumb_functions::ImageCreateFunction($scale * ImageSX($img_watermark), $scale * ImageSY($img_watermark))) { - ImageAlphaBlending($img_watermark2, false); - ImageSaveAlpha($img_watermark2, true); - $this->ImageResizeFunction($img_watermark2, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark2), ImageSY($img_watermark2), ImageSX($img_watermark), ImageSY($img_watermark)); + if ($img_watermark2 = phpthumb_functions::ImageCreateFunction($scale * imagesx($img_watermark), $scale * imagesy($img_watermark))) { + imagealphablending($img_watermark2, false); + imagesavealpha($img_watermark2, true); + $this->ImageResizeFunction($img_watermark2, $img_watermark, 0, 0, 0, 0, imagesx($img_watermark2), imagesy($img_watermark2), imagesx($img_watermark), imagesy($img_watermark)); $img_watermark = $img_watermark2; } else { - $this->DebugMessage('ImageCreateFunction('.($scale * ImageSX($img_watermark)).', '.($scale * ImageSX($img_watermark)).') failed', __FILE__, __LINE__); + $this->DebugMessage('ImageCreateFunction('.($scale * imagesx($img_watermark)).', '.($scale * imagesx($img_watermark)).') failed', __FILE__, __LINE__); } } - $watermark_dest_x = round($matches[1] - (ImageSX($img_watermark) / 2)); - $watermark_dest_y = round($matches[2] - (ImageSY($img_watermark) / 2)); + $watermark_dest_x = round($matches[1] - (imagesx($img_watermark) / 2)); + $watermark_dest_y = round($matches[2] - (imagesy($img_watermark) / 2)); $alignment = $watermark_dest_x.'x'.$watermark_dest_y; } $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark, $alignment, $opacity, $margin['x'], $margin['y']); - ImageDestroy($img_watermark); + imagedestroy($img_watermark); if (isset($img_watermark2) && is_resource($img_watermark2)) { - ImageDestroy($img_watermark2); + imagedestroy($img_watermark2); } } else { $this->DebugMessage('ImageCreateFromFilename() failed for "'.$filename.'"', __FILE__, __LINE__); @@ -2878,25 +2989,26 @@ function ApplyFilters() { break; case 'wmt': // WaterMarkText - @list($text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend) = explode('|', $parameter, 11); + @list($text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend, $lineheight) = explode('|', $parameter, 12); $text = ($text ? $text : ''); $size = ($size ? $size : 3); $alignment = ($alignment ? $alignment : 'BR'); $hex_color = ($hex_color ? $hex_color : '000000'); $ttffont = ($ttffont ? $ttffont : ''); - $opacity = (strlen($opacity) ? $opacity : 50); - $margin = (strlen($margin) ? $margin : 5); - $angle = (strlen($angle) ? $angle : 0); + $opacity = ('' !== $opacity ? $opacity : 50); + $margin = ('' !== $margin ? $margin : 5); + $angle = ('' !== $angle ? $angle : 0); $bg_color = ($bg_color ? $bg_color : false); $bg_opacity = ($bg_opacity ? $bg_opacity : 0); $fillextend = ($fillextend ? $fillextend : ''); + $lineheight = ($lineheight ? $lineheight : 1.0); if (basename($ttffont) == $ttffont) { - $ttffont = realpath($this->config_ttf_directory.DIRECTORY_SEPARATOR.$ttffont); + $ttffont = $this->realPathSafe($this->config_ttf_directory.DIRECTORY_SEPARATOR.$ttffont); } else { $ttffont = $this->ResolveFilenameToAbsolute($ttffont); } - $phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend); + $phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend, $lineheight); break; case 'blur': // Blur @@ -2929,15 +3041,15 @@ function ApplyFilters() { @list($amount, $radius, $threshold) = explode('|', $parameter, 3); $amount = ($amount ? $amount : 80); $radius = ($radius ? $radius : 0.5); - $threshold = (strlen($threshold) ? $threshold : 3); + $threshold = ('' !== $threshold ? $threshold : 3); if (phpthumb_functions::gd_version() >= 2.0) { ob_start(); - if (!@include_once(dirname(__FILE__) . '/phpthumb.unsharp.php')) { + if (!@include_once __DIR__ .'/phpthumb.unsharp.php' ) { $include_error = ob_get_contents(); if ($include_error) { - $this->DebugMessage('include_once("'.dirname(__FILE__).'/phpthumb.unsharp.php") generated message: "'.$include_error.'"', __FILE__, __LINE__); + $this->DebugMessage('include_once("'. __DIR__ .'/phpthumb.unsharp.php") generated message: "'.$include_error.'"', __FILE__, __LINE__); } - $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.unsharp.php" which is required for unsharp masking', __FILE__, __LINE__); + $this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.unsharp.php" which is required for unsharp masking', __FILE__, __LINE__); ob_end_clean(); return false; } @@ -2951,38 +3063,37 @@ function ApplyFilters() { case 'size': // Resize @list($newwidth, $newheight, $stretch) = explode('|', $parameter); - $newwidth = (!$newwidth ? ImageSX($this->gdimg_output) : ((($newwidth > 0) && ($newwidth < 1)) ? round($newwidth * ImageSX($this->gdimg_output)) : round($newwidth))); - $newheight = (!$newheight ? ImageSY($this->gdimg_output) : ((($newheight > 0) && ($newheight < 1)) ? round($newheight * ImageSY($this->gdimg_output)) : round($newheight))); + $newwidth = (!$newwidth ? imagesx($this->gdimg_output) : ((($newwidth > 0) && ($newwidth < 1)) ? round($newwidth * imagesx($this->gdimg_output)) : round($newwidth))); + $newheight = (!$newheight ? imagesy($this->gdimg_output) : ((($newheight > 0) && ($newheight < 1)) ? round($newheight * imagesy($this->gdimg_output)) : round($newheight))); $stretch = ($stretch ? true : false); if ($stretch) { - $scale_x = phpthumb_functions::ScaleToFitInBox(ImageSX($this->gdimg_output), ImageSX($this->gdimg_output), $newwidth, $newwidth, true, true); - $scale_y = phpthumb_functions::ScaleToFitInBox(ImageSY($this->gdimg_output), ImageSY($this->gdimg_output), $newheight, $newheight, true, true); + $scale_x = phpthumb_functions::ScaleToFitInBox(imagesx($this->gdimg_output), imagesx($this->gdimg_output), $newwidth, $newwidth, true, true); + $scale_y = phpthumb_functions::ScaleToFitInBox(imagesy($this->gdimg_output), imagesy($this->gdimg_output), $newheight, $newheight, true, true); } else { - $scale_x = phpthumb_functions::ScaleToFitInBox(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output), $newwidth, $newheight, true, true); + $scale_x = phpthumb_functions::ScaleToFitInBox(imagesx($this->gdimg_output), imagesy($this->gdimg_output), $newwidth, $newheight, true, true); $scale_y = $scale_x; } $this->DebugMessage('Scaling watermark ('.($stretch ? 'with' : 'without').' stretch) by a factor of "'.number_format($scale_x, 4).' x '.number_format($scale_y, 4).'"', __FILE__, __LINE__); if (($scale_x > 1) || ($scale_x < 1) || ($scale_y > 1) || ($scale_y < 1)) { - if ($img_temp = phpthumb_functions::ImageCreateFunction(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output))) { - ImageCopy($img_temp, $this->gdimg_output, 0, 0, 0, 0, ImageSX($this->gdimg_output), ImageSY($this->gdimg_output)); - //ImageDestroy($this->gdimg_output); - if ($this->gdimg_output = phpthumb_functions::ImageCreateFunction($scale_x * ImageSX($img_temp), $scale_y * ImageSY($img_temp))) { - ImageAlphaBlending($this->gdimg_output, false); - ImageSaveAlpha($this->gdimg_output, true); - $this->ImageResizeFunction($this->gdimg_output, $img_temp, 0, 0, 0, 0, ImageSX($this->gdimg_output), ImageSY($this->gdimg_output), ImageSX($img_temp), ImageSY($img_temp)); + if ($img_temp = phpthumb_functions::ImageCreateFunction(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) { + imagecopy($img_temp, $this->gdimg_output, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output)); + if ($this->gdimg_output = phpthumb_functions::ImageCreateFunction($scale_x * imagesx($img_temp), $scale_y * imagesy($img_temp))) { + imagealphablending($this->gdimg_output, false); + imagesavealpha($this->gdimg_output, true); + $this->ImageResizeFunction($this->gdimg_output, $img_temp, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output), imagesx($img_temp), imagesy($img_temp)); } else { - $this->DebugMessage('ImageCreateFunction('.($scale_x * ImageSX($img_temp)).', '.($scale_y * ImageSY($img_temp)).') failed', __FILE__, __LINE__); + $this->DebugMessage('ImageCreateFunction('.($scale_x * imagesx($img_temp)).', '.($scale_y * imagesy($img_temp)).') failed', __FILE__, __LINE__); } - ImageDestroy($img_temp); + imagedestroy($img_temp); } else { - $this->DebugMessage('ImageCreateFunction('.ImageSX($this->gdimg_output).', '.ImageSY($this->gdimg_output).') failed', __FILE__, __LINE__); + $this->DebugMessage('ImageCreateFunction('.imagesx($this->gdimg_output).', '.imagesy($this->gdimg_output).') failed', __FILE__, __LINE__); } } break; case 'rot': // ROTate @list($angle, $bgcolor) = explode('|', $parameter, 2); - $phpthumbFilters->ImprovedImageRotate($this->gdimg_output, $angle, $bgcolor); + $phpthumbFilters->ImprovedImageRotate($this->gdimg_output, $angle, $bgcolor, null, $this); break; case 'stc': // Source Transparent Color @@ -2991,14 +3102,14 @@ function ApplyFilters() { $this->DebugMessage('Skipping SourceTransparentColor hex color is invalid ('.$hexcolor.')', __FILE__, __LINE__); return false; } - $min_limit = (strlen($min_limit) ? $min_limit : 5); - $max_limit = (strlen($max_limit) ? $max_limit : 10); + $min_limit = ('' !== $min_limit ? $min_limit : 5); + $max_limit = ('' !== $max_limit ? $max_limit : 10); if ($gdimg_mask = $phpthumbFilters->SourceTransparentColorMask($this->gdimg_output, $hexcolor, $min_limit, $max_limit)) { $this->is_alpha = true; $phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output); - ImageDestroy($gdimg_mask); + imagedestroy($gdimg_mask); } else { - $this->DebugMessage('SourceTransparentColorMask() failed', __FILE__, __LINE__); + $this->DebugMessage('SourceTransparentColorMask() failed for "'.$hexcolor.','.$min_limit.','.$max_limit.'"', __FILE__, __LINE__); } break; } @@ -3009,7 +3120,7 @@ function ApplyFilters() { } - function MaxFileSize() { + public function MaxFileSize() { if (phpthumb_functions::gd_version() < 2) { $this->DebugMessage('Skipping MaxFileSize() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__); return false; @@ -3027,38 +3138,33 @@ function MaxFileSize() { if (strlen($imgdata) > $this->maxb) { for ($i = 8; $i >= 1; $i--) { - $tempIMG = ImageCreateTrueColor(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output)); - ImageCopy($tempIMG, $this->gdimg_output, 0, 0, 0, 0, ImageSX($this->gdimg_output), ImageSY($this->gdimg_output)); - ImageTrueColorToPalette($tempIMG, true, pow(2, $i)); + $tempIMG = imagecreatetruecolor(imagesx($this->gdimg_output), imagesy($this->gdimg_output)); + imagecopy($tempIMG, $this->gdimg_output, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output)); + imagetruecolortopalette($tempIMG, true, pow(2, $i)); ob_start(); $imgRenderFunction($tempIMG); $imgdata = ob_get_contents(); ob_end_clean(); if (strlen($imgdata) <= $this->maxb) { - ImageTrueColorToPalette($this->gdimg_output, true, pow(2, $i)); + imagetruecolortopalette($this->gdimg_output, true, pow(2, $i)); break; } } } - if (strlen($imgdata) > $this->maxb) { - ImageTrueColorToPalette($this->gdimg_output, true, pow(2, $i)); - return false; - } break; case 'jpeg': ob_start(); - ImageJPEG($this->gdimg_output); + imagejpeg($this->gdimg_output); $imgdata = ob_get_contents(); ob_end_clean(); - $OriginalJPEGquality = $this->thumbnailQuality; if (strlen($imgdata) > $this->maxb) { for ($i = 3; $i < 20; $i++) { $q = round(100 * (1 - log10($i / 2))); ob_start(); - ImageJPEG($this->gdimg_output, null, $q); + imagejpeg($this->gdimg_output, null, $q); $imgdata = ob_get_contents(); ob_end_clean(); @@ -3075,14 +3181,13 @@ function MaxFileSize() { default: return false; - break; } } return true; } - function CalculateThumbnailDimensions() { + public function CalculateThumbnailDimensions() { $this->DebugMessage('CalculateThumbnailDimensions() starting with [W,H,sx,sy,sw,sh] initially set to ['.$this->source_width.','.$this->source_height.','.$this->sx.','.$this->sy.','.$this->sw.','.$this->sh.']', __FILE__, __LINE__); //echo $this->source_width.'x'.$this->source_height.'
        '; $this->thumbnailCropX = ($this->sx ? (($this->sx >= 2) ? $this->sx : round($this->sx * $this->source_width)) : 0); @@ -3177,24 +3282,23 @@ function CalculateThumbnailDimensions() { } - function CreateGDoutput() { + public function CreateGDoutput() { $this->CalculateThumbnailDimensions(); - // Create the GD image (either true-color or 256-color, depending on GD version) + // create the GD image (either true-color or 256-color, depending on GD version) $this->gdimg_output = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height); - // Images that have transparency must have the background filled with the configured 'bg' color - // otherwise the transparent color will appear as black - ImageSaveAlpha($this->gdimg_output, true); + // images that have transparency must have the background filled with the configured 'bg' color otherwise the transparent color will appear as black + imagesavealpha($this->gdimg_output, true); if ($this->is_alpha && phpthumb_functions::gd_version() >= 2) { - ImageAlphaBlending($this->gdimg_output, false); + imagealphablending($this->gdimg_output, false); $output_full_alpha = phpthumb_functions::ImageColorAllocateAlphaSafe($this->gdimg_output, 255, 255, 255, 127); - ImageFilledRectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $output_full_alpha); + imagefilledrectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $output_full_alpha); } else { - $current_transparent_color = ImageColorTransparent($this->gdimg_source); + $current_transparent_color = imagecolortransparent($this->gdimg_source); if ($this->bg || (@$current_transparent_color >= 0)) { $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor); @@ -3202,7 +3306,7 @@ function CreateGDoutput() { return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"'); } $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor); - ImageFilledRectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color); + imagefilledrectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color); } @@ -3211,7 +3315,7 @@ function CreateGDoutput() { return true; } - function SetOrientationDependantWidthHeight() { + public function SetOrientationDependantWidthHeight() { $this->DebugMessage('SetOrientationDependantWidthHeight() starting with "'.$this->source_width.'"x"'.$this->source_height.'"', __FILE__, __LINE__); if ($this->source_height > $this->source_width) { // portrait @@ -3228,55 +3332,51 @@ function SetOrientationDependantWidthHeight() { } //$this->w = round($this->w ? $this->w : (($this->h && $this->source_height) ? $this->h * $this->source_width / $this->source_height : $this->w)); //$this->h = round($this->h ? $this->h : (($this->w && $this->source_width) ? $this->w * $this->source_height / $this->source_width : $this->h)); - $this->DebugMessage('SetOrientationDependantWidthHeight() setting w="'.intval($this->w).'", h="'.intval($this->h).'"', __FILE__, __LINE__); + $this->DebugMessage('SetOrientationDependantWidthHeight() setting w="'. (int) $this->w .'", h="'. (int) $this->h .'"', __FILE__, __LINE__); return true; } - function ExtractEXIFgetImageSize() { + public function ExtractEXIFgetImageSize() { $this->DebugMessage('starting ExtractEXIFgetImageSize()', __FILE__, __LINE__); if (preg_match('#^http:#i', $this->src) && !$this->sourceFilename && $this->rawImageData) { - !$this->SourceDataToTempFile(); + $this->SourceDataToTempFile(); } - if (is_null($this->getimagesizeinfo)) { + if (null === $this->getimagesizeinfo) { if ($this->sourceFilename) { - $this->getimagesizeinfo = @GetImageSize($this->sourceFilename); + $this->getimagesizeinfo = @getimagesize($this->sourceFilename); $this->source_width = $this->getimagesizeinfo[0]; $this->source_height = $this->getimagesizeinfo[1]; - $this->DebugMessage('GetImageSize('.$this->sourceFilename.') says image is '.$this->source_width.'x'.$this->source_height, __FILE__, __LINE__); + $this->DebugMessage('getimagesize('.$this->sourceFilename.') says image is '.$this->source_width.'x'.$this->source_height, __FILE__, __LINE__); } else { - $this->DebugMessage('skipping GetImageSize() because $this->sourceFilename is empty', __FILE__, __LINE__); + $this->DebugMessage('skipping getimagesize() because $this->sourceFilename is empty', __FILE__, __LINE__); } } else { - $this->DebugMessage('skipping GetImageSize() because !is_null($this->getimagesizeinfo)', __FILE__, __LINE__); + $this->DebugMessage('skipping getimagesize() because !is_null($this->getimagesizeinfo)', __FILE__, __LINE__); } if (is_resource($this->gdimg_source)) { - $this->source_width = ImageSX($this->gdimg_source); - $this->source_height = ImageSY($this->gdimg_source); + $this->source_width = imagesx($this->gdimg_source); + $this->source_height = imagesy($this->gdimg_source); $this->SetOrientationDependantWidthHeight(); } elseif ($this->rawImageData && !$this->sourceFilename) { if ($this->SourceImageIsTooLarge($this->source_width, $this->source_height)) { - $this->DebugMessage('NOT bypassing EXIF and GetImageSize sections because source image is too large for GD ('.$this->source_width.'x'.$this->source_width.'='.($this->source_width * $this->source_height * 5).'MB)', __FILE__, __LINE__); + $this->DebugMessage('NOT bypassing EXIF and getimagesize sections because source image is too large for GD ('.$this->source_width.'x'.$this->source_width.'='.($this->source_width * $this->source_height * 5).'MB)', __FILE__, __LINE__); } else { - $this->DebugMessage('bypassing EXIF and GetImageSize sections because $this->rawImageData is set, and $this->sourceFilename is not set, and source image is not too large for GD ('.$this->source_width.'x'.$this->source_width.'='.($this->source_width * $this->source_height * 5).'MB)', __FILE__, __LINE__); + $this->DebugMessage('bypassing EXIF and getimagesize sections because $this->rawImageData is set, and $this->sourceFilename is not set, and source image is not too large for GD ('.$this->source_width.'x'.$this->source_width.'='.($this->source_width * $this->source_height * 5).'MB)', __FILE__, __LINE__); } } - if (is_null($this->getimagesizeinfo)) { - $this->getimagesizeinfo = @GetImageSize($this->sourceFilename); - } - if (!empty($this->getimagesizeinfo)) { // great $this->getimagesizeinfo['filesize'] = @filesize($this->sourceFilename); } elseif (!$this->rawImageData) { - $this->DebugMessage('GetImageSize("'.$this->sourceFilename.'") failed', __FILE__, __LINE__); + $this->DebugMessage('getimagesize("'.$this->sourceFilename.'") failed', __FILE__, __LINE__); } if ($this->config_prefer_imagemagick) { @@ -3291,7 +3391,7 @@ function ExtractEXIFgetImageSize() { $this->SetOrientationDependantWidthHeight(); - if (phpthumb_functions::version_compare_replacement(phpversion(), '4.2.0', '>=') && function_exists('exif_read_data')) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.2.0', '>=') && function_exists('exif_read_data')) { switch ($this->getimagesizeinfo[2]) { case IMAGETYPE_JPEG: case IMAGETYPE_TIFF_II: @@ -3308,7 +3408,7 @@ function ExtractEXIFgetImageSize() { $this->exif_thumbnail_type = ''; // The parameters width, height and imagetype are available since PHP v4.3.0 - if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.0', '>=')) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.0', '>=')) { $this->exif_thumbnail_data = @exif_thumbnail($this->sourceFilename, $this->exif_thumbnail_width, $this->exif_thumbnail_height, $this->exif_thumbnail_type); @@ -3322,8 +3422,8 @@ function ExtractEXIFgetImageSize() { if (!$exit_thumbnail_error && $this->exif_thumbnail_data) { if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) { - $this->exif_thumbnail_width = ImageSX($gdimg_exif_temp); - $this->exif_thumbnail_height = ImageSY($gdimg_exif_temp); + $this->exif_thumbnail_width = imagesx($gdimg_exif_temp); + $this->exif_thumbnail_height = imagesy($gdimg_exif_temp); $this->exif_thumbnail_type = 2; // (2 == JPEG) before PHP v4.3.0 only JPEG format EXIF thumbnails are returned unset($gdimg_exif_temp); } else { @@ -3340,7 +3440,7 @@ function ExtractEXIFgetImageSize() { } - $this->DebugMessage('EXIF thumbnail extraction: (size='.strlen($this->exif_thumbnail_data).'; type="'.$this->exif_thumbnail_type.'"; '.intval($this->exif_thumbnail_width).'x'.intval($this->exif_thumbnail_height).')', __FILE__, __LINE__); + $this->DebugMessage('EXIF thumbnail extraction: (size='.strlen($this->exif_thumbnail_data).'; type="'.$this->exif_thumbnail_type.'"; '. (int) $this->exif_thumbnail_width .'x'. (int) $this->exif_thumbnail_height .')', __FILE__, __LINE__); // see if EXIF thumbnail can be used directly with no processing if ($this->config_use_exif_thumbnail_for_speed && $this->exif_thumbnail_data) { @@ -3370,8 +3470,8 @@ function ExtractEXIFgetImageSize() { $this->DebugMessage('setting $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data)', __FILE__, __LINE__); $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data); - $this->source_width = ImageSX($this->gdimg_source); - $this->source_height = ImageSY($this->gdimg_source); + $this->source_width = imagesx($this->gdimg_source); + $this->source_height = imagesy($this->gdimg_source); return true; } } @@ -3393,12 +3493,12 @@ function ExtractEXIFgetImageSize() { } - function SetCacheFilename() { - if (!is_null($this->cache_filename)) { + public function SetCacheFilename() { + if (null !== $this->cache_filename) { $this->DebugMessage('$this->cache_filename already set, skipping SetCacheFilename()', __FILE__, __LINE__); return true; } - if (is_null($this->config_cache_directory)) { + if (null === $this->config_cache_directory) { $this->setCacheDirectory(); if (!$this->config_cache_directory) { $this->DebugMessage('SetCacheFilename() failed because $this->config_cache_directory is empty', __FILE__, __LINE__); @@ -3426,7 +3526,6 @@ function SetCacheFilename() { } $this->cache_filename = ''; - $broad_directory_name = ''; if ($this->new) { $broad_directory_name = strtolower(md5($this->new)); $this->cache_filename .= '_new'.$broad_directory_name; @@ -3466,12 +3565,12 @@ function SetCacheFilename() { $FilenameParameters2 = array('h', 'w', 'wl', 'wp', 'ws', 'hp', 'hs', 'xto', 'ra', 'iar', 'aoe', 'maxb', 'sfn', 'dpi'); foreach ($FilenameParameters2 as $key) { if ($this->$key) { - $ParametersString .= '_'.$key.intval($this->$key); + $ParametersString .= '_'.$key. (int) $this->$key; } } if ($this->thumbnailFormat == 'jpeg') { // only JPEG output has variable quality option - $ParametersString .= '_q'.intval($this->thumbnailQuality); + $ParametersString .= '_q'. (int) $this->thumbnailQuality; } $this->DebugMessage('SetCacheFilename() _par set from md5('.$ParametersString.')', __FILE__, __LINE__); $this->cache_filename .= '_par'.strtolower(md5($ParametersString)); @@ -3481,9 +3580,9 @@ function SetCacheFilename() { // do not source image modification date -- // cached image will be used even if file was modified or removed } elseif (!$this->config_cache_source_filemtime_ignore_remote && preg_match('#^(f|ht)tps?\://#i', $this->src)) { - $this->cache_filename .= '_dat'.intval(phpthumb_functions::filedate_remote($this->src)); + $this->cache_filename .= '_dat'. (int) phpthumb_functions::filedate_remote($this->src); } elseif (!$this->config_cache_source_filemtime_ignore_local && $this->src && !$this->rawImageData) { - $this->cache_filename .= '_dat'.intval(@filemtime($this->sourceFilename)); + $this->cache_filename .= '_dat'. (int) (@filemtime($this->sourceFilename)); } $this->cache_filename .= '.'.strtolower($this->thumbnailFormat); @@ -3497,32 +3596,31 @@ function SetCacheFilename() { } - function SourceImageIsTooLarge($width, $height) { + public function SourceImageIsTooLarge($width, $height) { if (!$this->config_max_source_pixels) { return false; } - if (function_exists('memory_get_usage')) { - $available_memory = max(intval(ini_get('memory_limit')), intval(get_cfg_var('memory_limit'))) * 1048576; - $available_memory -= memory_get_usage(); + if ($this->php_memory_limit && function_exists('memory_get_usage')) { + $available_memory = $this->php_memory_limit - memory_get_usage(); return (bool) (($width * $height * 5) > $available_memory); } return (bool) (($width * $height) > $this->config_max_source_pixels); } - function ImageCreateFromFilename($filename) { + public function ImageCreateFromFilename($filename) { // try to create GD image source directly via GD, if possible, - // rather than buffering to memory and creating with ImageCreateFromString + // rather than buffering to memory and creating with imagecreatefromstring $ImageCreateWasAttempted = false; $gd_image = false; $this->DebugMessage('starting ImageCreateFromFilename('.$filename.')', __FILE__, __LINE__); - if ($filename && ($getimagesizeinfo = @GetImageSize($filename))) { + if ($filename && ($getimagesizeinfo = @getimagesize($filename))) { if (!$this->SourceImageIsTooLarge($getimagesizeinfo[0], $getimagesizeinfo[1])) { $ImageCreateFromFunction = array( - 1 => 'ImageCreateFromGIF', - 2 => 'ImageCreateFromJPEG', - 3 => 'ImageCreateFromPNG', - 15 => 'ImageCreateFromWBMP', + 1 => 'imagecreatefromgif', + 2 => 'imagecreatefromjpeg', + 3 => 'imagecreatefrompng', + 15 => 'imagecreatefromwbmp', ); $this->DebugMessage('ImageCreateFromFilename found ($getimagesizeinfo[2]=='.@$getimagesizeinfo[2].')', __FILE__, __LINE__); switch (@$getimagesizeinfo[2]) { @@ -3564,13 +3662,13 @@ function ImageCreateFromFilename($filename) { return false; } } else { - $this->DebugMessage('empty $filename or GetImageSize('.$filename.') failed', __FILE__, __LINE__); + $this->DebugMessage('empty $filename or getimagesize('.$filename.') failed', __FILE__, __LINE__); } if (!$gd_image) { - // cannot create from filename, attempt to create source image with ImageCreateFromString, if possible + // cannot create from filename, attempt to create source image with imagecreatefromstring, if possible if ($ImageCreateWasAttempted) { - $this->DebugMessage(@$ImageCreateFromFunctionName.'() was attempted but FAILED', __FILE__, __LINE__); + $this->DebugMessage($ImageCreateFromFunctionName.'() was attempted but FAILED', __FILE__, __LINE__); } $this->DebugMessage('Populating $rawimagedata', __FILE__, __LINE__); $rawimagedata = ''; @@ -3593,10 +3691,10 @@ function ImageCreateFromFilename($filename) { return $gd_image; } - function SourceImageToGD() { + public function SourceImageToGD() { if (is_resource($this->gdimg_source)) { - $this->source_width = ImageSX($this->gdimg_source); - $this->source_height = ImageSY($this->gdimg_source); + $this->source_width = imagesx($this->gdimg_source); + $this->source_height = imagesy($this->gdimg_source); $this->DebugMessage('skipping SourceImageToGD() because $this->gdimg_source is already a resource ('.$this->source_width.'x'.$this->source_height.')', __FILE__, __LINE__); return true; } @@ -3614,6 +3712,7 @@ function SourceImageToGD() { } else { $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__); } + @chmod($tempnam, $this->getParameter('config_file_create_mask')); } else { $this->DebugMessage('failed to put $this->rawImageData into temp file "'.$tempnam.'"', __FILE__, __LINE__); } @@ -3745,7 +3844,7 @@ function SourceImageToGD() { break; } if ($imageHeader) { - // cannot create image for whatever reason (maybe ImageCreateFromJPEG et al are not available?) + // cannot create image for whatever reason (maybe imagecreatefromjpeg et al are not available?) // and ImageMagick is not available either, no choice but to output original (not resized/modified) data and exit if ($this->config_error_die_on_source_failure) { $errormessages = array(); @@ -3785,9 +3884,9 @@ function SourceImageToGD() { switch (@$this->getimagesizeinfo[2]) { case 6: ob_start(); - if (!@include_once(dirname(__FILE__).'/phpthumb.bmp.php')) { + if (!@include_once __DIR__ .'/phpthumb.bmp.php' ) { ob_end_clean(); - return $this->ErrorImage('include_once('.dirname(__FILE__).'/phpthumb.bmp.php) failed'); + return $this->ErrorImage('include_once('. __DIR__ .'/phpthumb.bmp.php) failed'); } ob_end_clean(); if ($fp = @fopen($this->sourceFilename, 'rb')) { @@ -3798,7 +3897,7 @@ function SourceImageToGD() { fclose($fp); } $phpthumb_bmp = new phpthumb_bmp(); - $this->gdimg_source = $phpthumb_bmp->phpthumb_bmp2gd($this->rawImageData, (phpthumb_functions::gd_version() >= 2.0)); + $this->gdimg_source = $phpthumb_bmp->phpthumb_bmp2gd($this->rawImageData, phpthumb_functions::gd_version() >= 2.0); unset($phpthumb_bmp); if ($this->gdimg_source) { $this->DebugMessage('$phpthumb_bmp->phpthumb_bmp2gd() succeeded', __FILE__, __LINE__); @@ -3821,7 +3920,6 @@ function SourceImageToGD() { } if (!$this->gdimg_source) { - $HeaderFourBytes = ''; if ($this->rawImageData) { $HeaderFourBytes = substr($this->rawImageData, 0, 4); } elseif ($this->sourceFilename) { @@ -3863,14 +3961,14 @@ function SourceImageToGD() { return false; } - $this->source_width = ImageSX($this->gdimg_source); - $this->source_height = ImageSY($this->gdimg_source); + $this->source_width = imagesx($this->gdimg_source); + $this->source_height = imagesy($this->gdimg_source); return true; } - function phpThumbDebugVarDump($var) { - if (is_null($var)) { + public function phpThumbDebugVarDump($var) { + if (null === $var) { return 'NULL'; } elseif (is_bool($var)) { return ($var ? 'TRUE' : 'FALSE'); @@ -3890,7 +3988,7 @@ function phpThumbDebugVarDump($var) { return gettype($var); } - function phpThumbDebug($level='') { + public function phpThumbDebug($level='') { if ($level && ($this->phpThumbDebug !== $level)) { return true; } @@ -3898,14 +3996,14 @@ function phpThumbDebug($level='') { return $this->ErrorImage('phpThumbDebug disabled'); } - $FunctionsExistance = array('exif_thumbnail', 'gd_info', 'image_type_to_mime_type', 'GetImageSize', 'ImageCopyResampled', 'ImageCopyResized', 'ImageCreate', 'ImageCreateFromString', 'ImageCreateTrueColor', 'ImageIsTrueColor', 'ImageRotate', 'ImageTypes', 'version_compare', 'ImageCreateFromGIF', 'ImageCreateFromJPEG', 'ImageCreateFromPNG', 'ImageCreateFromWBMP', 'ImageCreateFromXBM', 'ImageCreateFromXPM', 'ImageCreateFromString', 'ImageCreateFromGD', 'ImageCreateFromGD2', 'ImageCreateFromGD2Part', 'ImageJPEG', 'ImageGIF', 'ImagePNG', 'ImageWBMP'); + $FunctionsExistance = array('exif_thumbnail', 'gd_info', 'image_type_to_mime_type', 'getimagesize', 'imagecopyresampled', 'imagecopyresized', 'imagecreate', 'imagecreatefromstring', 'imagecreatetruecolor', 'imageistruecolor', 'imagerotate', 'imagetypes', 'version_compare', 'imagecreatefromgif', 'imagecreatefromjpeg', 'imagecreatefrompng', 'imagecreatefromwbmp', 'imagecreatefromxbm', 'imagecreatefromxpm', 'imagecreatefromstring', 'imagecreatefromgd', 'imagecreatefromgd2', 'imagecreatefromgd2part', 'imagejpeg', 'imagegif', 'imagepng', 'imagewbmp'); $ParameterNames = array('src', 'new', 'w', 'h', 'f', 'q', 'sx', 'sy', 'sw', 'sh', 'far', 'bg', 'bc', 'file', 'goto', 'err', 'xto', 'ra', 'ar', 'aoe', 'iar', 'maxb'); $ConfigVariableNames = array('document_root', 'temp_directory', 'output_format', 'output_maxwidth', 'output_maxheight', 'error_message_image_default', 'error_bgcolor', 'error_textcolor', 'error_fontsize', 'error_die_on_error', 'error_silent_die_on_error', 'error_die_on_source_failure', 'nohotlink_enabled', 'nohotlink_valid_domains', 'nohotlink_erase_image', 'nohotlink_text_message', 'nooffsitelink_enabled', 'nooffsitelink_valid_domains', 'nooffsitelink_require_refer', 'nooffsitelink_erase_image', 'nooffsitelink_text_message', 'high_security_enabled', 'allow_src_above_docroot', 'allow_src_above_phpthumb', 'max_source_pixels', 'use_exif_thumbnail_for_speed', 'border_hexcolor', 'background_hexcolor', 'ttf_directory', 'disable_pathinfo_parsing', 'disable_imagecopyresampled'); $OtherVariableNames = array('phpThumbDebug', 'thumbnailQuality', 'thumbnailFormat', 'gdimg_output', 'gdimg_source', 'sourceFilename', 'source_width', 'source_height', 'thumbnailCropX', 'thumbnailCropY', 'thumbnailCropW', 'thumbnailCropH', 'exif_thumbnail_width', 'exif_thumbnail_height', 'exif_thumbnail_type', 'thumbnail_width', 'thumbnail_height', 'thumbnail_image_width', 'thumbnail_image_height'); $DebugOutput = array(); $DebugOutput[] = 'phpThumb() version = '.$this->phpthumb_version; - $DebugOutput[] = 'phpversion() = '.@phpversion(); + $DebugOutput[] = 'phpversion() = '.@PHP_VERSION; $DebugOutput[] = 'PHP_OS = '.PHP_OS; $DebugOutput[] = '$_SERVER[SERVER_SOFTWARE] = '.@$_SERVER['SERVER_SOFTWARE']; $DebugOutput[] = '__FILE__ = '.__FILE__; @@ -4033,14 +4131,14 @@ function phpThumbDebug($level='') { return $this->ErrorImage(implode("\n", $DebugOutput), 700, 500, true); } - function FatalError($text) { - if (is_null($this->fatalerror)) { + public function FatalError($text) { + if (null === $this->fatalerror) { $this->fatalerror = $text; } return true; } - function ErrorImage($text, $width=0, $height=0, $forcedisplay=false) { + public function ErrorImage($text, $width=0, $height=0, $forcedisplay=false) { $width = ($width ? $width : $this->config_error_image_width); $height = ($height ? $height : $this->config_error_image_height); @@ -4083,15 +4181,15 @@ function ErrorImage($text, $width=0, $height=0, $forcedisplay=false) { exit; } - $FontWidth = ImageFontWidth($this->config_error_fontsize); - $FontHeight = ImageFontHeight($this->config_error_fontsize); + $FontWidth = imagefontwidth($this->config_error_fontsize); + $FontHeight = imagefontheight($this->config_error_fontsize); $LinesOfText = explode("\n", @wordwrap($text, floor($width / $FontWidth), "\n", true)); $height = max($height, count($LinesOfText) * $FontHeight); $headers_file = ''; $headers_line = ''; - if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.0', '>=') && headers_sent($headers_file, $headers_line)) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.0', '>=') && headers_sent($headers_file, $headers_line)) { echo "\n".'**Headers already sent in file "'.$headers_file.'" on line "'.$headers_line.'", dumping error message as text:**
        '."\n\n".$text."\n".'
        '; @@ -4099,45 +4197,44 @@ function ErrorImage($text, $width=0, $height=0, $forcedisplay=false) { echo "\n".'**Headers already sent, dumping error message as text:**
        '."\n\n".$text."\n".'
        '; - } elseif ($gdimg_error = ImageCreate($width, $height)) { + } elseif ($gdimg_error = imagecreate($width, $height)) { $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_bgcolor, true); $text_color = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_textcolor, true); - ImageFilledRectangle($gdimg_error, 0, 0, $width, $height, $background_color); + imagefilledrectangle($gdimg_error, 0, 0, $width, $height, $background_color); $lineYoffset = 0; foreach ($LinesOfText as $line) { - ImageString($gdimg_error, $this->config_error_fontsize, 2, $lineYoffset, $line, $text_color); + imagestring($gdimg_error, $this->config_error_fontsize, 2, $lineYoffset, $line, $text_color); $lineYoffset += $FontHeight; } - if (function_exists('ImageTypes')) { - $imagetypes = ImageTypes(); + if (function_exists('imagetypes')) { + $imagetypes = imagetypes(); if ($imagetypes & IMG_PNG) { header('Content-Type: image/png'); - ImagePNG($gdimg_error); + imagepng($gdimg_error); } elseif ($imagetypes & IMG_GIF) { header('Content-Type: image/gif'); - ImageGIF($gdimg_error); + imagegif($gdimg_error); } elseif ($imagetypes & IMG_JPG) { header('Content-Type: image/jpeg'); - ImageJPEG($gdimg_error); + imagejpeg($gdimg_error); } elseif ($imagetypes & IMG_WBMP) { header('Content-Type: image/vnd.wap.wbmp'); - ImageWBMP($gdimg_error); + imagewbmp($gdimg_error); } } - ImageDestroy($gdimg_error); + imagedestroy($gdimg_error); } if (!headers_sent()) { echo "\n".'**Failed to send graphical error image, dumping error message as text:**
        '."\n\n".$text; } exit; - return true; } - function ImageCreateFromStringReplacement(&$RawImageData, $DieOnErrors=false) { + public function ImageCreateFromStringReplacement(&$RawImageData, $DieOnErrors=false) { // there are serious bugs in the non-bundled versions of GD which may cause - // PHP to segfault when calling ImageCreateFromString() - avoid if at all possible + // PHP to segfault when calling imagecreatefromstring() - avoid if at all possible // when not using a bundled version of GD2 if (!phpthumb_functions::gd_version()) { if ($DieOnErrors) { @@ -4156,8 +4253,8 @@ function ImageCreateFromStringReplacement(&$RawImageData, $DieOnErrors=false) { } } if (phpthumb_functions::gd_is_bundled()) { - $this->DebugMessage('ImageCreateFromStringReplacement() calling built-in ImageCreateFromString()', __FILE__, __LINE__); - return @ImageCreateFromString($RawImageData); + $this->DebugMessage('ImageCreateFromStringReplacement() calling built-in imagecreatefromstring()', __FILE__, __LINE__); + return @imagecreatefromstring($RawImageData); } if ($this->issafemode) { $this->DebugMessage('ImageCreateFromStringReplacement() failed: cannot create temp file in SAFE_MODE', __FILE__, __LINE__); @@ -4166,29 +4263,31 @@ function ImageCreateFromStringReplacement(&$RawImageData, $DieOnErrors=false) { switch (substr($RawImageData, 0, 3)) { case 'GIF': - $ICFSreplacementFunctionName = 'ImageCreateFromGIF'; + $ICFSreplacementFunctionName = 'imagecreatefromgif'; break; case "\xFF\xD8\xFF": - $ICFSreplacementFunctionName = 'ImageCreateFromJPEG'; + $ICFSreplacementFunctionName = 'imagecreatefromjpeg'; break; case "\x89".'PN': - $ICFSreplacementFunctionName = 'ImageCreateFromPNG'; + $ICFSreplacementFunctionName = 'imagecreatefrompng'; break; default: $this->DebugMessage('ImageCreateFromStringReplacement() failed: unknown fileformat signature "'.phpthumb_functions::HexCharDisplay(substr($RawImageData, 0, 3)).'"', __FILE__, __LINE__); return false; break; } + $ErrorMessage = ''; if ($tempnam = $this->phpThumb_tempnam()) { if ($fp_tempnam = @fopen($tempnam, 'wb')) { fwrite($fp_tempnam, $RawImageData); fclose($fp_tempnam); - if (($ICFSreplacementFunctionName == 'ImageCreateFromGIF') && !function_exists($ICFSreplacementFunctionName)) { + @chmod($tempnam, $this->getParameter('config_file_create_mask')); + if (($ICFSreplacementFunctionName == 'imagecreatefromgif') && !function_exists($ICFSreplacementFunctionName)) { - // Need to create from GIF file, but ImageCreateFromGIF does not exist + // Need to create from GIF file, but imagecreatefromgif does not exist ob_start(); - if (!@include_once(dirname(__FILE__) . '/phpthumb.gif.php')) { - $ErrorMessage = 'Failed to include required file "'.dirname(__FILE__).'/phpthumb.gif.php" in '.__FILE__.' on line '.__LINE__; + if (!@include_once __DIR__ .'/phpthumb.gif.php' ) { + $ErrorMessage = 'Failed to include required file "'. __DIR__ .'/phpthumb.gif.php" in '.__FILE__.' on line '.__LINE__; $this->DebugMessage($ErrorMessage, __FILE__, __LINE__); } ob_end_clean(); @@ -4249,49 +4348,47 @@ function ImageCreateFromStringReplacement(&$RawImageData, $DieOnErrors=false) { return false; } - function ImageResizeFunction(&$dst_im, &$src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH) { + public function ImageResizeFunction(&$dst_im, &$src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH) { $this->DebugMessage('ImageResizeFunction($o, $s, '.$dstX.', '.$dstY.', '.$srcX.', '.$srcY.', '.$dstW.', '.$dstH.', '.$srcW.', '.$srcH.')', __FILE__, __LINE__); if (($dstW == $srcW) && ($dstH == $srcH)) { - return ImageCopy($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH); + return imagecopy($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH); } if (phpthumb_functions::gd_version() >= 2.0) { if ($this->config_disable_imagecopyresampled) { return phpthumb_functions::ImageCopyResampleBicubic($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH); } - return ImageCopyResampled($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH); + return imagecopyresampled($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH); } - return ImageCopyResized($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH); + return imagecopyresized($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH); } - function InitializeTempDirSetting() { - $this->config_temp_directory = realpath($this->config_temp_directory ? $this->config_temp_directory : (getenv('TMPDIR') ? getenv('TMPDIR') : getenv('TMP'))); + public function InitializeTempDirSetting() { + $this->config_temp_directory = ($this->config_temp_directory ? $this->config_temp_directory : $this->realPathSafe((function_exists('sys_get_temp_dir') ? sys_get_temp_dir() : ''))); // sys_get_temp_dir added in PHP v5.2.1 + $this->config_temp_directory = ($this->config_temp_directory ? $this->config_temp_directory : $this->realPathSafe(ini_get('upload_tmp_dir'))); + $this->config_temp_directory = ($this->config_temp_directory ? $this->config_temp_directory : $this->realPathSafe(getenv('TMPDIR'))); + $this->config_temp_directory = ($this->config_temp_directory ? $this->config_temp_directory : $this->realPathSafe(getenv('TMP'))); return true; } - function phpThumb_tempnam() { + public function phpThumb_tempnam() { $this->InitializeTempDirSetting(); - $tempnam = realpath(tempnam($this->config_temp_directory, 'pThumb')); + $tempnam = $this->realPathSafe(tempnam($this->config_temp_directory, 'pThumb')); $this->tempFilesToDelete[$tempnam] = $tempnam; $this->DebugMessage('phpThumb_tempnam() returning "'.$tempnam.'"', __FILE__, __LINE__); return $tempnam; } - function DebugMessage($message, $file='', $line='') { + public function DebugMessage($message, $file='', $line='') { $this->debugmessages[] = $message.($file ? ' in file "'.(basename($file) ? basename($file) : $file).'"' : '').($line ? ' on line '.$line : ''); return true; } - function DebugTimingMessage($message, $file='', $line='', $timestamp=0) { + public function DebugTimingMessage($message, $file='', $line='', $timestamp=0) { if (!$timestamp) { $timestamp = array_sum(explode(' ', microtime())); } $this->debugtiming[number_format($timestamp, 6, '.', '')] = ': '.$message.($file ? ' in file "'.(basename($file) ? basename($file) : $file).'"' : '').($line ? ' on line '.$line : ''); return true; } - - function customEscapeshellarg($fileName) - { - $input = str_replace('\'', '\\\'', $fileName); - return '\''.$input.'\''; - } + } diff --git a/assets/snippets/phpthumb/phpthumb.filters.php b/assets/snippets/phpthumb/phpthumb.filters.php index 1b7b194c7d..0dc589b569 100755 --- a/assets/snippets/phpthumb/phpthumb.filters.php +++ b/assets/snippets/phpthumb/phpthumb.filters.php @@ -11,13 +11,14 @@ class phpthumb_filters { - var $phpThumbObject = null; + /** + * @var phpthumb + */ + + public $phpThumbObject = null; - function __construct() { - return true; - } - function DebugMessage($message, $file='', $line='') { + public function DebugMessage($message, $file='', $line='') { if (is_object($this->phpThumbObject)) { return $this->phpThumbObject->DebugMessage($message, $file, $line); } @@ -25,43 +26,42 @@ function DebugMessage($message, $file='', $line='') { } - public function ApplyMask(&$gdimg_mask, &$gdimg_image) { if (phpthumb_functions::gd_version() < 2) { $this->DebugMessage('Skipping ApplyMask() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__); return false; } - if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.2', '>=')) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.2', '>=')) { $this->DebugMessage('Using alpha ApplyMask() technique', __FILE__, __LINE__); - if ($gdimg_mask_resized = phpthumb_functions::ImageCreateFunction(ImageSX($gdimg_image), ImageSY($gdimg_image))) { + if ($gdimg_mask_resized = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_image), imagesy($gdimg_image))) { - ImageCopyResampled($gdimg_mask_resized, $gdimg_mask, 0, 0, 0, 0, ImageSX($gdimg_image), ImageSY($gdimg_image), ImageSX($gdimg_mask), ImageSY($gdimg_mask)); - if ($gdimg_mask_blendtemp = phpthumb_functions::ImageCreateFunction(ImageSX($gdimg_image), ImageSY($gdimg_image))) { + imagecopyresampled($gdimg_mask_resized, $gdimg_mask, 0, 0, 0, 0, imagesx($gdimg_image), imagesy($gdimg_image), imagesx($gdimg_mask), imagesy($gdimg_mask)); + if ($gdimg_mask_blendtemp = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_image), imagesy($gdimg_image))) { - $color_background = ImageColorAllocate($gdimg_mask_blendtemp, 0, 0, 0); - ImageFilledRectangle($gdimg_mask_blendtemp, 0, 0, ImageSX($gdimg_mask_blendtemp), ImageSY($gdimg_mask_blendtemp), $color_background); - ImageAlphaBlending($gdimg_mask_blendtemp, false); - ImageSaveAlpha($gdimg_mask_blendtemp, true); - for ($x = 0; $x < ImageSX($gdimg_image); $x++) { - for ($y = 0; $y < ImageSY($gdimg_image); $y++) { + $color_background = imagecolorallocate($gdimg_mask_blendtemp, 0, 0, 0); + imagefilledrectangle($gdimg_mask_blendtemp, 0, 0, imagesx($gdimg_mask_blendtemp), imagesy($gdimg_mask_blendtemp), $color_background); + imagealphablending($gdimg_mask_blendtemp, false); + imagesavealpha($gdimg_mask_blendtemp, true); + for ($x = 0, $xMax = imagesx($gdimg_image); $x < $xMax; $x++) { + for ($y = 0, $yMax = imagesy($gdimg_image); $y < $yMax; $y++) { //$RealPixel = phpthumb_functions::GetPixelColor($gdimg_mask_blendtemp, $x, $y); $RealPixel = phpthumb_functions::GetPixelColor($gdimg_image, $x, $y); $MaskPixel = phpthumb_functions::GrayscalePixel(phpthumb_functions::GetPixelColor($gdimg_mask_resized, $x, $y)); $MaskAlpha = 127 - (floor($MaskPixel['red'] / 2) * (1 - ($RealPixel['alpha'] / 127))); $newcolor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_mask_blendtemp, $RealPixel['red'], $RealPixel['green'], $RealPixel['blue'], $MaskAlpha); - ImageSetPixel($gdimg_mask_blendtemp, $x, $y, $newcolor); + imagesetpixel($gdimg_mask_blendtemp, $x, $y, $newcolor); } } - ImageAlphaBlending($gdimg_image, false); - ImageSaveAlpha($gdimg_image, true); - ImageCopy($gdimg_image, $gdimg_mask_blendtemp, 0, 0, 0, 0, ImageSX($gdimg_mask_blendtemp), ImageSY($gdimg_mask_blendtemp)); - ImageDestroy($gdimg_mask_blendtemp); + imagealphablending($gdimg_image, false); + imagesavealpha($gdimg_image, true); + imagecopy($gdimg_image, $gdimg_mask_blendtemp, 0, 0, 0, 0, imagesx($gdimg_mask_blendtemp), imagesy($gdimg_mask_blendtemp)); + imagedestroy($gdimg_mask_blendtemp); } else { $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__); } - ImageDestroy($gdimg_mask_resized); + imagedestroy($gdimg_mask_resized); } else { $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__); @@ -69,43 +69,43 @@ public function ApplyMask(&$gdimg_mask, &$gdimg_image) { } else { // alpha merging requires PHP v4.3.2+ - $this->DebugMessage('Skipping ApplyMask() technique because PHP is v"'.phpversion().'"', __FILE__, __LINE__); + $this->DebugMessage('Skipping ApplyMask() technique because PHP is v"'. PHP_VERSION .'"', __FILE__, __LINE__); } return true; } - function Bevel(&$gdimg, $width, $hexcolor1, $hexcolor2) { + public function Bevel(&$gdimg, $width, $hexcolor1, $hexcolor2) { $width = ($width ? $width : 5); $hexcolor1 = ($hexcolor1 ? $hexcolor1 : 'FFFFFF'); $hexcolor2 = ($hexcolor2 ? $hexcolor2 : '000000'); - ImageAlphaBlending($gdimg, true); + imagealphablending($gdimg, true); for ($i = 0; $i < $width; $i++) { $alpha = round(($i / $width) * 127); $color1 = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor1, false, $alpha); $color2 = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor2, false, $alpha); - ImageLine($gdimg, $i, $i + 1, $i, ImageSY($gdimg) - $i - 1, $color1); // left - ImageLine($gdimg, $i, $i , ImageSX($gdimg) - $i, $i , $color1); // top - ImageLine($gdimg, ImageSX($gdimg) - $i, ImageSY($gdimg) - $i - 1, ImageSX($gdimg) - $i, $i + 1, $color2); // right - ImageLine($gdimg, ImageSX($gdimg) - $i, ImageSY($gdimg) - $i , $i, ImageSY($gdimg) - $i , $color2); // bottom + imageline($gdimg, $i, $i + 1, $i, imagesy($gdimg) - $i - 1, $color1); // left + imageline($gdimg, $i, $i , imagesx($gdimg) - $i, $i , $color1); // top + imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i - 1, imagesx($gdimg) - $i, $i + 1, $color2); // right + imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i , $i, imagesy($gdimg) - $i , $color2); // bottom } return true; } public function Blur(&$gdimg, $radius=0.5) { - // Taken from Torstein H?nsi's phpUnsharpMask (see phpthumb.unsharp.php) + // Taken from Torstein Hønsi's phpUnsharpMask (see phpthumb.unsharp.php) $radius = round(max(0, min($radius, 50)) * 2); if (!$radius) { return false; } - $w = ImageSX($gdimg); - $h = ImageSY($gdimg); - if ($imgBlur = ImageCreateTrueColor($w, $h)) { + $w = imagesx($gdimg); + $h = imagesy($gdimg); + if ($imgBlur = imagecreatetruecolor($w, $h)) { // Gaussian blur matrix: // 1 2 1 // 2 4 2 @@ -114,16 +114,16 @@ public function Blur(&$gdimg, $radius=0.5) { // Move copies of the image around one pixel at the time and merge them with weight // according to the matrix. The same matrix is simply repeated for higher radii. for ($i = 0; $i < $radius; $i++) { - ImageCopy ($imgBlur, $gdimg, 0, 0, 1, 1, $w - 1, $h - 1); // up left - ImageCopyMerge($imgBlur, $gdimg, 1, 1, 0, 0, $w, $h, 50.00000); // down right - ImageCopyMerge($imgBlur, $gdimg, 0, 1, 1, 0, $w - 1, $h, 33.33333); // down left - ImageCopyMerge($imgBlur, $gdimg, 1, 0, 0, 1, $w, $h - 1, 25.00000); // up right - ImageCopyMerge($imgBlur, $gdimg, 0, 0, 1, 0, $w - 1, $h, 33.33333); // left - ImageCopyMerge($imgBlur, $gdimg, 1, 0, 0, 0, $w, $h, 25.00000); // right - ImageCopyMerge($imgBlur, $gdimg, 0, 0, 0, 1, $w, $h - 1, 20.00000); // up - ImageCopyMerge($imgBlur, $gdimg, 0, 1, 0, 0, $w, $h, 16.666667); // down - ImageCopyMerge($imgBlur, $gdimg, 0, 0, 0, 0, $w, $h, 50.000000); // center - ImageCopy ($gdimg, $imgBlur, 0, 0, 0, 0, $w, $h); + imagecopy ($imgBlur, $gdimg, 0, 0, 1, 1, $w - 1, $h - 1); // up left + imagecopymerge($imgBlur, $gdimg, 1, 1, 0, 0, $w, $h, 50.00000); // down right + imagecopymerge($imgBlur, $gdimg, 0, 1, 1, 0, $w - 1, $h, 33.33333); // down left + imagecopymerge($imgBlur, $gdimg, 1, 0, 0, 1, $w, $h - 1, 25.00000); // up right + imagecopymerge($imgBlur, $gdimg, 0, 0, 1, 0, $w - 1, $h, 33.33333); // left + imagecopymerge($imgBlur, $gdimg, 1, 0, 0, 0, $w, $h, 25.00000); // right + imagecopymerge($imgBlur, $gdimg, 0, 0, 0, 1, $w, $h - 1, 20.00000); // up + imagecopymerge($imgBlur, $gdimg, 0, 1, 0, 0, $w, $h, 16.666667); // down + imagecopymerge($imgBlur, $gdimg, 0, 0, 0, 0, $w, $h, 50.000000); // center + imagecopy ($gdimg, $imgBlur, 0, 0, 0, 0, $w, $h); } return true; } @@ -132,24 +132,24 @@ public function Blur(&$gdimg, $radius=0.5) { public function BlurGaussian(&$gdimg) { - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - if (ImageFilter($gdimg, IMG_FILTER_GAUSSIAN_BLUR)) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + if (imagefilter($gdimg, IMG_FILTER_GAUSSIAN_BLUR)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_GAUSSIAN_BLUR)', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_GAUSSIAN_BLUR)', __FILE__, __LINE__); // fall through and try it the hard way } $this->DebugMessage('FAILED: phpthumb_filters::BlurGaussian($gdimg) [using phpthumb_filters::Blur() instead]', __FILE__, __LINE__); - return phpthumb_filters::Blur($gdimg, 0.5); + return $this->Blur($gdimg, 0.5); } public function BlurSelective(&$gdimg) { - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - if (ImageFilter($gdimg, IMG_FILTER_SELECTIVE_BLUR)) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + if (imagefilter($gdimg, IMG_FILTER_SELECTIVE_BLUR)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_SELECTIVE_BLUR)', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_SELECTIVE_BLUR)', __FILE__, __LINE__); // fall through and try it the hard way } // currently not implemented "the hard way" @@ -164,24 +164,25 @@ public function Brightness(&$gdimg, $amount=0) { } $amount = max(-255, min(255, $amount)); - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - if (ImageFilter($gdimg, IMG_FILTER_BRIGHTNESS, $amount)) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + if (imagefilter($gdimg, IMG_FILTER_BRIGHTNESS, $amount)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_BRIGHTNESS, '.$amount.')', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_BRIGHTNESS, '.$amount.')', __FILE__, __LINE__); // fall through and try it the hard way } $scaling = (255 - abs($amount)) / 255; $baseamount = (($amount > 0) ? $amount : 0); - for ($x = 0; $x < ImageSX($gdimg); $x++) { - for ($y = 0; $y < ImageSY($gdimg); $y++) { + for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { + for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); + $NewPixel = array(); foreach ($OriginalPixel as $key => $value) { $NewPixel[$key] = round($baseamount + ($OriginalPixel[$key] * $scaling)); } - $newColor = ImageColorAllocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']); - ImageSetPixel($gdimg, $x, $y, $newColor); + $newColor = imagecolorallocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']); + imagesetpixel($gdimg, $x, $y, $newColor); } } return true; @@ -194,13 +195,13 @@ public function Contrast(&$gdimg, $amount=0) { } $amount = max(-255, min(255, $amount)); - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - // ImageFilter(IMG_FILTER_CONTRAST) has range +100 to -100 (positive numbers make it darker!) + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + // imagefilter(IMG_FILTER_CONTRAST) has range +100 to -100 (positive numbers make it darker!) $amount = ($amount / 255) * -100; - if (ImageFilter($gdimg, IMG_FILTER_CONTRAST, $amount)) { + if (imagefilter($gdimg, IMG_FILTER_CONTRAST, $amount)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_CONTRAST, '.$amount.')', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_CONTRAST, '.$amount.')', __FILE__, __LINE__); // fall through and try it the hard way } @@ -209,16 +210,18 @@ public function Contrast(&$gdimg, $amount=0) { } else { $scaling = (255 - abs($amount)) / 255; } - for ($x = 0; $x < ImageSX($gdimg); $x++) { - for ($y = 0; $y < ImageSY($gdimg); $y++) { + for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { + for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); + $NewPixel = array(); foreach ($OriginalPixel as $key => $value) { $NewPixel[$key] = min(255, max(0, round($OriginalPixel[$key] * $scaling))); } - $newColor = ImageColorAllocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']); - ImageSetPixel($gdimg, $x, $y, $newColor); + $newColor = imagecolorallocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']); + imagesetpixel($gdimg, $x, $y, $newColor); } } + return true; } @@ -231,39 +234,41 @@ public function Colorize(&$gdimg, $amount, $targetColor) { return true; } - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { if ($targetColor == 'gray') { $targetColor = '808080'; } $r = round($amountPct * hexdec(substr($targetColor, 0, 2))); $g = round($amountPct * hexdec(substr($targetColor, 2, 2))); $b = round($amountPct * hexdec(substr($targetColor, 4, 2))); - if (ImageFilter($gdimg, IMG_FILTER_COLORIZE, $r, $g, $b)) { + if (imagefilter($gdimg, IMG_FILTER_COLORIZE, $r, $g, $b)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_COLORIZE)', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_COLORIZE)', __FILE__, __LINE__); // fall through and try it the hard way } // overridden below for grayscale + $TargetPixel = array(); if ($targetColor != 'gray') { $TargetPixel['red'] = hexdec(substr($targetColor, 0, 2)); $TargetPixel['green'] = hexdec(substr($targetColor, 2, 2)); $TargetPixel['blue'] = hexdec(substr($targetColor, 4, 2)); } - for ($x = 0; $x < ImageSX($gdimg); $x++) { - for ($y = 0; $y < ImageSY($gdimg); $y++) { + for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { + for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); if ($targetColor == 'gray') { $TargetPixel = phpthumb_functions::GrayscalePixel($OriginalPixel); } + $NewPixel = array(); foreach ($TargetPixel as $key => $value) { $NewPixel[$key] = round(max(0, min(255, ($OriginalPixel[$key] * ((100 - $amount) / 100)) + ($TargetPixel[$key] * $amountPct)))); } //$newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue'], $OriginalPixel['alpha']); - $newColor = ImageColorAllocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']); - ImageSetPixel($gdimg, $x, $y, $newColor); + $newColor = imagecolorallocate($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue']); + imagesetpixel($gdimg, $x, $y, $newColor); } } return true; @@ -274,8 +279,8 @@ public function Crop(&$gdimg, $left=0, $right=0, $top=0, $bottom=0) { if (!$left && !$right && !$top && !$bottom) { return true; } - $oldW = ImageSX($gdimg); - $oldH = ImageSY($gdimg); + $oldW = imagesx($gdimg); + $oldH = imagesy($gdimg); if (($left > 0) && ($left < 1)) { $left = round($left * $oldW); } if (($right > 0) && ($right < 1)) { $right = round($right * $oldW); } if (($top > 0) && ($top < 1)) { $top = round($top * $oldH); } @@ -285,14 +290,14 @@ public function Crop(&$gdimg, $left=0, $right=0, $top=0, $bottom=0) { $newW = $oldW - $left - $right; $newH = $oldH - $top - $bottom; - if ($imgCropped = ImageCreateTrueColor($newW, $newH)) { - ImageCopy($imgCropped, $gdimg, 0, 0, $left, $top, $newW, $newH); - if ($gdimg = ImageCreateTrueColor($newW, $newH)) { - ImageCopy($gdimg, $imgCropped, 0, 0, 0, 0, $newW, $newH); - ImageDestroy($imgCropped); + if ($imgCropped = imagecreatetruecolor($newW, $newH)) { + imagecopy($imgCropped, $gdimg, 0, 0, $left, $top, $newW, $newH); + if ($gdimg = imagecreatetruecolor($newW, $newH)) { + imagecopy($gdimg, $imgCropped, 0, 0, 0, 0, $newW, $newH); + imagedestroy($imgCropped); return true; } - ImageDestroy($imgCropped); + imagedestroy($imgCropped); } return false; } @@ -302,7 +307,7 @@ public function Desaturate(&$gdimg, $amount, $color='') { if ($amount == 0) { return true; } - return phpthumb_filters::Colorize($gdimg, $amount, (phpthumb_functions::IsHexColor($color) ? $color : 'gray')); + return $this->Colorize($gdimg, $amount, (phpthumb_functions::IsHexColor($color) ? $color : 'gray')); } @@ -325,29 +330,30 @@ public function DropShadow(&$gdimg, $distance, $width, $hexcolor, $angle, $alpha return true; } - $width_shadow = cos(deg2rad($angle)) * ($distance + $width); - $height_shadow = sin(deg2rad($angle)) * ($distance + $width); - - $scaling = min(ImageSX($gdimg) / (ImageSX($gdimg) + abs($width_shadow)), ImageSY($gdimg) / (ImageSY($gdimg) + abs($height_shadow))); + //$width_shadow = cos(deg2rad($angle)) * ($distance + $width); + //$height_shadow = sin(deg2rad($angle)) * ($distance + $width); + //$scaling = min(imagesx($gdimg) / (imagesx($gdimg) + abs($width_shadow)), imagesy($gdimg) / (imagesy($gdimg) + abs($height_shadow))); + $Offset = array(); for ($i = 0; $i < $width; $i++) { $WidthAlpha[$i] = (abs(($width / 2) - $i) / $width); $Offset['x'] = cos(deg2rad($angle)) * ($distance + $i); $Offset['y'] = sin(deg2rad($angle)) * ($distance + $i); } - $tempImageWidth = ImageSX($gdimg) + abs($Offset['x']); - $tempImageHeight = ImageSY($gdimg) + abs($Offset['y']); + $tempImageWidth = imagesx($gdimg) + abs($Offset['x']); + $tempImageHeight = imagesy($gdimg) + abs($Offset['y']); if ($gdimg_dropshadow_temp = phpthumb_functions::ImageCreateFunction($tempImageWidth, $tempImageHeight)) { - ImageAlphaBlending($gdimg_dropshadow_temp, false); - ImageSaveAlpha($gdimg_dropshadow_temp, true); + imagealphablending($gdimg_dropshadow_temp, false); + imagesavealpha($gdimg_dropshadow_temp, true); $transparent1 = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_dropshadow_temp, 0, 0, 0, 127); - ImageFill($gdimg_dropshadow_temp, 0, 0, $transparent1); + imagefill($gdimg_dropshadow_temp, 0, 0, $transparent1); - for ($x = 0; $x < ImageSX($gdimg); $x++) { - for ($y = 0; $y < ImageSY($gdimg); $y++) { + $PixelMap = array(); + for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { + for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { $PixelMap[$x][$y] = phpthumb_functions::GetPixelColor($gdimg, $x, $y); } } @@ -358,42 +364,42 @@ public function DropShadow(&$gdimg, $distance, $width, $hexcolor, $angle, $alpha if (!isset($PixelMap[$x][$y]['alpha']) || ($PixelMap[$x][$y]['alpha'] > 0)) { if (isset($PixelMap[$x + $Offset['x']][$y + $Offset['y']]['alpha']) && ($PixelMap[$x + $Offset['x']][$y + $Offset['y']]['alpha'] < 127)) { $thisColor = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor, false, $PixelMap[$x + $Offset['x']][$y + $Offset['y']]['alpha']); - ImageSetPixel($gdimg_dropshadow_temp, $x, $y, $thisColor); + imagesetpixel($gdimg_dropshadow_temp, $x, $y, $thisColor); } } } } } - ImageAlphaBlending($gdimg_dropshadow_temp, true); - for ($x = 0; $x < ImageSX($gdimg); $x++) { - for ($y = 0; $y < ImageSY($gdimg); $y++) { + imagealphablending($gdimg_dropshadow_temp, true); + for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { + for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { if ($PixelMap[$x][$y]['alpha'] < 127) { $thisColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_dropshadow_temp, $PixelMap[$x][$y]['red'], $PixelMap[$x][$y]['green'], $PixelMap[$x][$y]['blue'], $PixelMap[$x][$y]['alpha']); - ImageSetPixel($gdimg_dropshadow_temp, $x, $y, $thisColor); + imagesetpixel($gdimg_dropshadow_temp, $x, $y, $thisColor); } } } - ImageSaveAlpha($gdimg, true); - ImageAlphaBlending($gdimg, false); + imagesavealpha($gdimg, true); + imagealphablending($gdimg, false); //$this->is_alpha = true; $transparent2 = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, 0, 0, 0, 127); - ImageFilledRectangle($gdimg, 0, 0, ImageSX($gdimg), ImageSY($gdimg), $transparent2); - ImageCopyResampled($gdimg, $gdimg_dropshadow_temp, 0, 0, 0, 0, ImageSX($gdimg), ImageSY($gdimg), ImageSX($gdimg_dropshadow_temp), ImageSY($gdimg_dropshadow_temp)); + imagefilledrectangle($gdimg, 0, 0, imagesx($gdimg), imagesy($gdimg), $transparent2); + imagecopyresampled($gdimg, $gdimg_dropshadow_temp, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg), imagesx($gdimg_dropshadow_temp), imagesy($gdimg_dropshadow_temp)); - ImageDestroy($gdimg_dropshadow_temp); + imagedestroy($gdimg_dropshadow_temp); } return true; } public function EdgeDetect(&$gdimg) { - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - if (ImageFilter($gdimg, IMG_FILTER_EDGEDETECT)) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + if (imagefilter($gdimg, IMG_FILTER_EDGEDETECT)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_EDGEDETECT)', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_EDGEDETECT)', __FILE__, __LINE__); // fall through and try it the hard way } // currently not implemented "the hard way" @@ -402,39 +408,39 @@ public function EdgeDetect(&$gdimg) { } - public function Elipse($gdimg) { + public function Ellipse($gdimg) { if (phpthumb_functions::gd_version() < 2) { return false; } // generate mask at twice desired resolution and downsample afterwards for easy antialiasing - if ($gdimg_elipsemask_double = phpthumb_functions::ImageCreateFunction(ImageSX($gdimg) * 2, ImageSY($gdimg) * 2)) { - if ($gdimg_elipsemask = phpthumb_functions::ImageCreateFunction(ImageSX($gdimg), ImageSY($gdimg))) { + if ($gdimg_ellipsemask_double = phpthumb_functions::ImageCreateFunction(imagesx($gdimg) * 2, imagesy($gdimg) * 2)) { + if ($gdimg_ellipsemask = phpthumb_functions::ImageCreateFunction(imagesx($gdimg), imagesy($gdimg))) { - $color_transparent = ImageColorAllocate($gdimg_elipsemask_double, 255, 255, 255); - ImageFilledEllipse($gdimg_elipsemask_double, ImageSX($gdimg), ImageSY($gdimg), (ImageSX($gdimg) - 1) * 2, (ImageSY($gdimg) - 1) * 2, $color_transparent); - ImageCopyResampled($gdimg_elipsemask, $gdimg_elipsemask_double, 0, 0, 0, 0, ImageSX($gdimg), ImageSY($gdimg), ImageSX($gdimg) * 2, ImageSY($gdimg) * 2); + $color_transparent = imagecolorallocate($gdimg_ellipsemask_double, 255, 255, 255); + imagefilledellipse($gdimg_ellipsemask_double, imagesx($gdimg), imagesy($gdimg), (imagesx($gdimg) - 1) * 2, (imagesy($gdimg) - 1) * 2, $color_transparent); + imagecopyresampled($gdimg_ellipsemask, $gdimg_ellipsemask_double, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg), imagesx($gdimg) * 2, imagesy($gdimg) * 2); - phpthumb_filters::ApplyMask($gdimg_elipsemask, $gdimg); - ImageDestroy($gdimg_elipsemask); + $this->ApplyMask($gdimg_ellipsemask, $gdimg); + imagedestroy($gdimg_ellipsemask); return true; } else { - $this->DebugMessage('$gdimg_elipsemask = phpthumb_functions::ImageCreateFunction() failed', __FILE__, __LINE__); + $this->DebugMessage('$gdimg_ellipsemask = phpthumb_functions::ImageCreateFunction() failed', __FILE__, __LINE__); } - ImageDestroy($gdimg_elipsemask_double); + imagedestroy($gdimg_ellipsemask_double); } else { - $this->DebugMessage('$gdimg_elipsemask_double = phpthumb_functions::ImageCreateFunction() failed', __FILE__, __LINE__); + $this->DebugMessage('$gdimg_ellipsemask_double = phpthumb_functions::ImageCreateFunction() failed', __FILE__, __LINE__); } return false; } public function Emboss(&$gdimg) { - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - if (ImageFilter($gdimg, IMG_FILTER_EMBOSS)) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + if (imagefilter($gdimg, IMG_FILTER_EMBOSS)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_EMBOSS)', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_EMBOSS)', __FILE__, __LINE__); // fall through and try it the hard way } // currently not implemented "the hard way" @@ -447,20 +453,20 @@ public function Flip(&$gdimg, $x=false, $y=false) { if (!$x && !$y) { return false; } - if ($tempImage = phpthumb_functions::ImageCreateFunction(ImageSX($gdimg), ImageSY($gdimg))) { + if ($tempImage = phpthumb_functions::ImageCreateFunction(imagesx($gdimg), imagesy($gdimg))) { if ($x) { - ImageCopy($tempImage, $gdimg, 0, 0, 0, 0, ImageSX($gdimg), ImageSY($gdimg)); - for ($x = 0; $x < ImageSX($gdimg); $x++) { - ImageCopy($gdimg, $tempImage, ImageSX($gdimg) - 1 - $x, 0, $x, 0, 1, ImageSY($gdimg)); + imagecopy($tempImage, $gdimg, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg)); + for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { + imagecopy($gdimg, $tempImage, imagesx($gdimg) - 1 - $x, 0, $x, 0, 1, imagesy($gdimg)); } } if ($y) { - ImageCopy($tempImage, $gdimg, 0, 0, 0, 0, ImageSX($gdimg), ImageSY($gdimg)); - for ($y = 0; $y < ImageSY($gdimg); $y++) { - ImageCopy($gdimg, $tempImage, 0, ImageSY($gdimg) - 1 - $y, 0, $y, ImageSX($gdimg), 1); + imagecopy($tempImage, $gdimg, 0, 0, 0, 0, imagesx($gdimg), imagesy($gdimg)); + for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { + imagecopy($gdimg, $tempImage, 0, imagesy($gdimg) - 1 - $y, 0, $y, imagesx($gdimg), 1); } } - ImageDestroy($tempImage); + imagedestroy($tempImage); } return true; } @@ -478,21 +484,21 @@ public function Frame(&$gdimg, $frame_width, $edge_width, $hexcolor_frame, $hexc $color2 = phpthumb_functions::ImageHexColorAllocate($gdimg, $hexcolor2); for ($i = 0; $i < $edge_width; $i++) { // outer bevel - ImageLine($gdimg, $i, $i, $i, ImageSY($gdimg) - $i, $color1); // left - ImageLine($gdimg, $i, $i, ImageSX($gdimg) - $i, $i, $color1); // top - ImageLine($gdimg, ImageSX($gdimg) - $i, ImageSY($gdimg) - $i, ImageSX($gdimg) - $i, $i, $color2); // right - ImageLine($gdimg, ImageSX($gdimg) - $i, ImageSY($gdimg) - $i, $i, ImageSY($gdimg) - $i, $color2); // bottom + imageline($gdimg, $i, $i, $i, imagesy($gdimg) - $i, $color1); // left + imageline($gdimg, $i, $i, imagesx($gdimg) - $i, $i, $color1); // top + imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i, imagesx($gdimg) - $i, $i, $color2); // right + imageline($gdimg, imagesx($gdimg) - $i, imagesy($gdimg) - $i, $i, imagesy($gdimg) - $i, $color2); // bottom } for ($i = 0; $i < $frame_width; $i++) { // actual frame - ImageRectangle($gdimg, $edge_width + $i, $edge_width + $i, ImageSX($gdimg) - $edge_width - $i, ImageSY($gdimg) - $edge_width - $i, $color_frame); + imagerectangle($gdimg, $edge_width + $i, $edge_width + $i, imagesx($gdimg) - $edge_width - $i, imagesy($gdimg) - $edge_width - $i, $color_frame); } for ($i = 0; $i < $edge_width; $i++) { // inner bevel - ImageLine($gdimg, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, ImageSY($gdimg) - $frame_width - $edge_width - $i, $color2); // left - ImageLine($gdimg, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, ImageSX($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, $color2); // top - ImageLine($gdimg, ImageSX($gdimg) - $frame_width - $edge_width - $i, ImageSY($gdimg) - $frame_width - $edge_width - $i, ImageSX($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, $color1); // right - ImageLine($gdimg, ImageSX($gdimg) - $frame_width - $edge_width - $i, ImageSY($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, ImageSY($gdimg) - $frame_width - $edge_width - $i, $color1); // bottom + imageline($gdimg, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, imagesy($gdimg) - $frame_width - $edge_width - $i, $color2); // left + imageline($gdimg, $frame_width + $edge_width + $i, $frame_width + $edge_width + $i, imagesx($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, $color2); // top + imageline($gdimg, imagesx($gdimg) - $frame_width - $edge_width - $i, imagesy($gdimg) - $frame_width - $edge_width - $i, imagesx($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, $color1); // right + imageline($gdimg, imagesx($gdimg) - $frame_width - $edge_width - $i, imagesy($gdimg) - $frame_width - $edge_width - $i, $frame_width + $edge_width + $i, imagesy($gdimg) - $frame_width - $edge_width - $i, $color1); // bottom } return true; } @@ -502,25 +508,26 @@ public function Gamma(&$gdimg, $amount) { if (number_format($amount, 4) == '1.0000') { return true; } - return ImageGammaCorrect($gdimg, 1.0, $amount); + return imagegammacorrect($gdimg, 1.0, $amount); } public function Grayscale(&$gdimg) { - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - if (ImageFilter($gdimg, IMG_FILTER_GRAYSCALE)) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + if (imagefilter($gdimg, IMG_FILTER_GRAYSCALE)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_GRAYSCALE)', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_GRAYSCALE)', __FILE__, __LINE__); // fall through and try it the hard way } - return phpthumb_filters::Colorize($gdimg, 100, 'gray'); + return $this->Colorize($gdimg, 100, 'gray'); } public function HistogramAnalysis(&$gdimg, $calculateGray=false) { - $ImageSX = ImageSX($gdimg); - $ImageSY = ImageSY($gdimg); + $ImageSX = imagesx($gdimg); + $ImageSY = imagesy($gdimg); + $Analysis = array(); for ($x = 0; $x < $ImageSX; $x++) { for ($y = 0; $y < $ImageSY; $y++) { $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); @@ -549,9 +556,9 @@ public function HistogramStretch(&$gdimg, $band='*', $method=0, $threshold=0.1) // equivalent of "Auto Contrast" in Adobe Photoshop // method 0 stretches according to RGB colors. Gives a more conservative stretch. // method 1 band stretches according to grayscale which is color-biased (59% green, 30% red, 11% blue). May give a punchier / more aggressive stretch, possibly appearing over-saturated - $Analysis = phpthumb_filters::HistogramAnalysis($gdimg, true); - $keys = array('r'=>'red', 'g'=>'green', 'b'=>'blue', 'a'=>'alpha', '*'=>(($method == 0) ? 'all' : 'gray')); - $band = substr($band, 0, 1); + $Analysis = $this->HistogramAnalysis($gdimg, true); + $keys = array('r'=>'red', 'g'=>'green', 'b'=>'blue', 'a'=>'alpha', '*'=> ($method == 0) ? 'all' : 'gray' ); + $band = $band[ 0 ]; if (!isset($keys[$band])) { return false; } @@ -561,50 +568,47 @@ public function HistogramStretch(&$gdimg, $band='*', $method=0, $threshold=0.1) // pixel in the image could throw off the whole system. Instead, count up/down // from the limit and allow (default = 0.1%) of brightest/darkest // pixels to be clipped to min/max - $threshold = floatval($threshold) / 100; - $clip_threshold = ImageSX($gdimg) * ImageSX($gdimg) * $threshold; - //if ($min >= 0) { - // $range_min = min($min, 255); - //} else { - $countsum = 0; - for ($i = 0; $i <= 255; $i++) { - if ($method == 0) { - $countsum = max(@$Analysis['red'][$i], @$Analysis['green'][$i], @$Analysis['blue'][$i]); - } else { - $countsum += @$Analysis[$key][$i]; - } - if ($countsum >= $clip_threshold) { - $range_min = $i - 1; - break; - } + $threshold = (float) $threshold / 100; + $clip_threshold = imagesx($gdimg) * imagesx($gdimg) * $threshold; + + $countsum = 0; + $range_min = 0; + for ($i = 0; $i <= 255; $i++) { + if ($method == 0) { + $countsum = max(@$Analysis['red'][$i], @$Analysis['green'][$i], @$Analysis['blue'][$i]); + } else { + $countsum += @$Analysis[$key][$i]; } - $range_min = max($range_min, 0); - //} - //if ($max > 0) { - // $range_max = max($max, 255); - //} else { - $countsum = 0; - for ($i = 255; $i >= 0; $i--) { - if ($method == 0) { - $countsum = max(@$Analysis['red'][$i], @$Analysis['green'][$i], @$Analysis['blue'][$i]); - } else { - $countsum += @$Analysis[$key][$i]; - } - if ($countsum >= $clip_threshold) { - $range_max = $i + 1; - break; - } + if ($countsum >= $clip_threshold) { + $range_min = $i - 1; + break; + } + } + $range_min = max($range_min, 0); + + $countsum = 0; + $range_max = 255; + for ($i = 255; $i >= 0; $i--) { + if ($method == 0) { + $countsum = max(@$Analysis['red'][$i], @$Analysis['green'][$i], @$Analysis['blue'][$i]); + } else { + $countsum += @$Analysis[$key][$i]; } - $range_max = min($range_max, 255); - //} + if ($countsum >= $clip_threshold) { + $range_max = $i + 1; + break; + } + } + $range_max = min($range_max, 255); + $range_scale = (($range_max == $range_min) ? 1 : (255 / ($range_max - $range_min))); if (($range_min == 0) && ($range_max == 255)) { - // no adjustment neccesary - don't waste CPU time! + // no adjustment necessary - don't waste CPU time! return true; } - $ImageSX = ImageSX($gdimg); - $ImageSY = ImageSY($gdimg); + $ImageSX = imagesx($gdimg); + $ImageSY = imagesy($gdimg); for ($x = 0; $x < $ImageSX; $x++) { for ($y = 0; $y < $ImageSY; $y++) { $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); @@ -618,7 +622,7 @@ public function HistogramStretch(&$gdimg, $band='*', $method=0, $threshold=0.1) $new[$key] = min(255, max(0, ($OriginalPixel[$key] - $range_min) * $range_scale)); } $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, $new['red'], $new['green'], $new['blue'], $new['alpha']); - ImageSetPixel($gdimg, $x, $y, $newColor); + imagesetpixel($gdimg, $x, $y, $newColor); } } @@ -627,24 +631,24 @@ public function HistogramStretch(&$gdimg, $band='*', $method=0, $threshold=0.1) public function HistogramOverlay(&$gdimg, $bands='*', $colors='', $width=0.25, $height=0.25, $alignment='BR', $opacity=50, $margin_x=5, $margin_y=null) { - $margin_y = (is_null($margin_y) ? $margin_x : $margin_y); + $margin_y = (null === $margin_y ? $margin_x : $margin_y); - $Analysis = phpthumb_filters::HistogramAnalysis($gdimg, true); - $histW = round(($width > 1) ? min($width, ImageSX($gdimg)) : ImageSX($gdimg) * $width); - $histH = round(($width > 1) ? min($width, ImageSX($gdimg)) : ImageSX($gdimg) * $width); - if ($gdHist = ImageCreateTrueColor($histW, $histH)) { + $Analysis = $this->HistogramAnalysis($gdimg, true); + $histW = round(($width > 1) ? min($width, imagesx($gdimg)) : imagesx($gdimg) * $width); + $histH = round(($width > 1) ? min($width, imagesx($gdimg)) : imagesx($gdimg) * $width); + if ($gdHist = imagecreatetruecolor($histW, $histH)) { $color_back = phpthumb_functions::ImageColorAllocateAlphaSafe($gdHist, 0, 0, 0, 127); - ImageFilledRectangle($gdHist, 0, 0, $histW, $histH, $color_back); - ImageAlphaBlending($gdHist, false); - ImageSaveAlpha($gdHist, true); + imagefilledrectangle($gdHist, 0, 0, $histW, $histH, $color_back); + imagealphablending($gdHist, false); + imagesavealpha($gdHist, true); $HistogramTempWidth = 256; $HistogramTempHeight = 100; - if ($gdHistTemp = ImageCreateTrueColor($HistogramTempWidth, $HistogramTempHeight)) { + if ($gdHistTemp = imagecreatetruecolor($HistogramTempWidth, $HistogramTempHeight)) { $color_back_temp = phpthumb_functions::ImageColorAllocateAlphaSafe($gdHistTemp, 255, 0, 255, 127); - ImageAlphaBlending($gdHistTemp, false); - ImageSaveAlpha($gdHistTemp, true); - ImageFilledRectangle($gdHistTemp, 0, 0, ImageSX($gdHistTemp), ImageSY($gdHistTemp), $color_back_temp); + imagealphablending($gdHistTemp, false); + imagesavealpha($gdHistTemp, true); + imagefilledrectangle($gdHistTemp, 0, 0, imagesx($gdHistTemp), imagesy($gdHistTemp), $color_back_temp); $DefaultColors = array('r'=>'FF0000', 'g'=>'00FF00', 'b'=>'0000FF', 'a'=>'999999', '*'=>'FFFFFF'); $Colors = explode(';', $colors); @@ -657,19 +661,19 @@ public function HistogramOverlay(&$gdimg, $bands='*', $colors='', $width=0.25, $ $PeakValue = max($Analysis[$keys[$band]]); $thisColor = phpthumb_functions::ImageHexColorAllocate($gdHistTemp, phpthumb_functions::IsHexColor(@$Colors[$key]) ? $Colors[$key] : $DefaultColors[$band]); for ($x = 0; $x < $HistogramTempWidth; $x++) { - ImageLine($gdHistTemp, $x, $HistogramTempHeight - 1, $x, $HistogramTempHeight - 1 - round(@$Analysis[$keys[$band]][$x] / $PeakValue * $HistogramTempHeight), $thisColor); + imageline($gdHistTemp, $x, $HistogramTempHeight - 1, $x, $HistogramTempHeight - 1 - round(@$Analysis[$keys[$band]][$x] / $PeakValue * $HistogramTempHeight), $thisColor); } - ImageLine($gdHistTemp, 0, $HistogramTempHeight - 1, $HistogramTempWidth - 1, $HistogramTempHeight - 1, $thisColor); - ImageLine($gdHistTemp, 0, $HistogramTempHeight - 2, $HistogramTempWidth - 1, $HistogramTempHeight - 2, $thisColor); + imageline($gdHistTemp, 0, $HistogramTempHeight - 1, $HistogramTempWidth - 1, $HistogramTempHeight - 1, $thisColor); + imageline($gdHistTemp, 0, $HistogramTempHeight - 2, $HistogramTempWidth - 1, $HistogramTempHeight - 2, $thisColor); } - ImageCopyResampled($gdHist, $gdHistTemp, 0, 0, 0, 0, ImageSX($gdHist), ImageSY($gdHist), ImageSX($gdHistTemp), ImageSY($gdHistTemp)); - ImageDestroy($gdHistTemp); + imagecopyresampled($gdHist, $gdHistTemp, 0, 0, 0, 0, imagesx($gdHist), imagesy($gdHist), imagesx($gdHistTemp), imagesy($gdHistTemp)); + imagedestroy($gdHistTemp); } else { return false; } - phpthumb_filters::WatermarkOverlay($gdimg, $gdHist, $alignment, $opacity, $margin_x, $margin_y); - ImageDestroy($gdHist); + $this->WatermarkOverlay($gdimg, $gdHist, $alignment, $opacity, $margin_x, $margin_y); + imagedestroy($gdHist); return true; } return false; @@ -681,68 +685,63 @@ public function ImageBorder(&$gdimg, $border_width, $radius_x, $radius_y, $hexco $radius_x = ($radius_x ? $radius_x : 0); $radius_y = ($radius_y ? $radius_y : 0); - $output_width = ImageSX($gdimg); - $output_height = ImageSY($gdimg); + $output_width = imagesx($gdimg); + $output_height = imagesy($gdimg); list($new_width, $new_height) = phpthumb_functions::ProportionalResize($output_width, $output_height, $output_width - max($border_width * 2, $radius_x), $output_height - max($border_width * 2, $radius_y)); $offset_x = ($radius_x ? $output_width - $new_width - $radius_x : 0); - $offset_y = ($radius_y ? $output_height - $new_height - $radius_y : 0); -//header('Content-Type: image/png'); -//ImagePNG($gdimg); -//exit; if ($gd_border_canvas = phpthumb_functions::ImageCreateFunction($output_width, $output_height)) { - ImageSaveAlpha($gd_border_canvas, true); - ImageAlphaBlending($gd_border_canvas, false); + imagesavealpha($gd_border_canvas, true); + imagealphablending($gd_border_canvas, false); $color_background = phpthumb_functions::ImageColorAllocateAlphaSafe($gd_border_canvas, 255, 255, 255, 127); - ImageFilledRectangle($gd_border_canvas, 0, 0, $output_width, $output_height, $color_background); + imagefilledrectangle($gd_border_canvas, 0, 0, $output_width, $output_height, $color_background); $color_border = phpthumb_functions::ImageHexColorAllocate($gd_border_canvas, (phpthumb_functions::IsHexColor($hexcolor_border) ? $hexcolor_border : '000000')); for ($i = 0; $i < $border_width; $i++) { - ImageLine($gd_border_canvas, floor($offset_x / 2) + $radius_x, $i, $output_width - $radius_x - ceil($offset_x / 2), $i, $color_border); // top - ImageLine($gd_border_canvas, floor($offset_x / 2) + $radius_x, $output_height - 1 - $i, $output_width - $radius_x - ceil($offset_x / 2), $output_height - 1 - $i, $color_border); // bottom - ImageLine($gd_border_canvas, floor($offset_x / 2) + $i, $radius_y, floor($offset_x / 2) + $i, $output_height - $radius_y, $color_border); // left - ImageLine($gd_border_canvas, $output_width - 1 - $i - ceil($offset_x / 2), $radius_y, $output_width - 1 - $i - ceil($offset_x / 2), $output_height - $radius_y, $color_border); // right + imageline($gd_border_canvas, floor($offset_x / 2) + $radius_x, $i, $output_width - $radius_x - ceil($offset_x / 2), $i, $color_border); // top + imageline($gd_border_canvas, floor($offset_x / 2) + $radius_x, $output_height - 1 - $i, $output_width - $radius_x - ceil($offset_x / 2), $output_height - 1 - $i, $color_border); // bottom + imageline($gd_border_canvas, floor($offset_x / 2) + $i, $radius_y, floor($offset_x / 2) + $i, $output_height - $radius_y, $color_border); // left + imageline($gd_border_canvas, $output_width - 1 - $i - ceil($offset_x / 2), $radius_y, $output_width - 1 - $i - ceil($offset_x / 2), $output_height - $radius_y, $color_border); // right } if ($radius_x && $radius_y) { - // PHP bug: ImageArc() with thicknesses > 1 give bad/undesirable/unpredicatable results + // PHP bug: imagearc() with thicknesses > 1 give bad/undesirable/unpredicatable results // Solution: Draw multiple 1px arcs side-by-side. // Problem: parallel arcs give strange/ugly antialiasing problems // Solution: draw non-parallel arcs, from one side of the line thickness at the start angle // to the opposite edge of the line thickness at the terminating angle for ($thickness_offset = 0; $thickness_offset < $border_width; $thickness_offset++) { - ImageArc($gd_border_canvas, floor($offset_x / 2) + 1 + $radius_x, $thickness_offset - 1 + $radius_y, $radius_x * 2, $radius_y * 2, 180, 270, $color_border); // top-left - ImageArc($gd_border_canvas, $output_width - $radius_x - 1 - ceil($offset_x / 2), $thickness_offset - 1 + $radius_y, $radius_x * 2, $radius_y * 2, 270, 360, $color_border); // top-right - ImageArc($gd_border_canvas, $output_width - $radius_x - 1 - ceil($offset_x / 2), $output_height - $thickness_offset - $radius_y, $radius_x * 2, $radius_y * 2, 0, 90, $color_border); // bottom-right - ImageArc($gd_border_canvas, floor($offset_x / 2) + 1 + $radius_x, $output_height - $thickness_offset - $radius_y, $radius_x * 2, $radius_y * 2, 90, 180, $color_border); // bottom-left + imagearc($gd_border_canvas, floor($offset_x / 2) + 1 + $radius_x, $thickness_offset - 1 + $radius_y, $radius_x * 2, $radius_y * 2, 180, 270, $color_border); // top-left + imagearc($gd_border_canvas, $output_width - $radius_x - 1 - ceil($offset_x / 2), $thickness_offset - 1 + $radius_y, $radius_x * 2, $radius_y * 2, 270, 360, $color_border); // top-right + imagearc($gd_border_canvas, $output_width - $radius_x - 1 - ceil($offset_x / 2), $output_height - $thickness_offset - $radius_y, $radius_x * 2, $radius_y * 2, 0, 90, $color_border); // bottom-right + imagearc($gd_border_canvas, floor($offset_x / 2) + 1 + $radius_x, $output_height - $thickness_offset - $radius_y, $radius_x * 2, $radius_y * 2, 90, 180, $color_border); // bottom-left } if ($border_width > 1) { for ($thickness_offset = 0; $thickness_offset < $border_width; $thickness_offset++) { - ImageArc($gd_border_canvas, floor($offset_x / 2) + $thickness_offset + $radius_x, $radius_y, $radius_x * 2, $radius_y * 2, 180, 270, $color_border); // top-left - ImageArc($gd_border_canvas, $output_width - $thickness_offset - $radius_x - 1 - ceil($offset_x / 2), $radius_y, $radius_x * 2, $radius_y * 2, 270, 360, $color_border); // top-right - ImageArc($gd_border_canvas, $output_width - $thickness_offset - $radius_x - 1 - ceil($offset_x / 2), $output_height - $radius_y, $radius_x * 2, $radius_y * 2, 0, 90, $color_border); // bottom-right - ImageArc($gd_border_canvas, floor($offset_x / 2) + $thickness_offset + $radius_x, $output_height - $radius_y, $radius_x * 2, $radius_y * 2, 90, 180, $color_border); // bottom-left + imagearc($gd_border_canvas, floor($offset_x / 2) + $thickness_offset + $radius_x, $radius_y, $radius_x * 2, $radius_y * 2, 180, 270, $color_border); // top-left + imagearc($gd_border_canvas, $output_width - $thickness_offset - $radius_x - 1 - ceil($offset_x / 2), $radius_y, $radius_x * 2, $radius_y * 2, 270, 360, $color_border); // top-right + imagearc($gd_border_canvas, $output_width - $thickness_offset - $radius_x - 1 - ceil($offset_x / 2), $output_height - $radius_y, $radius_x * 2, $radius_y * 2, 0, 90, $color_border); // bottom-right + imagearc($gd_border_canvas, floor($offset_x / 2) + $thickness_offset + $radius_x, $output_height - $radius_y, $radius_x * 2, $radius_y * 2, 90, 180, $color_border); // bottom-left } } } $this->phpThumbObject->ImageResizeFunction($gd_border_canvas, $gdimg, floor(($output_width - $new_width) / 2), round(($output_height - $new_height) / 2), 0, 0, $new_width, $new_height, $output_width, $output_height); - ImageDestroy($gdimg); + imagedestroy($gdimg); $gdimg = phpthumb_functions::ImageCreateFunction($output_width, $output_height); - ImageSaveAlpha($gdimg, true); - ImageAlphaBlending($gdimg, false); + imagesavealpha($gdimg, true); + imagealphablending($gdimg, false); $gdimg_color_background = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, 255, 255, 255, 127); - ImageFilledRectangle($gdimg, 0, 0, $output_width, $output_height, $gdimg_color_background); + imagefilledrectangle($gdimg, 0, 0, $output_width, $output_height, $gdimg_color_background); - ImageCopy($gdimg, $gd_border_canvas, 0, 0, 0, 0, $output_width, $output_height); - //$gdimg = $gd_border_canvas; - ImageDestroy($gd_border_canvas); + imagecopy($gdimg, $gd_border_canvas, 0, 0, 0, 0, $output_width, $output_height); + imagedestroy($gd_border_canvas); return true; @@ -753,11 +752,11 @@ public function ImageBorder(&$gdimg, $border_width, $radius_x, $radius_y, $hexco } - public function ImprovedImageRotate(&$gdimg_source, $rotate_angle=0, $config_background_hexcolor='FFFFFF', $bg=null) { + public static function ImprovedImageRotate(&$gdimg_source, $rotate_angle=0, $config_background_hexcolor='FFFFFF', $bg=null, &$phpThumbObject) { while ($rotate_angle < 0) { $rotate_angle += 360; } - $rotate_angle = $rotate_angle % 360; + $rotate_angle %= 360; if ($rotate_angle != 0) { $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_source, $config_background_hexcolor); @@ -765,31 +764,33 @@ public function ImprovedImageRotate(&$gdimg_source, $rotate_angle=0, $config_bac if ((phpthumb_functions::gd_version() >= 2) && !$bg && ($rotate_angle % 90)) { //$this->DebugMessage('Using alpha rotate', __FILE__, __LINE__); - if ($gdimg_rotate_mask = phpthumb_functions::ImageCreateFunction(ImageSX($gdimg_source), ImageSY($gdimg_source))) { + if ($gdimg_rotate_mask = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_source), imagesy($gdimg_source))) { + $color_mask = array(); for ($i = 0; $i <= 255; $i++) { - $color_mask[$i] = ImageColorAllocate($gdimg_rotate_mask, $i, $i, $i); + $color_mask[$i] = imagecolorallocate($gdimg_rotate_mask, $i, $i, $i); } - ImageFilledRectangle($gdimg_rotate_mask, 0, 0, ImageSX($gdimg_rotate_mask), ImageSY($gdimg_rotate_mask), $color_mask[255]); - $imageX = ImageSX($gdimg_source); - $imageY = ImageSY($gdimg_source); + imagefilledrectangle($gdimg_rotate_mask, 0, 0, imagesx($gdimg_rotate_mask), imagesy($gdimg_rotate_mask), $color_mask[255]); + $imageX = imagesx($gdimg_source); + $imageY = imagesy($gdimg_source); for ($x = 0; $x < $imageX; $x++) { for ($y = 0; $y < $imageY; $y++) { $pixelcolor = phpthumb_functions::GetPixelColor($gdimg_source, $x, $y); - ImageSetPixel($gdimg_rotate_mask, $x, $y, $color_mask[255 - round($pixelcolor['alpha'] * 255 / 127)]); + imagesetpixel($gdimg_rotate_mask, $x, $y, $color_mask[255 - round($pixelcolor['alpha'] * 255 / 127)]); } } - $gdimg_rotate_mask = ImageRotate($gdimg_rotate_mask, $rotate_angle, $color_mask[0]); - $gdimg_source = ImageRotate($gdimg_source, $rotate_angle, $background_color); + $gdimg_rotate_mask = imagerotate($gdimg_rotate_mask, $rotate_angle, $color_mask[0]); + $gdimg_source = imagerotate($gdimg_source, $rotate_angle, $background_color); - ImageAlphaBlending($gdimg_source, false); - ImageSaveAlpha($gdimg_source, true); + imagealphablending($gdimg_source, false); + imagesavealpha($gdimg_source, true); //$this->is_alpha = true; - $phpThumbFilters = new phpthumb_filters(); - $phpThumbFilters->phpThumbObject = $this; + $phpThumbFilters = new self(); + //$phpThumbFilters->phpThumbObject = $this; + $phpThumbFilters->phpThumbObject = $phpThumbObject; $phpThumbFilters->ApplyMask($gdimg_rotate_mask, $gdimg_source); - ImageDestroy($gdimg_rotate_mask); + imagedestroy($gdimg_rotate_mask); } else { //$this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__); @@ -807,40 +808,40 @@ public function ImprovedImageRotate(&$gdimg_source, $rotate_angle=0, $config_bac //$this->DebugMessage('Using non-alpha rotate because $this->thumbnailFormat is "'.$this->thumbnailFormat.'"', __FILE__, __LINE__); } - if (ImageColorTransparent($gdimg_source) >= 0) { - // ImageRotate() forgets all about an image's transparency and sets the transparent color to black + if (imagecolortransparent($gdimg_source) >= 0) { + // imagerotate() forgets all about an image's transparency and sets the transparent color to black // To compensate, flood-fill the transparent color of the source image with the specified background color first // then rotate and the colors should match - if (!function_exists('ImageIsTrueColor') || !ImageIsTrueColor($gdimg_source)) { + if (!function_exists('imageistruecolor') || !imageistruecolor($gdimg_source)) { // convert paletted image to true-color before rotating to prevent nasty aliasing artifacts - //$this->source_width = ImageSX($gdimg_source); - //$this->source_height = ImageSY($gdimg_source); - $gdimg_newsrc = phpthumb_functions::ImageCreateFunction(ImageSX($gdimg_source), ImageSY($gdimg_source)); + //$this->source_width = imagesx($gdimg_source); + //$this->source_height = imagesy($gdimg_source); + $gdimg_newsrc = phpthumb_functions::ImageCreateFunction(imagesx($gdimg_source), imagesy($gdimg_source)); $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_newsrc, $config_background_hexcolor); - ImageFilledRectangle($gdimg_newsrc, 0, 0, ImageSX($gdimg_source), ImageSY($gdimg_source), phpthumb_functions::ImageHexColorAllocate($gdimg_newsrc, $config_background_hexcolor)); - ImageCopy($gdimg_newsrc, $gdimg_source, 0, 0, 0, 0, ImageSX($gdimg_source), ImageSY($gdimg_source)); - ImageDestroy($gdimg_source); + imagefilledrectangle($gdimg_newsrc, 0, 0, imagesx($gdimg_source), imagesy($gdimg_source), phpthumb_functions::ImageHexColorAllocate($gdimg_newsrc, $config_background_hexcolor)); + imagecopy($gdimg_newsrc, $gdimg_source, 0, 0, 0, 0, imagesx($gdimg_source), imagesy($gdimg_source)); + imagedestroy($gdimg_source); unset($gdimg_source); $gdimg_source = $gdimg_newsrc; unset($gdimg_newsrc); } else { - ImageColorSet( + imagecolorset( $gdimg_source, - ImageColorTransparent($gdimg_source), + imagecolortransparent($gdimg_source), hexdec(substr($config_background_hexcolor, 0, 2)), hexdec(substr($config_background_hexcolor, 2, 2)), hexdec(substr($config_background_hexcolor, 4, 2))); - ImageColorTransparent($gdimg_source, -1); + imagecolortransparent($gdimg_source, -1); } } - $gdimg_source = ImageRotate($gdimg_source, $rotate_angle, $background_color); + $gdimg_source = imagerotate($gdimg_source, $rotate_angle, $background_color); } } @@ -849,11 +850,11 @@ public function ImprovedImageRotate(&$gdimg_source, $rotate_angle=0, $config_bac public function MeanRemoval(&$gdimg) { - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - if (ImageFilter($gdimg, IMG_FILTER_MEAN_REMOVAL)) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + if (imagefilter($gdimg, IMG_FILTER_MEAN_REMOVAL)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_MEAN_REMOVAL)', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_MEAN_REMOVAL)', __FILE__, __LINE__); // fall through and try it the hard way } // currently not implemented "the hard way" @@ -863,20 +864,20 @@ public function MeanRemoval(&$gdimg) { public function Negative(&$gdimg) { - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - if (ImageFilter($gdimg, IMG_FILTER_NEGATE)) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + if (imagefilter($gdimg, IMG_FILTER_NEGATE)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_NEGATE)', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_NEGATE)', __FILE__, __LINE__); // fall through and try it the hard way } - $ImageSX = ImageSX($gdimg); - $ImageSY = ImageSY($gdimg); + $ImageSX = imagesx($gdimg); + $ImageSY = imagesy($gdimg); for ($x = 0; $x < $ImageSX; $x++) { for ($y = 0; $y < $ImageSY; $y++) { $currentPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); - $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, (~$currentPixel['red'] & 0xFF), (~$currentPixel['green'] & 0xFF), (~$currentPixel['blue'] & 0xFF), $currentPixel['alpha']); - ImageSetPixel($gdimg, $x, $y, $newColor); + $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, ~$currentPixel[ 'red'] & 0xFF, ~$currentPixel[ 'green'] & 0xFF, ~$currentPixel[ 'blue'] & 0xFF, $currentPixel[ 'alpha']); + imagesetpixel($gdimg, $x, $y, $newColor); } } return true; @@ -885,30 +886,30 @@ public function Negative(&$gdimg) { public function RoundedImageCorners(&$gdimg, $radius_x, $radius_y) { // generate mask at twice desired resolution and downsample afterwards for easy antialiasing - // mask is generated as a white double-size elipse on a triple-size black background and copy-paste-resampled + // mask is generated as a white double-size ellipse on a triple-size black background and copy-paste-resampled // onto a correct-size mask image as 4 corners due to errors when the entire mask is resampled at once (gray edges) if ($gdimg_cornermask_triple = phpthumb_functions::ImageCreateFunction($radius_x * 6, $radius_y * 6)) { - if ($gdimg_cornermask = phpthumb_functions::ImageCreateFunction(ImageSX($gdimg), ImageSY($gdimg))) { + if ($gdimg_cornermask = phpthumb_functions::ImageCreateFunction(imagesx($gdimg), imagesy($gdimg))) { - $color_transparent = ImageColorAllocate($gdimg_cornermask_triple, 255, 255, 255); - ImageFilledEllipse($gdimg_cornermask_triple, $radius_x * 3, $radius_y * 3, $radius_x * 4, $radius_y * 4, $color_transparent); + $color_transparent = imagecolorallocate($gdimg_cornermask_triple, 255, 255, 255); + imagefilledellipse($gdimg_cornermask_triple, $radius_x * 3, $radius_y * 3, $radius_x * 4, $radius_y * 4, $color_transparent); - ImageFilledRectangle($gdimg_cornermask, 0, 0, ImageSX($gdimg), ImageSY($gdimg), $color_transparent); + imagefilledrectangle($gdimg_cornermask, 0, 0, imagesx($gdimg), imagesy($gdimg), $color_transparent); - ImageCopyResampled($gdimg_cornermask, $gdimg_cornermask_triple, 0, 0, $radius_x, $radius_y, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); - ImageCopyResampled($gdimg_cornermask, $gdimg_cornermask_triple, 0, ImageSY($gdimg) - $radius_y, $radius_x, $radius_y * 3, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); - ImageCopyResampled($gdimg_cornermask, $gdimg_cornermask_triple, ImageSX($gdimg) - $radius_x, ImageSY($gdimg) - $radius_y, $radius_x * 3, $radius_y * 3, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); - ImageCopyResampled($gdimg_cornermask, $gdimg_cornermask_triple, ImageSX($gdimg) - $radius_x, 0, $radius_x * 3, $radius_y, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); + imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, 0, 0, $radius_x, $radius_y, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); + imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, 0, imagesy($gdimg) - $radius_y, $radius_x, $radius_y * 3, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); + imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, imagesx($gdimg) - $radius_x, imagesy($gdimg) - $radius_y, $radius_x * 3, $radius_y * 3, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); + imagecopyresampled($gdimg_cornermask, $gdimg_cornermask_triple, imagesx($gdimg) - $radius_x, 0, $radius_x * 3, $radius_y, $radius_x, $radius_y, $radius_x * 2, $radius_y * 2); - phpthumb_filters::ApplyMask($gdimg_cornermask, $gdimg); - ImageDestroy($gdimg_cornermask); + $this->ApplyMask($gdimg_cornermask, $gdimg); + imagedestroy($gdimg_cornermask); $this->DebugMessage('RoundedImageCorners('.$radius_x.', '.$radius_y.') succeeded', __FILE__, __LINE__); return true; } else { - $this->DebugMessage('FAILED: $gdimg_cornermask = phpthumb_functions::ImageCreateFunction('.ImageSX($gdimg).', '.ImageSY($gdimg).')', __FILE__, __LINE__); + $this->DebugMessage('FAILED: $gdimg_cornermask = phpthumb_functions::ImageCreateFunction('.imagesx($gdimg).', '.imagesy($gdimg).')', __FILE__, __LINE__); } - ImageDestroy($gdimg_cornermask_triple); + imagedestroy($gdimg_cornermask_triple); } else { $this->DebugMessage('FAILED: $gdimg_cornermask_triple = phpthumb_functions::ImageCreateFunction('.($radius_x * 6).', '.($radius_y * 6).')', __FILE__, __LINE__); @@ -925,7 +926,7 @@ public function Saturation(&$gdimg, $amount, $color='') { } else { $amount = abs($amount); } - return phpthumb_filters::Desaturate($gdimg, $amount, $color); + return $this->Desaturate($gdimg, $amount, $color); } @@ -938,21 +939,21 @@ public function Sepia(&$gdimg, $amount, $targetColor) { return true; } - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - if (ImageFilter($gdimg, IMG_FILTER_GRAYSCALE)) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + if (imagefilter($gdimg, IMG_FILTER_GRAYSCALE)) { $r = round($amountPct * hexdec(substr($targetColor, 0, 2))); $g = round($amountPct * hexdec(substr($targetColor, 2, 2))); $b = round($amountPct * hexdec(substr($targetColor, 4, 2))); - if (ImageFilter($gdimg, IMG_FILTER_COLORIZE, $r, $g, $b)) { + if (imagefilter($gdimg, IMG_FILTER_COLORIZE, $r, $g, $b)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_COLORIZE)', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_COLORIZE)', __FILE__, __LINE__); // fall through and try it the hard way } else { - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_GRAYSCALE)', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_GRAYSCALE)', __FILE__, __LINE__); // fall through and try it the hard way } @@ -962,8 +963,8 @@ public function Sepia(&$gdimg, $amount, $targetColor) { $TargetPixel['green'] = hexdec(substr($targetColor, 2, 2)); $TargetPixel['blue'] = hexdec(substr($targetColor, 4, 2)); - $ImageSX = ImageSX($gdimg); - $ImageSY = ImageSY($gdimg); + $ImageSX = imagesx($gdimg); + $ImageSY = imagesy($gdimg); for ($x = 0; $x < $ImageSX; $x++) { for ($y = 0; $y < $ImageSY; $y++) { $OriginalPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); @@ -974,11 +975,12 @@ public function Sepia(&$gdimg, $amount, $targetColor) { // the mid-tones: the lighter and darker areas appear to be closer to B&W." $SepiaAmount = ((128 - abs($GrayPixel['red'] - 128)) / 128) * $amountPct; + $NewPixel = array(); foreach ($TargetPixel as $key => $value) { $NewPixel[$key] = round(max(0, min(255, $GrayPixel[$key] * (1 - $SepiaAmount) + ($TargetPixel[$key] * $SepiaAmount)))); } $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, $NewPixel['red'], $NewPixel['green'], $NewPixel['blue'], $OriginalPixel['alpha']); - ImageSetPixel($gdimg, $x, $y, $newColor); + imagesetpixel($gdimg, $x, $y, $newColor); } } return true; @@ -990,11 +992,11 @@ public function Smooth(&$gdimg, $amount=6) { if ($amount == 0) { return true; } - if (phpthumb_functions::version_compare_replacement(phpversion(), '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { - if (ImageFilter($gdimg, IMG_FILTER_SMOOTH, $amount)) { + if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) { + if (imagefilter($gdimg, IMG_FILTER_SMOOTH, $amount)) { return true; } - $this->DebugMessage('FAILED: ImageFilter($gdimg, IMG_FILTER_SMOOTH, '.$amount.')', __FILE__, __LINE__); + $this->DebugMessage('FAILED: imagefilter($gdimg, IMG_FILTER_SMOOTH, '.$amount.')', __FILE__, __LINE__); // fall through and try it the hard way } // currently not implemented "the hard way" @@ -1004,9 +1006,9 @@ public function Smooth(&$gdimg, $amount=6) { public function SourceTransparentColorMask(&$gdimg, $hexcolor, $min_limit=5, $max_limit=10) { - $width = ImageSX($gdimg); - $height = ImageSY($gdimg); - if ($gdimg_mask = ImageCreateTrueColor($width, $height)) { + $width = imagesx($gdimg); + $height = imagesy($gdimg); + if ($gdimg_mask = imagecreatetruecolor($width, $height)) { $R = hexdec(substr($hexcolor, 0, 2)); $G = hexdec(substr($hexcolor, 2, 2)); $B = hexdec(substr($hexcolor, 4, 2)); @@ -1016,9 +1018,9 @@ public function SourceTransparentColorMask(&$gdimg, $hexcolor, $min_limit=5, $ma for ($y = 0; $y < $height; $y++) { $currentPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); $colorDiff = phpthumb_functions::PixelColorDifferencePercent($currentPixel, $targetPixel); - $grayLevel = min($cutoffRange, MAX(0, -$min_limit + $colorDiff)) * (255 / MAX(1, $cutoffRange)); - $newColor = ImageColorAllocate($gdimg_mask, $grayLevel, $grayLevel, $grayLevel); - ImageSetPixel($gdimg_mask, $x, $y, $newColor); + $grayLevel = min($cutoffRange, max(0, -$min_limit + $colorDiff)) * (255 / max(1, $cutoffRange)); + $newColor = imagecolorallocate($gdimg_mask, $grayLevel, $grayLevel, $grayLevel); + imagesetpixel($gdimg_mask, $x, $y, $newColor); } } return $gdimg_mask; @@ -1028,8 +1030,8 @@ public function SourceTransparentColorMask(&$gdimg, $hexcolor, $min_limit=5, $ma public function Threshold(&$gdimg, $cutoff) { - $width = ImageSX($gdimg); - $height = ImageSY($gdimg); + $width = imagesx($gdimg); + $height = imagesy($gdimg); $cutoff = min(255, max(0, ($cutoff ? $cutoff : 128))); for ($x = 0; $x < $width; $x++) { for ($y = 0; $y < $height; $y++) { @@ -1040,7 +1042,7 @@ public function Threshold(&$gdimg, $cutoff) { } else { $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg, 0xFF, 0xFF, 0xFF, $currentPixel['alpha']); } - ImageSetPixel($gdimg, $x, $y, $newColor); + imagesetpixel($gdimg, $x, $y, $newColor); } } return true; @@ -1050,22 +1052,22 @@ public function Threshold(&$gdimg, $cutoff) { public function ImageTrueColorToPalette2(&$image, $dither, $ncolors) { // http://www.php.net/manual/en/function.imagetruecolortopalette.php // zmorris at zsculpt dot com (17-Aug-2004 06:58) - $width = ImageSX($image); - $height = ImageSY($image); - $image_copy = ImageCreateTrueColor($width, $height); - //ImageCopyMerge($image_copy, $image, 0, 0, 0, 0, $width, $height, 100); - ImageCopy($image_copy, $image, 0, 0, 0, 0, $width, $height); - ImageTrueColorToPalette($image, $dither, $ncolors); - ImageColorMatch($image_copy, $image); - ImageDestroy($image_copy); + $width = imagesx($image); + $height = imagesy($image); + $image_copy = imagecreatetruecolor($width, $height); + //imagecopymerge($image_copy, $image, 0, 0, 0, 0, $width, $height, 100); + imagecopy($image_copy, $image, 0, 0, 0, 0, $width, $height); + imagetruecolortopalette($image, $dither, $ncolors); + imagecolormatch($image_copy, $image); + imagedestroy($image_copy); return true; } public function ReduceColorDepth(&$gdimg, $colors=256, $dither=true) { $colors = max(min($colors, 256), 2); - // ImageTrueColorToPalette usually makes ugly colors, the replacement is a bit better - //ImageTrueColorToPalette($gdimg, $dither, $colors); - phpthumb_filters::ImageTrueColorToPalette2($gdimg, $dither, $colors); + // imagetruecolortopalette usually makes ugly colors, the replacement is a bit better + //imagetruecolortopalette($gdimg, $dither, $colors); + $this->ImageTrueColorToPalette2($gdimg, $dither, $colors); return true; } @@ -1078,7 +1080,7 @@ public function WhiteBalance(&$gdimg, $targetColor='') { 'blue' => hexdec(substr($targetColor, 4, 2)) ); } else { - $Analysis = phpthumb_filters::HistogramAnalysis($gdimg, false); + $Analysis = $this->HistogramAnalysis($gdimg, false); $targetPixel = array( 'red' => max(array_keys($Analysis['red'])), 'green' => max(array_keys($Analysis['green'])), @@ -1090,8 +1092,8 @@ public function WhiteBalance(&$gdimg, $targetColor='') { $scaleG = $grayValue / $targetPixel['green']; $scaleB = $grayValue / $targetPixel['blue']; - for ($x = 0; $x < ImageSX($gdimg); $x++) { - for ($y = 0; $y < ImageSY($gdimg); $y++) { + for ($x = 0, $xMax = imagesx($gdimg); $x < $xMax; $x++) { + for ($y = 0, $yMax = imagesy($gdimg); $y < $yMax; $y++) { $currentPixel = phpthumb_functions::GetPixelColor($gdimg, $x, $y); $newColor = phpthumb_functions::ImageColorAllocateAlphaSafe( $gdimg, @@ -1100,29 +1102,30 @@ public function WhiteBalance(&$gdimg, $targetColor='') { max(0, min(255, round($currentPixel['blue'] * $scaleB))), $currentPixel['alpha'] ); - ImageSetPixel($gdimg, $x, $y, $newColor); + imagesetpixel($gdimg, $x, $y, $newColor); } } return true; } - public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000000', $ttffont='', $opacity=100, $margin=5, $angle=0, $bg_color=false, $bg_opacity=0, $fillextend='') { + public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000000', $ttffont='', $opacity=100, $margin=5, $angle=0, $bg_color=false, $bg_opacity=0, $fillextend='', $lineheight=1.0) { // text watermark requested if (!$text) { return false; } - ImageAlphaBlending($gdimg, true); + imagealphablending($gdimg, true); if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)(@[LCR])?$#i', $alignment, $matches)) { - $originOffsetX = intval($matches[1]); - $originOffsetY = intval($matches[2]); + $originOffsetX = (int) $matches[ 1]; + $originOffsetY = (int) $matches[ 2]; $alignment = (@$matches[4] ? $matches[4] : 'L'); $margin = 0; } else { $originOffsetX = 0; $originOffsetY = 0; } + $lineheight = min(100.0, max(0.01, (float) $lineheight)); $metaTextArray = array( '^Fb' => $this->phpThumbObject->getimagesizeinfo['filesize'], @@ -1130,25 +1133,27 @@ public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000 '^Fm' => round($this->phpThumbObject->getimagesizeinfo['filesize'] / 1048576), '^X' => $this->phpThumbObject->getimagesizeinfo[0], '^Y' => $this->phpThumbObject->getimagesizeinfo[1], - '^x' => ImageSX($gdimg), - '^y' => ImageSY($gdimg), + '^x' => imagesx($gdimg), + '^y' => imagesy($gdimg), '^^' => '^', ); $text = strtr($text, $metaTextArray); - $text = str_replace("\r\n", "\n", $text); - $text = str_replace("\r", "\n", $text); + $text = str_replace(array( + "\r\n", + "\r" + ), "\n", $text); $textlines = explode("\n", $text); $this->DebugMessage('Processing '.count($textlines).' lines of text', __FILE__, __LINE__); if (@is_readable($ttffont) && is_file($ttffont)) { - $opacity = 100 - intval(max(min($opacity, 100), 0)); + $opacity = 100 - (int) max(min($opacity, 100), 0); $letter_color_text = phpthumb_functions::ImageHexColorAllocate($gdimg, $hex_color, false, $opacity * 1.27); $this->DebugMessage('Using TTF font "'.$ttffont.'"', __FILE__, __LINE__); - $TTFbox = ImageTTFbBox($size, $angle, $ttffont, $text); + $TTFbox = imagettfbbox($size, $angle, $ttffont, $text); $min_x = min($TTFbox[0], $TTFbox[2], $TTFbox[4], $TTFbox[6]); $max_x = max($TTFbox[0], $TTFbox[2], $TTFbox[4], $TTFbox[6]); @@ -1160,7 +1165,7 @@ public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000 //$text_height = round($max_y - $min_y + ($size * 0.5)); $text_height = round($max_y - $min_y); - $TTFboxChar = ImageTTFbBox($size, $angle, $ttffont, 'jH'); + $TTFboxChar = imagettfbbox($size, $angle, $ttffont, 'jH'); $char_min_y = min($TTFboxChar[1], $TTFboxChar[3], $TTFboxChar[5], $TTFboxChar[7]); $char_max_y = max($TTFboxChar[1], $TTFboxChar[3], $TTFboxChar[5], $TTFboxChar[7]); $char_height = round($char_max_y - $char_min_y); @@ -1168,47 +1173,49 @@ public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000 if ($alignment == '*') { $text_origin_y = $char_height + $margin; - while (($text_origin_y - $text_height) < ImageSY($gdimg)) { + while (($text_origin_y - $text_height) < imagesy($gdimg)) { $text_origin_x = $margin; - while ($text_origin_x < ImageSX($gdimg)) { - ImageTTFtext($gdimg, $size, $angle, $text_origin_x, $text_origin_y, $letter_color_text, $ttffont, $text); + while ($text_origin_x < imagesx($gdimg)) { + imagettftext($gdimg, $size, $angle, $text_origin_x, $text_origin_y, $letter_color_text, $ttffont, $text); $text_origin_x += ($text_width + $margin); } - $text_origin_y += ($text_height + $margin); + $text_origin_y += ($text_height + $margin) * $lineheight; } } else { // this block for background color only + $text_origin_x = 0; + $text_origin_y = 0; switch ($alignment) { case '*': // handled separately break; case 'T': - $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((ImageSX($gdimg) - $text_width) / 2)); + $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((imagesx($gdimg) - $text_width) / 2)); $text_origin_y = $char_height + $margin + $originOffsetY; break; case 'B': - $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((ImageSX($gdimg) - $text_width) / 2)); - $text_origin_y = ImageSY($gdimg) + $TTFbox[1] - $margin + $originOffsetY; + $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((imagesx($gdimg) - $text_width) / 2)); + $text_origin_y = imagesy($gdimg) + $TTFbox[1] - $margin + $originOffsetY; break; case 'L': $text_origin_x = $margin + $originOffsetX; - $text_origin_y = ($originOffsetY ? $originOffsetY : round((ImageSY($gdimg) - $text_height) / 2) + $char_height); + $text_origin_y = ($originOffsetY ? $originOffsetY : round((imagesy($gdimg) - $text_height) / 2) + $char_height); break; case 'R': - $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : ImageSX($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); - $text_origin_y = ($originOffsetY ? $originOffsetY : round((ImageSY($gdimg) - $text_height) / 2) + $char_height); + $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : imagesx($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); + $text_origin_y = ($originOffsetY ? $originOffsetY : round((imagesy($gdimg) - $text_height) / 2) + $char_height); break; case 'C': - $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((ImageSX($gdimg) - $text_width) / 2)); - $text_origin_y = ($originOffsetY ? $originOffsetY : round((ImageSY($gdimg) - $text_height) / 2) + $char_height); + $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width / 2) : round((imagesx($gdimg) - $text_width) / 2)); + $text_origin_y = ($originOffsetY ? $originOffsetY : round((imagesy($gdimg) - $text_height) / 2) + $char_height); break; case 'TL': @@ -1217,23 +1224,22 @@ public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000 break; case 'TR': - $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : ImageSX($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); + $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : imagesx($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); $text_origin_y = $char_height + $margin + $originOffsetY; break; case 'BL': $text_origin_x = $margin + $originOffsetX; - $text_origin_y = ImageSY($gdimg) + $TTFbox[1] - $margin + $originOffsetY; + $text_origin_y = imagesy($gdimg) + $TTFbox[1] - $margin + $originOffsetY; break; case 'BR': default: - $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : ImageSX($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); - $text_origin_y = ImageSY($gdimg) + $TTFbox[1] - $margin + $originOffsetY; + $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width : imagesx($gdimg) - $text_width + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); + $text_origin_y = imagesy($gdimg) + $TTFbox[1] - $margin + $originOffsetY; break; } - //ImageRectangle($gdimg, $text_origin_x + $min_x, $text_origin_y + $TTFbox[1], $text_origin_x + $min_x + $text_width, $text_origin_y + $TTFbox[1] - $text_height, $letter_color_text); if (phpthumb_functions::IsHexColor($bg_color)) { $text_background_alpha = round(127 * ((100 - min(max(0, $bg_opacity), 100)) / 100)); $text_color_background = phpthumb_functions::ImageHexColorAllocate($gdimg, $bg_color, false, $text_background_alpha); @@ -1244,17 +1250,12 @@ public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000 $y1 = $text_origin_y + $TTFbox[1]; $x2 = $text_origin_x + $min_x + $text_width; $y2 = $text_origin_y + $TTFbox[1] - $text_height; - $x_TL = preg_match('#x#i', $fillextend) ? 0 : min($x1, $x2); - $y_TL = preg_match('#y#i', $fillextend) ? 0 : min($y1, $y2); - $x_BR = preg_match('#x#i', $fillextend) ? ImageSX($gdimg) : max($x1, $x2); - $y_BR = preg_match('#y#i', $fillextend) ? ImageSY($gdimg) : max($y1, $y2); - //while ($y_BR > ImageSY($gdimg)) { - // $y_TL--; - // $y_BR--; - // $text_origin_y--; - //} - $this->DebugMessage('WatermarkText() calling ImageFilledRectangle($gdimg, '.$x_TL.', '.$y_TL.', '.$x_BR.', '.$y_BR.', $text_color_background)', __FILE__, __LINE__); - ImageFilledRectangle($gdimg, $x_TL, $y_TL, $x_BR, $y_BR, $text_color_background); + $x_TL = false !== stripos($fillextend, 'x') ? 0 : min($x1, $x2); + $y_TL = false !== stripos($fillextend, 'y') ? 0 : min($y1, $y2); + $x_BR = false !== stripos($fillextend, 'x') ? imagesx($gdimg) : max($x1, $x2); + $y_BR = false !== stripos($fillextend, 'y') ? imagesy($gdimg) : max($y1, $y2); + $this->DebugMessage('WatermarkText() calling imagefilledrectangle($gdimg, '.$x_TL.', '.$y_TL.', '.$x_BR.', '.$y_BR.', $text_color_background)', __FILE__, __LINE__); + imagefilledrectangle($gdimg, $x_TL, $y_TL, $x_BR, $y_BR, $text_color_background); // end block for background color only @@ -1262,44 +1263,38 @@ public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000 $y_offset = 0; foreach ($textlines as $dummy => $line) { - $TTFboxLine = ImageTTFbBox($size, $angle, $ttffont, $line); + $TTFboxLine = imagettfbbox($size, $angle, $ttffont, $line); $min_x_line = min($TTFboxLine[0], $TTFboxLine[2], $TTFboxLine[4], $TTFboxLine[6]); $max_x_line = max($TTFboxLine[0], $TTFboxLine[2], $TTFboxLine[4], $TTFboxLine[6]); - //$text_width = round($max_x - $min_x + ($size * 0.5)); $text_width_line = round($max_x_line - $min_x_line); - $min_y_line = min($TTFboxLine[1], $TTFboxLine[3], $TTFboxLine[5], $TTFboxLine[7]); - $max_y_line = max($TTFboxLine[1], $TTFboxLine[3], $TTFboxLine[5], $TTFboxLine[7]); - //$text_height = round($max_y - $min_y + ($size * 0.5)); - $text_height_line = round($max_y_line - $min_y_line); - switch ($alignment) { // $text_origin_y set above, just re-set $text_origin_x here as needed case 'L': case 'TL': case 'BL': - // no change neccesary + // no change necessary break; case 'C': case 'T': case 'B': - $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width_line / 2) : round((ImageSX($gdimg) - $text_width_line) / 2)); + $text_origin_x = ($originOffsetX ? $originOffsetX - round($text_width_line / 2) : round((imagesx($gdimg) - $text_width_line) / 2)); break; case 'R': case 'TR': case 'BR': - $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width_line : ImageSX($gdimg) - $text_width_line + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); + $text_origin_x = ($originOffsetX ? $originOffsetX - $text_width_line : imagesx($gdimg) - $text_width_line + $TTFbox[0] - $min_x + round($size * 0.25) - $margin); break; } - //ImageTTFtext($gdimg, $size, $angle, $text_origin_x, $text_origin_y, $letter_color_text, $ttffont, $text); - $this->DebugMessage('WatermarkText() calling ImageTTFtext($gdimg, '.$size.', '.$angle.', '.$text_origin_x.', '.($text_origin_y + $y_offset).', $letter_color_text, '.$ttffont.', '.$line.')', __FILE__, __LINE__); - ImageTTFtext($gdimg, $size, $angle, $text_origin_x, $text_origin_y + $y_offset, $letter_color_text, $ttffont, $line); + //imagettftext($gdimg, $size, $angle, $text_origin_x, $text_origin_y, $letter_color_text, $ttffont, $text); + $this->DebugMessage('WatermarkText() calling imagettftext($gdimg, '.$size.', '.$angle.', '.$text_origin_x.', '.($text_origin_y + $y_offset).', $letter_color_text, '.$ttffont.', '.$line.')', __FILE__, __LINE__); + imagettftext($gdimg, $size, $angle, $text_origin_x, $text_origin_y + $y_offset, $letter_color_text, $ttffont, $line); - $y_offset += $char_height; + $y_offset += $char_height * $lineheight; } } @@ -1313,55 +1308,59 @@ public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000 $text_width = 0; $text_height = 0; foreach ($textlines as $dummy => $line) { - $text_width = max($text_width, ImageFontWidth($size) * strlen($line)); - $text_height += ImageFontHeight($size); + $text_width = max($text_width, imagefontwidth($size) * strlen($line)); + $text_height += imagefontheight($size); } if ($img_watermark = phpthumb_functions::ImageCreateFunction($text_width, $text_height)) { - ImageAlphaBlending($img_watermark, false); + imagealphablending($img_watermark, false); if (phpthumb_functions::IsHexColor($bg_color)) { $text_background_alpha = round(127 * ((100 - min(max(0, $bg_opacity), 100)) / 100)); $text_color_background = phpthumb_functions::ImageHexColorAllocate($img_watermark, $bg_color, false, $text_background_alpha); } else { $text_color_background = phpthumb_functions::ImageHexColorAllocate($img_watermark, 'FFFFFF', false, 127); } - $this->DebugMessage('WatermarkText() calling ImageFilledRectangle($img_watermark, 0, 0, '.ImageSX($img_watermark).', '.ImageSY($img_watermark).', $text_color_background)', __FILE__, __LINE__); - ImageFilledRectangle($img_watermark, 0, 0, ImageSX($img_watermark), ImageSY($img_watermark), $text_color_background); - - if ($angle && function_exists('ImageRotate')) { - // using $img_watermark_mask is pointless if ImageRotate function isn't available + $this->DebugMessage('WatermarkText() calling imagefilledrectangle($img_watermark, 0, 0, '.imagesx($img_watermark).', '.imagesy($img_watermark).', $text_color_background)', __FILE__, __LINE__); + imagefilledrectangle($img_watermark, 0, 0, imagesx($img_watermark), imagesy($img_watermark), $text_color_background); + + $img_watermark_mask = false; + $mask_color_background = false; + $mask_color_watermark = false; + if ($angle && function_exists('imagerotate')) { + // using $img_watermark_mask is pointless if imagerotate function isn't available if ($img_watermark_mask = phpthumb_functions::ImageCreateFunction($text_width, $text_height)) { - $mask_color_background = ImageColorAllocate($img_watermark_mask, 0, 0, 0); - ImageAlphaBlending($img_watermark_mask, false); - ImageFilledRectangle($img_watermark_mask, 0, 0, ImageSX($img_watermark_mask), ImageSY($img_watermark_mask), $mask_color_background); - $mask_color_watermark = ImageColorAllocate($img_watermark_mask, 255, 255, 255); + $mask_color_background = imagecolorallocate($img_watermark_mask, 0, 0, 0); + imagealphablending($img_watermark_mask, false); + imagefilledrectangle($img_watermark_mask, 0, 0, imagesx($img_watermark_mask), imagesy($img_watermark_mask), $mask_color_background); + $mask_color_watermark = imagecolorallocate($img_watermark_mask, 255, 255, 255); } } $text_color_watermark = phpthumb_functions::ImageHexColorAllocate($img_watermark, $hex_color); + $x_offset = 0; foreach ($textlines as $key => $line) { switch ($alignment) { case 'C': - $x_offset = round(($text_width - (ImageFontWidth($size) * strlen($line))) / 2); - $originOffsetX = (ImageSX($gdimg) - ImageSX($img_watermark)) / 2; - $originOffsetY = (ImageSY($gdimg) - ImageSY($img_watermark)) / 2; + $x_offset = round(($text_width - (imagefontwidth($size) * strlen($line))) / 2); + $originOffsetX = (imagesx($gdimg) - imagesx($img_watermark)) / 2; + $originOffsetY = (imagesy($gdimg) - imagesy($img_watermark)) / 2; break; case 'T': - $x_offset = round(($text_width - (ImageFontWidth($size) * strlen($line))) / 2); - $originOffsetX = (ImageSX($gdimg) - ImageSX($img_watermark)) / 2; + $x_offset = round(($text_width - (imagefontwidth($size) * strlen($line))) / 2); + $originOffsetX = (imagesx($gdimg) - imagesx($img_watermark)) / 2; $originOffsetY = $margin; break; case 'B': - $x_offset = round(($text_width - (ImageFontWidth($size) * strlen($line))) / 2); - $originOffsetX = (ImageSX($gdimg) - ImageSX($img_watermark)) / 2; - $originOffsetY = ImageSY($gdimg) - ImageSY($img_watermark) - $margin; + $x_offset = round(($text_width - (imagefontwidth($size) * strlen($line))) / 2); + $originOffsetX = (imagesx($gdimg) - imagesx($img_watermark)) / 2; + $originOffsetY = imagesy($gdimg) - imagesy($img_watermark) - $margin; break; case 'L': $x_offset = 0; $originOffsetX = $margin; - $originOffsetY = (ImageSY($gdimg) - ImageSY($img_watermark)) / 2; + $originOffsetY = (imagesy($gdimg) - imagesy($img_watermark)) / 2; break; case 'TL': @@ -1373,18 +1372,18 @@ public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000 case 'BL': $x_offset = 0; $originOffsetX = $margin; - $originOffsetY = ImageSY($gdimg) - ImageSY($img_watermark) - $margin; + $originOffsetY = imagesy($gdimg) - imagesy($img_watermark) - $margin; break; case 'R': - $x_offset = $text_width - (ImageFontWidth($size) * strlen($line)); - $originOffsetX = ImageSX($gdimg) - ImageSX($img_watermark) - $margin; - $originOffsetY = (ImageSY($gdimg) - ImageSY($img_watermark)) / 2; + $x_offset = $text_width - (imagefontwidth($size) * strlen($line)); + $originOffsetX = imagesx($gdimg) - imagesx($img_watermark) - $margin; + $originOffsetY = (imagesy($gdimg) - imagesy($img_watermark)) / 2; break; case 'TR': - $x_offset = $text_width - (ImageFontWidth($size) * strlen($line)); - $originOffsetX = ImageSX($gdimg) - ImageSX($img_watermark) - $margin; + $x_offset = $text_width - (imagefontwidth($size) * strlen($line)); + $originOffsetX = imagesx($gdimg) - imagesx($img_watermark) - $margin; $originOffsetY = $margin; break; @@ -1393,28 +1392,28 @@ public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000 if (!empty($originOffsetX) || !empty($originOffsetY)) { // absolute pixel positioning } else { - $x_offset = $text_width - (ImageFontWidth($size) * strlen($line)); - $originOffsetX = ImageSX($gdimg) - ImageSX($img_watermark) - $margin; - $originOffsetY = ImageSY($gdimg) - ImageSY($img_watermark) - $margin; + $x_offset = $text_width - (imagefontwidth($size) * strlen($line)); + $originOffsetX = imagesx($gdimg) - imagesx($img_watermark) - $margin; + $originOffsetY = imagesy($gdimg) - imagesy($img_watermark) - $margin; } break; } - $this->DebugMessage('WatermarkText() calling ImageString($img_watermark, '.$size.', '.$x_offset.', '.($key * ImageFontHeight($size)).', '.$line.', $text_color_watermark)', __FILE__, __LINE__); - ImageString($img_watermark, $size, $x_offset, $key * ImageFontHeight($size), $line, $text_color_watermark); + $this->DebugMessage('WatermarkText() calling imagestring($img_watermark, '.$size.', '.$x_offset.', '.($key * imagefontheight($size)).', '.$line.', $text_color_watermark)', __FILE__, __LINE__); + imagestring($img_watermark, $size, $x_offset, $key * imagefontheight($size), $line, $text_color_watermark); if ($angle && $img_watermark_mask) { - $this->DebugMessage('WatermarkText() calling ImageString($img_watermark_mask, '.$size.', '.$x_offset.', '.($key * ImageFontHeight($size)).', '.$text.', $mask_color_watermark)', __FILE__, __LINE__); - ImageString($img_watermark_mask, $size, $x_offset, $key * ImageFontHeight($size), $text, $mask_color_watermark); + $this->DebugMessage('WatermarkText() calling imagestring($img_watermark_mask, '.$size.', '.$x_offset.', '.($key * imagefontheight($size) * $lineheight).', '.$text.', $mask_color_watermark)', __FILE__, __LINE__); + imagestring($img_watermark_mask, $size, $x_offset, $key * imagefontheight($size) * $lineheight, $text, $mask_color_watermark); } } if ($angle && $img_watermark_mask) { - $img_watermark = ImageRotate($img_watermark, $angle, $text_color_background); - $img_watermark_mask = ImageRotate($img_watermark_mask, $angle, $mask_color_background); - phpthumb_filters::ApplyMask($img_watermark_mask, $img_watermark); + $img_watermark = imagerotate($img_watermark, $angle, $text_color_background); + $img_watermark_mask = imagerotate($img_watermark_mask, $angle, $mask_color_background); + $this->ApplyMask($img_watermark_mask, $img_watermark); } //phpthumb_filters::WatermarkOverlay($gdimg, $img_watermark, $alignment, $opacity, $margin); $this->DebugMessage('WatermarkText() calling phpthumb_filters::WatermarkOverlay($gdimg, $img_watermark, '.($originOffsetX.'x'.$originOffsetY).', '.$opacity.', 0)', __FILE__, __LINE__); - phpthumb_filters::WatermarkOverlay($gdimg, $img_watermark, $originOffsetX.'x'.$originOffsetY, $opacity, 0); - ImageDestroy($img_watermark); + $this->WatermarkOverlay($gdimg, $img_watermark, $originOffsetX.'x'.$originOffsetY, $opacity, 0); + imagedestroy($img_watermark); return true; } @@ -1426,42 +1425,42 @@ public function WatermarkText(&$gdimg, $text, $size, $alignment, $hex_color='000 public function WatermarkOverlay(&$gdimg_dest, &$img_watermark, $alignment='*', $opacity=50, $margin_x=5, $margin_y=null) { if (is_resource($gdimg_dest) && is_resource($img_watermark)) { - $watermark_source_x = 0; - $watermark_source_y = 0; - $img_source_width = ImageSX($gdimg_dest); - $img_source_height = ImageSY($gdimg_dest); - $watermark_source_width = ImageSX($img_watermark); - $watermark_source_height = ImageSY($img_watermark); + $img_source_width = imagesx($gdimg_dest); + $img_source_height = imagesy($gdimg_dest); + $watermark_source_width = imagesx($img_watermark); + $watermark_source_height = imagesy($img_watermark); $watermark_opacity_percent = max(0, min(100, $opacity)); - $margin_y = (is_null($margin_y) ? $margin_x : $margin_y); + $margin_y = (null === $margin_y ? $margin_x : $margin_y); $watermark_margin_x = ((($margin_x > 0) && ($margin_x < 1)) ? round((1 - $margin_x) * $img_source_width) : $margin_x); $watermark_margin_y = ((($margin_y > 0) && ($margin_y < 1)) ? round((1 - $margin_y) * $img_source_height) : $margin_y); + $watermark_destination_x = 0; + $watermark_destination_y = 0; if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) { - $watermark_destination_x = intval($matches[1]); - $watermark_destination_y = intval($matches[2]); + $watermark_destination_x = (int) $matches[ 1]; + $watermark_destination_y = (int) $matches[ 2]; } else { switch ($alignment) { case '*': if ($gdimg_tiledwatermark = phpthumb_functions::ImageCreateFunction($img_source_width, $img_source_height)) { - ImageAlphaBlending($gdimg_tiledwatermark, false); - ImageSaveAlpha($gdimg_tiledwatermark, true); + imagealphablending($gdimg_tiledwatermark, false); + imagesavealpha($gdimg_tiledwatermark, true); $text_color_transparent = phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_tiledwatermark, 255, 0, 255, 127); - ImageFill($gdimg_tiledwatermark, 0, 0, $text_color_transparent); + imagefill($gdimg_tiledwatermark, 0, 0, $text_color_transparent); // set the tiled image transparent color to whatever the untiled image transparency index is - // ImageColorTransparent($gdimg_tiledwatermark, ImageColorTransparent($img_watermark)); + // imagecolortransparent($gdimg_tiledwatermark, imagecolortransparent($img_watermark)); // a "cleaner" way of doing it, but can't handle the margin feature :( - // ImageSetTile($gdimg_tiledwatermark, $img_watermark); - // ImageFill($gdimg_tiledwatermark, 0, 0, IMG_COLOR_TILED); + // imagesettile($gdimg_tiledwatermark, $img_watermark); + // imagefill($gdimg_tiledwatermark, 0, 0, IMG_COLOR_TILED); // break; - // ImageFill($gdimg_tiledwatermark, 0, 0, ImageColorTransparent($gdimg_tiledwatermark)); + // imagefill($gdimg_tiledwatermark, 0, 0, imagecolortransparent($gdimg_tiledwatermark)); // tile the image as many times as can fit for ($x = $watermark_margin_x; $x < ($img_source_width + $watermark_source_width); $x += ($watermark_source_width + $watermark_margin_x)) { for ($y = $watermark_margin_y; $y < ($img_source_height + $watermark_source_height); $y += ($watermark_source_height + $watermark_margin_y)) { - ImageCopy( + imagecopy( $gdimg_tiledwatermark, $img_watermark, $x, @@ -1474,12 +1473,12 @@ public function WatermarkOverlay(&$gdimg_dest, &$img_watermark, $alignment='*', } } - $watermark_source_width = ImageSX($gdimg_tiledwatermark); - $watermark_source_height = ImageSY($gdimg_tiledwatermark); + $watermark_source_width = imagesx($gdimg_tiledwatermark); + $watermark_source_height = imagesy($gdimg_tiledwatermark); $watermark_destination_x = 0; $watermark_destination_y = 0; - ImageDestroy($img_watermark); + imagedestroy($img_watermark); $img_watermark = $gdimg_tiledwatermark; } break; @@ -1520,13 +1519,6 @@ public function WatermarkOverlay(&$gdimg_dest, &$img_watermark, $alignment='*', break; case 'BL': - //echo '
        ';
        -	////var_dump($watermark_destination_x);
        -	////var_dump($watermark_destination_y);
        -	//var_dump($watermark_margin_x);
        -	//var_dump($img_source_height);
        -	//var_dump($watermark_source_height);
        -	//var_dump($watermark_margin_y);
         						$watermark_destination_x = $watermark_margin_x;
         						$watermark_destination_y = $img_source_height - $watermark_source_height - $watermark_margin_y;
         						break;
        @@ -1538,9 +1530,9 @@ public function WatermarkOverlay(&$gdimg_dest, &$img_watermark, $alignment='*',
         						break;
         				}
         			}
        -			ImageAlphaBlending($gdimg_dest, false);
        -			ImageSaveAlpha($gdimg_dest, true);
        -			ImageSaveAlpha($img_watermark, true);
        +			imagealphablending($gdimg_dest, false);
        +			imagesavealpha($gdimg_dest, true);
        +			imagesavealpha($img_watermark, true);
         			phpthumb_functions::ImageCopyRespectAlpha($gdimg_dest, $img_watermark, $watermark_destination_x, $watermark_destination_y, 0, 0, $watermark_source_width, $watermark_source_height, $watermark_opacity_percent);
         
         			return true;
        diff --git a/assets/snippets/phpthumb/phpthumb.functions.php b/assets/snippets/phpthumb/phpthumb.functions.php
        index 0a7bc4b6ea..550a148b6f 100755
        --- a/assets/snippets/phpthumb/phpthumb.functions.php
        +++ b/assets/snippets/phpthumb/phpthumb.functions.php
        @@ -11,7 +11,7 @@
         
         class phpthumb_functions {
         
        -	static function user_function_exists($functionname) {
        +	public static function user_function_exists($functionname) {
         		if (function_exists('get_defined_functions')) {
         			static $get_defined_functions = array();
         			if (empty($get_defined_functions)) {
        @@ -23,7 +23,7 @@ static function user_function_exists($functionname) {
         	}
         
         
        -	static function builtin_function_exists($functionname) {
        +	public static function builtin_function_exists($functionname) {
         		if (function_exists('get_defined_functions')) {
         			static $get_defined_functions = array();
         			if (empty($get_defined_functions)) {
        @@ -35,7 +35,7 @@ static function builtin_function_exists($functionname) {
         	}
         
         
        -	static function version_compare_replacement_sub($version1, $version2, $operator='') {
        +	public static function version_compare_replacement_sub($version1, $version2, $operator='') {
         		// If you specify the third optional operator argument, you can test for a particular relationship.
         		// The possible operators are: <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne respectively.
         		// Using this argument, the function will return 1 if the relationship is the one specified by the operator, 0 otherwise.
        @@ -61,29 +61,29 @@ static function version_compare_replacement_sub($version1, $version2, $operator=
         		switch ($operator) {
         			case '<':
         			case 'lt':
        -				return intval($version1 < $version2);
        +				return (int) ($version1 < $version2);
         				break;
         			case '<=':
         			case 'le':
        -				return intval($version1 <= $version2);
        +				return (int) ($version1 <= $version2);
         				break;
         			case '>':
         			case 'gt':
        -				return intval($version1 > $version2);
        +				return (int) ($version1 > $version2);
         				break;
         			case '>=':
         			case 'ge':
        -				return intval($version1 >= $version2);
        +				return (int) ($version1 >= $version2);
         				break;
         			case '==':
         			case '=':
         			case 'eq':
        -				return intval($version1 == $version2);
        +				return (int) ($version1 == $version2);
         				break;
         			case '!=':
         			case '<>':
         			case 'ne':
        -				return intval($version1 != $version2);
        +				return (int) ($version1 != $version2);
         				break;
         		}
         		if ($version1 == $version2) {
        @@ -95,7 +95,7 @@ static function version_compare_replacement_sub($version1, $version2, $operator=
         	}
         
         
        -	static function version_compare_replacement($version1, $version2, $operator='') {
        +	public static function version_compare_replacement($version1, $version2, $operator='') {
         		if (function_exists('version_compare')) {
         			// built into PHP v4.1.0+
         			return version_compare($version1, $version2, $operator);
        @@ -107,14 +107,14 @@ static function version_compare_replacement($version1, $version2, $operator='')
         
         		// and also inserts dots . before and after any non number so that for example '4.3.2RC1' becomes '4.3.2.RC.1'.
         		// Then it splits the results like if you were using explode('.',$ver). Then it compares the parts starting from left to right.
        -		$version1 = preg_replace('#([0-9]+)([A-Z]+)([0-9]+)#i', "$1.$2.$3", $version1);
        -		$version2 = preg_replace('#([0-9]+)([A-Z]+)([0-9]+)#i', "$1.$2.$3", $version2);
        +		$version1 = preg_replace('#([\d]+)([A-Z]+)([\d]+)#i', '$1.$2.$3', $version1);
        +		$version2 = preg_replace('#([\d]+)([A-Z]+)([\d]+)#i', '$1.$2.$3', $version2);
         
         		$parts1 = explode('.', $version1);
         		$parts2 = explode('.', $version1);
         		$parts_count = max(count($parts1), count($parts2));
         		for ($i = 0; $i < $parts_count; $i++) {
        -			$comparison = phpthumb_functions::version_compare_replacement_sub($version1, $version2, $operator);
        +			$comparison = self::version_compare_replacement_sub($version1, $version2, $operator);
         			if ($comparison != 0) {
         				return $comparison;
         			}
        @@ -122,8 +122,14 @@ static function version_compare_replacement($version1, $version2, $operator='')
         		return 0;
         	}
         
        +	public static function escapeshellarg_replacement($arg) {
        +		if (function_exists('escapeshellarg') && !self::FunctionIsDisabled('escapeshellarg')) {
        +			return escapeshellarg($arg);
        +		}
        +		return '\''.str_replace('\'', '\\\'', $arg).'\'';
        +	}
         
        -	static function phpinfo_array() {
        +	public static function phpinfo_array() {
         		static $phpinfo_array = array();
         		if (empty($phpinfo_array)) {
         			ob_start();
        @@ -136,7 +142,7 @@ static function phpinfo_array() {
         	}
         
         
        -	static function exif_info() {
        +	public static function exif_info() {
         		static $exif_info = array();
         		if (empty($exif_info)) {
         			// based on code by johnschaefer at gmx dot de
        @@ -147,7 +153,7 @@ static function exif_info() {
         				'Supported EXIF Version' => '',
         				'Supported filetypes'    => ''
         			);
        -			$phpinfo_array = phpthumb_functions::phpinfo_array();
        +			$phpinfo_array = self::phpinfo_array();
         			foreach ($phpinfo_array as $line) {
         				$line = trim(strip_tags($line));
         				foreach ($exif_info as $key => $value) {
        @@ -162,7 +168,7 @@ static function exif_info() {
         	}
         
         
        -	static function ImageTypeToMIMEtype($imagetype) {
        +	public static function ImageTypeToMIMEtype($imagetype) {
         		if (function_exists('image_type_to_mime_type') && ($imagetype >= 1) && ($imagetype <= 16)) {
         			// PHP v4.3.0+
         			return image_type_to_mime_type($imagetype);
        @@ -197,7 +203,7 @@ static function ImageTypeToMIMEtype($imagetype) {
         	}
         
         
        -	static function TranslateWHbyAngle($width, $height, $angle) {
        +	public static function TranslateWHbyAngle($width, $height, $angle) {
         		if (($angle % 180) == 0) {
         			return array($width, $height);
         		}
        @@ -206,7 +212,7 @@ static function TranslateWHbyAngle($width, $height, $angle) {
         		return array($newwidth, $newheight);
         	}
         
        -	static function HexCharDisplay($string) {
        +	public static function HexCharDisplay($string) {
         		$len = strlen($string);
         		$output = '';
         		for ($i = 0; $i < $len; $i++) {
        @@ -216,50 +222,50 @@ static function HexCharDisplay($string) {
         	}
         
         
        -	static function IsHexColor($HexColorString) {
        +	public static function IsHexColor($HexColorString) {
         		return preg_match('#^[0-9A-F]{6}$#i', $HexColorString);
         	}
         
         
        -	static function ImageColorAllocateAlphaSafe(&$gdimg_hexcolorallocate, $R, $G, $B, $alpha=false) {
        -		if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.2', '>=') && ($alpha !== false)) {
        -			return ImageColorAllocateAlpha($gdimg_hexcolorallocate, $R, $G, $B, intval($alpha));
        +	public static function ImageColorAllocateAlphaSafe(&$gdimg_hexcolorallocate, $R, $G, $B, $alpha=false) {
        +		if (self::version_compare_replacement(PHP_VERSION, '4.3.2', '>=') && ($alpha !== false)) {
        +			return imagecolorallocatealpha($gdimg_hexcolorallocate, $R, $G, $B, (int) $alpha);
         		} else {
        -			return ImageColorAllocate($gdimg_hexcolorallocate, $R, $G, $B);
        +			return imagecolorallocate($gdimg_hexcolorallocate, $R, $G, $B);
         		}
         	}
         
        -	static function ImageHexColorAllocate(&$gdimg_hexcolorallocate, $HexColorString, $dieOnInvalid=false, $alpha=false) {
        +	public static function ImageHexColorAllocate(&$gdimg_hexcolorallocate, $HexColorString, $dieOnInvalid=false, $alpha=false) {
         		if (!is_resource($gdimg_hexcolorallocate)) {
         			die('$gdimg_hexcolorallocate is not a GD resource in ImageHexColorAllocate()');
         		}
        -		if (phpthumb_functions::IsHexColor($HexColorString)) {
        +		if (self::IsHexColor($HexColorString)) {
         			$R = hexdec(substr($HexColorString, 0, 2));
         			$G = hexdec(substr($HexColorString, 2, 2));
         			$B = hexdec(substr($HexColorString, 4, 2));
        -			return phpthumb_functions::ImageColorAllocateAlphaSafe($gdimg_hexcolorallocate, $R, $G, $B, $alpha);
        +			return self::ImageColorAllocateAlphaSafe($gdimg_hexcolorallocate, $R, $G, $B, $alpha);
         		}
         		if ($dieOnInvalid) {
         			die('Invalid hex color string: "'.$HexColorString.'"');
         		}
        -		return ImageColorAllocate($gdimg_hexcolorallocate, 0x00, 0x00, 0x00);
        +		return imagecolorallocate($gdimg_hexcolorallocate, 0x00, 0x00, 0x00);
         	}
         
         
        -	static function HexColorXOR($hexcolor) {
        +	public static function HexColorXOR($hexcolor) {
         		return strtoupper(str_pad(dechex(~hexdec($hexcolor) & 0xFFFFFF), 6, '0', STR_PAD_LEFT));
         	}
         
         
        -	static function GetPixelColor(&$img, $x, $y) {
        +	public static function GetPixelColor(&$img, $x, $y) {
         		if (!is_resource($img)) {
         			return false;
         		}
        -		return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y));
        +		return @imagecolorsforindex($img, @imagecolorat($img, $x, $y));
         	}
         
         
        -	static function PixelColorDifferencePercent($currentPixel, $targetPixel) {
        +	public static function PixelColorDifferencePercent($currentPixel, $targetPixel) {
         		$diff = 0;
         		foreach ($targetPixel as $channel => $currentvalue) {
         			$diff = max($diff, (max($currentPixel[$channel], $targetPixel[$channel]) - min($currentPixel[$channel], $targetPixel[$channel])) / 255);
        @@ -267,18 +273,18 @@ static function PixelColorDifferencePercent($currentPixel, $targetPixel) {
         		return $diff * 100;
         	}
         
        -	static function GrayscaleValue($r, $g, $b) {
        +	public static function GrayscaleValue($r, $g, $b) {
         		return round(($r * 0.30) + ($g * 0.59) + ($b * 0.11));
         	}
         
         
        -	static function GrayscalePixel($OriginalPixel) {
        -		$gray = phpthumb_functions::GrayscaleValue($OriginalPixel['red'], $OriginalPixel['green'], $OriginalPixel['blue']);
        +	public static function GrayscalePixel($OriginalPixel) {
        +		$gray = self::GrayscaleValue($OriginalPixel[ 'red'], $OriginalPixel[ 'green'], $OriginalPixel[ 'blue']);
         		return array('red'=>$gray, 'green'=>$gray, 'blue'=>$gray);
         	}
         
         
        -	static function GrayscalePixelRGB($rgb) {
        +	public static function GrayscalePixelRGB($rgb) {
         		$r = ($rgb >> 16) & 0xFF;
         		$g = ($rgb >>  8) & 0xFF;
         		$b =  $rgb        & 0xFF;
        @@ -286,9 +292,9 @@ static function GrayscalePixelRGB($rgb) {
         	}
         
         
        -	static function ScaleToFitInBox($width, $height, $maxwidth=null, $maxheight=null, $allow_enlarge=true, $allow_reduce=true) {
        -		$maxwidth  = (is_null($maxwidth)  ? $width  : $maxwidth);
        -		$maxheight = (is_null($maxheight) ? $height : $maxheight);
        +	public static function ScaleToFitInBox($width, $height, $maxwidth=null, $maxheight=null, $allow_enlarge=true, $allow_reduce=true) {
        +		$maxwidth  = (null === $maxwidth  ? $width  : $maxwidth);
        +		$maxheight = (null === $maxheight ? $height : $maxheight);
         		$scale_x = 1;
         		$scale_y = 1;
         		if (($width > $maxwidth) || ($width < $maxwidth)) {
        @@ -307,7 +313,7 @@ static function ScaleToFitInBox($width, $height, $maxwidth=null, $maxheight=null
         		return $scale;
         	}
         
        -	static function ImageCopyResampleBicubic($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) {
        +	public static function ImageCopyResampleBicubic($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) {
         		// ron at korving dot demon dot nl
         		// http://www.php.net/imagecopyresampled
         
        @@ -317,7 +323,7 @@ static function ImageCopyResampleBicubic($dst_img, $src_img, $dst_x, $dst_y, $sr
         		$scaleX2 = $scaleX / 2.0;
         		$scaleY2 = $scaleY / 2.0;
         
        -		$isTrueColor = ImageIsTrueColor($src_img);
        +		$isTrueColor = imageistruecolor($src_img);
         
         		for ($y = $src_y; $y < $src_y + $dst_h; $y++) {
         			$sY   = $y * $scaleY;
        @@ -331,10 +337,10 @@ static function ImageCopyResampleBicubic($dst_img, $src_img, $dst_x, $dst_y, $sr
         
         				if ($isTrueColor) {
         
        -					$c1 = ImageColorAt($src_img, $siX, $siY2);
        -					$c2 = ImageColorAt($src_img, $siX, $siY);
        -					$c3 = ImageColorAt($src_img, $siX2, $siY2);
        -					$c4 = ImageColorAt($src_img, $siX2, $siY);
        +					$c1 = imagecolorat($src_img, $siX, $siY2);
        +					$c2 = imagecolorat($src_img, $siX, $siY);
        +					$c3 = imagecolorat($src_img, $siX2, $siY2);
        +					$c4 = imagecolorat($src_img, $siX2, $siY);
         
         					$r = (( $c1             +  $c2             +  $c3             +  $c4            ) >> 2) & 0xFF0000;
         					$g = ((($c1 & 0x00FF00) + ($c2 & 0x00FF00) + ($c3 & 0x00FF00) + ($c4 & 0x00FF00)) >> 2) & 0x00FF00;
        @@ -342,27 +348,27 @@ static function ImageCopyResampleBicubic($dst_img, $src_img, $dst_x, $dst_y, $sr
         
         				} else {
         
        -					$c1 = ImageColorsForIndex($src_img, ImageColorAt($src_img, $siX, $siY2));
        -					$c2 = ImageColorsForIndex($src_img, ImageColorAt($src_img, $siX, $siY));
        -					$c3 = ImageColorsForIndex($src_img, ImageColorAt($src_img, $siX2, $siY2));
        -					$c4 = ImageColorsForIndex($src_img, ImageColorAt($src_img, $siX2, $siY));
        +					$c1 = imagecolorsforindex($src_img, imagecolorat($src_img, $siX, $siY2));
        +					$c2 = imagecolorsforindex($src_img, imagecolorat($src_img, $siX, $siY));
        +					$c3 = imagecolorsforindex($src_img, imagecolorat($src_img, $siX2, $siY2));
        +					$c4 = imagecolorsforindex($src_img, imagecolorat($src_img, $siX2, $siY));
         
         					$r = ($c1['red']   + $c2['red']   + $c3['red']   + $c4['red'] )  << 14;
         					$g = ($c1['green'] + $c2['green'] + $c3['green'] + $c4['green']) <<  6;
         					$b = ($c1['blue']  + $c2['blue']  + $c3['blue']  + $c4['blue'] ) >>  2;
         
         				}
        -				ImageSetPixel($dst_img, $dst_x + $x - $src_x, $dst_y + $y - $src_y, $r+$g+$b);
        +				imagesetpixel($dst_img, $dst_x + $x - $src_x, $dst_y + $y - $src_y, $r+$g+$b);
         			}
         		}
         		return true;
         	}
         
         
        -	static function ImageCreateFunction($x_size, $y_size) {
        -		$ImageCreateFunction = 'ImageCreate';
        -		if (phpthumb_functions::gd_version() >= 2.0) {
        -			$ImageCreateFunction = 'ImageCreateTrueColor';
        +	public static function ImageCreateFunction($x_size, $y_size) {
        +		$ImageCreateFunction = 'imagecreate';
        +		if (self::gd_version() >= 2.0) {
        +			$ImageCreateFunction = 'imagecreatetruecolor';
         		}
         		if (!function_exists($ImageCreateFunction)) {
         			return phpthumb::ErrorImage($ImageCreateFunction.'() does not exist - no GD support?');
        @@ -374,31 +380,32 @@ static function ImageCreateFunction($x_size, $y_size) {
         	}
         
         
        -	static function ImageCopyRespectAlpha(&$dst_im, &$src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $opacity_pct=100) {
        +	public static function ImageCopyRespectAlpha(&$dst_im, &$src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $opacity_pct=100) {
         		$opacipct = $opacity_pct / 100;
         		for ($x = $src_x; $x < $src_w; $x++) {
         			for ($y = $src_y; $y < $src_h; $y++) {
        -				$RealPixel    = phpthumb_functions::GetPixelColor($dst_im, $dst_x + $x, $dst_y + $y);
        -				$OverlayPixel = phpthumb_functions::GetPixelColor($src_im, $x, $y);
        +				$RealPixel    = self::GetPixelColor($dst_im, $dst_x + $x, $dst_y + $y);
        +				$OverlayPixel = self::GetPixelColor($src_im, $x, $y);
         				$alphapct = $OverlayPixel['alpha'] / 127;
         				$overlaypct = (1 - $alphapct) * $opacipct;
         
        -				$newcolor = phpthumb_functions::ImageColorAllocateAlphaSafe(
        +				$newcolor = self::ImageColorAllocateAlphaSafe(
         					$dst_im,
        -					round($RealPixel['red']   * (1 - $overlaypct)) + ($OverlayPixel['red']   * $overlaypct),
        -					round($RealPixel['green'] * (1 - $overlaypct)) + ($OverlayPixel['green'] * $overlaypct),
        -					round($RealPixel['blue']  * (1 - $overlaypct)) + ($OverlayPixel['blue']  * $overlaypct),
        -					//$RealPixel['alpha']);
        -					0);
        -
        -				ImageSetPixel($dst_im, $dst_x + $x, $dst_y + $y, $newcolor);
        +					$RealPixel['alpha'] == 127 ? $OverlayPixel['red'] : ($OverlayPixel['alpha'] == 127 ? $RealPixel['red'] : (round($RealPixel['red'] * (1 - $overlaypct)) + ($OverlayPixel['red'] * $overlaypct))),
        +					$RealPixel['alpha'] == 127 ? $OverlayPixel['green'] : ($OverlayPixel['alpha'] == 127 ? $RealPixel['green'] : (round($RealPixel['green'] * (1 - $overlaypct)) + ($OverlayPixel['green'] * $overlaypct))),
        +					$RealPixel['alpha'] == 127 ? $OverlayPixel['blue'] : ($OverlayPixel['alpha'] == 127 ? $RealPixel['blue'] : (round($RealPixel['blue'] * (1 - $overlaypct)) + ($OverlayPixel['blue'] * $overlaypct))),
        +//					0);
        +					min([$RealPixel['alpha'], floor($OverlayPixel['alpha'] * $opacipct)])
        +				);
        +
        +				imagesetpixel($dst_im, $dst_x + $x, $dst_y + $y, $newcolor);
         			}
         		}
         		return true;
         	}
         
         
        -	static function ProportionalResize($old_width, $old_height, $new_width=false, $new_height=false) {
        +	public static function ProportionalResize($old_width, $old_height, $new_width=false, $new_height=false) {
         		$old_aspect_ratio = $old_width / $old_height;
         		if (($new_width === false) && ($new_height === false)) {
         			return false;
        @@ -417,13 +424,16 @@ static function ProportionalResize($old_width, $old_height, $new_width=false, $n
         			// limited by height
         			$new_width = $new_height * $old_aspect_ratio;
         		}
        -		return array(intval(round($new_width)), intval(round($new_height)));
        +		return array(
        +			(int) round($new_width),
        +			(int) round($new_height)
        +		);
         	}
         
         
        -	static function FunctionIsDisabled($function) {
        +	public static function FunctionIsDisabled($function) {
         		static $DisabledFunctions = null;
        -		if (is_null($DisabledFunctions)) {
        +		if (null === $DisabledFunctions) {
         			$disable_functions_local  = explode(',',     strtolower(@ini_get('disable_functions')));
         			$disable_functions_global = explode(',', strtolower(@get_cfg_var('disable_functions')));
         			foreach ($disable_functions_local as $key => $value) {
        @@ -441,12 +451,12 @@ static function FunctionIsDisabled($function) {
         	}
         
         
        -	static function SafeExec($command) {
        +	public static function SafeExec($command) {
         		static $AllowedExecFunctions = array();
         		if (empty($AllowedExecFunctions)) {
         			$AllowedExecFunctions = array('shell_exec'=>true, 'passthru'=>true, 'system'=>true, 'exec'=>true);
         			foreach ($AllowedExecFunctions as $key => $value) {
        -				$AllowedExecFunctions[$key] = !phpthumb_functions::FunctionIsDisabled($key);
        +				$AllowedExecFunctions[$key] = !self::FunctionIsDisabled($key);
         			}
         		}
         		$command .= ' 2>&1'; // force redirect stderr to stdout
        @@ -482,9 +492,9 @@ static function SafeExec($command) {
         	}
         
         
        -	static function ApacheLookupURIarray($filename) {
        +	public static function ApacheLookupURIarray($filename) {
         		// apache_lookup_uri() only works when PHP is installed as an Apache module.
        -		if (php_sapi_name() == 'apache') {
        +		if (PHP_SAPI == 'apache') {
         			//$property_exists_exists = function_exists('property_exists');
         			$keys = array('status', 'the_request', 'status_line', 'method', 'content_type', 'handler', 'uri', 'filename', 'path_info', 'args', 'boundary', 'no_cache', 'no_local_copy', 'allowed', 'send_bodyct', 'bytes_sent', 'byterange', 'clength', 'unparsed_uri', 'mtime', 'request_time');
         			if ($apacheLookupURIobject = @apache_lookup_uri($filename)) {
        @@ -499,9 +509,9 @@ static function ApacheLookupURIarray($filename) {
         	}
         
         
        -	static function gd_is_bundled() {
        +	public static function gd_is_bundled() {
         		static $isbundled = null;
        -		if (is_null($isbundled)) {
        +		if (null === $isbundled) {
         			$gd_info = gd_info();
         			$isbundled = (strpos($gd_info['GD Version'], 'bundled') !== false);
         		}
        @@ -509,7 +519,7 @@ static function gd_is_bundled() {
         	}
         
         
        -	static function gd_version($fullstring=false) {
        +	public static function gd_version($fullstring=false) {
         		static $cache_gd_version = array();
         		if (empty($cache_gd_version)) {
         			$gd_info = gd_info();
        @@ -521,22 +531,22 @@ static function gd_version($fullstring=false) {
         				$cache_gd_version[0] = (float) substr($gd_info['GD Version'], 0, 3); // e.g. "1.6" (not "1.6.2 or higher")
         			}
         		}
        -		return $cache_gd_version[intval($fullstring)];
        +		return $cache_gd_version[ (int) $fullstring ];
         	}
         
         
        -	static function filesize_remote($remotefile, $timeout=10) {
        +	public static function filesize_remote($remotefile, $timeout=10) {
         		$size = false;
        -		$url = phpthumb_functions::ParseURLbetter($remotefile);
        -		if ($fp = @fsockopen($url['host'], ($url['port'] ? $url['port'] : 80), $errno, $errstr, $timeout)) {
        -			fwrite($fp, 'HEAD '.@$url['path'].@$url['query'].' HTTP/1.0'."\r\n".'Host: '.@$url['host']."\r\n\r\n");
        -			if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.0', '>=')) {
        +		$parsed_url = self::ParseURLbetter($remotefile);
        +		if ($fp = @fsockopen($parsed_url['host'], $parsed_url['port'], $errno, $errstr, $timeout)) {
        +			fwrite($fp, 'HEAD '.$parsed_url['path'].$parsed_url['query'].' HTTP/1.0'."\r\n".'Host: '.$parsed_url['host']."\r\n\r\n");
        +			if (self::version_compare_replacement(PHP_VERSION, '4.3.0', '>=')) {
         				stream_set_timeout($fp, $timeout);
         			}
         			while (!feof($fp)) {
         				$headerline = fgets($fp, 4096);
         				if (preg_match('#^Content-Length: (.*)#i', $headerline, $matches)) {
        -					$size = intval($matches[1]);
        +					$size = (int) $matches[ 1];
         					break;
         				}
         			}
        @@ -546,12 +556,12 @@ static function filesize_remote($remotefile, $timeout=10) {
         	}
         
         
        -	static function filedate_remote($remotefile, $timeout=10) {
        +	public static function filedate_remote($remotefile, $timeout=10) {
         		$date = false;
        -		$url = phpthumb_functions::ParseURLbetter($remotefile);
        -		if ($fp = @fsockopen($url['host'], ($url['port'] ? $url['port'] : 80), $errno, $errstr, $timeout)) {
        -			fwrite($fp, 'HEAD '.@$url['path'].@$url['query'].' HTTP/1.0'."\r\n".'Host: '.@$url['host']."\r\n\r\n");
        -			if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.0', '>=')) {
        +		$parsed_url = self::ParseURLbetter($remotefile);
        +		if ($fp = @fsockopen($parsed_url['host'], $parsed_url['port'], $errno, $errstr, $timeout)) {
        +			fwrite($fp, 'HEAD '.$parsed_url['path'].$parsed_url['query'].' HTTP/1.0'."\r\n".'Host: '.$parsed_url['host']."\r\n\r\n");
        +			if (self::version_compare_replacement(PHP_VERSION, '4.3.0', '>=')) {
         				stream_set_timeout($fp, $timeout);
         			}
         			while (!feof($fp)) {
        @@ -567,7 +577,7 @@ static function filedate_remote($remotefile, $timeout=10) {
         	}
         
         
        -	static function md5_file_safe($filename) {
        +	public static function md5_file_safe($filename) {
         		// md5_file() doesn't exist in PHP < 4.2.0
         		if (function_exists('md5_file')) {
         			return md5_file($filename);
        @@ -585,7 +595,7 @@ static function md5_file_safe($filename) {
         	}
         
         
        -	static function nonempty_min() {
        +	public static function nonempty_min() {
         		$arg_list = func_get_args();
         		$acceptable = array();
         		foreach ($arg_list as $arg) {
        @@ -597,16 +607,16 @@ static function nonempty_min() {
         	}
         
         
        -	static function LittleEndian2String($number, $minbytes=1) {
        +	public static function LittleEndian2String($number, $minbytes=1) {
         		$intstring = '';
         		while ($number > 0) {
        -			$intstring = $intstring.chr($number & 255);
        -			$number >>= 8;
        +			$intstring .= chr($number & 255);
        +			$number    >>= 8;
         		}
         		return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
         	}
         
        -	static function OneOfThese() {
        +	public static function OneOfThese() {
         		// return the first useful (non-empty/non-zero/non-false) value from those passed
         		$arg_list = func_get_args();
         		foreach ($arg_list as $key => $value) {
        @@ -617,7 +627,7 @@ static function OneOfThese() {
         		return false;
         	}
         
        -	static function CaseInsensitiveInArray($needle, $haystack) {
        +	public static function CaseInsensitiveInArray($needle, $haystack) {
         		$needle = strtolower($needle);
         		foreach ($haystack as $key => $value) {
         			if (is_array($value)) {
        @@ -629,31 +639,33 @@ static function CaseInsensitiveInArray($needle, $haystack) {
         		return false;
         	}
         
        -	static function URLreadFsock($host, $file, &$errstr, $successonly=true, $port=80, $timeout=10) {
        -		if (!function_exists('fsockopen') || phpthumb_functions::FunctionIsDisabled('fsockopen')) {
        -			$errstr = 'fsockopen() unavailable';
        +	public static function URLreadFsock($host, $file, &$errstr, $successonly=true, $port=-1, $timeout=10) {
        +		if (!function_exists('fsockopen') || self::FunctionIsDisabled('fsockopen')) {
        +			$errstr = 'URLreadFsock says: function fsockopen() unavailable';
         			return false;
         		}
        -		if ($fp = @fsockopen($host, $port, $errno, $errstr, $timeout)) {
        +		$port = (int) ($port ? $port : -1); // passing anything as the $port parameter (even empty values like null, false, 0, "") will override the default -1. fsockopen uses -1 as the default port value.
        +		//if ($fp = @fsockopen($host, $port, $errno, $errstr, $timeout)) {
        +		if ($fp = @fsockopen((($port == 443) ? 'ssl://' : '').$host, $port, $errno, $errstr, $timeout)) { // https://github.com/JamesHeinrich/phpThumb/issues/39
         			$out  = 'GET '.$file.' HTTP/1.0'."\r\n";
         			$out .= 'Host: '.$host."\r\n";
         			$out .= 'Connection: Close'."\r\n\r\n";
         			fwrite($fp, $out);
         
         			$isHeader = true;
        -			$Data_header = '';
        -			$Data_body   = '';
        +			$data_header = '';
        +			$data_body   = '';
         			$header_newlocation = '';
         			while (!feof($fp)) {
         				$line = fgets($fp, 1024);
         				if ($isHeader) {
        -					$Data_header .= $line;
        +					$data_header .= $line;
         				} else {
        -					$Data_body .= $line;
        +					$data_body .= $line;
         				}
        -				if (preg_match('#^HTTP/[\\.0-9]+ ([0-9]+) (.+)$#i', rtrim($line), $matches)) {
        -					list($dummy, $errno, $errstr) = $matches;
        -					$errno = intval($errno);
        +				if (preg_match('#^HTTP/[\\.\d]+ ([\d]+) (.+)$#i', rtrim($line), $matches)) {
        +					list( , $errno, $errstr) = $matches;
        +					$errno = (int) $errno;
         				} elseif (preg_match('#^Location: (.*)$#i', rtrim($line), $matches)) {
         					$header_newlocation = $matches[1];
         				}
        @@ -675,17 +687,17 @@ static function URLreadFsock($host, $file, &$errstr, $successonly=true, $port=80
         				}
         			}
         			fclose($fp);
        -			return $Data_body;
        +			return $data_body;
         		}
         		return null;
         	}
         
        -	static function CleanUpURLencoding($url, $queryseperator='&') {
        -		if (!preg_match('#^http#i', $url)) {
        +	public static function CleanUpURLencoding($url, $queryseperator='&') {
        +		if (!0 === stripos($url, "http") ) {
         			return $url;
         		}
        -		$parse_url = phpthumb_functions::ParseURLbetter($url);
        -		$pathelements = explode('/', $parse_url['path']);
        +		$parsed_url = self::ParseURLbetter($url);
        +		$pathelements = explode('/', $parsed_url['path']);
         		$CleanPathElements = array();
         		$TranslationMatrix = array(' '=>'%20');
         		foreach ($pathelements as $key => $pathelement) {
        @@ -697,7 +709,7 @@ static function CleanUpURLencoding($url, $queryseperator='&') {
         			}
         		}
         
        -		$queries = explode($queryseperator, (isset($parse_url['query']) ? $parse_url['query'] : ''));
        +		$queries = explode($queryseperator, $parsed_url['query']);
         		$CleanQueries = array();
         		foreach ($queries as $key => $query) {
         			@list($param, $value) = explode('=', $query);
        @@ -709,43 +721,47 @@ static function CleanUpURLencoding($url, $queryseperator='&') {
         			}
         		}
         
        -		$cleaned_url  = $parse_url['scheme'].'://';
        -		$cleaned_url .= (@$parse_url['username'] ? $parse_url['host'].(@$parse_url['password'] ? ':'.$parse_url['password'] : '').'@' : '');
        -		$cleaned_url .= $parse_url['host'];
        -		$cleaned_url .= ((!empty($parse_url['port']) && ($parse_url['port'] != 80)) ? ':'.$parse_url['port'] : '');
        +		$cleaned_url  = $parsed_url['scheme'].'://';
        +		$cleaned_url .= ($parsed_url['username'] ? $parsed_url['username'].($parsed_url['password'] ? ':'.$parsed_url['password'] : '').'@' : '');
        +		$cleaned_url .= $parsed_url['host'];
        +		$cleaned_url .= (($parsed_url['port'] && ($parsed_url['port'] != self::URLschemeDefaultPort($parsed_url['scheme']))) ? ':'.$parsed_url['port'] : '');
         		$cleaned_url .= '/'.implode('/', $CleanPathElements);
        -		$cleaned_url .= (@$CleanQueries ? '?'.implode($queryseperator, $CleanQueries) : '');
        +		$cleaned_url .= (!empty($CleanQueries) ? '?'.implode($queryseperator, $CleanQueries) : '');
         		return $cleaned_url;
         	}
         
        -	static function ParseURLbetter($url) {
        +	public static function URLschemeDefaultPort($scheme) {
        +		static $schemePort = array(
        +			'ftp'   => 21,
        +			'http'  => 80,
        +			'https' => 443,
        +		);
        +		return (isset($schemePort[strtolower($scheme)]) ? $schemePort[strtolower($scheme)] : null);
        +	}
        +
        +	public static function ParseURLbetter($url) {
         		$parsedURL = @parse_url($url);
        -		if (!@$parsedURL['port']) {
        -			switch (strtolower(@$parsedURL['scheme'])) {
        -				case 'ftp':
        -					$parsedURL['port'] = 21;
        -					break;
        -				case 'https':
        -					$parsedURL['port'] = 443;
        -					break;
        -				case 'http':
        -					$parsedURL['port'] = 80;
        -					break;
        +		foreach (array('scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment') as $key) { // ensure all possible array keys are always returned
        +			if (!array_key_exists($key, $parsedURL)) {
        +				$parsedURL[$key] = null;
         			}
         		}
        +		$parsedURL['port'] = ($parsedURL['port'] ? $parsedURL['port'] : self::URLschemeDefaultPort($parsedURL['scheme']));
         		return $parsedURL;
         	}
         
        -	static function SafeURLread($url, &$error, $timeout=10, $followredirects=true) {
        -		$error = '';
        +	public static function SafeURLread($url, &$error, $timeout=10, $followredirects=true) {
        +		$error   = '';
        +		$errstr  = '';
        +		$rawData = '';
         
        -		$parsed_url = phpthumb_functions::ParseURLbetter($url);
        +		$parsed_url = self::ParseURLbetter($url);
         		$alreadyLookedAtURLs[trim($url)] = true;
         
         		while (true) {
         			$tryagain = false;
        -			$rawData = phpthumb_functions::URLreadFsock(@$parsed_url['host'], @$parsed_url['path'].'?'.@$parsed_url['query'], $errstr, true, (@$parsed_url['port'] ? @$parsed_url['port'] : 80), $timeout);
        -			if (preg_match('#302 [a-z ]+; Location\\: (http.*)#i', $errstr, $matches)) {
        +			$rawData = self::URLreadFsock($parsed_url['host'], $parsed_url['path'].'?'.$parsed_url['query'], $errstr, true, $parsed_url['port'], $timeout);
        +			if ($followredirects && preg_match('#302 [a-z ]+; Location\\: (http.*)#i', $errstr, $matches)) {
         				$matches[1] = trim(@$matches[1]);
         				if (!@$alreadyLookedAtURLs[$matches[1]]) {
         					// loop through and examine new URL
        @@ -753,7 +769,7 @@ static function SafeURLread($url, &$error, $timeout=10, $followredirects=true) {
         
         					$tryagain = true;
         					$alreadyLookedAtURLs[$matches[1]] = true;
        -					$parsed_url = phpthumb_functions::ParseURLbetter($matches[1]);
        +					$parsed_url = self::ParseURLbetter($matches[ 1]);
         				}
         			}
         			if (!$tryagain) {
        @@ -771,12 +787,15 @@ static function SafeURLread($url, &$error, $timeout=10, $followredirects=true) {
         			return $rawData;
         		}
         
        -		if (function_exists('curl_version') && !phpthumb_functions::FunctionIsDisabled('curl_exec')) {
        +		if (function_exists('curl_version') && !self::FunctionIsDisabled('curl_exec')) {
         			$ch = curl_init();
         			curl_setopt($ch, CURLOPT_URL, $url);
         			curl_setopt($ch, CURLOPT_HEADER, false);
         			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
         			curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
        +			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
        +			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        +			curl_setopt($ch, CURLOPT_FOLLOWLOCATION, (bool) $followredirects);
         			curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
         			$rawData = curl_exec($ch);
         			curl_close($ch);
        @@ -790,8 +809,8 @@ static function SafeURLread($url, &$error, $timeout=10, $followredirects=true) {
         		}
         
         		$BrokenURLfopenPHPversions = array('4.4.2');
        -		if (in_array(phpversion(), $BrokenURLfopenPHPversions)) {
        -			$error .= 'fopen(URL) broken in PHP v'.phpversion().'; ';
        +		if (in_array(PHP_VERSION, $BrokenURLfopenPHPversions)) {
        +			$error .= 'fopen(URL) broken in PHP v'. PHP_VERSION .'; ';
         		} elseif (@ini_get('allow_url_fopen')) {
         			$rawData = '';
         			$error_fopen = '';
        @@ -819,13 +838,13 @@ static function SafeURLread($url, &$error, $timeout=10, $followredirects=true) {
         		return false;
         	}
         
        -	static function EnsureDirectoryExists($dirname) {
        +	public static function EnsureDirectoryExists($dirname, $mask = 0755) {
         		$directory_elements = explode(DIRECTORY_SEPARATOR, $dirname);
         		$startoffset = (!$directory_elements[0] ? 2 : 1);  // unix with leading "/" then start with 2nd element; Windows with leading "c:\" then start with 1st element
         		$open_basedirs = preg_split('#[;:]#', ini_get('open_basedir'));
         		foreach ($open_basedirs as $key => $open_basedir) {
         			if (preg_match('#^'.preg_quote($open_basedir).'#', $dirname) && (strlen($dirname) > strlen($open_basedir))) {
        -				$startoffset = count(explode(DIRECTORY_SEPARATOR, $open_basedir));
        +				$startoffset = substr_count($open_basedir, DIRECTORY_SEPARATOR) + 1;
         				break;
         			}
         		}
        @@ -841,9 +860,9 @@ static function EnsureDirectoryExists($dirname) {
         					// directory name already exists as a file
         					return false;
         				}
        -				@mkdir($test_directory, 0755);
        -				@chmod($test_directory, 0755);
        -				if (!@is_dir($test_directory) || !@is_writeable($test_directory)) {
        +				@mkdir($test_directory, $mask);
        +				@chmod($test_directory, $mask);
        +				if (!@is_dir($test_directory) || !@is_writable($test_directory)) {
         					return false;
         				}
         			}
        @@ -852,7 +871,7 @@ static function EnsureDirectoryExists($dirname) {
         	}
         
         
        -	static function GetAllFilesInSubfolders($dirname) {
        +	public static function GetAllFilesInSubfolders($dirname) {
         		$AllFiles = array();
         		$dirname = rtrim(realpath($dirname), '/\\');
         		if ($dirhandle = @opendir($dirname)) {
        @@ -868,7 +887,7 @@ static function GetAllFilesInSubfolders($dirname) {
         
         						default:
         							$AllFiles[] = $fullfilename;
        -							$subfiles = phpthumb_functions::GetAllFilesInSubfolders($fullfilename);
        +							$subfiles = self::GetAllFilesInSubfolders($fullfilename);
         							foreach ($subfiles as $filename) {
         								$AllFiles[] = $filename;
         							}
        @@ -885,14 +904,23 @@ static function GetAllFilesInSubfolders($dirname) {
         	}
         
         
        -	static function SanitizeFilename($filename) {
        +	public static function SanitizeFilename($filename) {
         		$filename = preg_replace('/[^'.preg_quote(' !#$%^()+,-.;<>=@[]_{}').'a-zA-Z0-9]/', '_', $filename);
        -		if (phpthumb_functions::version_compare_replacement(phpversion(), '4.1.0', '>=')) {
        +		if (self::version_compare_replacement(PHP_VERSION, '4.1.0', '>=')) {
         			$filename = trim($filename, '.');
         		}
         		return $filename;
         	}
         
        +	public static function PasswordStrength($password) {
        +		$strength = 0;
        +		$strength += strlen(preg_replace('#[^a-z]#',       '', $password)) * 0.5; // lowercase characters are weak
        +		$strength += strlen(preg_replace('#[^A-Z]#',       '', $password)) * 0.8; // uppercase characters are somewhat better
        +		$strength += strlen(preg_replace('#[^0-9]#',       '', $password)) * 1.0; // numbers are somewhat better
        +		$strength += strlen(preg_replace('#[a-zA-Z0-9]#',  '', $password)) * 2.0; // other non-alphanumeric characters are best
        +		return $strength;
        +	}
        +
         }
         
         
        @@ -931,8 +959,8 @@ function gd_info() {
         			}
         			if (empty($gd_info['GD Version'])) {
         				// probable cause: "phpinfo() disabled for security reasons"
        -				if (function_exists('ImageTypes')) {
        -					$imagetypes = ImageTypes();
        +				if (function_exists('imagetypes')) {
        +					$imagetypes = imagetypes();
         					if ($imagetypes & IMG_PNG) {
         						$gd_info['PNG Support'] = true;
         					}
        @@ -946,22 +974,23 @@ function gd_info() {
         						$gd_info['WBMP Support'] = true;
         					}
         				}
        -				// to determine capability of GIF creation, try to use ImageCreateFromGIF on a 1px GIF
        -				if (function_exists('ImageCreateFromGIF')) {
        +				// to determine capability of GIF creation, try to use imagecreatefromgif on a 1px GIF
        +				if (function_exists('imagecreatefromgif')) {
         					if ($tempfilename = phpthumb::phpThumb_tempnam()) {
         						if ($fp_tempfile = @fopen($tempfilename, 'wb')) {
         							fwrite($fp_tempfile, base64_decode('R0lGODlhAQABAIAAAH//AP///ywAAAAAAQABAAACAUQAOw==')); // very simple 1px GIF file base64-encoded as string
         							fclose($fp_tempfile);
        +							@chmod($tempfilename, $this->getParameter('config_file_create_mask'));
         
         							// if we can convert the GIF file to a GD image then GIF create support must be enabled, otherwise it's not
        -							$gd_info['GIF Read Support'] = (bool) @ImageCreateFromGIF($tempfilename);
        +							$gd_info['GIF Read Support'] = (bool) @imagecreatefromgif($tempfilename);
         						}
         						unlink($tempfilename);
         					}
         				}
        -				if (function_exists('ImageCreateTrueColor') && @ImageCreateTrueColor(1, 1)) {
        +				if (function_exists('imagecreatetruecolor') && @imagecreatetruecolor(1, 1)) {
         					$gd_info['GD Version'] = '2.0.1 or higher (assumed)';
        -				} elseif (function_exists('ImageCreate') && @ImageCreate(1, 1)) {
        +				} elseif (function_exists('imagecreate') && @imagecreate(1, 1)) {
         					$gd_info['GD Version'] = '1.6.0 or higher (assumed)';
         				}
         			}
        @@ -986,7 +1015,7 @@ function preg_quote($string, $delimiter='\\') {
         		static $preg_quote_array = array();
         		if (empty($preg_quote_array)) {
         			$escapeables = '.\\+*?[^]$(){}=!<>|:';
        -			for ($i = 0; $i < strlen($escapeables); $i++) {
        +			for ($i = 0, $iMax = strlen($escapeables); $i < $iMax; $i++) {
         				$strtr_preg_quote[$escapeables{$i}] = $delimiter.$escapeables{$i};
         			}
         		}
        @@ -1043,5 +1072,3 @@ function imagesavealpha(&$img, $blendmode=true) {
         		return true;
         	}
         }
        -
        -?>
        \ No newline at end of file
        diff --git a/assets/snippets/phpthumb/phpthumb.gif.php b/assets/snippets/phpthumb/phpthumb.gif.php
        index 7ed33880c7..f82d0365fd 100755
        --- a/assets/snippets/phpthumb/phpthumb.gif.php
        +++ b/assets/snippets/phpthumb/phpthumb.gif.php
        @@ -43,14 +43,14 @@ function gif_loadFileToGDimageResource($gifFilename, $bgColor = -1)
         		}
         		// general strategy: convert raw data to PNG then convert PNG data to GD image resource
         		$PNGdata = $gif->getPng($bgColor);
        -		if ($img = @ImageCreateFromString($PNGdata)) {
        +		if ($img = @imagecreatefromstring($PNGdata)) {
         
         			// excellent - PNG image data successfully converted to GD image
         			return $img;
         
         		} elseif ($img = $gif->getGD_PixelPlotterVersion()) {
         
        -			// problem: ImageCreateFromString() didn't like the PNG image data.
        +			// problem: imagecreatefromstring() didn't like the PNG image data.
         			//   This has been known to happen in PHP v4.0.6
         			// solution: take the raw image data and create a new GD image and plot
         			//   pixel-by-pixel on the GD image. This is extremely slow, but it does
        @@ -66,7 +66,7 @@ function gif_loadFileToGDimageResource($gifFilename, $bgColor = -1)
         
         function gif_outputAsBmp($gif, $lpszFileName, $bgColor = -1)
         {
        -	if (!isSet($gif) || (@get_class($gif) <> 'cgif') || !$gif->loaded() || ($lpszFileName == '')) {
        +	if (!isset($gif) || (@get_class($gif) <> 'cgif') || !$gif->loaded() || ($lpszFileName == '')) {
         		return false;
         	}
         
        @@ -111,26 +111,26 @@ function gif_outputAsPng($gif, $lpszFileName, $bgColor = -1)
         function gif_outputAsJpeg($gif, $lpszFileName, $bgColor = -1)
         {
         	// JPEG output that does not require cjpeg added by James Heinrich  - December 10, 2003
        -	if ((strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') && (file_exists('/usr/local/bin/cjpeg') || `which cjpeg`)) {
        +	if ((strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') && (file_exists('/usr/local/bin/cjpeg') || shell_exec('which cjpeg'))) {
         
         		if (gif_outputAsBmp($gif, $lpszFileName.'.bmp', $bgColor)) {
         			exec('cjpeg '.$lpszFileName.'.bmp >'.$lpszFileName.' 2>/dev/null');
        -			@unLink($lpszFileName.'.bmp');
        +			@unlink($lpszFileName.'.bmp');
         
         			if (@file_exists($lpszFileName)) {
        -				if (@fileSize($lpszFileName) > 0) {
        +				if (@filesize($lpszFileName) > 0) {
         					return true;
         				}
         
        -				@unLink($lpszFileName);
        +				@unlink($lpszFileName);
         			}
         		}
         
         	} else {
         
         		// either Windows, or cjpeg not found in path
        -		if ($img = @ImageCreateFromString($gif->getPng($bgColor))) {
        -			if (@ImageJPEG($img, $lpszFileName)) {
        +		if ($img = @imagecreatefromstring($gif->getPng($bgColor))) {
        +			if (@imagejpeg($img, $lpszFileName)) {
         				return true;
         			}
         		}
        @@ -163,14 +163,14 @@ function gif_getSize($gif, &$width, &$height)
         
         class CGIFLZW
         {
        -	var $MAX_LZW_BITS;
        -	var $Fresh, $CodeSize, $SetCodeSize, $MaxCode, $MaxCodeSize, $FirstCode, $OldCode;
        -	var $ClearCode, $EndCode, $Next, $Vals, $Stack, $sp, $Buf, $CurBit, $LastBit, $Done, $LastByte;
        +	public $MAX_LZW_BITS;
        +	public $Fresh, $CodeSize, $SetCodeSize, $MaxCode, $MaxCodeSize, $FirstCode, $OldCode;
        +	public $ClearCode, $EndCode, $Next, $Vals, $Stack, $sp, $Buf, $CurBit, $LastBit, $Done, $LastByte;
         
         	///////////////////////////////////////////////////////////////////////////
         
         	// CONSTRUCTOR
        -	function __construct()
        +	public function __construct()
         	{
         		$this->MAX_LZW_BITS = 12;
         		unSet($this->Next);
        @@ -186,7 +186,7 @@ function __construct()
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function deCompress($data, &$datLen)
        +	public function deCompress($data, &$datLen)
         	{
         		$stLen  = strlen($data);
         		$datLen = 0;
        @@ -210,7 +210,7 @@ function deCompress($data, &$datLen)
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function LZWCommand(&$data, $bInit)
        +	public function LZWCommand(&$data, $bInit)
         	{
         		if ($bInit) {
         			$this->SetCodeSize = ord($data{0});
        @@ -325,7 +325,7 @@ function LZWCommand(&$data, $bInit)
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function GetCode(&$data, $bInit)
        +	public function GetCode(&$data, $bInit)
         	{
         		if ($bInit) {
         			$this->CurBit   = 0;
        @@ -366,7 +366,7 @@ function GetCode(&$data, $bInit)
         
         		$iRet = 0;
         		for ($i = $this->CurBit, $j = 0; $j < $this->CodeSize; $i++, $j++) {
        -			$iRet |= (($this->Buf[intval($i / 8)] & (1 << ($i % 8))) != 0) << $j;
        +			$iRet |= (($this->Buf[ (int) ($i / 8) ] & (1 << ($i % 8))) != 0) << $j;
         		}
         
         		$this->CurBit += $this->CodeSize;
        @@ -378,13 +378,13 @@ function GetCode(&$data, $bInit)
         
         class CGIFCOLORTABLE
         {
        -	var $m_nColors;
        -	var $m_arColors;
        +	public $m_nColors;
        +	public $m_arColors;
         
         	///////////////////////////////////////////////////////////////////////////
         
         	// CONSTRUCTOR
        -	function __construct()
        +	public function __construct()
         	{
         		unSet($this->m_nColors);
         		unSet($this->m_arColors);
        @@ -392,7 +392,7 @@ function __construct()
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function load($lpData, $num)
        +	public function load($lpData, $num)
         	{
         		$this->m_nColors  = 0;
         		$this->m_arColors = array();
        @@ -412,13 +412,13 @@ function load($lpData, $num)
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function toString()
        +	public function toString()
         	{
         		$ret = '';
         
         		for ($i = 0; $i < $this->m_nColors; $i++) {
         			$ret .=
        -				chr(($this->m_arColors[$i] & 0x000000FF))       . // R
        +				chr($this->m_arColors[ $i] & 0x000000FF)       . // R
         				chr(($this->m_arColors[$i] & 0x0000FF00) >>  8) . // G
         				chr(($this->m_arColors[$i] & 0x00FF0000) >> 16);  // B
         		}
        @@ -428,7 +428,7 @@ function toString()
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function toRGBQuad()
        +	public function toRGBQuad()
         	{
         		$ret = '';
         
        @@ -436,7 +436,7 @@ function toRGBQuad()
         			$ret .=
         				chr(($this->m_arColors[$i] & 0x00FF0000) >> 16) . // B
         				chr(($this->m_arColors[$i] & 0x0000FF00) >>  8) . // G
        -				chr(($this->m_arColors[$i] & 0x000000FF))       . // R
        +				chr($this->m_arColors[ $i] & 0x000000FF)       . // R
         				"\x00";
         		}
         
        @@ -445,13 +445,14 @@ function toRGBQuad()
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function colorIndex($rgb)
        +	public function colorIndex($rgb)
         	{
        -		$rgb  = intval($rgb) & 0xFFFFFF;
        -		$r1   = ($rgb & 0x0000FF);
        -		$g1   = ($rgb & 0x00FF00) >>  8;
        -		$b1   = ($rgb & 0xFF0000) >> 16;
        -		$idx  = -1;
        +		$rgb = (int) $rgb & 0xFFFFFF;
        +		$r1  = ($rgb & 0x0000FF);
        +		$g1  = ($rgb & 0x00FF00) >>  8;
        +		$b1  = ($rgb & 0xFF0000) >> 16;
        +		$idx = -1;
        +		$dif = 0;
         
         		for ($i = 0; $i < $this->m_nColors; $i++) {
         			$r2 = ($this->m_arColors[$i] & 0x000000FF);
        @@ -473,21 +474,21 @@ function colorIndex($rgb)
         
         class CGIFFILEHEADER
         {
        -	var $m_lpVer;
        -	var $m_nWidth;
        -	var $m_nHeight;
        -	var $m_bGlobalClr;
        -	var $m_nColorRes;
        -	var $m_bSorted;
        -	var $m_nTableSize;
        -	var $m_nBgColor;
        -	var $m_nPixelRatio;
        -	var $m_colorTable;
        +	public $m_lpVer;
        +	public $m_nWidth;
        +	public $m_nHeight;
        +	public $m_bGlobalClr;
        +	public $m_nColorRes;
        +	public $m_bSorted;
        +	public $m_nTableSize;
        +	public $m_nBgColor;
        +	public $m_nPixelRatio;
        +	public $m_colorTable;
         
         	///////////////////////////////////////////////////////////////////////////
         
         	// CONSTRUCTOR
        -	function __construct()
        +	public function __construct()
         	{
         		unSet($this->m_lpVer);
         		unSet($this->m_nWidth);
        @@ -503,7 +504,7 @@ function __construct()
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function load($lpData, &$hdrLen)
        +	public function load($lpData, &$hdrLen)
         	{
         		$hdrLen = 0;
         
        @@ -518,13 +519,13 @@ function load($lpData, &$hdrLen)
         			return false;
         		}
         
        -		$b = ord(substr($lpData, 10, 1));
        +		$b = ord($lpData[ 10 ]);
         		$this->m_bGlobalClr  = ($b & 0x80) ? true : false;
         		$this->m_nColorRes   = ($b & 0x70) >> 4;
         		$this->m_bSorted     = ($b & 0x08) ? true : false;
         		$this->m_nTableSize  = 2 << ($b & 0x07);
        -		$this->m_nBgColor    = ord(substr($lpData, 11, 1));
        -		$this->m_nPixelRatio = ord(substr($lpData, 12, 1));
        +		$this->m_nBgColor    = ord($lpData[ 11 ]);
        +		$this->m_nPixelRatio = ord($lpData[ 12 ]);
         		$hdrLen = 13;
         
         		if ($this->m_bGlobalClr) {
        @@ -540,9 +541,9 @@ function load($lpData, &$hdrLen)
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function w2i($str)
        +	public function w2i($str)
         	{
        -		return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
        +		return ord($str[ 0 ]) + (ord($str[ 1 ]) << 8);
         	}
         }
         
        @@ -550,20 +551,20 @@ function w2i($str)
         
         class CGIFIMAGEHEADER
         {
        -	var $m_nLeft;
        -	var $m_nTop;
        -	var $m_nWidth;
        -	var $m_nHeight;
        -	var $m_bLocalClr;
        -	var $m_bInterlace;
        -	var $m_bSorted;
        -	var $m_nTableSize;
        -	var $m_colorTable;
        +	public $m_nLeft;
        +	public $m_nTop;
        +	public $m_nWidth;
        +	public $m_nHeight;
        +	public $m_bLocalClr;
        +	public $m_bInterlace;
        +	public $m_bSorted;
        +	public $m_nTableSize;
        +	public $m_colorTable;
         
         	///////////////////////////////////////////////////////////////////////////
         
         	// CONSTRUCTOR
        -	function __construct()
        +	public function __construct()
         	{
         		unSet($this->m_nLeft);
         		unSet($this->m_nTop);
        @@ -578,7 +579,7 @@ function __construct()
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function load($lpData, &$hdrLen)
        +	public function load($lpData, &$hdrLen)
         	{
         		$hdrLen = 0;
         
        @@ -611,9 +612,9 @@ function load($lpData, &$hdrLen)
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function w2i($str)
        +	public function w2i($str)
         	{
        -		return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
        +		return ord($str[ 0 ]) + (ord($str[ 1 ]) << 8);
         	}
         }
         
        @@ -621,19 +622,19 @@ function w2i($str)
         
         class CGIFIMAGE
         {
        -	var $m_disp;
        -	var $m_bUser;
        -	var $m_bTrans;
        -	var $m_nDelay;
        -	var $m_nTrans;
        -	var $m_lpComm;
        -	var $m_gih;
        -	var $m_data;
        -	var $m_lzw;
        +	public $m_disp;
        +	public $m_bUser;
        +	public $m_bTrans;
        +	public $m_nDelay;
        +	public $m_nTrans;
        +	public $m_lpComm;
        +	public $m_gih;
        +	public $m_data;
        +	public $m_lzw;
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function __construct()
        +	public function __construct()
         	{
         		unSet($this->m_disp);
         		unSet($this->m_bUser);
        @@ -648,7 +649,7 @@ function __construct()
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function load($data, &$datLen)
        +	public function load($data, &$datLen)
         	{
         		$datLen = 0;
         
        @@ -695,7 +696,7 @@ function load($data, &$datLen)
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function skipExt(&$data, &$extLen)
        +	public function skipExt(&$data, &$extLen)
         	{
         		$extLen = 0;
         
        @@ -740,16 +741,18 @@ function skipExt(&$data, &$extLen)
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function w2i($str)
        +	public function w2i($str)
         	{
        -		return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
        +		return ord($str[ 0 ]) + (ord($str[ 1 ]) << 8);
         	}
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function deInterlace()
        +	public function deInterlace()
         	{
         		$data = $this->m_data;
        +		$s = 0;
        +		$y = 0;
         
         		for ($i = 0; $i < 4; $i++) {
         			switch($i) {
        @@ -793,15 +796,15 @@ function deInterlace()
         
         class CGIF
         {
        -	var $m_gfh;
        -	var $m_lpData;
        -	var $m_img;
        -	var $m_bLoaded;
        +	public $m_gfh;
        +	public $m_lpData;
        +	public $m_img;
        +	public $m_bLoaded;
         
         	///////////////////////////////////////////////////////////////////////////
         
         	// CONSTRUCTOR
        -	function __construct()
        +	public function __construct()
         	{
         		$this->m_gfh     = new CGIFFILEHEADER();
         		$this->m_img     = new CGIFIMAGE();
        @@ -811,7 +814,7 @@ function __construct()
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function loadFile($lpszFileName, $iIndex)
        +	public function loadFile($lpszFileName, $iIndex)
         	{
         		if ($iIndex < 0) {
         			return false;
        @@ -821,7 +824,7 @@ function loadFile($lpszFileName, $iIndex)
         		if (!($fh = @fopen($lpszFileName, 'rb'))) {
         			return false;
         		}
        -		$this->m_lpData = @fRead($fh, @fileSize($lpszFileName));
        +		$this->m_lpData = @fread($fh, @filesize($lpszFileName));
         		fclose($fh);
         
         		// GET FILE HEADER
        @@ -844,12 +847,12 @@ function loadFile($lpszFileName, $iIndex)
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function getSize($lpszFileName, &$width, &$height)
        +	public function getSize($lpszFileName, &$width, &$height)
         	{
         		if (!($fh = @fopen($lpszFileName, 'rb'))) {
         			return false;
         		}
        -		$data = @fRead($fh, @fileSize($lpszFileName));
        +		$data = @fread($fh, @filesize($lpszFileName));
         		@fclose($fh);
         
         		$gfh = new CGIFFILEHEADER();
        @@ -864,7 +867,7 @@ function getSize($lpszFileName, &$width, &$height)
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function getBmp($bgColor)
        +	public function getBmp($bgColor)
         	{
         		$out = '';
         
        @@ -887,6 +890,7 @@ function getBmp($bgColor)
         			}
         		} else {
         			$nColors =  0;
        +			$rgbq    = '';
         			$bgColor = -1;
         		}
         
        @@ -963,7 +967,7 @@ function getBmp($bgColor)
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function getPng($bgColor)
        +	public function getPng($bgColor)
         	{
         		$out = '';
         
        @@ -986,6 +990,7 @@ function getPng($bgColor)
         			}
         		} else {
         			$nColors =  0;
        +			$pal     = '';
         			$bgColor = -1;
         		}
         
        @@ -1066,8 +1071,8 @@ function getPng($bgColor)
         	// Added by James Heinrich  - January 5, 2003
         
         	// Takes raw image data and plots it pixel-by-pixel on a new GD image and returns that
        -	// It's extremely slow, but the only solution when ImageCreateFromString() fails
        -	function getGD_PixelPlotterVersion()
        +	// It's extremely slow, but the only solution when imagecreatefromstring() fails
        +	public function getGD_PixelPlotterVersion()
         	{
         		if (!$this->m_bLoaded) {
         			return false;
        @@ -1082,14 +1087,15 @@ function getGD_PixelPlotterVersion()
         			die('No color table available in getGD_PixelPlotterVersion()');
         		}
         
        -		$PlottingIMG = ImageCreate($this->m_gfh->m_nWidth, $this->m_gfh->m_nHeight);
        +		$PlottingIMG = imagecreate($this->m_gfh->m_nWidth, $this->m_gfh->m_nHeight);
         		$NumColorsInPal = floor(strlen($pal) / 3);
        +		$ThisImageColor = array();
         		for ($i = 0; $i < $NumColorsInPal; $i++) {
        -			$ThisImageColor[$i] = ImageColorAllocate(
        +			$ThisImageColor[$i] = imagecolorallocate(
         									$PlottingIMG,
        -									ord($pal{(($i * 3) + 0)}),
        -									ord($pal{(($i * 3) + 1)}),
        -									ord($pal{(($i * 3) + 2)}));
        +									ord($pal{($i * 3) + 0}),
        +									ord($pal{($i * 3) + 1}),
        +									ord($pal{($i * 3) + 2}));
         		}
         
         		// PREPARE BITMAP BITS
        @@ -1107,13 +1113,13 @@ function getGD_PixelPlotterVersion()
         					($y <  ($this->m_img->m_gih->m_nTop  + $this->m_img->m_gih->m_nHeight))) {
         					// PART OF IMAGE
         					if (@$this->m_img->m_bTrans && (ord($data{$nPxl}) == $this->m_img->m_nTrans)) {
        -						ImageSetPixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[$this->m_gfh->m_nBgColor]);
        +						imagesetpixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[$this->m_gfh->m_nBgColor]);
         					} else {
        -						ImageSetPixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[ord($data{$nPxl})]);
        +						imagesetpixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[ord($data{$nPxl})]);
         					}
         				} else {
         					// BACKGROUND
        -					ImageSetPixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[$this->m_gfh->m_nBgColor]);
        +					imagesetpixel($PlottingIMG, $x, $this->m_gfh->m_nHeight - $y - 1, $ThisImageColor[$this->m_gfh->m_nBgColor]);
         				}
         			}
         			$nPxl -= $this->m_gfh->m_nWidth << 1;
        @@ -1125,49 +1131,45 @@ function getGD_PixelPlotterVersion()
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function dword($val)
        +	public function dword($val)
         	{
        -		$val = intval($val);
        +		$val = (int) $val;
         		return chr($val & 0xFF).chr(($val & 0xFF00) >> 8).chr(($val & 0xFF0000) >> 16).chr(($val & 0xFF000000) >> 24);
         	}
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function ndword($val)
        +	public function ndword($val)
         	{
        -		$val = intval($val);
        +		$val = (int) $val;
         		return chr(($val & 0xFF000000) >> 24).chr(($val & 0xFF0000) >> 16).chr(($val & 0xFF00) >> 8).chr($val & 0xFF);
         	}
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function width()
        +	public function width()
         	{
         		return $this->m_gfh->m_nWidth;
         	}
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function height()
        +	public function height()
         	{
         		return $this->m_gfh->m_nHeight;
         	}
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function comment()
        +	public function comment()
         	{
         		return $this->m_img->m_lpComm;
         	}
         
         	///////////////////////////////////////////////////////////////////////////
         
        -	function loaded()
        +	public function loaded()
         	{
         		return $this->m_bLoaded;
         	}
         }
        -
        -///////////////////////////////////////////////////////////////////////////////////////////////////
        -
        -?>
        \ No newline at end of file
        diff --git a/assets/snippets/phpthumb/phpthumb.ico.php b/assets/snippets/phpthumb/phpthumb.ico.php
        index 0daff8ab24..9c9061346e 100755
        --- a/assets/snippets/phpthumb/phpthumb.ico.php
        +++ b/assets/snippets/phpthumb/phpthumb.ico.php
        @@ -12,18 +12,20 @@
         
         class phpthumb_ico {
         
        -	function __construct() {
        -		return true;
        -	}
        -
        -
        -	function GD2ICOstring(&$gd_image_array) {
        +	public function GD2ICOstring(&$gd_image_array) {
        +		$ImageWidths  = array();
        +		$ImageHeights = array();
        +		$bpp          = array();
        +		$totalcolors  = array();
        +		$icXOR        = array();
        +		$icAND        = array();
        +		$icANDmask    = array();
         		foreach ($gd_image_array as $key => $gd_image) {
         
        -			$ImageWidths[$key]  = ImageSX($gd_image);
        -			$ImageHeights[$key] = ImageSY($gd_image);
        -	    	$bpp[$key]          = ImageIsTrueColor($gd_image) ? 32 : 24;
        -	    	$totalcolors[$key]  = ImageColorsTotal($gd_image);
        +			$ImageWidths[$key]  = imagesx($gd_image);
        +			$ImageHeights[$key] = imagesy($gd_image);
        +			$bpp[$key]          = imageistruecolor($gd_image) ? 32 : 24;
        +			$totalcolors[$key]  = imagecolorstotal($gd_image);
         
         			$icXOR[$key] = '';
         			for ($y = $ImageHeights[$key] - 1; $y >= 0; $y--) {
        @@ -53,31 +55,31 @@ function GD2ICOstring(&$gd_image_array) {
         			}
         			$icAND[$key] = '';
         			foreach ($icANDmask[$key] as $y => $scanlinemaskbits) {
        -				for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) {
        +				for ($i = 0, $iMax = strlen($scanlinemaskbits); $i < $iMax; $i += 8) {
         					$icAND[$key] .= chr(bindec(str_pad(substr($scanlinemaskbits, $i, 8), 8, '0', STR_PAD_LEFT)));
         				}
         			}
         
         		}
         
        -	    foreach ($gd_image_array as $key => $gd_image) {
        +		foreach ($gd_image_array as $key => $gd_image) {
         			$biSizeImage = $ImageWidths[$key] * $ImageHeights[$key] * ($bpp[$key] / 8);
         
        -	    	// BITMAPINFOHEADER - 40 bytes
        +			// BITMAPINFOHEADER - 40 bytes
         			$BitmapInfoHeader[$key]  = '';
         			$BitmapInfoHeader[$key] .= "\x28\x00\x00\x00";                              // DWORD  biSize;
         			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageWidths[$key], 4);      // LONG   biWidth;
         			// The biHeight member specifies the combined
         			// height of the XOR and AND masks.
         			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageHeights[$key] * 2, 4); // LONG   biHeight;
        -	    	$BitmapInfoHeader[$key] .= "\x01\x00";                                      // WORD   biPlanes;
        -	   		$BitmapInfoHeader[$key] .= chr($bpp[$key])."\x00";                          // wBitCount;
        +			$BitmapInfoHeader[$key] .= "\x01\x00";                                      // WORD   biPlanes;
        +			$BitmapInfoHeader[$key] .= chr($bpp[$key])."\x00";                          // wBitCount;
         			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                              // DWORD  biCompression;
         			$BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($biSizeImage, 4);            // DWORD  biSizeImage;
        -	    	$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                              // LONG   biXPelsPerMeter;
        -	    	$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                              // LONG   biYPelsPerMeter;
        -	    	$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                              // DWORD  biClrUsed;
        -	    	$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                              // DWORD  biClrImportant;
        +			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                              // LONG   biXPelsPerMeter;
        +			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                              // LONG   biYPelsPerMeter;
        +			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                              // DWORD  biClrUsed;
        +			$BitmapInfoHeader[$key] .= "\x00\x00\x00\x00";                              // DWORD  biClrImportant;
         		}
         
         
        @@ -87,34 +89,32 @@ function GD2ICOstring(&$gd_image_array) {
         
         		$dwImageOffset = 6 + (count($gd_image_array) * 16);
         		foreach ($gd_image_array as $key => $gd_image) {
        -	    	// ICONDIRENTRY   idEntries[1]; // An entry for each image (idCount of 'em)
        +			// ICONDIRENTRY   idEntries[1]; // An entry for each image (idCount of 'em)
         
        -	    	$icondata .= chr($ImageWidths[$key]);                     // bWidth;          // Width, in pixels, of the image
        -	    	$icondata .= chr($ImageHeights[$key]);                    // bHeight;         // Height, in pixels, of the image
        -	    	$icondata .= chr($totalcolors[$key]);                     // bColorCount;     // Number of colors in image (0 if >=8bpp)
        -	    	$icondata .= "\x00";                                      // bReserved;       // Reserved ( must be 0)
        +			$icondata .= chr($ImageWidths[$key]);                     // bWidth;          // Width, in pixels, of the image
        +			$icondata .= chr($ImageHeights[$key]);                    // bHeight;         // Height, in pixels, of the image
        +			$icondata .= chr($totalcolors[$key]);                     // bColorCount;     // Number of colors in image (0 if >=8bpp)
        +			$icondata .= "\x00";                                      // bReserved;       // Reserved ( must be 0)
         
        -	    	$icondata .= "\x01\x00";                                  // wPlanes;         // Color Planes
        +			$icondata .= "\x01\x00";                                  // wPlanes;         // Color Planes
         			$icondata .= chr($bpp[$key])."\x00";                      // wBitCount;       // Bits per pixel
         
         			$dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]);
         			$icondata .= phpthumb_functions::LittleEndian2String($dwBytesInRes, 4);       // dwBytesInRes;    // How many bytes in this resource?
         
        -		    $icondata .= phpthumb_functions::LittleEndian2String($dwImageOffset, 4);      // dwImageOffset;   // Where in the file is this image?
        +			$icondata .= phpthumb_functions::LittleEndian2String($dwImageOffset, 4);      // dwImageOffset;   // Where in the file is this image?
         			$dwImageOffset += strlen($BitmapInfoHeader[$key]);
         			$dwImageOffset += strlen($icXOR[$key]);
         			$dwImageOffset += strlen($icAND[$key]);
        -	    }
        +		}
         
        -	    foreach ($gd_image_array as $key => $gd_image) {
        +		foreach ($gd_image_array as $key => $gd_image) {
         			$icondata .= $BitmapInfoHeader[$key];
         			$icondata .= $icXOR[$key];
         			$icondata .= $icAND[$key];
        -	    }
        +		}
         
        -	    return $icondata;
        +		return $icondata;
         	}
         
         }
        -
        -?>
        \ No newline at end of file
        diff --git a/assets/snippets/phpthumb/phpthumb.unsharp.php b/assets/snippets/phpthumb/phpthumb.unsharp.php
        index 8e3505d5e0..a5c454ee1f 100755
        --- a/assets/snippets/phpthumb/phpthumb.unsharp.php
        +++ b/assets/snippets/phpthumb/phpthumb.unsharp.php
        @@ -3,7 +3,7 @@
         ////
         ////            Unsharp Mask for PHP - version 2.1.1
         ////
        -////    Unsharp mask algorithm by Torstein H?nsi 2003-07.
        +////    Unsharp mask algorithm by Torstein Hønsi 2003-07.
         ////             thoensi_at_netcom_dot_no.
         ////               Please leave this notice.
         ////
        @@ -37,13 +37,13 @@
         this means that low-contrast areas of the picture are left unrendered whereas edges
         are treated normally. This is good for pictures of e.g. skin or blue skies.
         
        -Any suggenstions for improvement of the algorithm, expecially regarding the speed
        +Any suggenstions for improvement of the algorithm, especially regarding the speed
         and the roundoff errors in the Gaussian blur process, are welcome.
         */
         
         class phpUnsharpMask {
         
        -	static function applyUnsharpMask(&$img, $amount, $radius, $threshold) {
        +	public static function applyUnsharpMask(&$img, $amount, $radius, $threshold) {
         
         		// $img is an image that is already created within php using
         		// imgcreatetruecolor. No url! $img must be a truecolor image.
        @@ -55,10 +55,10 @@ static function applyUnsharpMask(&$img, $amount, $radius, $threshold) {
         		if ($radius == 0) {
         			return true;
         		}
        -		$w = ImageSX($img);
        -		$h = ImageSY($img);
        -		$imgCanvas = ImageCreateTrueColor($w, $h);
        -		$imgBlur   = ImageCreateTrueColor($w, $h);
        +		$w = imagesx($img);
        +		$h = imagesy($img);
        +		$imgCanvas = imagecreatetruecolor($w, $h);
        +		$imgBlur   = imagecreatetruecolor($w, $h);
         
         		// Gaussian blur matrix:
         		//
        @@ -74,20 +74,20 @@ static function applyUnsharpMask(&$img, $amount, $radius, $threshold) {
         				array(2, 4, 2),
         				array(1, 2, 1)
         			);
        -			ImageCopy($imgBlur, $img, 0, 0, 0, 0, $w, $h);
        -			ImageConvolution($imgBlur, $matrix, 16, 0);
        +			imagecopy($imgBlur, $img, 0, 0, 0, 0, $w, $h);
        +			imageconvolution($imgBlur, $matrix, 16, 0);
         
         		} else {
         
         			// Move copies of the image around one pixel at the time and merge them with weight
         			// according to the matrix. The same matrix is simply repeated for higher radii.
         			for ($i = 0; $i < $radius; $i++)    {
        -				ImageCopy(     $imgBlur,   $img,       0, 0, 1, 0, $w - 1, $h);               // left
        -				ImageCopyMerge($imgBlur,   $img,       1, 0, 0, 0, $w    , $h,     50);       // right
        -				ImageCopyMerge($imgBlur,   $img,       0, 0, 0, 0, $w    , $h,     50);       // center
        -				ImageCopy(     $imgCanvas, $imgBlur,   0, 0, 0, 0, $w    , $h);
        -				ImageCopyMerge($imgBlur,   $imgCanvas, 0, 0, 0, 1, $w    , $h - 1, 33.33333); // up
        -				ImageCopyMerge($imgBlur,   $imgCanvas, 0, 1, 0, 0, $w    , $h,     25);       // down
        +				imagecopy(     $imgBlur,   $img,       0, 0, 1, 0, $w - 1, $h);               // left
        +				imagecopymerge($imgBlur,   $img,       1, 0, 0, 0, $w    , $h,     50);       // right
        +				imagecopymerge($imgBlur,   $img,       0, 0, 0, 0, $w    , $h,     50);       // center
        +				imagecopy(     $imgCanvas, $imgBlur,   0, 0, 0, 0, $w    , $h);
        +				imagecopymerge($imgBlur,   $imgCanvas, 0, 0, 0, 1, $w    , $h - 1, 33.33333); // up
        +				imagecopymerge($imgBlur,   $imgCanvas, 0, 1, 0, 0, $w    , $h,     25);       // down
         			}
         		}
         
        @@ -97,12 +97,12 @@ static function applyUnsharpMask(&$img, $amount, $radius, $threshold) {
         			for ($x = 0; $x < $w-1; $x++)    { // each row
         				for ($y = 0; $y < $h; $y++)    { // each pixel
         
        -					$rgbOrig = ImageColorAt($img, $x, $y);
        +					$rgbOrig = imagecolorat($img, $x, $y);
         					$rOrig = (($rgbOrig >> 16) & 0xFF);
         					$gOrig = (($rgbOrig >>  8) & 0xFF);
         					$bOrig =  ($rgbOrig        & 0xFF);
         
        -					$rgbBlur = ImageColorAt($imgBlur, $x, $y);
        +					$rgbBlur = imagecolorat($imgBlur, $x, $y);
         
         					$rBlur = (($rgbBlur >> 16) & 0xFF);
         					$gBlur = (($rgbBlur >>  8) & 0xFF);
        @@ -115,20 +115,20 @@ static function applyUnsharpMask(&$img, $amount, $radius, $threshold) {
         					$bNew = ((abs($bOrig - $bBlur) >= $threshold) ? max(0, min(255, ($amount * ($bOrig - $bBlur)) + $bOrig)) : $bOrig);
         
         					if (($rOrig != $rNew) || ($gOrig != $gNew) || ($bOrig != $bNew)) {
        -						$pixCol = ImageColorAllocate($img, $rNew, $gNew, $bNew);
        -						ImageSetPixel($img, $x, $y, $pixCol);
        +						$pixCol = imagecolorallocate($img, $rNew, $gNew, $bNew);
        +						imagesetpixel($img, $x, $y, $pixCol);
         					}
         				}
         			}
         		} else {
         			for ($x = 0; $x < $w; $x++)    { // each row
         				for ($y = 0; $y < $h; $y++)    { // each pixel
        -					$rgbOrig = ImageColorAt($img, $x, $y);
        +					$rgbOrig = imagecolorat($img, $x, $y);
         					$rOrig = (($rgbOrig >> 16) & 0xFF);
         					$gOrig = (($rgbOrig >>  8) & 0xFF);
         					$bOrig =  ($rgbOrig        & 0xFF);
         
        -					$rgbBlur = ImageColorAt($imgBlur, $x, $y);
        +					$rgbBlur = imagecolorat($imgBlur, $x, $y);
         
         					$rBlur = (($rgbBlur >> 16) & 0xFF);
         					$gBlur = (($rgbBlur >>  8) & 0xFF);
        @@ -138,13 +138,12 @@ static function applyUnsharpMask(&$img, $amount, $radius, $threshold) {
         					$gNew = min(255, max(0, ($amount * ($gOrig - $gBlur)) + $gOrig));
         					$bNew = min(255, max(0, ($amount * ($bOrig - $bBlur)) + $bOrig));
         					$rgbNew = ($rNew << 16) + ($gNew <<8) + $bNew;
        -					ImageSetPixel($img, $x, $y, $rgbNew);
        +					imagesetpixel($img, $x, $y, $rgbNew);
         				}
         			}
         		}
        -		ImageDestroy($imgCanvas);
        -		ImageDestroy($imgBlur);
        +		imagedestroy($imgCanvas);
        +		imagedestroy($imgBlur);
         		return true;
         	}
         }
        -?>
        diff --git a/assets/snippets/phpthumb/snippet.phpthumb.php b/assets/snippets/phpthumb/snippet.phpthumb.php
        index 9ed86ebc81..d1b3da6e4a 100755
        --- a/assets/snippets/phpthumb/snippet.phpthumb.php
        +++ b/assets/snippets/phpthumb/snippet.phpthumb.php
        @@ -4,11 +4,11 @@
          *
          * PHPThumb creates thumbnails and altered images on the fly and caches them
          *
        - * @category 	snippet
        - * @version 	1.3
        - * @license 	http://www.gnu.org/copyleft/gpl.html GNU Public License (GPL)
        - * @internal	@properties
        - * @internal	@modx_category Content
        + * @category    snippet
        + * @version    1.3.3
        + * @license    http://www.gnu.org/copyleft/gpl.html GNU Public License (GPL)
        + * @internal    @properties
        + * @internal    @modx_category Content
          * @internal    @installset base, sample
          * @documentation Usage: [[phpthumb? &input=`[+image+]` &options=`w=150,h=76,far=C,bg=FFFFFF`]]
          * @documentation phpThumb docs http://phpthumb.sourceforge.net/demo/docs/phpthumb.readme.txt
        @@ -16,71 +16,87 @@
          * @link        noimage.png here [+site_url+]assets/snippets/phpthumb/noimage.png
          * @author      Bumkaka
          * @author      Many contributors since then
        - * @lastupdate  09/04/2016
        + * @lastupdate  26/11/2018
          */
        -if(!defined('MODX_BASE_PATH')){die('What are you doing? Get out of here!');}
        -
        -$newfolderaccessmode = $modx->config['new_folder_permissions'] ? octdec($modx->config['new_folder_permissions']) : 0777;
        -
        -$cacheFolder=isset($cacheFolder) ? $cacheFolder : "assets/cache/images";
        -if(!is_dir(MODX_BASE_PATH.$cacheFolder)) {
        -    mkdir(MODX_BASE_PATH.$cacheFolder);
        -    chmod(MODX_BASE_PATH.$cacheFolder, $newfolderaccessmode);
        +if (! defined('MODX_BASE_PATH')) {
        +    die('What are you doing? Get out of here!');
         }
         
        -$tmpFolder = 'assets/cache/tmp';
        -if (!empty($input)) $input = rawurldecode($input);
        +$newFolderAccessMode = $modx->getConfig('new_folder_permissions');
        +$newFolderAccessMode = empty($new) ? 0777 : octdec($newFolderAccessMode);
        +
        +$cacheFolder = isset($cacheFolder) ? $cacheFolder : $modx->getCacheFolder() . 'images';
        +$phpThumbPath = isset($phpThumbPath) ? $phpThumbPath : 'assets/snippets/phpthumb/';
         
        -if(empty($input) || !file_exists(MODX_BASE_PATH . $input)){
        -    $input = isset($noImage) ? $noImage : 'assets/snippets/phpthumb/noimage.png';
        +/**
        + * @see: https://github.com/kalessil/phpinspectionsea/blob/master/docs/probable-bugs.md#mkdir-race-condition
        + */
        +$path = MODX_BASE_PATH . $cacheFolder;
        +if (! file_exists($path) && mkdir($path) && is_dir($path)) {
        +    chmod($path, $newFolderAccessMode);
         }
         
        -// allow read in phpthumb cache folder
        -if (strpos($cacheFolder, 'assets/cache/') === 0 && $cacheFolder != 'assets/cache/' && !is_file(MODX_BASE_PATH . $cacheFolder . '/.htaccess')) {
        -	file_put_contents(MODX_BASE_PATH . $cacheFolder . '/.htaccess', "order deny,allow\nallow from all\n");
        +if (!empty($input)) {
        +    $input = rawurldecode($input);
         }
         
        +if (empty($input) || ! file_exists(MODX_BASE_PATH . $input)) {
        +    $input = isset($noImage) ? $noImage : $phpThumbPath . 'noimage.png';
        +}
         
        -if(!is_dir(MODX_BASE_PATH.$tmpFolder)) {
        -    mkdir(MODX_BASE_PATH.$tmpFolder);
        -    chmod(MODX_BASE_PATH.$tmpFolder, $newfolderaccessmode);
        +/**
        + * allow read in phpthumb cache folder
        + */
        +if (! file_exists(MODX_BASE_PATH . $cacheFolder . '/.htaccess') &&
        +    $cacheFolder !== $modx->getCacheFolder() &&
        +    strpos($cacheFolder, $modx->getCacheFolder()) === 0
        +) {
        +    file_put_contents(MODX_BASE_PATH . $cacheFolder . '/.htaccess', "order deny,allow\nallow from all\n");
         }
         
        -$path_parts=pathinfo($input);
        -$tmpImagesFolder=str_replace(MODX_BASE_PATH . "assets/images","",$path_parts['dirname']);
        -$tmpImagesFolder=str_replace("assets/images","",$tmpImagesFolder);
        -$tmpImagesFolder=explode("/",$tmpImagesFolder);
        -$ext=strtolower($path_parts['extension']);
        -$options = 'f='.(in_array($ext,explode(",","png,gif,jpeg"))?$ext:"jpg&q=85").'&'.strtr($options, Array("," => "&", "_" => "=", '{' => '[', '}' => ']'));
        +$path_parts = pathinfo($input);
        +$tmpImagesFolder = str_replace('assets/images', '', $path_parts['dirname']);
        +$tmpImagesFolder = explode('/', $tmpImagesFolder);
        +$ext = strtolower($path_parts['extension']);
        +$options = 'f=' . (in_array($ext, array('png', 'gif', 'jpeg')) ? $ext : 'jpg&q=85') . '&' .
        +    strtr($options, array(',' => '&', '_' => '=', '{' => '[', '}' => ']'));
        +
         parse_str($options, $params);
         foreach ($tmpImagesFolder as $folder) {
        -    if (!empty($folder)) {
        -        $cacheFolder.="/".$folder;
        -        if(!is_dir(MODX_BASE_PATH.$cacheFolder)) {
        -            mkdir(MODX_BASE_PATH.$cacheFolder);
        -            chmod(MODX_BASE_PATH.$cacheFolder, $newfolderaccessmode);
        +    if (! empty($folder)) {
        +        $cacheFolder .= '/' . $folder;
        +        $path = MODX_BASE_PATH . $cacheFolder;
        +        if (! file_exists($path) && mkdir($path) && is_dir($path)) {
        +            chmod($path, $newFolderAccessMode);
                 }
             }
         }
         
        -$fname_preffix = "$cacheFolder/";
        -$fname = $path_parts['filename'];
        -$fname_suffix = "-{$params['w']}x{$params['h']}-".substr(md5(serialize($params).filemtime(MODX_BASE_PATH . $input)),0,3).".{$params['f']}";
        -$outputFilename = MODX_BASE_PATH.$fname_preffix.$fname.$fname_suffix;
        -if (!file_exists($outputFilename)) {
        -    require_once MODX_BASE_PATH.'assets/snippets/phpthumb/phpthumb.class.php';
        +$fNamePref = rtrim($cacheFolder, '/') . '/';
        +$fName = $path_parts['filename'];
        +$fNameSuf = '-' .
        +    (isset($params['w']) ? $params['w'] : '') .'x' . (isset($params['h']) ? $params['h'] : '') . '-' .
        +    substr(md5(serialize($params) . filemtime(MODX_BASE_PATH . $input)), 0, 3) .
        +    '.' . $params['f'];
        +
        +$outputFilename = MODX_BASE_PATH . $fNamePref . $fName . $fNameSuf;
        +if (! file_exists($outputFilename)) {
        +    if (! class_exists('phpthumb')) {
        +        require_once MODX_BASE_PATH . $phpThumbPath . '/phpthumb.class.php';
        +    }
             $phpThumb = new phpthumb();
        -    $phpThumb->config_temp_directory = $tmpFolder;
        +    $phpThumb->config_cache_directory = MODX_BASE_PATH . $modx->getCacheFolder();
        +    $phpThumb->config_temp_directory = $modx->getCacheFolder();
             $phpThumb->config_document_root = MODX_BASE_PATH;
             $phpThumb->setSourceFilename(MODX_BASE_PATH . $input);
             foreach ($params as $key => $value) {
                 $phpThumb->setParameter($key, $value);
             }
        -	if ($phpThumb->GenerateThumbnail()) {
        +    if ($phpThumb->GenerateThumbnail()) {
                 $phpThumb->RenderToFile($outputFilename);
        -	} else {
        +    } else {
                 $modx->logEvent(0, 3, implode('
        ', $phpThumb->debugmessages), 'phpthumb'); } } -return $fname_preffix.rawurlencode($fname).$fname_suffix; -?> + +return $fNamePref . rawurlencode($fName) . $fNameSuf; diff --git a/index.php b/index.php index 5322472776..d4daf929ee 100644 --- a/index.php +++ b/index.php @@ -135,6 +135,6 @@ } // execute the parser if index.php was not included -if (!MODX_API_MODE) { +if (!MODX_API_MODE && !MODX_CLI) { $modx->executeParser(); } diff --git a/install/actions/action_connection.php b/install/actions/action_connection.php index 8f89954a52..e97479c3bb 100755 --- a/install/actions/action_connection.php +++ b/install/actions/action_connection.php @@ -16,7 +16,8 @@ // We need to have all connection settings - but prefix may be empty so we have to ignore it if ($dbase) { $database_name = trim($dbase, '`'); - if (!$conn = mysqli_connect($database_server, $database_user, $database_password)) + $host = explode(':', $database_server, 2); + if (!$conn = mysqli_connect($host[0], $database_user, $database_password,'', isset($host[1]) ? $host[1] : null)) $upgradeable = (isset($_POST['installmode']) && $_POST['installmode']=='new') ? 0 : 2; elseif (! mysqli_select_db($conn, trim($dbase, '`'))) $upgradeable = (isset($_POST['installmode']) && $_POST['installmode']=='new') ? 0 : 2; diff --git a/install/actions/action_mode.php b/install/actions/action_mode.php index 385464fadb..32a855388e 100755 --- a/install/actions/action_mode.php +++ b/install/actions/action_mode.php @@ -5,7 +5,8 @@ include_once $base_path . MGR_DIR . '/includes/config.inc.php'; // We need to have all connection settings - tho prefix may be empty so we have to ignore it if (isset($dbase)) { - if (!$conn = @mysqli_connect($database_server, $database_user, $database_password)) + $host = explode(':', $database_server, 2); + if (!$conn = @mysqli_connect($host[0], $database_user, $database_password,'', isset($host[1]) ? $host[1] : null)) $upgradeable = isset($_POST['installmode']) && $_POST['installmode'] == 'new' ? 0 : 2; elseif (!@mysqli_select_db($conn, trim($dbase, '`'))) $upgradeable = isset($_POST['installmode']) && $_POST['installmode'] == 'new' ? 0 : 2; diff --git a/install/actions/action_options.php b/install/actions/action_options.php index c94fdc158f..84e0e9b47f 100755 --- a/install/actions/action_options.php +++ b/install/actions/action_options.php @@ -195,7 +195,8 @@ function getSnippets($presets = array()) break; case 1: include $base_path . MGR_DIR . '/includes/config.inc.php'; - if (@ $conn = mysqli_connect($database_server, $database_user, $database_password)) { + $host = explode(':', $database_server, 2); + if (@ $conn = mysqli_connect($host[0], $database_user, $database_password,'', isset($host[1]) ? $host[1] : null)) { if (@ mysqli_query($conn, "USE {$dbase}")) { if (!$rs = mysqli_query($conn, "show session variables like 'collation_database'")) { $rs = mysqli_query($conn, "show session variables like 'collation_server'"); diff --git a/install/actions/action_summary.php b/install/actions/action_summary.php index ad7a5911aa..f72b874f4e 100755 --- a/install/actions/action_summary.php +++ b/install/actions/action_summary.php @@ -200,7 +200,8 @@ function f_owc($path, $data, $mode = null){ $table_prefix = $_POST['tableprefix']; } echo '

        '.$_lang['creating_database_connection']; -if (!$conn = mysqli_connect($database_server, $database_user, $database_password)) { +$host = explode(':', $database_server, 2); +if (!$conn = mysqli_connect($host[0], $database_user, $database_password,'', isset($host[1]) ? $host[1] : null)) { $errors++; echo ''.$_lang['database_connection_failed'].'

        '.$_lang['database_connection_failed_note'].'

        '; } else { diff --git a/install/assets/plugins/ElementsInTree.tpl b/install/assets/plugins/ElementsInTree.tpl index e151eab56c..e46372d774 100755 --- a/install/assets/plugins/ElementsInTree.tpl +++ b/install/assets/plugins/ElementsInTree.tpl @@ -5,7 +5,7 @@ * Get access to all Elements and Modules inside Manager sidebar * * @category plugin - * @version 1.5.9 + * @version 1.5.10 * @license http://creativecommons.org/licenses/GPL/2.0/ GNU Public License (GPL v2) * @internal @properties &adminRoleOnly=Administrators only;list;yes,no;yes;;Show tabs only for users with administrator role. &treeButtonsInTab=Tree buttons in tab;list;yes,no;yes;;Move Tree buttons into Site Tree tab. * @internal @events OnManagerTreePrerender,OnManagerTreeRender,OnManagerMainFrameHeaderHTMLBlock,OnTempFormSave,OnTVFormSave,OnChunkFormSave,OnSnipFormSave,OnPluginFormSave,OnModFormSave,OnTempFormDelete,OnTVFormDelete,OnChunkFormDelete,OnSnipFormDelete,OnPluginFormDelete,OnModFormDelete @@ -20,7 +20,8 @@ * @author Nicola1971 https://github.com/Nicola1971 * @author Deesen https://github.com/Deesen * @author yama https://github.com/yama - * @lastupdate 01/09/2017 + * @author Agel_Nash https://github.com/AgelxNash + * @lastupdate 04/11/2018 */ require MODX_BASE_PATH.'assets/plugins/elementsintree/plugin.elementsintree.php'; diff --git a/install/assets/plugins/OutdatedExtrasCheck.tpl b/install/assets/plugins/OutdatedExtrasCheck.tpl index e1fe43acb8..ed82af0d66 100755 --- a/install/assets/plugins/OutdatedExtrasCheck.tpl +++ b/install/assets/plugins/OutdatedExtrasCheck.tpl @@ -1,288 +1,18 @@ /** * OutdatedExtrasCheck * - * Check for Outdated critical extras not compatible with EVO 1.4.0 + * Check for Outdated critical extras not compatible with EVO 1.4.6 * * @category plugin - * @version 1.4.0 + * @version 1.4.6 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License (GPL) * @package evo * @author Author: Nicola Lambathakis * @internal @events OnManagerWelcomeHome - * @internal @properties &wdgVisibility=Show widget for:;menu;All,AdminOnly,AdminExcluded,ThisRoleOnly,ThisUserOnly;All &ThisRole=Run only for this role:;string;;;(role id) &ThisUser=Run only for this user:;string;;;(username) &DittoVersion=Min Ditto version:;string;2.1.3 &EformVersion=Min eForm version:;string;1.4.9 &AjaxSearchVersion=Min AjaxSearch version:;string;1.11.0 &WayfinderVersion=Min Wayfinder version:;string;2.0.5 &WebLoginVersion=Min WebLogin version:;string;1.2 &WebSignupVersion=Min WebSignup version:;string;1.1.2 &WebChangePwdVersion=Min WebChangePwd version:;string;1.1.2 &BreadcrumbsVersion=Min Breadcrumbs version:;string;1.0.5 &ReflectVersion=Min Reflect version:;string;2.2 &JotVersion=Min Jot version:;string;1.1.5 &MtvVersion=Min multiTV version:;string;2.0.13 &badthemes=Outdated Manager Themes:;string;MODxRE2_DropdownMenu,MODxRE2,MODxRE,MODxCarbon,D3X,MODxFLAT,wMOD,ScienceStyle + * @internal @properties &wdgVisibility=Show widget for:;menu;All,AdminOnly,AdminExcluded,ThisRoleOnly,ThisUserOnly;AdminOnly &ThisRole=Run only for this role:;string;;;(role id) &ThisUser=Run only for this user:;string;;;(username) * @internal @modx_category Manager and Admin * @internal @installset base * @internal @disabled 0 */ -// get manager role check -$internalKey = $modx->getLoginUserID(); -$sid = $modx->sid; -$role = $_SESSION['mgrRole']; -$user = $_SESSION['mgrShortname']; -// show widget only to Admin role 1 -if(($role!=1) AND ($wdgVisibility == 'AdminOnly')) {} -// show widget to all manager users excluded Admin role 1 -else if(($role==1) AND ($wdgVisibility == 'AdminExcluded')) {} -// show widget only to "this" role id -else if(($role!=$ThisRole) AND ($wdgVisibility == 'ThisRoleOnly')) {} -// show widget only to "this" username -else if(($user!=$ThisUser) AND ($wdgVisibility == 'ThisUserOnly')) {} -else { -// get plugin id and setting button -$result = $modx->db->select('id', $this->getFullTableName("site_plugins"), "name='{$modx->event->activePlugin}' AND disabled=0"); -$pluginid = $modx->db->getValue($result); -if($modx->hasPermission('edit_plugin')) { -$button_pl_config = ' '; -} -$modx->setPlaceholder('button_pl_config', $button_pl_config); -//plugin lang -$_oec_lang = array(); -$plugin_path = $modx->config['base_path'] . "assets/plugins/extrascheck/"; -include($plugin_path . 'lang/english.php'); -if (file_exists($plugin_path . 'lang/' . $modx->config['manager_language'] . '.php')) { -include($plugin_path . 'lang/' . $modx->config['manager_language'] . '.php'); -} -//run the plugin -// get globals -global $modx,$_lang; -//function to extract snippet version from description tags -if (!function_exists('getver')) { -function getver($string, $tag) -{ -$content ="/<$tag>(.*?)<\/$tag>/"; -preg_match($content, $string, $text); -return $text[1]; - } -} -$e = &$modx->Event; -$EVOversion = $modx->config['settings_version']; -$output = ''; -//get extras module id for the link -$modtable = $modx->getFullTableName('site_modules'); -$getExtra = $modx->db->select( "id, name", $modtable, "name='Extras'" ); -while( $row = $modx->db->getRow( $getExtra ) ) { -$ExtrasID = $row['id']; -} -//check outdated files -//ajax index -$indexajax = "../index-ajax.php"; -if (file_exists($indexajax)){ - $output .= '
        index-ajax.php '.$_oec_lang['not_used'].' Evolution '.$EVOversion.'. '.$_oec_lang['if_dont_use'].', '.$_oec_lang['please_delete'].'.
        '; -} -//check outdated default manager themes -$oldthemes = explode(",","$badthemes"); -foreach ($oldthemes as $oldtheme){ - if (file_exists('media/style/'.$oldtheme)){ - $output .= '
        '.$oldtheme.' '.$_lang["manager_theme"].', '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_delete'].' '.$_oec_lang['from_folder'].' ' . MODX_MANAGER_PATH . 'media/style/.
        '; -} -} -//get site snippets table -$table = $modx->getFullTableName('site_snippets'); -//check ditto -//get min version from config -$minDittoVersion = $DittoVersion; -//search the snippet by name -$CheckDitto = $modx->db->select( "id, name, description", $table, "name='Ditto'" ); -if($CheckDitto != ''){ -while( $row = $modx->db->getRow( $CheckDitto ) ) { -//extract snippet version from description tags -$curr_ditto_version = getver($row['description'],"strong"); -//check snippet version and return an alert if outdated -if (version_compare($curr_ditto_version,$minDittoVersion,'lt')){ -$output .= '
        ' . $row['name'] . ' '.$_lang["snippet"].' (version ' . $curr_ditto_version . ') '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_update'].' ' . $row['name'] . ' '.$_oec_lang["to_latest"].' ('.$_oec_lang['min _required'].' '.$minDittoVersion.') '.$_oec_lang['from'].' '.$_oec_lang['extras_module'].' '.$_oec_lang['or_move_to'].' DocLister
        '; - } - } -} -//end check ditto - -//check eform -//get min version from config -$minEformVersion = $EformVersion; -//search the snippet by name -$CheckEform = $modx->db->select( "id, name, description", $table, "name='eForm'" ); -if($CheckEform != ''){ -while( $row = $modx->db->getRow( $CheckEform ) ) { -//extract snippet version from description tags -$curr_Eform_version = getver($row['description'],"strong"); -//check snippet version and return an alert if outdated -if (version_compare($curr_Eform_version,$minEformVersion,'lt')){ -$output .= '
        ' . $row['name'] . ' '.$_lang["snippet"].' (version ' . $curr_Eform_version . ') '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_update'].' ' . $row['name'] . ' '.$_oec_lang["to_latest"].' ('.$_oec_lang['min _required'].' '.$minEformVersion.') '.$_oec_lang['from'].' '.$_oec_lang['extras_module'].' '.$_oec_lang['or_move_to'].' FormLister
        '; - } - } -} -//end check eform - -//check AjaxSearch -//get min version from config -$minAjaxSearchVersion = $AjaxSearchVersion; -//search the snippet by name -$CheckAjaxSearch = $modx->db->select( "id, name, description", $table, "name='AjaxSearch'" ); -if($CheckAjaxSearch != ''){ -while( $row = $modx->db->getRow( $CheckAjaxSearch ) ) { -//extract snippet version from description tags -$curr_AjaxSearch_version = getver($row['description'],"strong"); -//check snippet version and return an alert if outdated -if (version_compare($curr_AjaxSearch_version,$minAjaxSearchVersion,'lt')){ -$output .= '
        ' . $row['name'] . ' '.$_lang["snippet"].' (version ' . $curr_AjaxSearch_version . ') '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_update'].' ' . $row['name'] . ' '.$_oec_lang["to_latest"].' ('.$_oec_lang['min _required'].' '.$minAjaxSearchVersion.') '.$_oec_lang['from'].' '.$_oec_lang['extras_module'].'.
        '; - } - } -} -//end check AjaxSearch - -//check Wayfinder -//get min version from config -$minWayfinderVersion = $WayfinderVersion; -//search the snippet by name -$CheckWayfinder = $modx->db->select( "id, name, description", $table, "name='Wayfinder'" ); -if($CheckWayfinder != ''){ -while( $row = $modx->db->getRow( $CheckWayfinder ) ) { -//extract snippet version from description tags -$curr_Wayfinder_version = getver($row['description'],"strong"); -//check snippet version and return an alert if outdated -if (version_compare($curr_Wayfinder_version,$minWayfinderVersion,'lt')){ -$output .= '
        ' . $row['name'] . ' '.$_lang["snippet"].' (version ' . $curr_Wayfinder_version . ') '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_update'].' ' . $row['name'] . ' '.$_oec_lang["to_latest"].' ('.$_oec_lang['min _required'].' '.$minWayfinderVersion.') '.$_oec_lang['from'].' '.$_oec_lang['extras_module'].'.
        '; - } - } -} -//end check Wayfinder - -//check WebLogin -//get min version from config -$minWebLoginVersion = $WebLoginVersion; -//search the snippet by name -$CheckWebLogin = $modx->db->select( "id, name, description", $table, "name='WebLogin'" ); -if($CheckWebLogin != ''){ -while( $row = $modx->db->getRow( $CheckWebLogin ) ) { -//extract snippet version from description tags -$curr_WebLogin_version = getver($row['description'],"strong"); -//check snippet version and return an alert if outdated -if (version_compare($curr_WebLogin_version,$minWebLoginVersion,'lt')){ -$output .= '
        ' . $row['name'] . ' '.$_lang["snippet"].' (version ' . $curr_WebLogin_version . ') '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_update'].' ' . $row['name'] . ' '.$_oec_lang["to_latest"].' ('.$_oec_lang['min _required'].' '.$minWebLoginVersion.') '.$_oec_lang['from'].' '.$_oec_lang['extras_module'].' '.$_oec_lang['or_move_to'].' FormLister
        '; - } - } -} -//end check WebLogin - -//check WebChangePwd -//get min version from config -$minWebChangePwdVersion = $WebChangePwdVersion; -//search the snippet by name -$CheckWebChangePwd = $modx->db->select( "id, name, description", $table, "name='WebChangePwd'" ); -if($CheckWebLogin != ''){ -while( $row = $modx->db->getRow( $CheckWebChangePwd ) ) { -//extract snippet version from description tags -$curr_WebChangePwd_version = getver($row['description'],"strong"); -//check snippet version and return an alert if outdated -if (version_compare($curr_WebChangePwd_version,$minWebChangePwdVersion,'lt')){ -$output .= '
        ' . $row['name'] . ' '.$_lang["snippet"].' (version ' . $curr_WebChangePwd_version . ') '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_update'].' ' . $row['name'] . ' '.$_oec_lang["to_latest"].' ('.$_oec_lang['min _required'].' '.$minWebChangePwdVersion.') '.$_oec_lang['from'].' '.$_oec_lang['extras_module'].' '.$_oec_lang['or_move_to'].' FormLister
        '; - } - } -} -//end check WebChangePwd - -//check WebSignup -//get min version from config -$minWebSignupVersion = $WebSignupVersion; -//search the snippet by name -$CheckWebSignup = $modx->db->select( "id, name, description", $table, "name='WebSignup'" ); -if($CheckWebSignup != ''){ -while( $row = $modx->db->getRow( $CheckWebSignup ) ) { -//extract snippet version from description tags -$curr_WebSignup_version = getver($row['description'],"strong"); -//check snippet version and return an alert if outdated -if (version_compare($curr_WebSignup_version,$minWebSignupVersion,'lt')){ -$output .= '
        ' . $row['name'] . ' '.$_lang["snippet"].' (version ' . $curr_WebSignup_version . ') '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_update'].' ' . $row['name'] . ' '.$_oec_lang["to_latest"].' ('.$_oec_lang['min _required'].' '.$minWebSignupVersion.') '.$_oec_lang['from'].' '.$_oec_lang['extras_module'].' '.$_oec_lang['or_move_to'].' FormLister
        '; - } - } -} -//end check WebSignup - -//check Breadcrumbs -//get min version from config -$minBreadcrumbsVersion = $BreadcrumbsVersion; -//search the snippet by name -$CheckBreadcrumbs = $modx->db->select( "id, name, description", $table, "name='Breadcrumbs'" ); -if($CheckBreadcrumbs != ''){ -while( $row = $modx->db->getRow( $CheckBreadcrumbs ) ) { -//extract snippet version from description tags -$curr_Breadcrumbs_version = getver($row['description'],"strong"); -//check snippet version and return an alert if outdated -if (version_compare($curr_Breadcrumbs_version,$minBreadcrumbsVersion,'lt')){ -$output .= '
        ' . $row['name'] . ' '.$_lang["snippet"].' (version ' . $curr_Breadcrumbs_version . ') '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_update'].' ' . $row['name'] . ' '.$_oec_lang["to_latest"].' ('.$_oec_lang['min _required'].' '.$minBreadcrumbsVersion.') '.$_oec_lang['from'].' '.$_oec_lang['extras_module'].'.
        '; - } - } -} -//end check Breadcrumbs - -//check Reflect -//get min version from config -$minReflectVersion = $ReflectVersion; -//search the snippet by name -$CheckReflect = $modx->db->select( "id, name, description", $table, "name='Reflect'" ); -if($CheckReflect != ''){ -while( $row = $modx->db->getRow( $CheckReflect ) ) { -//extract snippet version from description tags -$curr_Reflect_version = getver($row['description'],"strong"); -//check snippet version and return an alert if outdated -if (version_compare($curr_Reflect_version,$minReflectVersion,'lt')){ -$output .= '
        ' . $row['name'] . ' '.$_lang["snippet"].' (version ' . $curr_Reflect_version . ') '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_update'].' ' . $row['name'] . ' '.$_oec_lang["to_latest"].' ('.$_oec_lang['min _required'].' '.$minReflectVersion.') '.$_oec_lang['from'].' '.$_oec_lang['extras_module'].'.
        '; - } - } -} -//end check Reflect - -//check Jot -//get min version from config -$minJotVersion = $JotVersion; -//search the snippet by name -$CheckJot = $modx->db->select( "id, name, description", $table, "name='Jot'" ); -if($CheckJot != ''){ -while( $row = $modx->db->getRow( $CheckJot ) ) { -//extract snippet version from description tags -$curr_Jot_version = getver($row['description'],"strong"); -//check snippet version and return an alert if outdated -if (version_compare($curr_Jot_version,$minJotVersion,'lt')){ -$output .= '
        ' . $row['name'] . ' '.$_lang["snippet"].' (version ' . $curr_Jot_version . ') '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_update'].' ' . $row['name'] . ' '.$_oec_lang["to_latest"].' ('.$_oec_lang['min _required'].' '.$minJotVersion.') '.$_oec_lang['from'].' '.$_oec_lang['extras_module'].'.
        '; - } - } -} -//end check Jot - -//check Multitv -//get min version from config -$minMtvVersion = $MtvVersion; -//search the snippet by name -$CheckMtv = $modx->db->select( "id, name, description", $table, "name='multiTV'" ); -if($CheckMtv != ''){ -while( $row = $modx->db->getRow( $CheckMtv ) ) { -//extract snippet version from description tags -$curr_mtv_version = getver($row['description'],"strong"); -//check snippet version and return an alert if outdated -if (version_compare($curr_mtv_version,$minMtvVersion,'lt')){ -$output .= '
        ' . $row['name'] . ' '.$_lang["snippet"].' (version ' . $curr_mtv_version . ') '.$_oec_lang['isoutdated'].' Evolution '.$EVOversion.'. '.$_oec_lang['please_update'].' ' . $row['name'] . ' '.$_oec_lang["to_latest"].' ('.$_oec_lang['min _required'].' '.$minMtvVersion.') '.$_oec_lang['from'].' '.$_oec_lang['extras_module'].'
        '; - } - } -} -//end check Multitv - -if($output != ''){ -if($e->name == 'OnManagerWelcomeHome') { -$out = $output; -$wdgTitle = 'EVO '.$EVOversion.' - '.$_oec_lang['title'].''; -$widgets['xtraCheck'] = array( - 'menuindex' =>'0', - 'id' => 'xtraCheck'.$pluginid.'', - 'cols' => 'col-12', - 'headAttr' => 'style="background-color:#B60205; color:#FFFFFF;"', - 'bodyAttr' => '', - 'icon' => 'fa-warning', - 'title' => ''.$wdgTitle.' '.$button_pl_config.'', - 'body' => '
        '.$out.'
        ', - 'hide' => '0' - ); - $e->output(serialize($widgets)); -return; - } - } -} \ No newline at end of file +require MODX_BASE_PATH . 'assets/plugins/extrascheck/OutdatedExtrasCheck.plugin.php'; diff --git a/install/assets/plugins/userHelper.tpl b/install/assets/plugins/userHelper.tpl index e3f2e6fb52..74d19f6d76 100644 --- a/install/assets/plugins/userHelper.tpl +++ b/install/assets/plugins/userHelper.tpl @@ -5,8 +5,8 @@ * addition to FormLister * * @category plugin - * @version 1.7.19 - * @internal @properties &logoutKey=Request key;text;logout &cookieName=Cookie Name;text;WebLoginPE &cookieLifetime=Cookie Lifetime, seconds;text;157680000 &maxFails=Max failed logins;text;3 &blockTime=Block for, seconds;text;3600 + * @version 1.8.1 + * @internal @properties &logoutKey=Request key;text;logout &cookieName=Cookie Name;text;WebLoginPE &cookieLifetime=Cookie Lifetime, seconds;text;157680000 &maxFails=Max failed logins;text;3 &blockTime=Block for, seconds;text;3600 &trackWebUserActivity=Track web user activity;list;No,Yes;No * @internal @events OnWebAuthentication,OnWebPageInit,OnPageNotFound,OnWebLogin * @internal @modx_category Content * @internal @disabled 1 diff --git a/install/assets/snippets/DLcrumbs.tpl b/install/assets/snippets/DLcrumbs.tpl index 6472e9eb89..d26f4abd7f 100755 --- a/install/assets/snippets/DLcrumbs.tpl +++ b/install/assets/snippets/DLcrumbs.tpl @@ -12,4 +12,4 @@ * @internal @installset base, sample */ -return require MODX_BASE_PATH.'assets/snippets/DocLister/snippet.DLCrumbs.php'; \ No newline at end of file +return require MODX_BASE_PATH.'assets/snippets/DocLister/snippet.DLCrumbs.php'; diff --git a/install/assets/snippets/DocLister.tpl b/install/assets/snippets/DocLister.tpl index 1d16f93786..5a16f1c58f 100644 --- a/install/assets/snippets/DocLister.tpl +++ b/install/assets/snippets/DocLister.tpl @@ -5,7 +5,7 @@ * Snippet to display the information of the tables by the description rules. The main goal - replacing Ditto and CatalogView * * @category snippet - * @version 2.3.15 + * @version 2.4.1 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License (GPL) * @internal @properties * @internal @modx_category Content diff --git a/install/assets/snippets/FormLister.tpl b/install/assets/snippets/FormLister.tpl index eb79cd901b..c885c87bd8 100644 --- a/install/assets/snippets/FormLister.tpl +++ b/install/assets/snippets/FormLister.tpl @@ -5,7 +5,7 @@ * Form processor * * @category snippet - * @version 1.7.19 + * @version 1.8.1 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License (GPL) * @internal @modx_category Content * @internal @installset base, sample diff --git a/install/assets/snippets/docinfo.tpl b/install/assets/snippets/docinfo.tpl index b82aad245c..09ecc3944c 100755 --- a/install/assets/snippets/docinfo.tpl +++ b/install/assets/snippets/docinfo.tpl @@ -1,13 +1,13 @@ //'.$_lang['status_failed'].''; } else { diff --git a/install/connection.servertest.php b/install/connection.servertest.php index d81e9dabc5..920c69abbc 100755 --- a/install/connection.servertest.php +++ b/install/connection.servertest.php @@ -16,7 +16,8 @@ $output = $_lang["status_connecting"]; if (function_exists('mysqli_connect')) { - if (!$conn = @mysqli_connect($host, $uid, $pwd)) { + $h = explode(':', $host, 2); + if (!$conn = @mysqli_connect($h[0], $uid, $pwd,'', isset($h[1]) ? $h[1] : null)) { $output .= ' '.$_lang['status_failed'].''; } else { $output .= ' '.$_lang['status_passed_server'].''; @@ -43,4 +44,4 @@ } else { $output .= ' '.$_lang['status_failed_mysqli'].''; } -echo $output; \ No newline at end of file +echo $output; diff --git a/install/functions.php b/install/functions.php index f13d4606cd..ec3be7e5bd 100755 --- a/install/functions.php +++ b/install/functions.php @@ -98,7 +98,8 @@ function get_installmode() if (!isset($dbase) || empty($dbase)) { $installmode = 0; } else { - $conn = mysqli_connect($database_server, $database_user, $database_password); + $host = explode(':', $database_server, 2); + $conn = mysqli_connect($host[0], $database_user, $database_password,'', isset($host[1]) ? $host[1] : null); if ($conn) { $_SESSION['database_server'] = $database_server; $_SESSION['database_user'] = $database_user; diff --git a/install/instprocessor.php b/install/instprocessor.php index 0db8a64b3e..1aa29b643c 100755 --- a/install/instprocessor.php +++ b/install/instprocessor.php @@ -73,7 +73,8 @@ // connect to the database echo "

        ". $_lang['setup_database_create_connection']; -if (!$conn = mysqli_connect($database_server, $database_user, $database_password)) { +$host = explode(':', $database_server, 2); +if (!$conn = mysqli_connect($host[0], $database_user, $database_password,'', isset($host[1]) ? $host[1] : null)) { echo ''.$_lang["setup_database_create_connection_failed"]."

        ".$_lang['setup_database_create_connection_failed_note']."

        "; return; } else { @@ -125,35 +126,6 @@ } } -if(!function_exists('parseProperties')) { - /** - * parses a resource property string and returns the result as an array - * duplicate of method in documentParser class - * - * @param string $propertyString - * @return array - */ - function parseProperties($propertyString) { - $parameter= array (); - if (!empty ($propertyString)) { - $tmpParams= explode("&", $propertyString); - $countParams = count($tmpParams); - for ($x= 0; $x < $countParams; $x++) { - if (strpos($tmpParams[$x], '=', 0)) { - $pTmp= explode("=", $tmpParams[$x]); - $pvTmp= explode(";", trim($pTmp[1])); - if ($pvTmp[1] == 'list' && $pvTmp[3] != "") - $parameter[trim($pTmp[0])]= $pvTmp[3]; //list default - else - if ($pvTmp[1] != 'list' && $pvTmp[2] != "") - $parameter[trim($pTmp[0])]= $pvTmp[2]; - } - } - } - return $parameter; - } -} - // check status of Inherit Parent Template plugin $auto_template_logic = 'parent'; if ($installMode != 0) { @@ -183,6 +155,7 @@ function parseProperties($propertyString) { include "{$setupPath}/setup.info.php"; include "{$setupPath}/sqlParser.class.php"; $sqlParser = new SqlParser($database_server, $database_user, $database_password, str_replace("`", "", $dbase), $table_prefix, $adminname, $adminemail, $adminpass, $database_connection_charset, $managerlanguage, $database_connection_method, $auto_template_logic); +$sqlParser->database_collation = $database_collation; $sqlParser->mode = ($installMode < 1) ? "new" : "upd"; /* image and file manager paths now handled via settings screen in Manager $sqlParser->imageUrl = 'http://' . $_SERVER['SERVER_NAME'] . $base_url . "assets/"; @@ -588,8 +561,7 @@ function parseProperties($propertyString) { } } if($insert === true) { - $properties = mysqli_real_escape_string($conn, propUpdate($properties,$row['properties'])); - if(!mysqli_query($sqlParser->conn, "INSERT INTO $dbase.`".$table_prefix."site_plugins` (name,description,plugincode,properties,moduleguid,disabled,category) VALUES('$name','$desc','$plugin','$properties','$guid','0',$category);")) { + if(!mysqli_query($sqlParser->conn, "INSERT INTO $dbase.`".$table_prefix."site_plugins` (name,description,plugincode,properties,moduleguid,disabled,category) VALUES('$name','$desc','$plugin','$props','$guid','0',$category);")) { echo "

        ".mysqli_error($sqlParser->conn)."

        "; return; } @@ -609,10 +581,11 @@ function parseProperties($propertyString) { if ($ds) { $row = mysqli_fetch_assoc($ds); $id = $row["id"]; - // remove existing events - mysqli_query($sqlParser->conn, 'DELETE FROM ' . $dbase . '.`' . $table_prefix . 'site_plugin_events` WHERE pluginid = \'' . $id . '\''); + $_events = implode("','", $events); // add new events - mysqli_query($sqlParser->conn, "INSERT INTO $dbase.`" . $table_prefix . "site_plugin_events` (pluginid, evtid) SELECT '$id' as 'pluginid',se.id as 'evtid' FROM $dbase.`" . $table_prefix . "system_eventnames` se WHERE name IN ('" . implode("','", $events) . "')"); + mysqli_query($sqlParser->conn, "INSERT IGNORE INTO $dbase.`" . $table_prefix . "site_plugin_events` (pluginid, evtid) SELECT '$id' as 'pluginid',se.id as 'evtid' FROM $dbase.`" . $table_prefix . "system_eventnames` se WHERE name IN ('{$_events}')"); + // remove absent events + mysqli_query($sqlParser->conn, "DELETE `pe` FROM {$dbase}.`{$table_prefix}site_plugin_events` `pe` LEFT JOIN {$dbase}.`{$table_prefix}system_eventnames` `se` ON `pe`.`evtid`=`se`.`id` AND `name` IN ('{$_events}') WHERE ISNULL(`name`) AND `pluginid` = {$id}"); } } } diff --git a/install/lang/polish-utf8.inc.php b/install/lang/polish-utf8.inc.php index 80b8602f54..3945afcb97 100755 --- a/install/lang/polish-utf8.inc.php +++ b/install/lang/polish-utf8.inc.php @@ -2,8 +2,8 @@ /** * EVO Installer language file * - * @version 1.5.0 - * @date 2018/02/23 + * @version 1.5.1 + * @date 2018/10/31 * @author EVO Project Team * * @language Polish @@ -32,7 +32,7 @@ $_lang["btnclose_value"] = 'Zamknij'; $_lang["btnnext_value"] = 'Dalej'; $_lang["cant_write_config_file"] = 'EVO nie może zapisać pliku konfiguracyjnego. Skopiuj następujący kod do pliku'; -$_lang["cant_write_config_file_note"] = 'Once that\'s been done, you can log into EVO Admin by pointing your browser at YourSiteName.com/[+MGR_DIR+]/.'; +$_lang["cant_write_config_file_note"] = 'Po zakończeniu instalacji będziesz mógł zalogować się do EVO Admin pod adresem: twojadomena.com/[+MGR_DIR+]/'; $_lang["checkbox_select_options"] = 'Zaznacz wybrane opcje: '; $_lang["checking_if_cache_exist"] = 'Sprawdzanie, czy istnieją foldery /assets/cache oraz /assets/cache/rss: '; $_lang["checking_iconv"] = 'Sprawdzanie czy rozszerzenie iconv jest dostępne: '; @@ -49,7 +49,7 @@ $_lang["checking_mysql_version"] = 'Sprawdzanie wersji MySQL: '; $_lang["checking_php_version"] = 'Sprawdzanie wersji PHP: '; $_lang["checking_registerglobals"] = 'Sprawdzanie, czy zmienne globalne (Register_Globals) są wyłączone: '; -$_lang["checking_registerglobals_note"] = 'This configuration makes your site much more susceptible to Cross Site Scripting (XSS) attacks. You should speak to your host about disabling this setting, usually by one of three ways: modifying the global php.ini file, adding rules to a .htaccess file in the root of your EVO install, or adding custom php.ini override files in every directory on your install (and there\'s a lot of them). You will still be able to install EVO, but consider yourself warned.'; +$_lang["checking_registerglobals_note"] = 'Taka konfiguracja powoduje, że Twoja strona jest znacznie bardziej podatna na ataki typu Cross Site Scripting (XSS). Powinieneś wyłączyć tę opcję na serwerze. Są trzy podstawowe sposoby, aby to zrobić: można zmodyfikować główny plik php.ini, dodać regułę w pliku .htaccess znajdującym się w głównym folderze EVO lub dodać własny plik php.ini w każdym z folderów EVO (a jest ich sporo) z ustawieniami nadpisującymi ustawienia globalne. W dalszym ciągu możesz zainstalować EVO - pamiętaj jednak, że zostałeś ostrzeżony.'; $_lang["checking_sessions"] = 'Sprawdzanie, czy obsługa sesji jest skonfigurowana poprawnie: '; $_lang["checking_table_prefix"] = 'Sprawdzanie prefiksu tabeli `'; $_lang["choose_language"] = 'Wybierz język'; @@ -58,7 +58,7 @@ $_lang["connection_screen_collation"] = 'System porównań (collation): '; $_lang["connection_screen_connection_method"] = 'Metoda połączenia: '; $_lang["connection_screen_database_connection_information"] = 'Informacje o bazie danych'; -$_lang["connection_screen_database_connection_note"] = 'Enter the database name to use or which you wish to create for this EVO install. If no database exists, the installer will attempt to create one. This may fail depending on the MySQL user permissions.'; +$_lang["connection_screen_database_connection_note"] = 'Wybierz nazwę bazy danych, którą chcesz użyć dla tej instalacji EVO. Jeśli baza danych nie istnieje, instalator podejmie próbę utworzenia jej. Utworzenie nowej bazy danych może się nie powieść, jeśli użytkownik MySQL nie ma wystarczających uprawnień.'; $_lang["connection_screen_database_host"] = 'Host bazy danych:'; $_lang["connection_screen_database_info"] = 'Informacje o bazie danych'; $_lang["connection_screen_database_login"] = 'Nazwa użytkownika bazy: '; @@ -83,7 +83,7 @@ $_lang["database_use_failed"] = 'Baza danych nie może być użyta!'; $_lang["database_use_failed_note"] = 'Sprawdź prawa dostępu do bazy danych dla wybranego użytkownika i spróbuj ponownie.'; $_lang["default_language"] = 'Domyślny język Menedżera'; -$_lang["default_language_description"] = 'This is the default language that will be used in the EVO Manager back end control panel.'; +$_lang["default_language_description"] = 'Domyślny język dla EVO Manager.'; $_lang["depedency_create"] = 'Zależność utworzona'; $_lang["depedency_update"] = 'Zależność uaktualniona'; $_lang["during_execution_of_sql"] = ' podczas wykonywania zapytania SQL '; @@ -94,8 +94,8 @@ $_lang["guid_set"] = 'GUID ustawiony'; $_lang["help"] = 'Pomoc!'; $_lang["help_link"] = 'https://evo.im/'; -$_lang["help_title"] = 'Installation assistance in the EVO forums'; -$_lang["iagree_box"] = 'I agree to the terms of the EVO license. For translations of the GPL version 2 license, please visit the GNU Operating System website.'; +$_lang["help_title"] = 'Wsparcie przy instalacji EVO'; +$_lang["iagree_box"] = 'Akceptuję warunki licencji EVO. Tłumaczenia licencji GPL w wersji 2 znajdziesz na stronie GNU Operating System.'; $_lang["install"] = 'Instaluj'; $_lang["install_overwrite"] = 'Instaluj/Nadpisz: '; $_lang["install_results"] = 'Wyniki instalacji'; @@ -105,7 +105,7 @@ $_lang["installation_install_new_note"] = 'Wybór tej opcji może spowodować nadpisanie danych w wybranej bazie danych.'; $_lang["installation_mode"] = 'Typ instalacji'; $_lang["installation_new_installation"] = 'Nowa instalacja'; -$_lang["installation_note"] = 'Note: After logging into the manager you should edit and save your System Configuration settings before browsing the site by choosing Tools -> System Configuration in the EVO Manager.'; +$_lang["installation_note"] = 'Uwaga: Zanim zaczniesz przeglądać zasoby swojej strony zaloguj się do Menedżera i zapisz konfigurację. Wybierz zakładkę: Ustawienia -> Konfiguracja systemu.'; $_lang["installation_successful"] = 'Instalacja zakończona pomyślnie!'; $_lang["installation_upgrade_advanced"] = 'Zaawansowany tryb aktualizacji'; $_lang["installation_upgrade_advanced_note"] = 'Tryb dla użytkowników zaawansowanych. Wybierz go, jeśli przenosisz instalację do bazy danych z innym kodowaniem znaków.
        Będziesz potrzebował pełnej nazwy bazy danych, nazwy użytkownika oraz jego hasła, jak również szczegółów dotyczących połączenia i systemu porównań.'; @@ -116,10 +116,10 @@ $_lang["language_code"] = 'pl'; $_lang["loading"] = 'Ładowanie...'; $_lang["modules"] = 'Moduły'; -$_lang["modx_footer1"] = '© 2005-[+current_year+] the EVO Content Management Framework (CMF) project. All rights reserved. EVO is licensed under the GNU GPL.'; -$_lang["modx_footer2"] = 'EVO is free software. We encourage you to be creative and make use of EVO in any way you see fit. Just make sure that if you do make changes and decide to redistribute your modified EVO, that you keep the source code free!'; -$_lang["modx_install"] = 'EVO » Instaluj'; -$_lang["modx_requires_php"] = ', i EVO wymagają PHP [+min_version+] lub późniejszy '; +$_lang["modx_footer1"] = '© 2005-[+current_year+] Evolution CMS. Wszystkie prawa zastrzeżone. EVO działa na licencji GNU GPL.'; +$_lang["modx_footer2"] = 'EVO jest wolnym oprogramowaniem. Zachęcamy Cię, abyś kreatywnie wykorzystywał EVO w jakikolwiek sposób, który uznasz za przydatny. Prosimy jedynie, abyś pozostawił kod źródłowy otwartym i darmowym w przypadku gdy zdecydujesz się na redystrybucję EVO w zmodyfikowanej przez siebie wersji.'; +$_lang["modx_install"] = 'EVO » Instalacja'; +$_lang["modx_requires_php"] = ', i EVO wymagają PHP [+min_version+] lub nowszego'; $_lang["mysql_5051"] = ' MySQL w wersji 5.0.51!'; $_lang["mysql_5051_warning"] = 'Wersja 5.0.51 MySQL posiada wiele dobrze znanych błędów, które mogą przyczynić się do nieprawidłowego działania EVO. Zalecamy uaktualnienie MySQL przed kontynuowaniem instalacji.'; $_lang["mysql_version_is"] = 'Wersja MySQL: '; @@ -129,7 +129,7 @@ $_lang["ok"] = 'OK!'; $_lang["optional_items"] = 'Komponenty opcjonalne'; $_lang["optional_items_note"] = 'Wybierz opcje instalacji, a następnie kliknij przycisk `Instaluj`: '; -$_lang["php_security_notice"] = 'Security notice

        While EVO will work on your PHP version, usage of EVO on this version is not recommended. Your version of PHP is vulnerable to numerous security holes. Please upgrade to PHP version is 5.6 or higher, which patches these holes. It is recommended you upgrade to this version for the security of your own website.

        '; +$_lang["php_security_notice"] = 'Informacja dotycząca bezpieczeństwa

        EVO będzie działać na tej wersji PHP, jednak nie jest ona zalecana. Używana przez Ciebie wersja PHP posiada wiele błędów związanych z bezpieczeństwem. Zaktualizuj PHP do wersji 5.6 lub nowszej, w której błędy bezpieczeństwa nie występują. Zalecamy zmianę wersji PHP na wyższą, ze względu na bezpieczeństwo Twojej strony internetowej.

        '; $_lang["please_correct_error"] = '. Proszę popraw błąd'; $_lang["please_correct_errors"] = '. Proszę popraw błędy'; $_lang["plugins"] = 'Pluginy'; @@ -149,7 +149,7 @@ $_lang["session_problem"] = 'Wystąpił problem z obsługą sesji przez serwer. Proszę skonsultuj się z administratorem aby usunąć ten problem.'; $_lang["session_problem_try_again"] = 'Ponowić próbę?'; $_lang["setup_cannot_continue"] = 'Z powodów wymienionych powyżej instalacja nie może być kontynuowana'; -$_lang["setup_couldnt_install"] = 'EVO setup couldn\'t install/alter some tables inside the selected database.'; +$_lang["setup_couldnt_install"] = 'Instalator EVO nie mógł zainstalować/zmodyfikować niektórych tabel w wybranej bazie danych.'; $_lang["setup_database"] = 'Instalator spróbuje teraz skonfigurować bazę danych:
        '; $_lang["setup_database_create_connection"] = 'Łączenie z bazą danych: '; $_lang["setup_database_create_connection_failed"] = 'Połączenie z bazą danych nie powiodło się!'; @@ -170,12 +170,12 @@ $_lang["status_failed_could_not_create_database"] = 'BŁĄD! - nie można utworzyć bazy danych'; $_lang["status_failed_database_collation_does_not_match"] = 'BŁĄD! - niezgodność systemów porównań; użyj SET NAMES lub wybierz %s'; $_lang["status_failed_table_prefix_already_in_use"] = 'BŁĄD! - wybrany prefiks tabeli jest już wykorzystywany!'; -$_lang['status_failed_mysqli'] = 'error - mysqli extension for PHP is not installed!'; +$_lang['status_failed_mysqli'] = 'Błąd - rozszerzenie mysqli dla PHP nie jest zainstalowane!'; $_lang["status_passed"] = 'OK - baza danych została wybrana'; $_lang["status_passed_database_created"] = 'OK - baza danych utworzona'; $_lang["status_passed_server"] = 'OK - system porównań dostępny'; $_lang["strict_mode"] = 'Tryb `strict sql_mode` dla MySQL jest włączony!'; -$_lang["strict_mode_error"] = 'Certain features of EVO may not work properly unless the STRICT_TRANS_TABLES sql_mode is disabled. You can set the MySQL mode by editing the my.cnf file or contact your server administrator.'; +$_lang["strict_mode_error"] = 'Niektóre z funkcji EVO mogą działać niepoprawnie gdy tryb STRICT_TRANS_TABLES sql_mode jest włączony. Możesz zmienić tryb MySQL edytując plik my.cnf lub kontaktując się z administratorem serwera.'; $_lang["summary_setup_check"] = 'Instalator wykonał serię testów aby sprawdzić, czy wszystko jest gotowe do rozpoczęcia procesu instalacji.'; $_lang["system_configuration"] = 'Konfiguracja systemu'; $_lang["system_configuration_validate_referer_description"] = 'Włączenie weryfikacji nagłówków HTTP_REFERER jest rekomendowane aby zmniejszyć prawdopodobieństwo ataków CSRF, jednak przy niektórych konfiguracjach serwera może spowodować, że Menedżer EVO będzie niedostępny.'; @@ -195,11 +195,11 @@ $_lang["upgrade_note"] = 'Uwaga: Przed rozpoczęciem przeglądania swojej strony zaloguj się jako administrator do Menedżera EVO, a następnie sprawdź i zapisz konfigurację systemu.'; $_lang["upgraded"] = 'Zaktualizowano'; $_lang["validate_referer_title"] = 'Weryfikuj nagłówki HTTP_REFERER?'; -$_lang["visit_forum"] = ', visit the EVO Forums.'; +$_lang["visit_forum"] = ', odwiedź Forum EVO.'; $_lang["warning"] = 'UWAGA!'; $_lang["welcome_message_start"] = 'Najpierw wybierz typ instalacji: '; $_lang["welcome_message_text"] = 'Ten kreator przeprowadzi Cię przez proces instalacji.'; -$_lang["welcome_message_welcome"] = 'Welcome to the EVO installation program.'; +$_lang["welcome_message_welcome"] = 'Witamy w instalatorze EVO.'; $_lang["writing_config_file"] = 'Zapisywanie pliku konfiguracyjnego: '; $_lang["yes"] = 'Tak'; $_lang["you_running_php"] = '- włączone PHP'; diff --git a/install/lang/russian-UTF8.inc.php b/install/lang/russian-UTF8.inc.php index 91b0161174..4802e134a7 100755 --- a/install/lang/russian-UTF8.inc.php +++ b/install/lang/russian-UTF8.inc.php @@ -6,8 +6,8 @@ * @author Safronovich Victor * @author Rudnykh Vitalii * @author Russian EVO Community - * @version 1.5.0 - * @date 2018/02/23 + * @version 1.4.5 + * @date 2018/10/31 * * @language Russian * @package modx @@ -38,6 +38,8 @@ $_lang["cant_write_config_file"] = 'Программа установки не смогла записать файл конфигурации. Скопируйте вышеперечисленное в файл '; $_lang["cant_write_config_file_note"] = 'Как только вы это сделаете, вы можете войти в панель управления, перейдя в браузере по адресу Адрес_Вашего_Сайта/[+MGR_DIR+]/.'; $_lang["checkbox_select_options"] = 'Параметры выбора флажков:'; +$_lang["checking_iconv"] = 'Проверка доступности iconv: '; +$_lang["checking_iconv_note"] = 'Необходимо установить/включить расширение iconv. Пожалуйста, обратитесь к администратору сервера, чтобы сделать это.'; $_lang["checking_if_cache_exist"] = 'Проверка существования папок /assets/cache и /assets/cache/rss: '; $_lang["checking_if_cache_file_writable"] = 'Проверка возможности записи в файл /assets/cache/siteCache.idx.php: '; $_lang["checking_if_cache_file2_writable"] = 'Проверка возможности записи в файл /assets/cache/sitePublishing.idx.php: '; @@ -136,11 +138,14 @@ $_lang["please_correct_errors"] = '. Исправьте эти ошибки'; $_lang["plugins"] = 'Плагины'; $_lang["preinstall_validation"] = 'Проверка перед установкой'; +$_lang["recommend_collation"] = 'utf8_general_ci'; +$_lang["recommend_collations_order"] = 'utf8mb4_unicode_ci,utf8mb4_general_ci,utf8_unicode_ci,utf8_general_ci,utf8mb4_bin,utf8_bin,utf8mb4_unicode_520_ci,utf8_unicode_520_ci,utf8_general_mysql500_ci'; $_lang["recommend_setting_change_title"] = 'Рекомендуемое изменение настройки'; $_lang["recommend_setting_change_validate_referer_confirmation"] = 'Изменить установку: Проверять заголовки HTTP_REFERER?'; $_lang["recommend_setting_change_validate_referer_description"] = 'Ваш сайт не настроен на проверку серверных заголовков HTTP_REFERER во входящих запросах в систему управления. Мы настоятельно рекомендуем включить этот параметр, чтобы снизить риск CSRF (Cross Site Request Forgery - подделка межсайтовых запросов) атак.'; $_lang["remove_install_folder_auto"] = 'Удалить папку и файлы программы установки с моего сайта
         (Для выполнения этой операции необходимы права на запись в папку install).'; $_lang["remove_install_folder_manual"] = 'Пожалуйста, удалите папку "install" прежде чем войти в панель управления.'; +$_lang["resetting_database"] = 'Обновить базу данных демо-сайта: '; $_lang["retry"] = 'Повторить'; $_lang["running_database_updates"] = 'Обновление базы данных: '; $_lang["sample_web_site"] = 'Пример веб-сайта'; @@ -202,4 +207,3 @@ $_lang["writing_config_file"] = 'Запись конфигурационного файла: '; $_lang["yes"] = 'Да'; $_lang["you_running_php"] = ' - вы используете PHP '; -?> \ No newline at end of file diff --git a/install/lang/spanish-utf8.inc.php b/install/lang/spanish-utf8.inc.php index 94fc6cbab2..d158c8b1ca 100755 --- a/install/lang/spanish-utf8.inc.php +++ b/install/lang/spanish-utf8.inc.php @@ -1,13 +1,13 @@ assets/cache existe: '; +$_lang["checking_iconv"] = 'Checking if extension iconv is available: '; +$_lang["checking_iconv_note"] = 'It is important to install/enable extension iconv. Please speak to your host if you don´t know how to enable it.'; $_lang["checking_if_cache_file_writable"] = 'Comprobando que el archivo assets/cache/siteCache.idx.php es escribible: '; $_lang["checking_if_cache_file2_writable"] = 'Comprobando que el archivo assets/cache/sitePublishing.idx.php es escribible: '; $_lang["checking_if_cache_writable"] = 'Comprobando que el directorio assets/cache es escribible: '; @@ -47,7 +49,7 @@ $_lang["checking_mysql_version"] = 'Checando la versión de MySQL: '; $_lang["checking_php_version"] = 'Checando la versión de PHP: '; $_lang["checking_registerglobals"] = 'Checando si Register_Globals está deshabilitado (off): '; -$_lang["checking_registerglobals_note"] = 'Esta configuración hace tu sitio mucho más propenso a ataques de programas (Cross Site Scripting - XSS). Deberías hablar con tu proveedor de hospedaje para deshabilitar esta configuración, normalmente de una de estas tres maneras: modificando el archivo php.ini global, añadiendo reglas al archivo .htaccess en la raíz de tu instalación de MODX o añadiendo archivos personalizados de php.ini en cada directorio de tu instalación (y hay muchos de ellos). Todavía podrás instalar MODX, pero considérate advertido.'; +$_lang["checking_registerglobals_note"] = 'Esta configuración hace tu sitio mucho más propenso a ataques de programas (Cross Site Scripting - XSS). Deberías hablar con tu proveedor de hospedaje para deshabilitar esta configuración, normalmente de una de estas tres maneras: modificando el archivo php.ini global, añadiendo reglas al archivo .htaccess en la raíz de tu instalación de Evo o añadiendo archivos personalizados de php.ini en cada directorio de tu instalación (y hay muchos de ellos). Todavía podrás instalar Evo, pero considérate advertido.'; $_lang["checking_sessions"] = 'Checando si las sesiones están apropiadamente configuradas: '; $_lang["checking_table_prefix"] = 'Checando el prefijo de las tablas `'; $_lang["choose_language"] = 'Elige Lengua'; @@ -56,7 +58,7 @@ $_lang["connection_screen_collation"] = 'Compaginación:'; $_lang["connection_screen_connection_method"] = 'Método de Conexión:'; $_lang["connection_screen_database_connection_information"] = 'Información de la base de datos'; -$_lang["connection_screen_database_connection_note"] = 'Favor de escribir el nombre de la base de datos creada para MODX. Si no existe una base de datos todavía, el instalador tratará de crear una para ti. Esto puede fallar dependiendo de la configuración de MySQL o de los permisos del usuario de bases de datos para tu dominio/instalación.'; +$_lang["connection_screen_database_connection_note"] = 'Favor de escribir el nombre de la base de datos creada para Evo. Si no existe una base de datos todavía, el instalador tratará de crear una para ti. Esto puede fallar dependiendo de la configuración de MySQL o de los permisos del usuario de bases de datos para tu dominio/instalación.'; $_lang["connection_screen_database_host"] = 'Servidor de base de datos:'; $_lang["connection_screen_database_info"] = 'Información de la base de datos'; $_lang["connection_screen_database_login"] = 'Nombre de usuario de la base de datos:'; @@ -65,7 +67,7 @@ $_lang["connection_screen_database_test_connection"] = 'Haz clic aquí para crear tu base de datos o para probar la selección de tu base de datos'; $_lang["connection_screen_default_admin_email"] = 'Email del administrador:'; $_lang["connection_screen_default_admin_login"] = 'Nombre de usuario para el administrador:'; -$_lang["connection_screen_default_admin_note"] = 'Ahora necesitarás escribir algunos detalles para la cuenta principal del administrador de MODX. Puedes llenar tu nombre y una contraseña que no se te vaya a olvidar. Necesitarás esta información para entrar al administrador una vez que la configuración esté completa.'; +$_lang["connection_screen_default_admin_note"] = 'Ahora necesitarás escribir algunos detalles para la cuenta principal del administrador de Evo. Puedes llenar tu nombre y una contraseña que no se te vaya a olvidar. Necesitarás esta información para entrar al administrador una vez que la configuración esté completa.'; $_lang["connection_screen_default_admin_password"] = 'Contraseña para Administrador:'; $_lang["connection_screen_default_admin_password_confirm"] = 'Confirmar contraseña:'; $_lang["connection_screen_default_admin_user"] = 'Usuario Administrador Prefijado'; @@ -81,7 +83,7 @@ $_lang["database_use_failed"] = '¡No se pudo seleccionar la base de datos!'; $_lang["database_use_failed_note"] = 'Favor de revisar los permisos de base de datos para el usuario especificado y vuélvelo a intentar.'; $_lang["default_language"] = 'Idioma del Administrador Prefijado'; -$_lang["default_language_description"] = 'Este es el idioma prefijado que será usado en el panel de control del Administrador de MODX.'; +$_lang["default_language_description"] = 'Este es el idioma prefijado que será usado en el panel de control del Administrador de Evo.'; $_lang["depedency_create"] = 'Dependencia creada'; $_lang["depedency_update"] = 'Dependencia actualizada'; $_lang["during_execution_of_sql"] = ' durante la ejecución del comando SQL '; @@ -92,8 +94,8 @@ $_lang["guid_set"] = 'Ajuste del GUID'; $_lang["help"] = '!Ayuda!'; $_lang["help_link"] = 'http://forums.modx.com/'; -$_lang["help_title"] = 'Asistencia para la instalación en los foros de MODX'; -$_lang["iagree_box"] = 'Estoy de acuerdo con los términos de la licencia de MODX. Para las traducciones de la licencia GPL version 2, por favor visitar el sitio del Sistema Operativo GNU.'; +$_lang["help_title"] = 'Asistencia para la instalación en los foros de Evo'; +$_lang["iagree_box"] = 'Estoy de acuerdo con los términos de la licencia de Evo. Para las traducciones de la licencia GPL version 2, por favor visitar el sitio del Sistema Operativo GNU.'; $_lang["install"] = 'Instalar'; $_lang["install_overwrite"] = 'Instalar/Sobrescribir'; $_lang["install_results"] = 'Resultados de Instalación'; @@ -103,7 +105,7 @@ $_lang["installation_install_new_note"] = 'Favor de notar que esta opción puede sobreescribir cualquier dato en tu base de datos.'; $_lang["installation_mode"] = 'Modo de Instalación'; $_lang["installation_new_installation"] = 'Instalación Nueva'; -$_lang["installation_note"] = 'Nota: Después de entrar al sistema de administración de MODX, debes de editar y guardar las configuraciones del sistema antes de navegar por el sitio al ir a Herramientas -> Configuración del Sistema en el administrador de MODX.'; +$_lang["installation_note"] = 'Nota: Después de entrar al sistema de administración de Evo, debes de editar y guardar las configuraciones del sistema antes de navegar por el sitio al ir a Herramientas -> Configuración del Sistema en el administrador de Evo.'; $_lang["installation_successful"] = '¡La instalación fue exitosa!'; $_lang["installation_upgrade_advanced"] = 'Actualización Avanzada'; $_lang["installation_upgrade_advanced_note"] = 'Para administradores avanzados de base de datos o para cambiar a servidores con una conexión de base de datos con un conjunto de caracteres diferente. Necesitarás saber el nombre completo de tu base de datos, su usuario, contraseña, y detalles de su conexión y compaginación.'; @@ -114,10 +116,10 @@ $_lang["language_code"] = 'es'; $_lang["loading"] = 'Cargando...'; $_lang["modules"] = 'Módulos'; -$_lang["modx_footer1"] = '© 2005-[+current_year+] del proyecto de MODX Content Management Framework (CMF). Todos los derechos reservados. MODX tiene licencia GPL de GNU.'; -$_lang["modx_footer2"] = 'MODX es software gratuito. Te invitamos a ser creativo y usarlo de cualquier manera que se te antoje. Sólo asegura que si haces cambios y decides distribuir una versión modificada de MODX que el código fuente siga siendo gratis.'; -$_lang["modx_install"] = 'MODX » Instalar'; -$_lang["modx_requires_php"] = ', y MODX requiere de PHP versión [+min_version+] o mayor'; +$_lang["modx_footer1"] = '© 2005-[+current_year+] del proyecto de Evo Content Management Framework (CMF). Todos los derechos reservados. Evo tiene licencia GPL de GNU.'; +$_lang["modx_footer2"] = 'Evo es software gratuito. Te invitamos a ser creativo y usarlo de cualquier manera que se te antoje. Sólo asegura que si haces cambios y decides distribuir una versión modificada de Evo que el código fuente siga siendo gratis.'; +$_lang["modx_install"] = 'Evo » Instalar'; +$_lang["modx_requires_php"] = ', y Evo requiere de PHP versión [+min_version+] o mayor'; $_lang["mysql_5051"] = ' la versión del servidor de MySQL es 5.0.51!'; $_lang["mysql_5051_warning"] = 'Se sabe de algunos problemas con MySQL 5.0.51. Es recomendado que actualices antes de continuar.'; $_lang["mysql_version_is"] = ' Tu versión de MySQL es: '; @@ -127,16 +129,19 @@ $_lang["ok"] = 'OK'; $_lang["optional_items"] = 'Opciones adicionales'; $_lang["optional_items_note"] = 'Escoge tus opciones de instalación y haz clic en Instalar:'; -$_lang["php_security_notice"] = 'Aviso de Seguridad

        Aunque MODX puede funcionar con esta versión de PHP, no lo recomendamos. Tu versión de PHP es vulnerable a numerosos problemas de seguridad. Por favor actualiza a la versión PHP 4.3.8 o mayor, la cual resuelve estos problemas. Se recomienda que actualices a esta versión para la seguridad de tu propio sitio de internet.

        '; +$_lang["php_security_notice"] = 'Aviso de Seguridad

        Aunque Evo puede funcionar con esta versión de PHP, no lo recomendamos. Tu versión de PHP es vulnerable a numerosos problemas de seguridad. Por favor actualiza a la versión PHP 4.3.8 o mayor, la cual resuelve estos problemas. Se recomienda que actualices a esta versión para la seguridad de tu propio sitio de internet.

        '; $_lang["please_correct_error"] = '. Favor de corregir el error'; $_lang["please_correct_errors"] = '. Favor de corregir los errores'; $_lang["plugins"] = 'Plugins'; $_lang["preinstall_validation"] = 'Validación previa a la instalación'; +$_lang["recommend_collation"] = 'utf8_general_ci'; +$_lang["recommend_collations_order"] = 'utf8mb4_unicode_ci,utf8mb4_general_ci,utf8_unicode_ci,utf8_general_ci,utf8mb4_bin,utf8_bin,utf8mb4_unicode_520_ci,utf8_unicode_520_ci,utf8_general_mysql500_ci'; $_lang["recommend_setting_change_title"] = 'Se Recomienda cambiar configuración'; $_lang["recommend_setting_change_validate_referer_confirmation"] = 'Cambiar configuración: ¿ Validar cabeceras HTTP_REFERER ?'; $_lang["recommend_setting_change_validate_referer_description"] = 'Su sitio web no está configurado para validar las peticiones entrantes HTTP_REFERER al Manager. Recomendamos habilitar esta configuración para reducir el riesgo de un ataque CSRF (Falsificación de petición en sitios cruzados).'; $_lang["remove_install_folder_auto"] = 'Borrar la carpeta de instalación y sus archivos de mi sitio de internet
         (Esta operación requiere los permisos correctos para borrar la carpeta).'; $_lang["remove_install_folder_manual"] = 'Por favor recuerda borrar la carpeta "install" antes de entrar al sistema de administración.'; +$_lang["resetting_database"] = 'Resetting database for demo-site: '; $_lang["retry"] = 'Volver a Intentar'; $_lang["running_database_updates"] = 'Actualizando la base de datos: '; $_lang["sample_web_site"] = 'Sitio de Muestra'; @@ -144,7 +149,7 @@ $_lang["session_problem"] = 'Un problema fue detectado con tus sesiones de servidor. Por favor consulta con tu admin de servidor para corregir este problema.'; $_lang["session_problem_try_again"] = '¿Intentar nuevamente?'; $_lang["setup_cannot_continue"] = 'Desafortunadamente, el configurador no puede continuar en este momento, debido a lo anterior '; -$_lang["setup_couldnt_install"] = 'El configurador de MODX no pudo instalar/alterar algunas tablas dentro de la base de datos seleccionada.'; +$_lang["setup_couldnt_install"] = 'El configurador de Evo no pudo instalar/alterar algunas tablas dentro de la base de datos seleccionada.'; $_lang["setup_database"] = 'El configurador intentará ahora configurar la base de datos:
        '; $_lang["setup_database_create_connection"] = 'Creando una conexión a la base de datos: '; $_lang["setup_database_create_connection_failed"] = '¡La conexión a la base de datos falló!'; @@ -170,17 +175,16 @@ $_lang["status_passed_database_created"] = 'pasó - base de datos creada'; $_lang["status_passed_server"] = 'pasó - compaginaciones ahora disponibles'; $_lang["strict_mode"] = ' !El modo sql_mode estricto del servidor MySQL está habilitado!'; -$_lang["strict_mode_error"] = 'Algunas características de MODX pueden no trabajar apropiadamente a no se de que el modo STRICT_TRANS_TABLES sql_mode esté habilitado. Puedes configurar el modo de MySQL al editar el archivo my.cnf o contactar al administrador de tu servidor.'; +$_lang["strict_mode_error"] = 'Algunas características de Evo pueden no trabajar apropiadamente a no se de que el modo STRICT_TRANS_TABLES sql_mode esté habilitado. Puedes configurar el modo de MySQL al editar el archivo my.cnf o contactar al administrador de tu servidor.'; $_lang["summary_setup_check"] = 'El configurador ha revisado varios elementos para ver si todo está listo para comenzar la configuración.'; $_lang["system_configuration"] = 'Configuración de sistema'; -$_lang["system_configuration_validate_referer_description"] = 'Es recomendable configurar la Validación de Cabeceras HTTP_REFERER para proteger su sitio contra ataques CSRF, pero en algunos servidores esta opción puede ser inaccesible. -'; +$_lang["system_configuration_validate_referer_description"] = 'Es recomendable configurar la Validación de Cabeceras HTTP_REFERER para proteger su sitio contra ataques CSRF, pero en algunos servidores esta opción puede ser inaccesible.'; $_lang["table_prefix_already_inuse"] = ' - ¡Este prefijo ya se está usando en esta base de datos!'; $_lang["table_prefix_already_inuse_note"] = 'El configurador no puede instalar en la base de datos seleccionada, ya contiene tablas con el prefijo que especificaste. Por favor escoge un nuevo prefijo para tablas y corre el configurador otra vez.'; $_lang["table_prefix_not_exist"] = ' - ¡Este prefijo no existe en esta base de datos!'; $_lang["table_prefix_not_exist_note"] = 'El configurador no pudo instalar en la base de datos seleccionada, no contiene tablas existentes con el prefijo que especificaste para ser actualizadas. Por favor escoge un prefijo de tablas existente y corre el configurador otra vez.'; $_lang["templates"] = 'Templates'; -$_lang["to_log_into_content_manager"] = 'Para entrar al sistema de administración de MODX ([+MGR_DIR+]/index.php) dando clic en el botón de `Cerrar`.'; +$_lang["to_log_into_content_manager"] = 'Para entrar al sistema de administración de Evo ([+MGR_DIR+]/index.php) dando clic en el botón de `Cerrar`.'; $_lang["toggle"] = 'Invertir'; $_lang['tvs'] = 'Template Variables'; $_lang["unable_install_chunk"] = 'No se pudo instalar el chunk. Archivo'; @@ -191,11 +195,11 @@ $_lang["upgrade_note"] = 'Nota: Antes de navegar por tu sitio debes de entrar al admin con una cuenta de administrador, revisar y guardar tus configuraciones del Sistema.'; $_lang["upgraded"] = 'Actualizado'; $_lang["validate_referer_title"] = 'Validar encabezados HTTP_REFERER?'; -$_lang["visit_forum"] = 'visita los Foros de MODX.'; +$_lang["visit_forum"] = 'visita los Foros de Evo.'; $_lang["warning"] = '!ADVERTENCIA!'; $_lang["welcome_message_start"] = 'Primero, elige el tipo de instalación a efectuarse:'; $_lang["welcome_message_text"] = 'Este programa te guiará por el resto de la instalación.'; -$_lang["welcome_message_welcome"] = 'Bienvenido al programa de instalación de MODX.'; +$_lang["welcome_message_welcome"] = 'Bienvenido al programa de instalación de Evo.'; $_lang["writing_config_file"] = 'Escribiendo el archivo de configuración: '; $_lang["yes"] = 'Si'; $_lang["you_running_php"] = ' - Estás operando con PHP '; diff --git a/install/setup.data.sql b/install/setup.data.sql index 1b50219ed0..fe2cb4f4f4 100755 --- a/install/setup.data.sql +++ b/install/setup.data.sql @@ -18,7 +18,7 @@ REPLACE INTO `{PREFIX}site_content` VALUES ('1','document','text/html','Home','W REPLACE INTO `{PREFIX}site_content` VALUES ('2','document','text/html','Blog','My Blog','','blog','','1','0','0','0','1','','[[DocLister? \n &jotcount=`1`\n &parents=`2` \n &display=`2`\n &tvPrefix=``\n &tvList=`image`\n &prepare=`prepareBlog`\n &summary=`notags,len:350` \n &tpl=`@CODE:\n
        \n [+blog-image+] \n

        [+e.title+]

        \n
        \n By [+author+] on [+date+].\n Comments [+jotcount+]\n
        \n [+summary+]\n

        [+link+]

        \n
        ` \n &paginate=`1` \n]]\n\n

        Showing [+current+] of [+totalPages+] Pages

        \n
        [+pages+]
        \n

         

        ','0','4','1','0','1','1','1144904400','1','1507727477','0','0','0','0','0','Blog','0','0','0','0','0','1'); -REPLACE INTO `{PREFIX}site_content` VALUES ('4','document','text/html','Profile','User profile','','profile','','1','0','0','0','1','','[!FormLister?\n&debug=`1`\n&formid=`login`\n&controller=`Login`\n&loginField=`email`\n&redirectTo=`49`\n&defaults=`{\"rememberme\":1}`\n&rules=`{\n \"email\":{\n \"required\":\"Enter your Email\"\n },\n \"password\":{\n \"required\":\"Enter your password\"\n }\n}`\n&formTpl=`@CODE:\n\n

        In order to comment on blog entries, you must be a registered user of [(site_name)]. If you haven\'t already registered, you can request an account.

        \n\n
        \n [+form.messages+]\n \n
        \n
        \n \n \n
        \n
        \n
        \n
        \n \n \n
        \n
        \n\n
        \n \n
        \n \n
        \n
        \n
        \n`\n&skipTpl=`@CODE:\n
        Hello!
        \n `\n\n&allowedFields=`email,password`\n&errorTpl=`@CODE:

        [+message+]

        `\n&messagesOuterTpl=`@CODE:\n
        [+messages+]
        `\n\n&errorClass=` has-error` \n&requiredClass=` has-warning`\n!] \n','0','4','6','0','1','1','1144904400','1','1509817775','0','0','0','0','0','','0','0','0','0','0','0'); +REPLACE INTO `{PREFIX}site_content` VALUES ('4','document','text/html','Profile','User profile','','profile','','1','0','0','0','1','','[!FormLister?\n&formid=`login`\n&controller=`Login`\n&loginField=`email`\n&redirectTo=`49`\n&defaults=`{\"rememberme\":1}`\n&formControls=`rememberme`\n&rules=`{\n \"email\":{\n \"required\":\"Enter your Email\",\n \"email\":\"You should enter correct Email\"\n },\n \"password\":{\n \"required\":\"Enter your password\"\n }\n}`\n&formTpl=`@CODE:\n\n

        In order to comment on blog entries, you must be a registered user of [(site_name)]. If you haven\'t already registered, you can request an account.

        \n\n
        \n [+form.messages+]\n \n
        \n
        \n \n \n
        \n
        \n
        \n
        \n \n \n
        \n
        \n
        \n
        \n
        \n \n
        \n
        \n
        \n
        \n \n
        \n \n
        \n
        \n \n
        \n`\n&skipTpl=`@CODE:\n
        Hello!
        \n `\n&errorTpl=`@CODE:

        [+message+]

        `\n&messagesOuterTpl=`@CODE:\n
        [+messages+]
        `\n&errorClass=` has-error` \n&requiredClass=` has-warning`\n!]','0','4','6','0','1','1','1144904400','1','1533412259','0','0','0','0','0','','0','0','0','0','0','0'); REPLACE INTO `{PREFIX}site_content` VALUES ('5','document','text/html','Request an Account','Sign Up for Full Site Privileges','','request-an-account','','1','0','0','4','0','',' [!FormLister?\n &formid=`registerForm`\n &controller=`Register`\n &requiredClass=`has-warning`\n &errorClass=`has-error`\n &errorTpl=`@CODE:[+message+]`\n &allowedFields=`email,username,fullname,country`\n &rules=`{\n \"username\":{\n \"required\":\"Enter your username\",\n \"alphaNumeric\":\"Only letters and numbers\",\n \"custom\":{\n \"function\":\"\\\\FormLister\\\\Register::uniqueUsername\",\n \"message\":\"Name already taken\"\n }\n },\n \"email\":{\n \"required\":\"Enter email\",\n \"email\":\"Incorrect email\",\n \"custom\":{\n \"function\":\"\\\\FormLister\\\\Register::uniqueEmail\",\n \"message\":\"This email is already in use by another user\"\n }\n },\n \"password\":{\n \"required\":\"Enter password\"\n },\n \"repeatPassword\":{\n \"required\":\"Retype password\",\n \"equals\":{\n \"message\":\"Passwords do not match\"\n }\n }\n }`\n &captcha=`modxCaptcha`\n &formTpl=`@CODE: \n\n
        \n \n

        User Details

        \n
        \n \n Items marked by * are required\n
        \n \n
        \n \n \n [+username.error+]\n
        \n \n
        \n \n \n [+fullname.error+]\n
        \n \n
        \n \n \n [+email.error+]\n
        \n\n
        \n

        Password

        \n \n \n [+password.error+]\n
        \n
        \n \n \n [+repeatPassword.error+]\n
        \n \n
        \n

        Optional Account Profile Info

        \n \n \n [+country.error+]\n
        \n \n
        \n

        Bot-Patrol

        \n

        Enter the word/number combination shown in the image below.

        \n \n

        \"If

        \n \n [+vericode.error+]\n
        \n \n
        \n \n
        \n\n
        \n\n\n\n `\n &successTpl=`@CODE:\n

        Signup completed successfully!
        \n Your account was created. A copy of your signup information was sent to your email address.

        \n `\n &subject=`New registration, [(site_name)]`\n &ccSender=`1`\n &ccSenderTpl=`@CODE:\n

        [+fullname.value+], signup completed successfully!

        \n Login: [+email.value+]
        \n Password: [+user.password+]
        \n `\n !]','0','4','1','0','1','1','1144904400','1','1515584252','0','0','0','0','0','','0','0','0','0','1','1'); @@ -40,9 +40,9 @@ REPLACE INTO `{PREFIX}site_content` VALUES ('16','document','text/html','Ajax',' REPLACE INTO `{PREFIX}site_content` VALUES ('18','document','text/html','Just a pretend, older post','This post should in fact be archived','','article-1128398162','','1','0','0','2','0','','

        Not so exciting, after all, eh?

        ','1','4','2','1','1','-1','1144904400','1','1509818884','0','0','0','0','0','','0','0','0','0','1','1'); -REPLACE INTO `{PREFIX}site_content` VALUES ('22','document','text/html','Menus and Lists','Flexible Menus and Lists','','menus','','1','1159178400','0','15','0','','

        Your documents - listed how you want them

        \n

        EVO\'s document data structure has been designed to allow many different routines to redisplay the information in ways that suit your needs, such as a dynamic menu in your template.

        \n

        Since the last release of EVO, the community has produced many great snippets - reusable functions that you can call in your content or template. Two of the most widely useful are Ditto and Wayfinder.

        \n

        Wayfinder - the menu builder

        \n

        Allows you to template every part of the menu. On this site, Wayfinder is being used to generate the drop-down menus, but many types of menus and sitemaps are possible.

        \n

        Ditto - the document lister

        \n

        Uses include listing the most recent blog posts, producing a site map, listing related documents (using a TV filter) and generating an RSS feed. You could even write a menu with it. On this site, Ditto is being used for the blog posts list on the Blog page, and the list on the right of some templates.

        \n

        Unlimited Customization

        \n

        If you can\'t quite get your desired effect using templating and the many options of Ditto and Wayfinder, you can write your own routine, or look for other snippets in the EVO repository. EVO\'s fields for Menu Title, summaries, menu position etc can be used via the API to produce anything you can imagine.

        ','1','4','2','1','1','1','1144904400','1','1160148522','0','0','0','0','0','Menus and Lists','0','0','0','0','0','1'); +REPLACE INTO `{PREFIX}site_content` VALUES ('22','document','text/html','Menus and Lists','Flexible Menus and Lists','','menus','','1','1159178400','0','15','0','','

        Your documents - listed how you want them

        \n

        EVO\'s document data structure has been designed to allow many different routines to redisplay the information in ways that suit your needs, such as a dynamic menu in your template.

        \n

        Since the last release of EVO, the community has produced many great snippets - reusable functions that you can call in your content or template. Two of the most widely useful are Ditto and Wayfinder.

        \n

        Wayfinder - the menu builder

        \n

        Allows you to template every part of the menu. On this site, Wayfinder is being used to generate the drop-down menus, but many types of menus and sitemaps are possible.

        \n

        Ditto - the document lister

        \n

        Uses include listing the most recent blog posts, producing a site map, listing related documents (using a TV filter) and generating an RSS feed. You could even write a menu with it. On this site, Ditto is being used for the blog posts list on the Blog page, and the list on the right of some templates.

        \n

        Unlimited Customization

        \n

        If you can\'t quite get your desired effect using templating and the many options of Ditto and Wayfinder, you can write your own routine, or look for other snippets in the EVO repository. EVO\'s fields for Menu Title, summaries, menu position etc can be used via the API to produce anything you can imagine.

        ','1','4','2','1','1','1','1144904400','1','1160148522','0','0','0','0','0','Menus and Lists','0','0','0','0','0','1'); -REPLACE INTO `{PREFIX}site_content` VALUES ('24','document','text/html','Extendable by design','Extendable by design','','extendable','','1','1159092732','0','15','0','','

        The EVO community has created many add-ons which can be found in the Repository, from image galleries and e-commerce to smaller utilities.

        \n

        Template Variables with Bindings

        \n

        TVs - Template Variables - are powerful extra fields that you can use with your documents. As an example of an advanced template element that returns a different thing dependent on code or data, we created an @BINDING for the name of the Login menu item. This changes the menu name from Login to Logout based on your logged in state. The @BINDING as follows was placed in the default value as: @EVAL if ($modx->getLoginUserID()) return \'Logout\'; else return \'Login\';

        \n

        Using jQuery-effects

        \n

        We used some simple effects to highlight various things on the front/home page to demonstrate how easy it is to create a useful way to draw attention to things. To see them in action on the home page, click the Integrated Site Search, Related Links or Newest Documents headers.

        \n

        Custom Forms

        \n

        To demonstrate how to link to custom forms, we customized the calls to the Webuser Registration system and the Login system.

        \n

        And more

        \n

        Rich Text Editor for blog entries. To make it easier to format blog posts with simple text formatting, we modified the blog to use a custom RTE-enabled Template Variable (TV).

        \n

        Smart-Summary logic. When splitting the full blog/news posts you simply insert a \"<!-- splitter -->\" where you want the break to occur. In addition, if that leaves any important tags open, it will try to match them and close them so it doesn\'t mess up your site layout with unclosed OL, UL or DIV tags.

        ','1','4','4','1','1','2','1144904400','1','1159309971','0','0','0','0','0','Extendability','0','0','0','0','0','1'); +REPLACE INTO `{PREFIX}site_content` VALUES ('24','document','text/html','Extendable by design','Extendable by design','','extendable','','1','1159092732','0','15','0','','

        The EVO community has created many add-ons which can be found in the Repository, from image galleries and e-commerce to smaller utilities.

        \n

        Template Variables with Bindings

        \n

        TVs - Template Variables - are powerful extra fields that you can use with your documents. As an example of an advanced template element that returns a different thing dependent on code or data, we created an @BINDING for the name of the Login menu item. This changes the menu name from Login to Logout based on your logged in state. The @BINDING as follows was placed in the default value as: @EVAL if ($modx->getLoginUserID()) return \'Logout\'; else return \'Login\';

        \n

        Using jQuery-effects

        \n

        We used some simple effects to highlight various things on the front/home page to demonstrate how easy it is to create a useful way to draw attention to things. To see them in action on the home page, click the Integrated Site Search, Related Links or Newest Documents headers.

        \n

        Custom Forms

        \n

        To demonstrate how to link to custom forms, we customized the calls to the Webuser Registration system and the Login system.

        \n

        And more

        \n

        Rich Text Editor for blog entries. To make it easier to format blog posts with simple text formatting, we modified the blog to use a custom RTE-enabled Template Variable (TV).

        \n

        Smart-Summary logic. When splitting the full blog/news posts you simply insert a \"<!-- splitter -->\" where you want the break to occur. In addition, if that leaves any important tags open, it will try to match them and close them so it doesn\'t mess up your site layout with unclosed OL, UL or DIV tags.

        ','1','4','4','1','1','2','1144904400','1','1159309971','0','0','0','0','0','Extendability','0','0','0','0','0','1'); REPLACE INTO `{PREFIX}site_content` VALUES ('32','document','text/html','Design','Site Design','','design','','1','0','0','0','0','','

        Credits

        \n

        The EVO Starter-theme is based on Bootstrap 3.3.6 and made by graffx.nl and fuseit.de.

        ','1','4','4','1','1','2','1144904400','1','1160112322','0','0','0','1144912754','1','Design','0','0','0','0','0','1'); @@ -170,7 +170,7 @@ REPLACE INTO `{PREFIX}webgroup_names` VALUES ('2','Registered Users'); # -CREATE TABLE IF NOT EXISTS `{PREFIX}jot_content` (`id` int(10) NOT NULL auto_increment, `title` varchar(255) default NULL, `tagid` varchar(50) default NULL, `published` int(1) NOT NULL default '0', `uparent` int(10) NOT NULL default '0', `parent` int(10) NOT NULL default '0', `flags` varchar(25) default NULL, `secip` varchar(32) default NULL, `sechash` varchar(32) default NULL, `content` mediumtext, `customfields` mediumtext, `mode` int(1) NOT NULL default '1', `createdby` int(10) NOT NULL default '0', `createdon` int(20) NOT NULL default '0', `editedby` int(10) NOT NULL default '0', `editedon` int(20) NOT NULL default '0', `deleted` int(1) NOT NULL default '0', `deletedon` int(20) NOT NULL default '0', `deletedby` int(10) NOT NULL default '0', `publishedon` int(20) NOT NULL default '0', `publishedby` int(10) NOT NULL default '0', PRIMARY KEY (`id`), KEY `parent` (`parent`), KEY `secip` (`secip`), KEY `tagidx` (`tagid`), KEY `uparent` (`uparent`)) ENGINE=MyISAM; +CREATE TABLE IF NOT EXISTS `{PREFIX}jot_content` (`id` int(10) NOT NULL auto_increment, `title` varchar(255) default NULL, `tagid` varchar(50) default NULL, `published` int(1) NOT NULL default '0', `uparent` int(10) NOT NULL default '0', `parent` int(10) NOT NULL default '0', `flags` varchar(25) default NULL, `secip` varchar(32) default NULL, `sechash` varchar(32) default NULL, `content` mediumtext, `customfields` mediumtext, `mode` int(1) NOT NULL default '1', `createdby` int(10) NOT NULL default '0', `createdon` int(20) NOT NULL default '0', `editedby` int(10) NOT NULL default '0', `editedon` int(20) NOT NULL default '0', `deleted` int(1) NOT NULL default '0', `deletedon` int(20) NOT NULL default '0', `deletedby` int(10) NOT NULL default '0', `publishedon` int(20) NOT NULL default '0', `publishedby` int(10) NOT NULL default '0', PRIMARY KEY (`id`), KEY `parent` (`parent`), KEY `secip` (`secip`), KEY `tagidx` (`tagid`), KEY `uparent` (`uparent`)) ENGINE=MyISAM {TABLEENCODING}; # @@ -204,5 +204,5 @@ REPLACE INTO `{PREFIX}jot_content` VALUES ('15','I\'m untrusted','','0','9','0', # -CREATE TABLE IF NOT EXISTS `{PREFIX}jot_subscriptions` (`id` mediumint(10) NOT NULL auto_increment, `uparent` mediumint(10) NOT NULL default '0', `tagid` varchar(50) NOT NULL default '', `userid` mediumint(10) NOT NULL default '0', PRIMARY KEY (`id`), KEY `uparent` (`uparent`), KEY `tagid` (`tagid`), KEY `userid` (`userid`)) ENGINE=MyISAM; +CREATE TABLE IF NOT EXISTS `{PREFIX}jot_subscriptions` (`id` mediumint(10) NOT NULL auto_increment, `uparent` mediumint(10) NOT NULL default '0', `tagid` varchar(50) NOT NULL default '', `userid` mediumint(10) NOT NULL default '0', PRIMARY KEY (`id`), KEY `uparent` (`uparent`), KEY `tagid` (`tagid`), KEY `userid` (`userid`)) ENGINE=MyISAM {TABLEENCODING}; diff --git a/install/setup.info.php b/install/setup.info.php index 6b72ab72bf..89b06f11af 100755 --- a/install/setup.info.php +++ b/install/setup.info.php @@ -62,7 +62,7 @@ $params['output_widget'], $params['output_widget_params'], "$templatePath/{$params['filename']}", /* not currently used */ - $params['template_assignments']!="*"?$params['template_assignments']:implode(",",array_map(create_function('$v','return $v[0];'),$mt)), /* comma-separated list of template names */ + $params['template_assignments']!="*"?$params['template_assignments']:implode(",",array_map(function($value){return isset($value[0]) && is_scalar($value[0]);},$mt)), /* comma-separated list of template names */ $params['modx_category'], $params['lock_tv'], /* value should be 1 or 0 */ array_key_exists('installset', $params) ? preg_split("/\s*,\s*/", $params['installset']) : false diff --git a/install/setup.sql b/install/setup.sql index bae0c3cb95..c8429ead75 100755 --- a/install/setup.sql +++ b/install/setup.sql @@ -1,7 +1,7 @@ # EVO Database Script for New/Upgrade Installations -# EVO was created By Raymond Irving - Nov 2004 +# EVO was created By Raymond Irving - Nov 2004 # -# Each sql command is separated by double lines \n\n +# Each sql command is separated by double lines \n\n DROP TABLE IF EXISTS `{PREFIX}active_users`; @@ -13,8 +13,8 @@ CREATE TABLE `{PREFIX}active_users` ( `lasthit` int(20) NOT NULL default '0', `action` varchar(10) NOT NULL default '', `id` int(10) default NULL, - PRIMARY KEY (`sid`) -) ENGINE=MyISAM COMMENT='Contains data about last user action.'; + PRIMARY KEY (`sid`, `username`) +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data about last user action.'; DROP TABLE IF EXISTS `{PREFIX}active_user_locks`; @@ -27,7 +27,7 @@ CREATE TABLE `{PREFIX}active_user_locks` ( `lasthit` int(20) NOT NULL default '0', PRIMARY KEY(`id`), UNIQUE INDEX ix_element_id (`elementType`,`elementId`,`sid`) -) ENGINE=MyISAM COMMENT='Contains data about locked elements.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data about locked elements.'; DROP TABLE IF EXISTS `{PREFIX}active_user_sessions`; @@ -37,14 +37,14 @@ CREATE TABLE `{PREFIX}active_user_sessions` ( `lasthit` int(20) NOT NULL default '0', `ip` varchar(50) NOT NULL default '', PRIMARY KEY(`sid`) -) ENGINE=MyISAM COMMENT='Contains data about valid user sessions.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data about valid user sessions.'; CREATE TABLE IF NOT EXISTS `{PREFIX}categories` ( `id` integer NOT NULL AUTO_INCREMENT, `category` varchar(45) NOT NULL DEFAULT '', `rank` INT(5) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY(`id`) -) ENGINE=MyISAM COMMENT='Categories to be used snippets,tv,chunks, etc'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Categories to be used snippets,tv,chunks, etc'; CREATE TABLE IF NOT EXISTS `{PREFIX}document_groups` ( `id` int(10) NOT NULL auto_increment, @@ -54,7 +54,7 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}document_groups` ( KEY `document` (`document`), KEY `document_group` (`document_group`), UNIQUE INDEX `ix_dg_id` (`document_group`,`document`) -) ENGINE=MyISAM COMMENT='Contains data used for access permissions.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data used for access permissions.'; CREATE TABLE IF NOT EXISTS `{PREFIX}documentgroup_names` ( `id` int(10) NOT NULL auto_increment, @@ -63,7 +63,7 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}documentgroup_names` ( `private_webgroup` tinyint DEFAULT 0 COMMENT 'determines whether the document is private to web users', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) -) ENGINE=MyISAM COMMENT='Contains data used for access permissions.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data used for access permissions.'; CREATE TABLE IF NOT EXISTS `{PREFIX}event_log` ( `id` integer NOT NULL AUTO_INCREMENT, @@ -76,7 +76,7 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}event_log` ( `description` text, PRIMARY KEY(`id`), KEY `user`(`user`) -) ENGINE=MyISAM COMMENT='Stores event and error logs'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Stores event and error logs'; CREATE TABLE IF NOT EXISTS `{PREFIX}manager_log` ( `id` int(10) NOT NULL auto_increment, @@ -87,10 +87,10 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}manager_log` ( `itemid` varchar(10) default '0', `itemname` varchar(255) default NULL, `message` varchar(255) NOT NULL default '', - `ip` varchar(15), + `ip` varchar(46), `useragent` varchar(255), PRIMARY KEY (`id`) -) ENGINE=MyISAM COMMENT='Contains a record of user interaction.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains a record of user interaction.'; CREATE TABLE IF NOT EXISTS `{PREFIX}manager_users` ( `id` int(10) NOT NULL auto_increment, @@ -98,7 +98,7 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}manager_users` ( `password` varchar(100) NOT NULL default '', PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) -) ENGINE=MyISAM COMMENT='Contains login information for backend users.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains login information for backend users.'; CREATE TABLE IF NOT EXISTS `{PREFIX}member_groups` ( `id` int(10) NOT NULL auto_increment, @@ -106,21 +106,21 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}member_groups` ( `member` int(10) NOT NULL default '0', PRIMARY KEY (`id`), UNIQUE INDEX `ix_group_member` (`user_group`,`member`) -) ENGINE=MyISAM COMMENT='Contains data used for access permissions.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data used for access permissions.'; CREATE TABLE IF NOT EXISTS `{PREFIX}membergroup_access` ( `id` int(10) NOT NULL auto_increment, `membergroup` int(10) NOT NULL default '0', `documentgroup` int(10) NOT NULL default '0', PRIMARY KEY (`id`) -) ENGINE=MyISAM COMMENT='Contains data used for access permissions.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data used for access permissions.'; CREATE TABLE IF NOT EXISTS `{PREFIX}membergroup_names` ( `id` int(10) NOT NULL auto_increment, `name` varchar(245) NOT NULL default '', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) -) ENGINE=MyISAM COMMENT='Contains data used for access permissions.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data used for access permissions.'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_content` ( `id` int(10) NOT NULL auto_increment, @@ -136,7 +136,7 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}site_content` ( `unpub_date` int(20) NOT NULL default '0', `parent` int(10) NOT NULL default '0', `isfolder` int(1) NOT NULL default '0', - `introtext` text COMMENT 'Used to provide quick summary of the document', + `introtext` text COMMENT 'Used to provide quick summary of the document', `content` mediumtext, `richtext` tinyint(1) NOT NULL default '1', `template` int(10) NOT NULL default '0', @@ -165,7 +165,7 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}site_content` ( KEY aliasidx (`alias`), KEY typeidx (`type`), FULLTEXT KEY `content_ft_idx` (`pagetitle`,`description`,`content`) -) ENGINE=MyISAM COMMENT='Contains the site document tree.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains the site document tree.'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_htmlsnippets` ( @@ -178,11 +178,11 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}site_htmlsnippets` ( `cache_type` tinyint(1) NOT NULL default '0' COMMENT 'Cache option', `snippet` mediumtext, `locked` tinyint(4) NOT NULL default '0', - `createdon` integer NOT NULL DEFAULT '0', + `createdon` integer NOT NULL DEFAULT '0', `editedon` integer NOT NULL DEFAULT '0', `disabled` tinyint NOT NULL DEFAULT '0' COMMENT 'Disables the snippet', PRIMARY KEY (`id`) -) ENGINE=MyISAM COMMENT='Contains the site chunks.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains the site chunks.'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_modules` ( `id` integer NOT NULL AUTO_INCREMENT, @@ -196,14 +196,14 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}site_modules` ( `icon` varchar(255) NOT NULL DEFAULT '' COMMENT 'url to module icon', `enable_resource` tinyint NOT NULL DEFAULT '0' COMMENT 'enables the resource file feature', `resourcefile` varchar(255) NOT NULL DEFAULT '' COMMENT 'a physical link to a resource file', - `createdon` integer NOT NULL DEFAULT '0', + `createdon` integer NOT NULL DEFAULT '0', `editedon` integer NOT NULL DEFAULT '0', `guid` varchar(32) NOT NULL DEFAULT '' COMMENT 'globally unique identifier', `enable_sharedparams` tinyint NOT NULL DEFAULT '0', `properties` text, `modulecode` mediumtext COMMENT 'module boot up code', PRIMARY KEY(`id`) -) ENGINE=MyISAM COMMENT='Site Modules'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Site Modules'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_module_depobj` ( `id` integer NOT NULL AUTO_INCREMENT, @@ -211,14 +211,14 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}site_module_depobj` ( `resource` integer NOT NULL DEFAULT 0, `type` integer(2) NOT NULL DEFAULT 0 COMMENT '10-chunks, 20-docs, 30-plugins, 40-snips, 50-tpls, 60-tvs', PRIMARY KEY(`id`) -) ENGINE=MyISAM COMMENT='Module Dependencies'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Module Dependencies'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_module_access` ( `id` integer UNSIGNED NOT NULL AUTO_INCREMENT, `module` integer NOT NULL DEFAULT 0, `usergroup` integer NOT NULL DEFAULT 0, PRIMARY KEY(`id`) -) ENGINE=MyISAM COMMENT='Module users group access permission'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Module users group access permission'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_plugins` ( `id` int(10) NOT NULL auto_increment, @@ -229,20 +229,20 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}site_plugins` ( `cache_type` tinyint(1) NOT NULL default '0' COMMENT 'Cache option', `plugincode` mediumtext, `locked` tinyint(4) NOT NULL default '0', - `properties` text COMMENT 'Default Properties', + `properties` text COMMENT 'Default Properties', `disabled` tinyint NOT NULL DEFAULT '0' COMMENT 'Disables the plugin', `moduleguid` varchar(32) NOT NULL default '' COMMENT 'GUID of module from which to import shared parameters', - `createdon` integer NOT NULL DEFAULT '0', + `createdon` integer NOT NULL DEFAULT '0', `editedon` integer NOT NULL DEFAULT '0', PRIMARY KEY (`id`) -) ENGINE=MyISAM COMMENT='Contains the site plugins.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains the site plugins.'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_plugin_events` ( `pluginid` INT(10) NOT NULL, `evtid` INT(10) NOT NULL default 0, `priority` INT(10) NOT NULL default 0 COMMENT 'determines plugin run order', PRIMARY KEY ( `pluginid` , `evtid` ) -) ENGINE=MyISAM COMMENT='Links to system events'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Links to system events'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_snippets` ( `id` int(10) NOT NULL auto_increment, @@ -253,13 +253,13 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}site_snippets` ( `cache_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Cache option', `snippet` mediumtext, `locked` tinyint(4) NOT NULL default '0', - `properties` text COMMENT 'Default Properties', + `properties` text COMMENT 'Default Properties', `moduleguid` varchar(32) NOT NULL default '' COMMENT 'GUID of module from which to import shared parameters', - `createdon` integer NOT NULL DEFAULT '0', + `createdon` integer NOT NULL DEFAULT '0', `editedon` integer NOT NULL DEFAULT '0', `disabled` tinyint NOT NULL DEFAULT '0' COMMENT 'Disables the snippet', PRIMARY KEY (`id`) -) ENGINE=MyISAM COMMENT='Contains the site snippets.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains the site snippets.'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_templates` ( `id` int(10) NOT NULL auto_increment, @@ -272,10 +272,10 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}site_templates` ( `content` mediumtext, `locked` tinyint(4) NOT NULL default '0', `selectable` tinyint(4) NOT NULL default '1', - `createdon` integer NOT NULL DEFAULT '0', + `createdon` integer NOT NULL DEFAULT '0', `editedon` integer NOT NULL DEFAULT '0', PRIMARY KEY (`id`) -) ENGINE=MyISAM COMMENT='Contains the site templates.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains the site templates.'; CREATE TABLE IF NOT EXISTS `{PREFIX}system_eventnames` ( `id` INT(10) NOT NULL AUTO_INCREMENT, @@ -283,20 +283,20 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}system_eventnames` ( `service` tinyint NOT NULL default '0' COMMENT 'System Service number', `groupname` varchar(20) NOT NULL default '', PRIMARY KEY(`id`) -) ENGINE=MyISAM COMMENT='System Event Names.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='System Event Names.'; CREATE TABLE IF NOT EXISTS `{PREFIX}system_settings` ( `setting_name` varchar(50) NOT NULL default '', `setting_value` text, PRIMARY KEY (`setting_name`) -) ENGINE=MyISAM COMMENT='Contains Content Manager settings.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains Content Manager settings.'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_tmplvar_access` ( `id` int(10) NOT NULL auto_increment, `tmplvarid` int(10) NOT NULL default '0', `documentgroup` int(10) NOT NULL default '0', PRIMARY KEY (`id`) -) ENGINE=MyISAM COMMENT='Contains data used for template variable access permissions.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data used for template variable access permissions.'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_tmplvar_contentvalues` ( `id` int(11) NOT NULL auto_increment, @@ -308,14 +308,14 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}site_tmplvar_contentvalues` ( KEY idx_id (contentid), FULLTEXT KEY `value_ft_idx` (`value`), UNIQUE INDEX `ix_tvid_contentid` (`tmplvarid`,`contentid`) -) ENGINE=MyISAM COMMENT='Site Template Variables Content Values Link Table'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Site Template Variables Content Values Link Table'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_tmplvar_templates` ( `tmplvarid` int(10) NOT NULL default '0' COMMENT 'Template Variable id', `templateid` int(11) NOT NULL default '0', `rank` int(11) NOT NULL default '0', PRIMARY KEY (`tmplvarid`, `templateid`) -) ENGINE=MyISAM COMMENT='Site Template Variables Templates Link Table'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Site Template Variables Templates Link Table'; CREATE TABLE IF NOT EXISTS `{PREFIX}site_tmplvars` ( `id` INT(11) NOT NULL auto_increment, @@ -331,11 +331,11 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}site_tmplvars` ( `display` varchar(20) NOT NULL default '' COMMENT 'Display Control', `display_params` text COMMENT 'Display Control Properties', `default_text` text, - `createdon` integer NOT NULL DEFAULT '0', + `createdon` integer NOT NULL DEFAULT '0', `editedon` integer NOT NULL DEFAULT '0', PRIMARY KEY (id), KEY `indx_rank`(`rank`) -) ENGINE=MyISAM COMMENT='Site Template Variables'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Site Template Variables'; CREATE TABLE IF NOT EXISTS `{PREFIX}user_attributes` ( `id` int(10) NOT NULL auto_increment, @@ -363,11 +363,11 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}user_attributes` ( `fax` varchar(100) NOT NULL default '', `photo` varchar(255) NOT NULL default '' COMMENT 'link to photo', `comment` text, - `createdon` integer NOT NULL DEFAULT '0', - `editedon` integer NOT NULL DEFAULT '0', + `createdon` integer NOT NULL DEFAULT '0', + `editedon` integer NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `userid` (`internalKey`) -) ENGINE=MyISAM COMMENT='Contains information about the backend users.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains information about the backend users.'; CREATE TABLE IF NOT EXISTS `{PREFIX}user_messages` ( `id` int(10) NOT NULL auto_increment, @@ -380,7 +380,7 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}user_messages` ( `postdate` int(20) NOT NULL default '0', `messageread` tinyint(1) NOT NULL default '0', PRIMARY KEY (`id`) -) ENGINE=MyISAM COMMENT='Contains messages for the Content Manager messaging system.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains messages for the Content Manager messaging system.'; CREATE TABLE IF NOT EXISTS `{PREFIX}user_roles` ( `id` int(10) NOT NULL auto_increment, @@ -458,7 +458,7 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}user_roles` ( `display_locks` int(1) NOT NULL default '0', `change_resourcetype` int(1) NOT NULL default '0', PRIMARY KEY (`id`) -) ENGINE=MyISAM COMMENT='Contains information describing the user roles.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains information describing the user roles.'; CREATE TABLE IF NOT EXISTS `{PREFIX}user_settings` ( `user` integer NOT NULL, @@ -467,7 +467,7 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}user_settings` ( PRIMARY KEY ( `user` , `setting_name` ), KEY `setting_name` (`setting_name`), KEY `user` (`user`) -) ENGINE=MyISAM COMMENT='Contains backend user settings.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains backend user settings.'; CREATE TABLE IF NOT EXISTS `{PREFIX}web_groups` ( `id` int(10) NOT NULL auto_increment, @@ -475,21 +475,21 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}web_groups` ( `webuser` int(10) NOT NULL default '0', PRIMARY KEY (`id`), UNIQUE INDEX `ix_group_user` (`webgroup`,`webuser`) -) ENGINE=MyISAM COMMENT='Contains data used for web access permissions.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data used for web access permissions.'; CREATE TABLE IF NOT EXISTS `{PREFIX}webgroup_access` ( `id` int(10) NOT NULL auto_increment, `webgroup` int(10) NOT NULL default '0', `documentgroup` int(10) NOT NULL default '0', PRIMARY KEY (`id`) -) ENGINE=MyISAM COMMENT='Contains data used for web access permissions.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data used for web access permissions.'; CREATE TABLE IF NOT EXISTS `{PREFIX}webgroup_names` ( `id` int(10) NOT NULL auto_increment, `name` varchar(245) NOT NULL default '', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) -) ENGINE=MyISAM COMMENT='Contains data used for web access permissions.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains data used for web access permissions.'; CREATE TABLE IF NOT EXISTS `{PREFIX}web_user_attributes` ( `id` int(10) NOT NULL auto_increment, @@ -517,11 +517,11 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}web_user_attributes` ( `fax` varchar(100) NOT NULL default '', `photo` varchar(255) NOT NULL default '' COMMENT 'link to photo', `comment` text, - `createdon` integer NOT NULL DEFAULT '0', - `editedon` integer NOT NULL DEFAULT '0', + `createdon` integer NOT NULL DEFAULT '0', + `editedon` integer NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `userid` (`internalKey`) -) ENGINE=MyISAM COMMENT='Contains information for web users.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains information for web users.'; CREATE TABLE IF NOT EXISTS `{PREFIX}web_users` ( `id` int(10) NOT NULL auto_increment, @@ -530,7 +530,7 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}web_users` ( `cachepwd` varchar(100) NOT NULL default '' COMMENT 'Store new unconfirmed password', PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) -) ENGINE=MyISAM; +) ENGINE=MyISAM {TABLEENCODING}; CREATE TABLE IF NOT EXISTS `{PREFIX}web_user_settings` ( `webuser` integer NOT NULL, @@ -539,7 +539,7 @@ CREATE TABLE IF NOT EXISTS `{PREFIX}web_user_settings` ( PRIMARY KEY ( `webuser` , `setting_name` ), KEY `setting_name` (`setting_name`), KEY `webuserid` (`webuser`) -) ENGINE=MyISAM COMMENT='Contains web user settings.'; +) ENGINE=MyISAM {TABLEENCODING} COMMENT='Contains web user settings.'; # upgrade-able[[ - This block of code will be executed during upgrades @@ -563,7 +563,7 @@ ALTER TABLE `{PREFIX}site_htmlsnippets` ADD COLUMN `editor_name` VARCHAR(50) NOT NULL DEFAULT 'none' AFTER `editor_type`; ALTER TABLE `{PREFIX}site_htmlsnippets` - ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; + ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}site_htmlsnippets` ADD COLUMN `editedon` integer NOT NULL DEFAULT '0'; @@ -581,7 +581,7 @@ ALTER TABLE `{PREFIX}site_templates` ADD COLUMN `editedon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}site_templates` - ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; + ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}site_tmplvar_templates` ADD COLUMN `rank` integer(11) NOT NULL DEFAULT '0' AFTER `templateid`; @@ -590,7 +590,7 @@ ALTER TABLE `{PREFIX}site_tmplvars` ADD COLUMN `editedon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}site_tmplvars` - ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; + ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}user_attributes` ADD COLUMN `street` varchar(255) NOT NULL DEFAULT '' AFTER `country`; @@ -602,7 +602,7 @@ ALTER TABLE `{PREFIX}user_attributes` ADD COLUMN `editedon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}user_attributes` - ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; + ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}user_roles` ADD COLUMN `edit_chunk` INT(1) NOT NULL DEFAULT '0' AFTER `delete_snippet`; @@ -662,10 +662,10 @@ ALTER TABLE `{PREFIX}web_user_attributes` ADD COLUMN `editedon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}web_user_attributes` - ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; + ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}site_snippets` - ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; + ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}site_snippets` ADD COLUMN `editedon` integer NOT NULL DEFAULT '0'; @@ -674,13 +674,13 @@ ALTER TABLE `{PREFIX}site_snippets` ADD COLUMN `disabled` tinyint NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}site_plugins` - ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; + ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}site_plugins` ADD COLUMN `editedon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}site_templates` - ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; + ADD COLUMN `createdon` integer NOT NULL DEFAULT '0'; ALTER TABLE `{PREFIX}site_templates` ADD COLUMN `editedon` integer NOT NULL DEFAULT '0'; @@ -863,10 +863,13 @@ ALTER TABLE `{PREFIX}web_groups` ADD UNIQUE INDEX `ix_group_user` (`webgroup`,`w ALTER TABLE `{PREFIX}document_groups` ADD UNIQUE INDEX `ix_dg_id` (`document_group`,`document`); ALTER TABLE `{PREFIX}manager_log` - ADD COLUMN `ip` varchar(15); + ADD COLUMN `ip` varchar(46); ALTER TABLE `{PREFIX}manager_log` - ADD COLUMN `useragent` varchar(255); + ADD COLUMN `useragent` varchar(255); + +ALTER TABLE `{PREFIX}manager_log` + CHANGE COLUMN `ip` `ip` VARCHAR(46) NULL DEFAULT NULL AFTER `message`; # ]]upgrade-able @@ -881,7 +884,7 @@ ALTER TABLE `{PREFIX}manager_log` # Default Site Template -REPLACE INTO `{PREFIX}site_templates` +REPLACE INTO `{PREFIX}site_templates` (id, templatename, description, editor_type, category, icon, template_type, content, locked, selectable) VALUES ('3','Minimal Template','Default minimal empty template (content returned only)','0','0','','0','[*content*]','0','1'); @@ -891,16 +894,16 @@ REPLACE INTO `{PREFIX}site_templates` REPLACE INTO `{PREFIX}site_content` VALUES (1,'document','text/html','Evolution CMS Install Success','Welcome to the EVO Content Management System','','minimal-base','',1,0,0,0,0,'','

        Install Successful!

        \r\n

        You have successfully installed Evolution CMS.

        \r\n\r\n

        Getting Help

        \r\n

        The EVO Community provides a great starting point to learn all things Evolution CMS, or you can also see some great learning resources (books, tutorials, blogs and screencasts).

        \r\n

        Welcome to EVO!

        \r\n',1,3,0,1,1,1,1130304721,1,1130304927,0,0,0,1130304721,1,'Base Install',0,0,0,0,0,1); -REPLACE INTO `{PREFIX}manager_users` -(id, username, password)VALUES +REPLACE INTO `{PREFIX}manager_users` +(id, username, password)VALUES (1, '{ADMIN}', MD5('{ADMINPASS}')); -REPLACE INTO `{PREFIX}user_attributes` -(id, internalKey, fullname, role, email, phone, mobilephone, blocked, blockeduntil, blockedafter, logincount, lastlogin, thislogin, failedlogincount, sessionid, dob, gender, country, street, city, state, zip, fax, photo, comment) VALUES +REPLACE INTO `{PREFIX}user_attributes` +(id, internalKey, fullname, role, email, phone, mobilephone, blocked, blockeduntil, blockedafter, logincount, lastlogin, thislogin, failedlogincount, sessionid, dob, gender, country, street, city, state, zip, fax, photo, comment) VALUES (1, 1, 'Admin', 1, '{ADMINEMAIL}', '', '', 0, 0, 0, 0, 0, 0, 0, '', 0, 0, '', '', '', '', '', '', '', ''); -REPLACE INTO `{PREFIX}user_roles` +REPLACE INTO `{PREFIX}user_roles` (id,name,description,frames,home,view_document,new_document,save_document,publish_document,delete_document,empty_trash,action_ok,logout,help,messages,new_user,edit_user,logs,edit_parser,save_parser,edit_template,settings,credits,new_template,save_template,delete_template,edit_snippet,new_snippet,save_snippet,delete_snippet,edit_chunk,new_chunk,save_chunk,delete_chunk,empty_cache,edit_document,change_password,error_dialog,about,file_manager,save_user,delete_user,save_password,edit_role,save_role,delete_role,new_role,access_permissions,bk_manager,new_plugin,edit_plugin,save_plugin,delete_plugin,new_module,edit_module,save_module,exec_module,delete_module,view_eventlog,delete_eventlog,new_web_user,edit_web_user,save_web_user,delete_web_user,web_access_permissions,view_unpublished,import_static,export_static,remove_locks,assets_images,assets_files,change_resourcetype,display_locks,category_manager) VALUES (2,'Editor','Limited to managing content',1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,1,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,0), (3,'Publisher','Editor with expanded permissions including manage users\, update Elements and site settings',1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,1,1,1,0,1,0,0,1,1,1,1,1,0); @@ -912,8 +915,8 @@ REPLACE INTO `{PREFIX}user_roles` # Default Site Settings -INSERT IGNORE INTO `{PREFIX}system_settings` -(setting_name, setting_value) VALUES +INSERT IGNORE INTO `{PREFIX}system_settings` +(setting_name, setting_value) VALUES ('settings_version',''), ('manager_theme','default'), ('server_offset_time','0'), @@ -962,17 +965,17 @@ INSERT IGNORE INTO `{PREFIX}system_settings` ('show_newresource_btn', '0'), ('show_fullscreen_btn', '0'); -REPLACE INTO `{PREFIX}user_roles` -(id,name,description,frames,home,view_document,new_document,save_document,publish_document,delete_document,empty_trash,action_ok,logout,help,messages,new_user,edit_user,logs,edit_parser,save_parser,edit_template,settings,credits,new_template,save_template,delete_template,edit_snippet,new_snippet,save_snippet,delete_snippet,edit_chunk,new_chunk,save_chunk,delete_chunk,empty_cache,edit_document,change_password,error_dialog,about,file_manager,save_user,delete_user,save_password,edit_role,save_role,delete_role,new_role,access_permissions,bk_manager,new_plugin,edit_plugin,save_plugin,delete_plugin,new_module,edit_module,save_module,exec_module,delete_module,view_eventlog,delete_eventlog,new_web_user,edit_web_user,save_web_user,delete_web_user,web_access_permissions,view_unpublished,import_static,export_static,remove_locks,assets_images,assets_files,change_resourcetype,display_locks,category_manager) VALUES +REPLACE INTO `{PREFIX}user_roles` +(id,name,description,frames,home,view_document,new_document,save_document,publish_document,delete_document,empty_trash,action_ok,logout,help,messages,new_user,edit_user,logs,edit_parser,save_parser,edit_template,settings,credits,new_template,save_template,delete_template,edit_snippet,new_snippet,save_snippet,delete_snippet,edit_chunk,new_chunk,save_chunk,delete_chunk,empty_cache,edit_document,change_password,error_dialog,about,file_manager,save_user,delete_user,save_password,edit_role,save_role,delete_role,new_role,access_permissions,bk_manager,new_plugin,edit_plugin,save_plugin,delete_plugin,new_module,edit_module,save_module,exec_module,delete_module,view_eventlog,delete_eventlog,new_web_user,edit_web_user,save_web_user,delete_web_user,web_access_permissions,view_unpublished,import_static,export_static,remove_locks,assets_images,assets_files,change_resourcetype,display_locks,category_manager) VALUES (1, 'Administrator', 'Site administrators have full access to all functions',1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); # 1 - "Parser Service Events", 2 - "Manager Access Events", 3 - "Web Access Service Events", 4 - "Cache Service Events", 5 - "Template Service Events", 6 - Custom Events -REPLACE INTO `{PREFIX}system_eventnames` -(id,name,service,groupname) VALUES -('1','OnDocPublished','5',''), +REPLACE INTO `{PREFIX}system_eventnames` +(id,name,service,groupname) VALUES +('1','OnDocPublished','5',''), ('2','OnDocUnPublished','5',''), ('3','OnWebPagePrerender','5',''), ('4','OnWebLogin','3',''), @@ -1105,17 +1108,27 @@ REPLACE INTO `{PREFIX}system_eventnames` ('225','OnBeforeMinifyCss', '1', ''), ('999','OnPageUnauthorized','1',''), ('1000','OnPageNotFound','1',''), -('1001','OnFileBrowserUpload','1','File Browser Events'); +('1001','OnFileBrowserUpload','1','File Browser Events'), +('1002','OnBeforeFileBrowserUpload','1','File Browser Events'), +('1003','OnFileBrowserDelete','1','File Browser Events'), +('1004','OnBeforeFileBrowserDelete','1','File Browser Events'), +('1005','OnFileBrowserInit','1','File Browser Events'), +('1006','OnFileBrowserMove','1','File Browser Events'), +('1007','OnBeforeFileBrowserMove','1','File Browser Events'), +('1008','OnFileBrowserCopy','1','File Browser Events'), +('1009','OnBeforeFileBrowserCopy','1','File Browser Events'), +('1010','OnBeforeFileBrowserRename','1','File Browser Events'), +('1011','OnFileBrowserRename','1','File Browser Events'); # ^ I don't think we need more than 1000 built-in events. Custom events will start at 1001 -# Update System Tables +# Update System Tables #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -UPDATE `{PREFIX}user_roles` SET +UPDATE `{PREFIX}user_roles` SET bk_manager=1, new_plugin=1, edit_plugin=1, diff --git a/install/sqlParser.class.php b/install/sqlParser.class.php index f94f7f3841..f5e7785e64 100755 --- a/install/sqlParser.class.php +++ b/install/sqlParser.class.php @@ -27,6 +27,7 @@ class SqlParser { public $connection_method; public $ignoreDuplicateErrors; public $autoTemplateLogic; + public $database_collation; public function __construct($host, $user, $password, $db, $prefix='modx_', $adminname, $adminemail, $adminpass, $connection_charset= 'utf8', $managerlanguage='english', $connection_method = 'SET CHARACTER SET', $auto_template_logic = 'parent') { $this->host = $host; @@ -45,7 +46,8 @@ public function __construct($host, $user, $password, $db, $prefix='modx_', $admi } public function connect() { - $this->conn = mysqli_connect($this->host, $this->user, $this->password); + $host = explode(':', $this->host, 2); + $this->conn = mysqli_connect($host[0], $this->user, $this->password,'', isset($host[1]) ? $host[1] : null); mysqli_select_db($this->conn, $this->dbname); if (function_exists('mysqli_set_charset')) mysqli_set_charset($this->conn, $this->connection_charset); @@ -91,6 +93,7 @@ public function process($filename) { // replace {} tags $idata = str_replace('{PREFIX}', $this->prefix, $idata); + $idata = str_replace('{TABLEENCODING}', $this->getTableEncoding(), $idata); $idata = str_replace('{ADMIN}', $this->adminname, $idata); $idata = str_replace('{ADMINEMAIL}', $this->adminemail, $idata); $idata = str_replace('{ADMINPASS}', $this->adminpass, $idata); @@ -138,6 +141,16 @@ public function process($filename) { } } + public function getTableEncoding() + { + $out = 'DEFAULT CHARSET=' . $this->connection_charset; + if (!empty($this->database_collation)) { + $out .= ' COLLATE=' . $this->database_collation; + } + + return $out; + } + public function close() { mysqli_close($this->conn); } diff --git a/manager/actions/access_permissions.dynamic.php b/manager/actions/access_permissions.dynamic.php index 0450f6ad9a..53d9c0909c 100755 --- a/manager/actions/access_permissions.dynamic.php +++ b/manager/actions/access_permissions.dynamic.php @@ -84,7 +84,7 @@ function deletegroup(groupid, type) {

        -
        +
        @@ -97,9 +97,9 @@ function deletegroup(groupid, type) {
        db->select('groupnames.*, users.id AS user_id, users.username user_name', $tbl_membergroup_names . ' AS groupnames - LEFT JOIN ' . $tbl_member_groups . ' AS groups ON groups.user_group = groupnames.id - LEFT JOIN ' . $tbl_manager_users . ' AS users ON users.id = groups.member', '', 'groupnames.name, user_name'); - if($modx->db->getRecordCount($rs) < 1) { + LEFT JOIN ' . $tbl_member_groups . ' AS groups_member ON groups_member.user_group = groupnames.id + LEFT JOIN ' . $tbl_manager_users . ' AS users ON users.id = groups_member.member', '', 'groupnames.name, user_name'); + if($modx->db->getRecordCount($rs) < 1) { ?>
        '; } ?> - + @@ -155,7 +155,7 @@ function deletegroup(groupid, type) {

        - +
        @@ -185,7 +185,7 @@ function deletegroup(groupid, type) { echo '
        '; } ?> - + @@ -237,7 +237,7 @@ function deletegroup(groupid, type) { ?>
        - + diff --git a/manager/actions/bkmanager.static.php b/manager/actions/bkmanager.static.php index 6927c17d53..2760834f93 100755 --- a/manager/actions/bkmanager.static.php +++ b/manager/actions/bkmanager.static.php @@ -292,7 +292,7 @@ function showhide(a)
        - + "snapshot_path={$modx->config['snapshot_path']}")) ?>
        - + @@ -387,7 +387,7 @@ function checked($cond)
        - + diff --git a/manager/actions/document_data.static.php b/manager/actions/document_data.static.php index 84b7e291ee..055338f260 100755 --- a/manager/actions/document_data.static.php +++ b/manager/actions/document_data.static.php @@ -188,9 +188,9 @@ //$class .= ($children['hidemenu'] ? ' text-muted' : ' text-primary'); //$class .= ($children['isfolder'] ? ' font-weight-bold' : ''); if($modx->hasPermission('edit_document')) { - $title = '' . $icon . '' . '' . $children['pagetitle'] . ''; + $title = '' . $icon . '' . '' . html_escape($children['pagetitle'], $modx->config['modx_charset']) . ''; } else { - $title = '' . $icon . '' . $children['pagetitle'] . ''; + $title = '' . $icon . '' . html_escape($children['pagetitle'], $modx->config['modx_charset']) . ''; } $icon_pub_unpub = (!$children['published']) ? '' : ''; @@ -257,7 +257,7 @@ class="' . $_style["icons_move_document"] . '">' . $icon_pub_unpub : '')

        - config['modx_charset']) . (iconv_strlen($content['pagetitle'], $modx->config['modx_charset']) > 50 ? '...' : '') . ' (' . $_REQUEST['id'] . ')' ?> + config['modx_charset']), $modx->config['modx_charset']) . (iconv_strlen($content['pagetitle'], $modx->config['modx_charset']) > 50 ? '...' : '') . ' (' . (int)$_REQUEST['id'] . ')' ?>

        @@ -279,21 +279,21 @@ class="' . $_style["icons_move_document"] . '">' . $icon_pub_unpub : '') : - + config['modx_charset']) ?> : - " . $_lang['not_set'] . ")" ?> + config['modx_charset']) : "(" . $_lang['not_set'] . ")" ?> : - " . $_lang['not_set'] . ")" ?> + config['modx_charset']) : "(" . $_lang['not_set'] . ")" ?> : - " . $_lang['not_set'] . ")" ?> + config['modx_charset']) : "(" . $_lang['not_set'] . ")" ?> : @@ -301,7 +301,7 @@ class="' . $_style["icons_move_document"] . '">' . $icon_pub_unpub : '') : - " . $_lang['not_set'] . ")" ?> + config['modx_charset']) : "(" . $_lang['not_set'] . ")" ?>   @@ -311,13 +311,13 @@ class="' . $_style["icons_move_document"] . '">' . $icon_pub_unpub : '') : - toDateFormat($content['createdon'] + $server_offset_time) ?> () + toDateFormat($content['createdon'] + $server_offset_time) ?> (config['modx_charset']) ?>) : - toDateFormat($content['editedon'] + $server_offset_time) ?> () + toDateFormat($content['editedon'] + $server_offset_time) ?> (config['modx_charset']) ?>) @@ -349,7 +349,7 @@ class="' . $_style["icons_move_document"] . '">' . $icon_pub_unpub : '') : - + config['modx_charset']) ?> : @@ -371,7 +371,7 @@ class="' . $_style["icons_move_document"] . '">' . $icon_pub_unpub : '') : - + config['modx_charset']) ?> : @@ -393,7 +393,7 @@ class="' . $_style["icons_move_document"] . '">' . $icon_pub_unpub : '')
        0) : ?>
        - () + (config['modx_charset']) ?>)
        diff --git a/manager/actions/export_site.static.php b/manager/actions/export_site.static.php index 878cad704f..2fcd072369 100755 --- a/manager/actions/export_site.static.php +++ b/manager/actions/export_site.static.php @@ -40,7 +40,7 @@ echo $rs; } else { ?> - + - - -
        -
        + + +
        +
        - - [+OnManagerLoginFormPrerender+] - - - - - -
        - - -
        + + [+OnManagerLoginFormPrerender+] + + + + + +
        + + +
        + + +
        + + +
        + + +
        +
        [+login_captcha_message+]
        +

        [+captcha_image+]

        + [+captcha_input+] +
        + + +
        + + +
        + + + [+OnManagerLoginFormRender+] - -
        - - -
        - - -
        -
        [+login_captcha_message+]
        -

        [+captcha_image+]

        - [+captcha_input+] -
        - - -
        - - -
        - - - [+OnManagerLoginFormRender+] - -
        +
        - -
        + +

        © 2005-2018 by the EVO. EVO™ is licensed under the GPL.
        -
        - - -
        - - - - - \ No newline at end of file + }; + xhr.send('ajax=1&username=' + encodeURIComponent(form.username.value) + '&password=' + encodeURIComponent(form.password.value) + (form.captcha_code ? '&captcha_code=' + encodeURIComponent(form.captcha_code.value) : '') + '&rememberme=' + form.rememberme.value); + e.preventDefault(); + }; + /* ]]> */ + + + diff --git a/manager/media/style/default/manager.lockout.tpl b/manager/media/style/default/manager.lockout.tpl index 6d62485d02..f35eac5490 100755 --- a/manager/media/style/default/manager.lockout.tpl +++ b/manager/media/style/default/manager.lockout.tpl @@ -1,66 +1,321 @@ - EVO Content Manager - - - - - + [(site_name)] (Evolution CMS Manager Login) + + + + + + - - -
        -
        - -
        - [+logo_slogan+] -
        - -
        -

        [(site_name)]

        -
        [+manager_lockout_message+]
        -
        - -   - -
        -
        -
        -
        + +
        +
        +
        + + + + +
        +

        [(site_name)]

        + + [+manager_lockout_message+] +
        + + +
        + + +
        + +
        +
        + + +
        +

        +
        © 2005-2018 by the EVO. EVO™ is licensed under the GPL.
        +
        - - -

        EVO™ is licensed under the GPL license. © 2005-2018 EVO.

        + + - + \ No newline at end of file diff --git a/manager/media/style/default/snippets/welcome/RecentInfo.php b/manager/media/style/default/snippets/welcome/RecentInfo.php new file mode 100644 index 0000000000..509f2cdc5d --- /dev/null +++ b/manager/media/style/default/snippets/welcome/RecentInfo.php @@ -0,0 +1,103 @@ +getDatabase()->select('*', $modx->getDatabase()->getFullTableName('site_content'), '', 'editedon DESC', 10); + +if ($modx->getDatabase()->getRecordCount($rs) < 1) { + return '[%no_activity_message%]'; +} +$tpl = ' + [+id+] + [+pagetitle+] + [+editedon:math("%s+[(server_offset_time)]"):dateFormat=`'.$modx->toDateFormat(0,'formatOnly').' %H:%M:%S`+] + [+username+] + [+edit_btn+][+preview_btn+][+delete_btn+][+publish_btn+][+info_btn+] + + + +
        +
          +
        • [%long_title%]: [+longtitle+]
        • +
        • [%description%]: [+description+]
        • +
        • [%resource_summary%]: [+introtext+]
        • +
        • [%type%]: [+type:is(reference):then([%weblink%]):else([%resource%])+]
        • +
        • [%resource_alias%]: [+alias+]
        • +
        • [%page_data_cacheable%]: [+cacheable:is(1):then([%yes%]):else([%no%])+]
        • +
        • [%resource_opt_show_menu%]: [+hidemenu:is(0):then([%yes%]):else([%no%])+]
        • +
        • [%page_data_template%]: [+template:templatename+]
        • +
        +
        + +'; + +$btntpl['edit'] = ' '; +$btntpl['preview_btn'] = ' '; + +$output = array(); +while ($ph = $modx->getDatabase()->getRow($rs)) { + $docid = $ph['id']; + $_ = $modx->getUserInfo($ph['editedby']); + $ph['username'] = $_['username']; + + if ($ph['deleted'] == 1) { + $ph['status'] = 'deleted text-danger'; + } elseif ($ph['published'] == 0) { + $ph['status'] = 'unpublished font-italic text-muted'; + } else { + $ph['status'] = 'published'; + } + + if ($modx->hasPermission('edit_document')) { + $ph['edit_btn'] = str_replace('[+id+]', $docid, $btntpl['edit']); + } else { + $ph['edit_btn'] = ''; + } + + $preview_disabled = ($ph['deleted'] == 1) ? 'disabled' : ''; + $ph['preview_btn'] = str_replace(array( + '[+id+]', + '[+preview_disabled+]' + ), array( + $docid, + $preview_disabled + ), $btntpl['preview_btn']); + + if ($modx->hasPermission('delete_document')) { + if ($ph['deleted'] == 0) { + $delete_btn = ' '; + } else { + $delete_btn = ' '; + } + $ph['delete_btn'] = str_replace('[+id+]', $docid, $delete_btn); + } else { + $ph['delete_btn'] = ''; + } + + if ($ph['deleted'] == 1 && $ph['published'] == 0) { + $publish_btn = ' '; + } elseif ($ph['deleted'] == 1 && $ph['published'] == 1) { + $publish_btn = ' '; + } elseif ($ph['deleted'] == 0 && $ph['published'] == 0) { + $publish_btn = ' '; + } else { + $publish_btn = ' '; + } + $ph['publish_btn'] = str_replace('[+id+]', $docid, $publish_btn); + + $ph['info_btn'] = str_replace('[+id+]', $docid, ''); + + if ($ph['longtitle'] == '') { + $ph['longtitle'] = '([%not_set%])'; + } + if ($ph['description'] == '') { + $ph['description'] = '([%not_set%])'; + } + if ($ph['introtext'] == '') { + $ph['introtext'] = '([%not_set%])'; + } + if ($ph['alias'] == '') { + $ph['alias'] = '([%not_set%])'; + } + + $output[] = $modx->parseText($tpl, $ph); +} + +return implode("\n", $output); diff --git a/manager/processors/cache_sync.class.processor.php b/manager/processors/cache_sync.class.processor.php index 678ada027a..8d6b9c8efc 100755 --- a/manager/processors/cache_sync.class.processor.php +++ b/manager/processors/cache_sync.class.processor.php @@ -252,7 +252,7 @@ public function buildCache($modx) $config = array(); $content .= '$c=&$this->config;'; while (list($key, $value) = $modx->db->getRow($rs, 'num')) { - $content .= '$c[\'' . $key . '\']="' . $this->escapeDoubleQuotes($value) . '";'; + $content .= '$c[\'' . $modx->db->escape($key) . '\']="' . $this->escapeDoubleQuotes($value) . '";'; $config[$key] = $value; } @@ -313,10 +313,7 @@ public function buildCache($modx) $rs = $modx->db->select('*', '[+prefix+]site_htmlsnippets'); $content .= '$c=&$this->chunkCache;'; while ($doc = $modx->db->getRow($rs)) { - if ($modx->config['minifyphp_incache']) { - $doc['snippet'] = $this->php_strip_whitespace($doc['snippet']); - } - $content .= '$c[\'' . $doc['name'] . '\']=\'' . ($doc['disabled'] ? '' : $this->escapeSingleQuotes($doc['snippet'])) . '\';'; + $content .= '$c[\'' . $modx->db->escape($doc['name']) . '\']=\'' . ($doc['disabled'] ? '' : $this->escapeSingleQuotes($doc['snippet'])) . '\';'; } // WRITE snippets to cache file @@ -325,7 +322,7 @@ public function buildCache($modx) $rs = $modx->db->select($f, $from); $content .= '$s=&$this->snippetCache;'; while ($row = $modx->db->getRow($rs)) { - $key = $row['name']; + $key = $modx->db->escape($row['name']); if ($row['disabled']) { $content .= '$s[\'' . $key . '\']=\'return false;\';'; } else { @@ -351,7 +348,7 @@ public function buildCache($modx) $rs = $modx->db->select($f, $from, 'sp.disabled=0'); $content .= '$p=&$this->pluginCache;'; while ($row = $modx->db->getRow($rs)) { - $key = $row['name']; + $key = $modx->db->escape($row['name']); $value = trim($row['plugincode']); if ($modx->config['minifyphp_incache']) { $value = $this->php_strip_whitespace($value); diff --git a/manager/processors/duplicate_tmplvars.processor.php b/manager/processors/duplicate_tmplvars.processor.php index 74d80a4c52..cdf8c82e0f 100755 --- a/manager/processors/duplicate_tmplvars.processor.php +++ b/manager/processors/duplicate_tmplvars.processor.php @@ -26,12 +26,12 @@ 'description'=>'', 'default_text'=>'', 'elements'=>'', - 'rank'=>'', + '`rank`'=>'', 'display'=>'', 'display_params'=>'', 'category'=>'', ), $modx->getFullTableName('site_tmplvars'), // Insert into - "type, CONCAT(name, ' {$_lang['duplicated_el_suffix']}{$count}') AS name, CONCAT(caption, ' Duplicate{$count}') AS caption, description, default_text, elements, rank, display, display_params, category", $modx->getFullTableName('site_tmplvars'), "id='{$id}'"); // Copy from + "type, CONCAT(name, ' {$_lang['duplicated_el_suffix']}{$count}') AS name, CONCAT(caption, ' Duplicate{$count}') AS caption, description, default_text, elements, `rank`, display, display_params, category", $modx->getFullTableName('site_tmplvars'), "id='{$id}'"); // Copy from // duplicate TV Template Access Permissions @@ -39,9 +39,9 @@ array( 'tmplvarid'=>'', 'templateid'=>'', - 'rank'=>'', + '`rank`'=>'', ), $modx->getFullTableName('site_tmplvar_templates'), // Insert into - "'{$newid}', templateid, rank", $modx->getFullTableName('site_tmplvar_templates'), "tmplvarid='{$id}'"); // Copy from + "'{$newid}', templateid, `rank`", $modx->getFullTableName('site_tmplvar_templates'), "tmplvarid='{$id}'"); // Copy from // duplicate TV Access Permissions $modx->db->insert( diff --git a/manager/processors/execute_module.processor.php b/manager/processors/execute_module.processor.php index ee31459948..6ef338771c 100755 --- a/manager/processors/execute_module.processor.php +++ b/manager/processors/execute_module.processor.php @@ -59,12 +59,7 @@ // Set the item name for logger $_SESSION['itemname'] = $content['name']; - -$output = evalModule($content["modulecode"],$parameter); -if (strpos(trim($output),'<')===0 && strpos(trim($output),'@supports (-webkit-overflow-scrolling: touch) {body,html {-webkit-overflow-scrolling: touch;overflow:auto!important;height:100%!important}}"; // for iframe scroller -} -echo $output; +echo evalModule($content["modulecode"], $parameter); include MODX_MANAGER_PATH."includes/sysalert.display.inc.php"; /** diff --git a/manager/processors/login.processor.php b/manager/processors/login.processor.php index 5d0e1b0371..f7f4b0c4d0 100755 --- a/manager/processors/login.processor.php +++ b/manager/processors/login.processor.php @@ -20,7 +20,6 @@ if($manager_language !== 'english' && is_file("{$core_path}lang/{$manager_language}.inc.php")) { include_once("{$core_path}lang/{$manager_language}.inc.php"); } - // include the logger include_once("{$core_path}log.class.inc.php"); @@ -180,6 +179,8 @@ $matchPassword = true; } +$blocked_minutes = (int)$modx->config['blocked_minutes']; + if(!$matchPassword) { jsAlert($_lang['login_processor_wrong_password']); incrementFailedLoginCount($internalKey, $failedlogins, $failed_allowed, $blocked_minutes); diff --git a/manager/processors/save_content.processor.php b/manager/processors/save_content.processor.php index 749b34c2c4..d9dd58977c 100755 --- a/manager/processors/save_content.processor.php +++ b/manager/processors/save_content.processor.php @@ -14,30 +14,30 @@ $description = $modx->db->escape($_POST['description']); $alias = $modx->db->escape($_POST['alias']); $link_attributes = $modx->db->escape($_POST['link_attributes']); -$isfolder = $_POST['isfolder']; -$richtext = $_POST['richtext']; -$published = $_POST['published']; -$parent = $_POST['parent'] != '' ? $_POST['parent'] : 0; -$template = $_POST['template']; -$menuindex = !empty($_POST['menuindex']) ? $_POST['menuindex'] : 0; -$searchable = $_POST['searchable']; -$cacheable = $_POST['cacheable']; -$syncsite = $_POST['syncsite']; +$isfolder = (int)$_POST['isfolder']; +$richtext = (int)$_POST['richtext']; +$published = (int)$_POST['published']; +$parent = $_POST['parent'] != '' ? (int)$_POST['parent'] : 0; +$template = (int)$_POST['template']; +$menuindex = !empty($_POST['menuindex']) ? (int)$_POST['menuindex'] : 0; +$searchable = (int)$_POST['searchable']; +$cacheable = (int)$_POST['cacheable']; +$syncsite = (int)$_POST['syncsite']; $pub_date = $_POST['pub_date']; $unpub_date = $_POST['unpub_date']; $document_groups = (isset($_POST['chkalldocs']) && $_POST['chkalldocs'] == 'on') ? array() : $_POST['docgroups']; -$type = $_POST['type']; +$type = $modx->db->escape($_POST['type']); $contentType = $modx->db->escape($_POST['contentType']); $contentdispo = (int)$_POST['content_dispo']; $longtitle = $modx->db->escape($_POST['longtitle']); $donthit = (int)$_POST['donthit']; $menutitle = $modx->db->escape($_POST['menutitle']); $hidemenu = (int)$_POST['hidemenu']; -$aliasvisible = $_POST['alias_visible']; +$aliasvisible = (int)$_POST['alias_visible']; /************* webber ********/ -$sd=isset($_POST['dir'])?'&dir='.$_POST['dir']:'&dir=DESC'; -$sb=isset($_POST['sort'])?'&sort='.$_POST['sort']:'&sort=pub_date'; +$sd=isset($_POST['dir']) && strtolower($_POST['dir']) === 'asc' ? '&dir=ASC' : '&dir=DESC'; +$sb=isset($_POST['sort'])?'&sort='.html_escape($_POST['sort'], $modx->config['modx_charset']):'&sort=pub_date'; $pg=isset($_POST['page'])?'&page='.(int)$_POST['page']:''; $add_path=$sd.$sb.$pg; @@ -190,7 +190,7 @@ } $rs = $modx->db->select( - "DISTINCT tv.*, IF(tvc.value!='',tvc.value,tv.default_text) as value", + "DISTINCT tv.*, IF(tvc.value!='',tvc.value,tv.default_text) as value", "{$tbl_site_tmplvars} AS tv INNER JOIN {$tbl_site_tmplvar_templates} AS tvtpl ON tvtpl.tmplvarid = tv.id LEFT JOIN {$tbl_site_tmplvar_contentvalues} AS tvc ON tvc.tmplvarid=tv.id AND tvc.contentid = '{$id}' @@ -222,7 +222,7 @@ // handles checkboxes & multiple selects elements $feature_insert = array (); $lst = $_POST["tv" . $row['id']]; - while (list ($featureValue, $feature_item) = each($lst)) { + foreach($lst as $featureValue => $feature_item) { $feature_insert[count($feature_insert)] = $feature_item; } $tmplvar = implode("||", $feature_insert); @@ -591,10 +591,10 @@ $isManager = $modx->hasPermission('access_permissions'); $isWeb = $modx->hasPermission('web_access_permissions'); $rs = $modx->db->select( - 'groups.id, groups.document_group', - "{$tbl_document_groups} AS groups - LEFT JOIN {$tbl_documentgroup_names} AS dgn ON dgn.id = groups.document_group", - "((1=".(int)$isManager." AND dgn.private_memgroup) OR (1=".(int)$isWeb." AND dgn.private_webgroup)) AND groups.document = '{$id}'" + 'groups_document.id, groups_document.document_group', + "{$tbl_document_groups} AS groups_document + LEFT JOIN {$tbl_documentgroup_names} AS dgn ON dgn.id = groups_document.document_group", + "((1=".(int)$isManager." AND dgn.private_memgroup) OR (1=".(int)$isWeb." AND dgn.private_webgroup)) AND groups_document.document = '{$id}'" ); $old_groups = array(); while ($row = $modx->db->getRow($rs)) $old_groups[$row['document_group']] = $row['id']; diff --git a/manager/processors/save_plugin.processor.php b/manager/processors/save_plugin.processor.php index 1d25a72b8e..8d2805ac81 100755 --- a/manager/processors/save_plugin.processor.php +++ b/manager/processors/save_plugin.processor.php @@ -189,6 +189,7 @@ function saveEventListeners($id, $sysevents, $mode) } else { $priority = isset($prevPriority) ? $prevPriority : 1; } + $priority = (int)$priority; $formEventList[] = array('pluginid' => $id, 'evtid' => $evtId, 'priority' => $priority); } diff --git a/manager/processors/save_settings.processor.php b/manager/processors/save_settings.processor.php index ebe7c6f654..01894cfd42 100755 --- a/manager/processors/save_settings.processor.php +++ b/manager/processors/save_settings.processor.php @@ -69,9 +69,6 @@ $data['mail_check_timeperiod'] = (int)$data['mail_check_timeperiod'] < 60 ? 60 : $data['mail_check_timeperiod']; // updateMail() in mainMenu no faster than every minute foreach ($data as $k => $v) { switch ($k) { - case 'site_name': - $v = htmlspecialchars($v); - break; case 'settings_version':{ if($modx->getVersionData('version')!=$data['settings_version']){ $modx->logEvent(17,2,'
        '.var_export($data['settings_version'],true).'
        ','fake settings_version'); diff --git a/manager/processors/save_template.processor.php b/manager/processors/save_template.processor.php index ed4dca716c..f4ee95894d 100755 --- a/manager/processors/save_template.processor.php +++ b/manager/processors/save_template.processor.php @@ -154,7 +154,7 @@ function saveTemplateAccess($id) $newAssignedTvs = $_POST['assignedTv']; // Preserve rankings of already assigned TVs - $rs = $modx->db->select("tmplvarid, rank", $modx->getFullTableName('site_tmplvar_templates'), "templateid='{$id}'", ""); + $rs = $modx->db->select("`tmplvarid`, `rank`", $modx->getFullTableName('site_tmplvar_templates'), "templateid='{$id}'", ""); $ranksArr = array(); $highest = 0; diff --git a/manager/processors/save_tmplvars.processor.php b/manager/processors/save_tmplvars.processor.php index 8d05b975e0..7260cabd83 100755 --- a/manager/processors/save_tmplvars.processor.php +++ b/manager/processors/save_tmplvars.processor.php @@ -191,7 +191,7 @@ function saveTemplateVarAccess() $getRankArray = array(); - $getRank = $modx->db->select("templateid, rank", $tbl_site_tmplvar_templates, "tmplvarid='{$id}'"); + $getRank = $modx->db->select("`templateid`, `rank`", $tbl_site_tmplvar_templates, "tmplvarid='{$id}'"); while ($row = $modx->db->getRow($getRank)) { $getRankArray[$row['templateid']] = $row['rank']; diff --git a/manager/processors/save_user.processor.php b/manager/processors/save_user.processor.php index ae20f92be2..6b9361e5b4 100755 --- a/manager/processors/save_user.processor.php +++ b/manager/processors/save_user.processor.php @@ -1,9 +1,9 @@ INCLUDE_ORDERING_ERROR

        Please use the EVO Content Manager instead of accessing this file directly."); +if (!defined('IN_MANAGER_MODE') || IN_MANAGER_MODE !== true) { + die("INCLUDE_ORDERING_ERROR

        Please use the EVO Content Manager instead of accessing this file directly."); } -if(!$modx->hasPermission('save_user')) { - $modx->webAlertAndQuit($_lang["error_no_privileges"]); +if (!$modx->hasPermission('save_user')) { + $modx->webAlertAndQuit($_lang["error_no_privileges"]); } $modx->loadExtension('phpass'); @@ -44,308 +44,319 @@ $user_groups = $input['user_groups']; // verify password -if($passwordgenmethod == "spec" && $input['specifiedpassword'] != $input['confirmpassword']) { - webAlertAndQuit("Password typed is mismatched"); +if ($passwordgenmethod == "spec" && $input['specifiedpassword'] != $input['confirmpassword']) { + webAlertAndQuit("Password typed is mismatched"); } // verify email -if($email == '' || !preg_match("/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,24}$/i", $email)) { - webAlertAndQuit("E-mail address doesn't seem to be valid!"); +if ($email == '' || !preg_match("/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,24}$/i", $email)) { + webAlertAndQuit("E-mail address doesn't seem to be valid!"); } // verify admin security -if($_SESSION['mgrRole'] != 1) { - // Check to see if user tried to spoof a "1" (admin) role - if(!$modx->hasPermission('save_role')) { - webAlertAndQuit("Illegal attempt to create/modify administrator by non-administrator!"); - } - // Verify that the user being edited wasn't an admin and the user ID got spoofed - $rs = $modx->db->select('count(internalKey)', $tbl_user_attributes, "internalKey='{$id}' AND role=1"); - $limit = $modx->db->getValue($rs); - if($limit > 0) { - webAlertAndQuit("You cannot alter an administrative user."); - } +if ($_SESSION['mgrRole'] != 1) { + // Check to see if user tried to spoof a "1" (admin) role + if (!$modx->hasPermission('save_user')) { + webAlertAndQuit("Illegal attempt to create/modify administrator by non-administrator!", 12); + } + // Verify that the user being edited wasn't an admin and the user ID got spoofed + $rs = $modx->db->select('count(internalKey)', $tbl_user_attributes, "internalKey='{$id}' AND role=1"); + $limit = $modx->db->getValue($rs); + if ($limit > 0) { + webAlertAndQuit("You cannot alter an administrative user."); + } } -switch($input['mode']) { - case '11' : // new user - // check if this user name already exist - $rs = $modx->db->select('count(id)', $tbl_manager_users, sprintf("username='%s'", $modx->db->escape($newusername))); - $limit = $modx->db->getValue($rs); - if($limit > 0) { - webAlertAndQuit("User name is already in use!"); - } - - // check if the email address already exist - $rs = $modx->db->select('count(internalKey)', $tbl_user_attributes, sprintf("email='%s' AND id!='%s'", $modx->db->escape($email), $id)); - $limit = $modx->db->getValue($rs); - if($limit > 0) { - webAlertAndQuit("Email is already in use!"); - } - - // generate a new password for this user - if($specifiedpassword != "" && $passwordgenmethod == "spec") { - if(strlen($specifiedpassword) < 6) { - webAlertAndQuit("Password is too short!"); - } else { - $newpassword = $specifiedpassword; - } - } elseif($specifiedpassword == "" && $passwordgenmethod == "spec") { - webAlertAndQuit("You didn't specify a password for this user!"); - } elseif($passwordgenmethod == 'g') { - $newpassword = generate_password(8); - } else { - webAlertAndQuit("No password generation method specified!"); - } - - // invoke OnBeforeUserFormSave event - $modx->invokeEvent("OnBeforeUserFormSave", array( - "mode" => "new", - )); - - // create the user account - $internalKey = $modx->db->insert(array('username' => $modx->db->escape($newusername)), $tbl_manager_users); - - $field = array(); - $field['password'] = $modx->phpass->HashPassword($newpassword); - $modx->db->update($field, $tbl_manager_users, "id='{$internalKey}'"); - - $field = compact('internalKey', 'fullname', 'role', 'email', 'phone', 'mobilephone', 'fax', 'zip', 'street', 'city', 'state', 'country', 'gender', 'dob', 'photo', 'comment', 'blocked', 'blockeduntil', 'blockedafter'); - $field = $modx->db->escape($field); - $modx->db->insert($field, $tbl_user_attributes); - - // Save user settings - saveUserSettings($internalKey); - - // invoke OnManagerSaveUser event - $modx->invokeEvent("OnManagerSaveUser", array( - "mode" => "new", - "userid" => $internalKey, - "username" => $newusername, - "userpassword" => $newpassword, - "useremail" => $email, - "userfullname" => $fullname, - "userroleid" => $role - )); - - // invoke OnUserFormSave event - $modx->invokeEvent("OnUserFormSave", array( - "mode" => "new", - "id" => $internalKey - )); - - // Set the item name for logger - $_SESSION['itemname'] = $newusername; - - /*******************************************************************************/ - // put the user in the user_groups he/ she should be in - // first, check that up_perms are switched on! - if($use_udperms == 1) { - if(!empty($user_groups)) { - for($i = 0; $i < count($user_groups); $i++) { - $f = array(); - $f['user_group'] = (int)$user_groups[$i]; - $f['member'] = $internalKey; - $modx->db->insert($f, $tbl_member_groups); - } - } - } - // end of user_groups stuff! - - if($passwordnotifymethod == 'e') { - sendMailMessage($email, $newusername, $newpassword, $fullname); - if($input['stay'] != '') { - $a = ($input['stay'] == '2') ? "12&id={$internalKey}" : "11"; - $header = "Location: index.php?a={$a}&r=2&stay=" . $input['stay']; - header($header); - } else { - $header = "Location: index.php?a=75&r=2"; - header($header); - } - } else { - if($input['stay'] != '') { - $a = ($input['stay'] == '2') ? "12&id={$internalKey}" : "11"; - $stayUrl = "index.php?a={$a}&r=2&stay=" . $input['stay']; - } else { - $stayUrl = "index.php?a=75&r=2"; - } - - include_once "header.inc.php"; - ?> - -

        - -
        - -
        - -
        -
        -
        -
        -

        - htmlspecialchars($newusername), $modx->htmlspecialchars($newpassword)); ?> -

        -
        -
        -
        - db->select('count(id)', $tbl_manager_users, sprintf("username='%s' AND id!='%s'", $modx->db->escape($newusername), $id)); - $limit = $modx->db->getValue($rs); - if($limit > 0) { - webAlertAndQuit("User name is already in use!"); - } - - // check if the email address already exists - $rs = $modx->db->select('count(internalKey)', $tbl_user_attributes, sprintf("email='%s' AND internalKey!='%s'", $modx->db->escape($email), $id)); - $limit = $modx->db->getValue($rs); - if($limit > 0) { - webAlertAndQuit("Email is already in use!"); - } - - // invoke OnBeforeUserFormSave event - $modx->invokeEvent("OnBeforeUserFormSave", array( - "mode" => "upd", - "id" => $id - )); - - // update user name and password - $field = array(); - $field['username'] = $modx->db->escape($newusername); - if($genpassword == 1) { - $field['password'] = $modx->phpass->HashPassword($newpassword); - } - $modx->db->update($field, $tbl_manager_users, "id='{$id}'"); - $field = compact('fullname', 'role', 'email', 'phone', 'mobilephone', 'fax', 'zip', 'street', 'city', 'state', 'country', 'gender', 'dob', 'photo', 'comment', 'failedlogincount', 'blocked', 'blockeduntil', 'blockedafter'); - $field = $modx->db->escape($field); - $modx->db->update($field, $tbl_user_attributes, "internalKey='{$id}'"); - - // Save user settings - saveUserSettings($id); - - // Set the item name for logger - $_SESSION['itemname'] = $newusername; - - // invoke OnManagerSaveUser event - $modx->invokeEvent("OnManagerSaveUser", array( - "mode" => "upd", - "userid" => $id, - "username" => $newusername, - "userpassword" => $newpassword, - "useremail" => $email, - "userfullname" => $fullname, - "userroleid" => $role, - "oldusername" => (($oldusername != $newusername) ? $oldusername : ""), - "olduseremail" => (($oldemail != $email) ? $oldemail : "") - )); - - // invoke OnManagerChangePassword event - if($genpassword == 1) { - $modx->invokeEvent("OnManagerChangePassword", array( - "userid" => $id, - "username" => $newusername, - "userpassword" => $newpassword - )); - } - - // invoke OnUserFormSave event - $modx->invokeEvent("OnUserFormSave", array( - "mode" => "upd", - "id" => $id - )); - - /*******************************************************************************/ - // put the user in the user_groups he/ she should be in - // first, check that up_perms are switched on! - if($use_udperms == 1) { - // as this is an existing user, delete his/ her entries in the groups before saving the new groups - $modx->db->delete($tbl_member_groups, "member='{$id}'"); - if(!empty($user_groups)) { - for($i = 0; $i < count($user_groups); $i++) { - $field = array(); - $field['user_group'] = (int)$user_groups[$i]; - $field['member'] = $id; - $modx->db->insert($field, $tbl_member_groups); - } - } - } - // end of user_groups stuff! - /*******************************************************************************/ - if($id == $modx->getLoginUserID() && ($genpassword !== 1 && $passwordnotifymethod != 's')) { - $modx->webAlertAndQuit($_lang["user_changeddata"], 'javascript:top.location.href="index.php?a=8";'); - } - if($genpassword == 1 && $passwordnotifymethod == 's') { - if($input['stay'] != '') { - $a = ($input['stay'] == '2') ? "12&id={$id}" : "11"; - $stayUrl = "index.php?a={$a}&r=2&stay=" . $input['stay']; - } else { - $stayUrl = "index.php?a=75&r=2"; - } - - include_once "header.inc.php"; - ?> - -

        - - - -
        -
        -
        -
        -

        htmlspecialchars($newusername), $modx->htmlspecialchars($newpassword)) . (($id == $modx->getLoginUserID()) ? ' ' . $_lang['user_changeddata'] : ''); ?>

        -
        -
        -
        - db->select('count(id)', $tbl_manager_users, + sprintf("username='%s'", $modx->db->escape($newusername))); + $limit = $modx->db->getValue($rs); + if ($limit > 0) { + webAlertAndQuit("User name is already in use!"); + } + + // check if the email address already exist + $rs = $modx->db->select('count(internalKey)', $tbl_user_attributes, + sprintf("email='%s' AND id!='%s'", $modx->db->escape($email), $id)); + $limit = $modx->db->getValue($rs); + if ($limit > 0) { + webAlertAndQuit("Email is already in use!"); + } + + // generate a new password for this user + if ($specifiedpassword != "" && $passwordgenmethod == "spec") { + if (strlen($specifiedpassword) < 6) { + webAlertAndQuit("Password is too short!"); + } else { + $newpassword = $specifiedpassword; + } + } elseif ($specifiedpassword == "" && $passwordgenmethod == "spec") { + webAlertAndQuit("You didn't specify a password for this user!"); + } elseif ($passwordgenmethod == 'g') { + $newpassword = generate_password(8); + } else { + webAlertAndQuit("No password generation method specified!"); + } + + // invoke OnBeforeUserFormSave event + $modx->invokeEvent("OnBeforeUserFormSave", array( + "mode" => "new", + )); + + // create the user account + $internalKey = $modx->db->insert(array('username' => $modx->db->escape($newusername)), $tbl_manager_users); + + $field = array(); + $field['password'] = $modx->phpass->HashPassword($newpassword); + $modx->db->update($field, $tbl_manager_users, "id='{$internalKey}'"); + + $field = compact('internalKey', 'fullname', 'role', 'email', 'phone', 'mobilephone', 'fax', 'zip', 'street', + 'city', 'state', 'country', 'gender', 'dob', 'photo', 'comment', 'blocked', 'blockeduntil', 'blockedafter'); + $field = $modx->db->escape($field); + $modx->db->insert($field, $tbl_user_attributes); + + // Save user settings + saveUserSettings($internalKey); + + // invoke OnManagerSaveUser event + $modx->invokeEvent("OnManagerSaveUser", array( + "mode" => "new", + "userid" => $internalKey, + "username" => $newusername, + "userpassword" => $newpassword, + "useremail" => $email, + "userfullname" => $fullname, + "userroleid" => $role + )); + + // invoke OnUserFormSave event + $modx->invokeEvent("OnUserFormSave", array( + "mode" => "new", + "id" => $internalKey + )); + + // Set the item name for logger + $_SESSION['itemname'] = $newusername; + + /*******************************************************************************/ + // put the user in the user_groups he/ she should be in + // first, check that up_perms are switched on! + if ($use_udperms == 1) { + if (!empty($user_groups)) { + for ($i = 0; $i < count($user_groups); $i++) { + $f = array(); + $f['user_group'] = (int)$user_groups[$i]; + $f['member'] = $internalKey; + $modx->db->insert($f, $tbl_member_groups); + } + } + } + // end of user_groups stuff! + + if ($passwordnotifymethod == 'e') { + sendMailMessage($email, $newusername, $newpassword, $fullname); + if ($input['stay'] != '') { + $a = ($input['stay'] == '2') ? "12&id={$internalKey}" : "11"; + $header = "Location: index.php?a={$a}&r=2&stay=" . $input['stay']; + header($header); + } else { + $header = "Location: index.php?a=75&r=2"; + header($header); + } + } else { + if ($input['stay'] != '') { + $a = ($input['stay'] == '2') ? "12&id={$internalKey}" : "11"; + $stayUrl = "index.php?a={$a}&r=2&stay=" . $input['stay']; + } else { + $stayUrl = "index.php?a=75&r=2"; + } + + include_once "header.inc.php"; + ?> + +

        + +
        +
        + "> + +
        +
        + +
        +
        +
        +

        + htmlspecialchars($newusername), + $modx->htmlspecialchars($newpassword)); ?> +

        +
        +
        +
        + db->select('count(id)', $tbl_manager_users, + sprintf("username='%s' AND id!='%s'", $modx->db->escape($newusername), $id)); + $limit = $modx->db->getValue($rs); + if ($limit > 0) { + webAlertAndQuit("User name is already in use!"); + } + + // check if the email address already exists + $rs = $modx->db->select('count(internalKey)', $tbl_user_attributes, + sprintf("email='%s' AND internalKey!='%s'", $modx->db->escape($email), $id)); + $limit = $modx->db->getValue($rs); + if ($limit > 0) { + webAlertAndQuit("Email is already in use!"); + } + + // invoke OnBeforeUserFormSave event + $modx->invokeEvent("OnBeforeUserFormSave", array( + "mode" => "upd", + "id" => $id + )); + + // update user name and password + $field = array(); + $field['username'] = $modx->db->escape($newusername); + if ($genpassword == 1) { + $field['password'] = $modx->phpass->HashPassword($newpassword); + } + $modx->db->update($field, $tbl_manager_users, "id='{$id}'"); + $field = compact('fullname', 'role', 'email', 'phone', 'mobilephone', 'fax', 'zip', 'street', 'city', 'state', + 'country', 'gender', 'dob', 'photo', 'comment', 'failedlogincount', 'blocked', 'blockeduntil', + 'blockedafter'); + $field = $modx->db->escape($field); + $modx->db->update($field, $tbl_user_attributes, "internalKey='{$id}'"); + + // Save user settings + saveUserSettings($id); + + // Set the item name for logger + $_SESSION['itemname'] = $newusername; + + // invoke OnManagerSaveUser event + $modx->invokeEvent("OnManagerSaveUser", array( + "mode" => "upd", + "userid" => $id, + "username" => $newusername, + "userpassword" => $newpassword, + "useremail" => $email, + "userfullname" => $fullname, + "userroleid" => $role, + "oldusername" => (($oldusername != $newusername) ? $oldusername : ""), + "olduseremail" => (($oldemail != $email) ? $oldemail : "") + )); + + // invoke OnManagerChangePassword event + if ($genpassword == 1) { + $modx->invokeEvent("OnManagerChangePassword", array( + "userid" => $id, + "username" => $newusername, + "userpassword" => $newpassword + )); + } + + // invoke OnUserFormSave event + $modx->invokeEvent("OnUserFormSave", array( + "mode" => "upd", + "id" => $id + )); + + /*******************************************************************************/ + // put the user in the user_groups he/ she should be in + // first, check that up_perms are switched on! + if ($use_udperms == 1) { + // as this is an existing user, delete his/ her entries in the groups before saving the new groups + $modx->db->delete($tbl_member_groups, "member='{$id}'"); + if (!empty($user_groups)) { + for ($i = 0; $i < count($user_groups); $i++) { + $field = array(); + $field['user_group'] = (int)$user_groups[$i]; + $field['member'] = $id; + $modx->db->insert($field, $tbl_member_groups); + } + } + } + // end of user_groups stuff! + /*******************************************************************************/ + if ($id == $modx->getLoginUserID() && ($genpassword !== 1 && $passwordnotifymethod != 's')) { + $modx->webAlertAndQuit($_lang["user_changeddata"], 'javascript:top.location.href="index.php?a=8";'); + } + if ($genpassword == 1 && $passwordnotifymethod == 's') { + if ($input['stay'] != '') { + $a = ($input['stay'] == '2') ? "12&id={$id}" : "11"; + $stayUrl = "index.php?a={$a}&r=2&stay=" . $input['stay']; + } else { + $stayUrl = "index.php?a=75&r=2"; + } + + include_once "header.inc.php"; + ?> + +

        + + + +
        +
        +
        +

        htmlspecialchars($newusername), + $modx->htmlspecialchars($newpassword)) . (($id == $modx->getLoginUserID()) ? ' ' . $_lang['user_changeddata'] : ''); ?>

        +
        +
        +
        + "; - $param['subject'] = $emailsubject; - $param['body'] = $message; - $param['to'] = $email; - $param['type'] = 'text'; - $rs = $modx->sendmail($param); - if(!$rs) { - $modx->manager->saveFormValues(); - $modx->messageQuit("{$email} - {$_lang['error_sending_email']}"); - } +function sendMailMessage( + $email, + $uid, + $pwd, + $ufn +) { + $modx = evolutionCMS(); + global $_lang, $signupemail_message; + global $emailsubject, $emailsender; + global $site_name; + $manager_url = MODX_MANAGER_URL; + $message = sprintf($signupemail_message, $uid, $pwd); // use old method + // replace placeholders + $message = str_replace("[+uid+]", $uid, $message); + $message = str_replace("[+pwd+]", $pwd, $message); + $message = str_replace("[+ufn+]", $ufn, $message); + $message = str_replace("[+sname+]", $site_name, $message); + $message = str_replace("[+saddr+]", $emailsender, $message); + $message = str_replace("[+semail+]", $emailsender, $message); + $message = str_replace("[+surl+]", $manager_url, $message); + + $param = array(); + $param['from'] = "{$site_name}<{$emailsender}>"; + $param['subject'] = $emailsubject; + $param['body'] = $message; + $param['to'] = $email; + $param['type'] = 'text'; + $rs = $modx->sendmail($param); + if (!$rs) { + $modx->manager->saveFormValues(); + $modx->messageQuit("{$email} - {$_lang['error_sending_email']}"); + } } /** @@ -389,87 +406,89 @@ function sendMailMessage($email, $uid, $pwd, $ufn) { * * @param int $id */ -function saveUserSettings($id) { - $modx = evolutionCMS(); - $tbl_user_settings = $modx->getFullTableName('user_settings'); - - $ignore = array( - 'id', - 'oldusername', - 'oldemail', - 'newusername', - 'fullname', - 'newpassword', - 'newpasswordcheck', - 'passwordgenmethod', - 'passwordnotifymethod', - 'specifiedpassword', - 'confirmpassword', - 'email', - 'phone', - 'mobilephone', - 'fax', - 'dob', - 'country', - 'street', - 'city', - 'state', - 'zip', - 'gender', - 'photo', - 'comment', - 'role', - 'failedlogincount', - 'blocked', - 'blockeduntil', - 'blockedafter', - 'user_groups', - 'mode', - 'blockedmode', - 'stay', - 'save', - 'theme_refresher' - ); - - // determine which settings can be saved blank (based on 'default_{settingname}' POST checkbox values) - $defaults = array( - 'upload_images', - 'upload_media', - 'upload_flash', - 'upload_files' - ); - - // get user setting field names - $settings = array(); - foreach($_POST as $n => $v) { - if(in_array($n, $ignore) || (!in_array($n, $defaults) && is_scalar($v) && trim($v) == '') || (!in_array($n, $defaults) && is_array($v) && empty($v))) { - continue; - } // ignore blacklist and empties - $settings[$n] = $v; // this value should be saved - } - - foreach($defaults as $k) { - if(isset($settings['default_' . $k]) && $settings['default_' . $k] == '1') { - unset($settings[$k]); - } - unset($settings['default_' . $k]); - } - - $modx->db->delete($tbl_user_settings, "user='{$id}'"); - - foreach($settings as $n => $vl) { - if(is_array($vl)) { - $vl = implode(",", $vl); - } - if($vl != '') { - $f = array(); - $f['user'] = $id; - $f['setting_name'] = $n; - $f['setting_value'] = $vl; - $f = $modx->db->escape($f); - $modx->db->insert($f, $tbl_user_settings); - } - } +function saveUserSettings($id) +{ + $modx = evolutionCMS(); + $tbl_user_settings = $modx->getFullTableName('user_settings'); + + $ignore = array( + 'id', + 'oldusername', + 'oldemail', + 'newusername', + 'fullname', + 'newpassword', + 'newpasswordcheck', + 'passwordgenmethod', + 'passwordnotifymethod', + 'specifiedpassword', + 'confirmpassword', + 'email', + 'phone', + 'mobilephone', + 'fax', + 'dob', + 'country', + 'street', + 'city', + 'state', + 'zip', + 'gender', + 'photo', + 'comment', + 'role', + 'failedlogincount', + 'blocked', + 'blockeduntil', + 'blockedafter', + 'user_groups', + 'mode', + 'blockedmode', + 'stay', + 'save', + 'theme_refresher' + ); + + // determine which settings can be saved blank (based on 'default_{settingname}' POST checkbox values) + $defaults = array( + 'upload_images', + 'upload_media', + 'upload_flash', + 'upload_files' + ); + + // get user setting field names + $settings = array(); + foreach ($_POST as $n => $v) { + if (in_array($n, $ignore) || (!in_array($n, $defaults) && is_scalar($v) && trim($v) == '') || (!in_array($n, + $defaults) && is_array($v) && empty($v))) { + continue; + } // ignore blacklist and empties + $settings[$n] = $v; // this value should be saved + } + + foreach ($defaults as $k) { + if (isset($settings['default_' . $k]) && $settings['default_' . $k] == '1') { + unset($settings[$k]); + } + unset($settings['default_' . $k]); + } + + $modx->db->delete($tbl_user_settings, "user='{$id}'"); + + foreach ($settings as $n => $vl) { + if (is_array($vl)) { + $vl = implode(",", $vl); + } + if ($vl != '') { + $f = array(); + $f['user'] = $id; + $f['setting_name'] = $n; + $f['setting_value'] = $vl; + $f = $modx->db->escape($f); + $modx->db->insert($f, $tbl_user_settings); + } + } } /** @@ -477,11 +496,12 @@ function saveUserSettings($id) { * * @param $msg */ -function webAlertAndQuit($msg) { - global $id, $modx; - $mode = $_POST['mode']; - $modx->manager->saveFormValues($mode); - $modx->webAlertAndQuit($msg, "index.php?a={$mode}" . ($mode == '12' ? "&id={$id}" : '')); +function webAlertAndQuit($msg) +{ + global $id, $modx; + $mode = $_POST['mode']; + $modx->manager->saveFormValues($mode); + $modx->webAlertAndQuit($msg, "index.php?a={$mode}" . ($mode == '12' ? "&id={$id}" : '')); } /** @@ -490,13 +510,14 @@ function webAlertAndQuit($msg) { * @param int $length * @return string */ -function generate_password($length = 10) { - $allowable_characters = "abcdefghjkmnpqrstuvxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; - $ps_len = strlen($allowable_characters); - mt_srand((double) microtime() * 1000000); - $pass = ""; - for($i = 0; $i < $length; $i++) { - $pass .= $allowable_characters[mt_rand(0, $ps_len - 1)]; - } - return $pass; +function generate_password($length = 10) +{ + $allowable_characters = "abcdefghjkmnpqrstuvxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; + $ps_len = strlen($allowable_characters); + mt_srand((double)microtime() * 1000000); + $pass = ""; + for ($i = 0; $i < $length; $i++) { + $pass .= $allowable_characters[mt_rand(0, $ps_len - 1)]; + } + return $pass; } diff --git a/manager/processors/save_web_user.processor.php b/manager/processors/save_web_user.processor.php index 4292a8b13c..8a4728ff79 100755 --- a/manager/processors/save_web_user.processor.php +++ b/manager/processors/save_web_user.processor.php @@ -1,9 +1,9 @@ INCLUDE_ORDERING_ERROR

        Please use the EVO Content Manager instead of accessing this file directly."); +if (!defined('IN_MANAGER_MODE') || IN_MANAGER_MODE !== true) { + die("INCLUDE_ORDERING_ERROR

        Please use the EVO Content Manager instead of accessing this file directly."); } -if(!$modx->hasPermission('save_web_user')) { - $modx->webAlertAndQuit($_lang["error_no_privileges"]); +if (!$modx->hasPermission('save_web_user')) { + $modx->webAlertAndQuit($_lang["error_no_privileges"]); } $tbl_web_users = $modx->getFullTableName('web_users'); @@ -11,11 +11,11 @@ $tbl_web_groups = $modx->getFullTableName('web_groups'); $input = $_POST; -foreach($input as $k => $v) { - if($k !== 'comment') { - $v = sanitize($v); - } - $input[$k] = $v; +foreach ($input as $k => $v) { + if ($k !== 'comment' && $k !== 'user_groups') { + $v = sanitize($v); + } + $input[$k] = $v; } $id = (int)$input['id']; @@ -50,83 +50,84 @@ $user_groups = $input['user_groups']; // verify password -if($passwordgenmethod == "spec" && $input['specifiedpassword'] != $input['confirmpassword']) { - webAlertAndQuit("Password typed is mismatched"); +if ($passwordgenmethod == "spec" && $input['specifiedpassword'] != $input['confirmpassword']) { + webAlertAndQuit("Password typed is mismatched"); } // verify email -if($email == '' || !preg_match("/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,24}$/i", $email)) { - webAlertAndQuit("E-mail address doesn't seem to be valid!"); +if ($email == '' || !preg_match("/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,24}$/i", $email)) { + webAlertAndQuit("E-mail address doesn't seem to be valid!"); } -switch($input['mode']) { - case '87' : // new user - // check if this user name already exist - $rs = $modx->db->select('count(id)', $tbl_web_users, "username='{$esc_newusername}'"); - $limit = $modx->db->getValue($rs); - if($limit > 0) { - webAlertAndQuit("User name is already in use!"); - } - - // check if the email address already exist - if ($modx->config['allow_multiple_emails'] != 1) { - $rs = $modx->db->select('count(id)', $tbl_web_user_attributes, "email='{$esc_email}' AND id!='{$id}'"); - $limit = $modx->db->getValue($rs); - if($limit > 0) { - webAlertAndQuit("Email is already in use!"); - } - } - - // generate a new password for this user - if($specifiedpassword != "" && $passwordgenmethod == "spec") { - if(strlen($specifiedpassword) < 6) { - webAlertAndQuit("Password is too short!"); - } else { - $newpassword = $specifiedpassword; - } - } elseif($specifiedpassword == "" && $passwordgenmethod == "spec") { - webAlertAndQuit("You didn't specify a password for this user!"); - } elseif($passwordgenmethod == 'g') { - $newpassword = generate_password(8); - } else { - webAlertAndQuit("No password generation method specified!"); - } - - // invoke OnBeforeWUsrFormSave event - $modx->invokeEvent("OnBeforeWUsrFormSave", array( - "mode" => "new", - )); - - // create the user account - $field = array(); - $field['username'] = $esc_newusername; - $field['password'] = md5($newpassword); - $internalKey = $modx->db->insert($field, $tbl_web_users); - - $field = compact('internalKey', 'fullname', 'role', 'email', 'phone', 'mobilephone', 'fax', 'zip', 'street', 'city', 'state', 'country', 'gender', 'dob', 'photo', 'comment', 'blocked', 'blockeduntil', 'blockedafter'); - $field = $modx->db->escape($field); - $modx->db->insert($field, $tbl_web_user_attributes); - - // Save User Settings - saveUserSettings($internalKey); - - // Set the item name for logger - $_SESSION['itemname'] = $newusername; - - /*******************************************************************************/ - // put the user in the user_groups he/ she should be in - // first, check that up_perms are switched on! - if($use_udperms == 1) { - if(!empty($user_groups)) { - for($i = 0; $i < count($user_groups); $i++) { - $f = array(); - $f['webgroup'] = (int)$user_groups[$i]; - $f['webuser'] = $internalKey; - $modx->db->insert($f, $tbl_web_groups); - } - } - } - // end of user_groups stuff! +switch ($input['mode']) { + case '87' : // new user + // check if this user name already exist + $rs = $modx->db->select('count(id)', $tbl_web_users, "username='{$esc_newusername}'"); + $limit = $modx->db->getValue($rs); + if ($limit > 0) { + webAlertAndQuit("User name is already in use!"); + } + + // check if the email address already exist + if ($modx->config['allow_multiple_emails'] != 1) { + $rs = $modx->db->select('count(id)', $tbl_web_user_attributes, "email='{$esc_email}' AND id!='{$id}'"); + $limit = $modx->db->getValue($rs); + if ($limit > 0) { + webAlertAndQuit("Email is already in use!"); + } + } + + // generate a new password for this user + if ($specifiedpassword != "" && $passwordgenmethod == "spec") { + if (strlen($specifiedpassword) < 6) { + webAlertAndQuit("Password is too short!"); + } else { + $newpassword = $specifiedpassword; + } + } elseif ($specifiedpassword == "" && $passwordgenmethod == "spec") { + webAlertAndQuit("You didn't specify a password for this user!"); + } elseif ($passwordgenmethod == 'g') { + $newpassword = generate_password(8); + } else { + webAlertAndQuit("No password generation method specified!"); + } + + // invoke OnBeforeWUsrFormSave event + $modx->invokeEvent("OnBeforeWUsrFormSave", array( + "mode" => "new", + )); + + // create the user account + $field = array(); + $field['username'] = $esc_newusername; + $field['password'] = md5($newpassword); + $internalKey = $modx->db->insert($field, $tbl_web_users); + + $field = compact('internalKey', 'fullname', 'role', 'email', 'phone', 'mobilephone', 'fax', 'zip', 'street', + 'city', 'state', 'country', 'gender', 'dob', 'photo', 'comment', 'blocked', 'blockeduntil', 'blockedafter'); + $field = $modx->db->escape($field); + $modx->db->insert($field, $tbl_web_user_attributes); + + // Save User Settings + saveUserSettings($internalKey); + + // Set the item name for logger + $_SESSION['itemname'] = $newusername; + + /*******************************************************************************/ + // put the user in the user_groups he/ she should be in + // first, check that up_perms are switched on! + if ($use_udperms == 1) { + if (!empty($user_groups)) { + for ($i = 0; $i < count($user_groups); $i++) { + $f = array(); + $f['webgroup'] = (int)$user_groups[$i]; + $f['webuser'] = $internalKey; + $modx->db->insert($f, $tbl_web_groups); + } + } + } + // end of user_groups stuff! // invoke OnWebSaveUser event $modx->invokeEvent("OnWebSaveUser", array( @@ -144,127 +145,130 @@ "id" => $internalKey )); - if($passwordnotifymethod == 'e') { - sendMailMessage($email, $newusername, $newpassword, $fullname); - if($input['stay'] != '') { - $a = ($input['stay'] == '2') ? "88&id={$internalKey}" : "87"; - $header = "Location: index.php?a={$a}&r=2&stay=" . $input['stay']; - header($header); - } else { - $header = "Location: index.php?a=99&r=2"; - header($header); - } - } else { - if($input['stay'] != '') { - $a = ($input['stay'] == '2') ? "88&id={$internalKey}" : "87"; - $stayUrl = "index.php?a={$a}&r=2&stay=" . $input['stay']; - } else { - $stayUrl = "index.php?a=99&r=2"; - } - - include_once "header.inc.php"; - ?> - -

        - -
        - -
        - -
        -
        -
        -
        -

        - -

        -
        -
        -
        - db->select('count(id)', $tbl_web_users, "username='{$esc_newusername}' AND id!='{$id}'"); - $limit = $modx->db->getValue($rs); - if($limit > 0) { - webAlertAndQuit("User name is already in use!"); - } - - // check if the email address already exists - if ($modx->config['allow_multiple_emails'] != 1) { - $rs = $modx->db->select('count(internalKey)', $tbl_web_user_attributes, "email='{$esc_email}' AND internalKey!='{$id}'"); - $limit = $modx->db->getValue($rs); - if($limit > 0) { - webAlertAndQuit("Email is already in use!"); - } - } - - // invoke OnBeforeWUsrFormSave event - $modx->invokeEvent("OnBeforeWUsrFormSave", array( - "mode" => "upd", - "id" => $id - )); - - // update user name and password - $field = array(); - $field['username'] = $esc_newusername; - if($genpassword == 1) { - $field['password'] = md5($newpassword); - } - $modx->db->update($field, $tbl_web_users, "id='{$id}'"); - $field = compact('fullname', 'role', 'email', 'phone', 'mobilephone', 'fax', 'zip', 'street', 'city', 'state', 'country', 'gender', 'dob', 'photo', 'comment', 'failedlogincount', 'blocked', 'blockeduntil', 'blockedafter'); - $field = $modx->db->escape($field); - $modx->db->update($field, $tbl_web_user_attributes, "internalKey='{$id}'"); - - // Save User Settings - saveUserSettings($id); - - // Set the item name for logger - $_SESSION['itemname'] = $newusername; - - /*******************************************************************************/ - // put the user in the user_groups he/ she should be in - // first, check that up_perms are switched on! - if($use_udperms == 1) { - // as this is an existing user, delete his/ her entries in the groups before saving the new groups - $modx->db->delete($tbl_web_groups, "webuser='{$id}'"); - if(!empty($user_groups)) { - for($i = 0; $i < count($user_groups); $i++) { - $field = array(); - $field['webgroup'] = (int)$user_groups[$i]; - $field['webuser'] = $id; - $modx->db->insert($field, $tbl_web_groups); - } - } - } - // end of user_groups stuff! - /*******************************************************************************/ + if ($passwordnotifymethod == 'e') { + sendMailMessage($email, $newusername, $newpassword, $fullname); + if ($input['stay'] != '') { + $a = ($input['stay'] == '2') ? "88&id={$internalKey}" : "87"; + $header = "Location: index.php?a={$a}&r=2&stay=" . $input['stay']; + header($header); + } else { + $header = "Location: index.php?a=99&r=2"; + header($header); + } + } else { + if ($input['stay'] != '') { + $a = ($input['stay'] == '2') ? "88&id={$internalKey}" : "87"; + $stayUrl = "index.php?a={$a}&r=2&stay=" . $input['stay']; + } else { + $stayUrl = "index.php?a=99&r=2"; + } + + include_once "header.inc.php"; + ?> + +

        + +
        +
        + "> + +
        +
        + +
        +
        +
        +

        + +

        +
        +
        +
        + db->select('count(id)', $tbl_web_users, "username='{$esc_newusername}' AND id!='{$id}'"); + $limit = $modx->db->getValue($rs); + if ($limit > 0) { + webAlertAndQuit("User name is already in use!"); + } + + // check if the email address already exists + if ($modx->config['allow_multiple_emails'] != 1) { + $rs = $modx->db->select('count(internalKey)', $tbl_web_user_attributes, + "email='{$esc_email}' AND internalKey!='{$id}'"); + $limit = $modx->db->getValue($rs); + if ($limit > 0) { + webAlertAndQuit("Email is already in use!"); + } + } + + // invoke OnBeforeWUsrFormSave event + $modx->invokeEvent("OnBeforeWUsrFormSave", array( + "mode" => "upd", + "id" => $id + )); + + // update user name and password + $field = array(); + $field['username'] = $esc_newusername; + if ($genpassword == 1) { + $field['password'] = md5($newpassword); + } + $modx->db->update($field, $tbl_web_users, "id='{$id}'"); + $field = compact('fullname', 'role', 'email', 'phone', 'mobilephone', 'fax', 'zip', 'street', 'city', 'state', + 'country', 'gender', 'dob', 'photo', 'comment', 'failedlogincount', 'blocked', 'blockeduntil', + 'blockedafter'); + $field = $modx->db->escape($field); + $modx->db->update($field, $tbl_web_user_attributes, "internalKey='{$id}'"); + + // Save User Settings + saveUserSettings($id); + + // Set the item name for logger + $_SESSION['itemname'] = $newusername; + + /*******************************************************************************/ + // put the user in the user_groups he/ she should be in + // first, check that up_perms are switched on! + if ($use_udperms == 1) { + // as this is an existing user, delete his/ her entries in the groups before saving the new groups + $modx->db->delete($tbl_web_groups, "webuser='{$id}'"); + if (!empty($user_groups)) { + for ($i = 0; $i < count($user_groups); $i++) { + $field = array(); + $field['webgroup'] = (int)$user_groups[$i]; + $field['webuser'] = $id; + $modx->db->insert($field, $tbl_web_groups); + } + } + } + // end of user_groups stuff! + /*******************************************************************************/ // invoke OnWebSaveUser event $modx->invokeEvent("OnWebSaveUser", array( @@ -279,7 +283,7 @@ )); // invoke OnWebChangePassword event - if($genpassword == 1) { + if ($genpassword == 1) { $modx->invokeEvent("OnWebChangePassword", array( "userid" => $id, "username" => $newusername, @@ -293,49 +297,49 @@ "id" => $id )); - if($genpassword == 1 && $passwordnotifymethod == 's') { - if($input['stay'] != '') { - $a = ($input['stay'] == '2') ? "88&id={$id}" : "87"; - $stayUrl = "index.php?a={$a}&r=2&stay=" . $input['stay']; - } else { - $stayUrl = "index.php?a=99&r=2"; - } - - include_once "header.inc.php"; - ?> - -

        - -
        - -
        - -
        -
        -
        -
        -

        -
        -
        -
        - + +

        + +
        +
        + "> + +
        +
        + +
        +
        +
        +

        +
        +
        +
        + "; - $param['subject'] = $emailsubject; - $param['body'] = $message; - $param['to'] = $email; - $param['type'] = 'text'; - $rs = $modx->sendmail($param); - if(!$rs) { - $modx->manager->saveFormValues(); - $modx->messageQuit("{$email} - {$_lang['error_sending_email']}"); - } +function sendMailMessage( + $email, + $uid, + $pwd, + $ufn +) { + $modx = evolutionCMS(); + global $_lang, $websignupemail_message; + global $emailsubject, $emailsender; + global $site_name, $site_url; + $message = sprintf($websignupemail_message, $uid, $pwd); // use old method + // replace placeholders + $message = str_replace("[+uid+]", $uid, $message); + $message = str_replace("[+pwd+]", $pwd, $message); + $message = str_replace("[+ufn+]", $ufn, $message); + $message = str_replace("[+sname+]", $site_name, $message); + $message = str_replace("[+saddr+]", $emailsender, $message); + $message = str_replace("[+semail+]", $emailsender, $message); + $message = str_replace("[+surl+]", $site_url, $message); + + $param = array(); + $param['from'] = "{$site_name}<{$emailsender}>"; + $param['subject'] = $emailsubject; + $param['body'] = $message; + $param['to'] = $email; + $param['type'] = 'text'; + $rs = $modx->sendmail($param); + if (!$rs) { + $modx->manager->saveFormValues(); + $modx->messageQuit("{$email} - {$_lang['error_sending_email']}"); + } } // Save User Settings -function saveUserSettings($id) { - $modx = evolutionCMS(); - $tbl_web_user_settings = $modx->getFullTableName('web_user_settings'); - - $settings = array( - "login_home", - "allowed_ip", - "allowed_days" - ); - - $modx->db->delete($tbl_web_user_settings, "webuser='{$id}'"); - - foreach($settings as $n) { - $vl = $_POST[$n]; - if(is_array($vl)) { - $vl = implode(",", $vl); - } - if($vl != '') { - $f = array(); - $f['webuser'] = $id; - $f['setting_name'] = $n; - $f['setting_value'] = $vl; - $f = $modx->db->escape($f); - $modx->db->insert($f, $tbl_web_user_settings); - } - } +function saveUserSettings($id) +{ + $modx = evolutionCMS(); + $tbl_web_user_settings = $modx->getFullTableName('web_user_settings'); + + $settings = array( + "login_home", + "allowed_ip", + "allowed_days" + ); + + $modx->db->delete($tbl_web_user_settings, "webuser='{$id}'"); + + foreach ($settings as $n) { + $vl = $_POST[$n]; + if (is_array($vl)) { + $vl = implode(",", $vl); + } + if ($vl != '') { + $f = array(); + $f['webuser'] = $id; + $f['setting_name'] = $n; + $f['setting_value'] = $vl; + $f = $modx->db->escape($f); + $modx->db->insert($f, $tbl_web_user_settings); + } + } } // Web alert - sends an alert to web browser -function webAlertAndQuit($msg) { - global $id, $modx; - $mode = $_POST['mode']; - $modx->manager->saveFormValues($mode); - $modx->webAlertAndQuit($msg, "index.php?a={$mode}" . ($mode == '88' ? "&id={$id}" : '')); +function webAlertAndQuit($msg) +{ + global $id, $modx; + $mode = $_POST['mode']; + $modx->manager->saveFormValues($mode); + $modx->webAlertAndQuit($msg, "index.php?a={$mode}" . ($mode == '88' ? "&id={$id}" : '')); } // Generate password -function generate_password($length = 10) { - $allowable_characters = "abcdefghjkmnpqrstuvxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; - $ps_len = strlen($allowable_characters); - mt_srand((double) microtime() * 1000000); - $pass = ""; - for($i = 0; $i < $length; $i++) { - $pass .= $allowable_characters[mt_rand(0, $ps_len - 1)]; - } - return $pass; +function generate_password($length = 10) +{ + $allowable_characters = "abcdefghjkmnpqrstuvxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"; + $ps_len = strlen($allowable_characters); + mt_srand((double)microtime() * 1000000); + $pass = ""; + for ($i = 0; $i < $length; $i++) { + $pass .= $allowable_characters[mt_rand(0, $ps_len - 1)]; + } + return $pass; } -function sanitize($str = '', $safecount = 0) { - $modx = evolutionCMS(); - $safecount++; - if(1000 < $safecount) { - exit("error too many loops '{$safecount}'"); - } - if(is_array($str)) { - foreach($str as $i => $v) { - $str[$i] = sanitize($v, $safecount); - } - } else { - // $str = strip_tags($str); // LEAVE < and > intact - $str = htmlspecialchars($str, ENT_NOQUOTES, $modx->config['modx_charset']); - } - return $str; +function sanitize( + $str = '', + $safecount = 0 +) { + $modx = evolutionCMS(); + $safecount++; + if (1000 < $safecount) { + exit("error too many loops '{$safecount}'"); + } + if (is_array($str)) { + foreach ($str as $i => $v) { + $str[$i] = sanitize($v, $safecount); + } + } else { + // $str = strip_tags($str); // LEAVE < and > intact + $str = htmlspecialchars($str, ENT_NOQUOTES, $modx->config['modx_charset']); + } + return $str; }