�PNG  IHDR22?�� pHYs  �� OiCCPPhotoshop ICC profilexڝSgTS�=���BK���KoR RB���&*! J�!��Q�EEȠ�����Q, � ��!���������{�kּ������>���� �H3Q5� �B�������.@� $p�d!s�#�~<<+"��x� �M��0���B�\���t�8K�@z�B�@F���&S�`�cb�P-`'������{[�!�� e�Dh;��V�EX0fK�9�-0IWfH���� � 0Q��){`�##x��F�W<�+��*x��<�$9E�[-qWW.(�I+6aa�@.�y�2�4���������x����6��_-��"bb���ϫp@�t~��,/��;�m��%�h^ �u��f�@����W�p�~<�5�j>{�-�]c�K'Xt����o��(�h���w��?�G�%�fI�q^D$.Tʳ?�D��*�A��,���� �`6�B$��BB d�r`)��B(�Ͱ*`/�@4�Qh��p.�U�=p�a��(�� A�a!ڈb�X#����!�H�$ ɈQ"K�5H1R�T UH�=r9�\F��;�2����G1���Q=� �C��7�F� �dt1�����r�=�6��Ыhڏ>C�0��3�l0.��B�8, �c˱"� ���V����cϱw�E� 6wB aAHXLXN�H� $4� 7 �Q�'"��K�&���b21�XH,#��/{�C�7$�C2'��I��T��F�nR#�,��4H#���dk�9�, +ȅ����3��!�[ �b@q��S�(R�jJ��4�e�2AU��Rݨ�T5�ZB���R�Q��4u�9̓IK�����hh�i��t�ݕN��W���G���w ��Ljg(�gw��L�Ӌ�T071���oUX*�*|�� �J�&�*/T����ު U�U�T��^S}�FU3S� Ԗ�U��P�SSg�;���g�oT?�~Y��Y�L�OC�Q��_�� c�x,!k ��u�5�&���|v*�����=���9C3J3W�R�f?�q��tN �(���~���)�)�4L�1e\k����X�H�Q�G�6������E�Y��A�J'\'Gg����S�Sݧ �M=:��.�k���Dw�n��^��Lo��y���}/�T�m���G X� $� �<�5qo</���QC]�@C�a�a�ᄑ��<��F�F�i�\�$�m�mƣ&&!&KM�M�RM��)�;L;L���͢�֙5�=1�2��כ߷`ZxZ,����eI��Z�Yn�Z9Y�XUZ]�F���%ֻ�����N�N���gð�ɶ�����ۮ�m�}agbg�Ů��}�}��= ���Z~s�r:V:ޚΜ�?}����/gX���3��)�i�S��Ggg�s�󈋉K��.�>.���Ƚ�Jt�q]�z���������ۯ�6�i�ܟ�4�)�Y3s���C�Q��? ��0k߬~OCO�g��#/c/�W�װ��w��a�>�>r��>�<7�2�Y_�7��ȷ�O�o�_��C#�d�z����%g��A�[��z|!��?:�e����A���AA�������!h�쐭!��Α�i�P~���a�a��~ '���W�?�p�X�1�5w��Cs�D�D�Dޛg1O9�-J5*>�.j<�7�4�?�.fY��X�XIlK9.*�6nl������� �{�/�]py�����.,:�@L�N8��A*��%�w%� y��g"/�6ш�C\*N�H*Mz�쑼5y$�3�,幄'���L Lݛ:��v m2=:�1����qB�!M��g�g�fvˬe����n��/��k���Y- �B��TZ(�*�geWf�͉�9���+��̳�ې7�����ᒶ��KW-X潬j9�������(�x��oʿ�ܔ���Ĺd�f�f���-�[����n �ڴ �V����E�/��(ۻ��C���<��e����;?T�T�T�T6��ݵa��n��{��4���[���>ɾ�UUM�f�e�I���?�������m]�Nmq����#�׹���=TR��+�G�����w- 6 U����#pDy��� �� :�v�{���vg/jB��F�S��[b[�O�>����z�G��499�?r����C�d�&����ˮ/~�����јѡ�򗓿m|������������x31^�V���w�w��O�| (�h���SЧ��������c3-� cHRMz%������u0�`:�o�_�F5IDATx��ytUս�?�;���fN$$��@B�!�k��� -*�gE���j�O�kQ�ʠ`U�B_ �AÐ0%�Ȕ�@r3ޛ;߳��$�@��v����^�s����������$��ߢ !�W��5�̱'-٘������4�>�Rƫ$�G��0U�H}�_ _� #��k�MJ/=�9Du *ڲ�k�PQ;0��j|�*�$�^컂脛y���>�z×� B��� ��(�:$�ʔ_�6��C!B����MVx��a��ζyY����j��ƋY2�9�F�{r��r�딟F��Q��hY6��� x��[l��RC��������nt@��;P��3��� F�w��7��:�P���ɋ'���mj���Bƪ�$�Q�L��y��߷g��\���z����v5�p�v$�v櫻�`6~K �Y�X����,�:��"�o�e0II"(��,������l_�C���/4�+f�E�!q��:����u����c��樼.UE�@� �]K�W���$-�h]�JG���Dz)�`��.�A/ ���mᏣc�3jK� �!�>���$�Q�!�_�? \�C2(E �M$Z I{�U���s�ǣ���=��@Բe ޻��W�����@ �w����}�9v,)��.}*|"�s��di���,���G�]W�AC�������|<����[��ߕ������K�*�G nߴ!��‹��J�!��6(L�a)��Am��������;adf��:�xm��nh�;֦I��(���o�C~ډa?�=��s����h��E������xp����)���_���t��W�����´;8���`dz=(��@@�+,�;�`�fhl��XȌ�3,uI�~z(J����� �ZX�A����H'�À�㜦�82|��a�n�z2��I���� ���EY�h�ε<�0�q�{��C��v�˅��?"@��χ�x�WS+��N�~�KQ�J�8ل�� _.W��� !TU{�����,��"�� �;�������HI S� ��))�o�1�H�D� ���� (� ;����"Ҕ��,���� �F=���O��&�Ph>�`���y��߲ &S��P�<��'��1s�1cĂ�N����2)����@�u��tv��<�+�-&�����h��[!FSG���' � z z0��<����8d&�����E0�,��<��"!P�b4��� �{S�����X����.�囤���T��hEF��X�q0"-<����h���]�Py*����F⩍��@v�˂�Y08�� .q��a��s����(!<̫1�3�L�H��7sYW�`��qtu�\7��?�@�Y�� %Ka�x�GZ�*W�P��y�����N0r9��Z�c�%���q,��k�����!!,��>���IB��� �x1�Xu�Y���v-���ֺ��N������JP��a�2`�e5��w��u;�6�i���̃��(K���ťa��(l51��JL��O'%���]���ٖ뿉!��{*�p+f ���i8��D�ȑ���ܩ�M��V��ӟz��x�7Z�1i}�^͜���6e����x��)u�d�ˏ�V�eG�\�X1�����=n�U'�~Y����L�\,�(d!x ,�:�TW8� M`r���@��r+v�Q0��>^;˴�VbF��('����� �*O��i��j�Ӆ����^�S3&� ���{������.ی�� N;��NU%d0�Ce\r"�C�b��&t7N�7��� �ȪD�[%l�۪�$��'m?�A9tI�9>��NVL ��� 6v~M�����ъ�B���0����9$&=ώm��W�0���L���&��E���f�f��'+�9��hv��7,���M��6�D�&�^� �����8 D֮�����o��k^z��O��hP�8q�5d*��YVq3�{��������#LX4�?��jP=3�~�؅c�ݰ�̱�ұ��8̲��2�G�����j��έ�9��w7���U�X�w�85C��?!I&���o&����L���I#�^�eV�,�^t5�k� �xs˛\��U�8��."���{���ǵ�l4��ݼ�;��r"���G�/~���gJV�N糦��ZZ^k+NN�D��I$�=OE�z����|*�*{��%k���G��>�`9��b;�s���8,�qs��c��.b��q�%�>r��n�R�Ƨ�%�,�A��le#�8���}; 21�0�b�&�QX�f���q�00����$>�h�N�'�a3��A���/�r ��L5�8�GԲ'�����w;��c#�q1���h$*��V^�k��QĽ�b:i������� ����H F#�_���,��]g����Ը����`RUU���� ��"�qD���>-��ϤI�~��3�̴�����NZ[[555�eeek7�m����YF#[��Đ��R��i��L�H�r ��@��J-�Pŝ��_|�-��6y��ks�V�U~��6���w.����(��0A� 4��f��� /���C�xŊ�ٳ����z=6�����rg���mKo��o�/����a�g���?'9%9��P��斓��~���L{�� �H��{AW��B��$����v�1b�&Mb�ر��ر#�0`�`xMBp! )Z�Nmo�mZ�g�}�eذaWTVV ���'99��C5��&�&+5�bT>|8��PUUETT����&���t��~TE%��'������b�tEGG;RSS�S�N�v��ѯ��t����u1@�ޚ"f��͈���r'L�Ph��m��ƌ�74o��`�x�q�P���NRSS�X,�����l&&&��MFFA!-��`��ҷ�n��Yuu�����x<I�LB%����KԒ50�!�3�bz�����ʸKL���;---�l6[��`��������Ȏ;�����egg4��!D�T��jWujyZ��������K����%����p�^���X,6��sV=�ܖ����6�3�X ���4ҿ��A2�&����_k�;d�� �VfOIEND�B`�
Warning: session_start(): Session cannot be started after headers have already been sent in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 124

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 130

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 131

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 132

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 133

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 134

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 135

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 547

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 548

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 549

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 550

Warning: Cannot modify header information - headers already sent by (output started at /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php:1) in /home/mciraet/www/wp-includes/php-ai-client/src/Providers/Enums/Documentsoliders.php on line 551
setWAF($waf); $this->setRuleID($ruleID); $this->setType($type); $this->setCategory($category); $this->setScore($score); $this->setDescription($description); $this->setWhitelist($whitelist); $this->setAction($action); $this->setComparisonGroup($comparisonGroup); } public function __sleep() { return array( 'ruleID', 'type', 'category', 'score', 'description', 'whitelist', 'action', 'comparisonGroup', ); } /** * @return string */ public function render() { return sprintf('%s::create($this, %d, %s, %s, %s, %s, %d, %s, %s)', get_class($this), $this->getRuleID(), var_export($this->getType(), true), var_export($this->getCategory(), true), var_export($this->getScore(), true), var_export($this->getDescription(), true), var_export($this->getWhitelist(), true), var_export($this->getAction(), true), $this->getComparisonGroup()->render() ); } /** * @return string */ public function renderRule() { return sprintf(<<getComparisonGroup()->renderRule(), $this->getAction(), join(', ', array_filter(array( $this->getRuleID() ? 'id=' . (int) $this->getRuleID() : '', $this->getCategory() ? 'category=' . self::exportString($this->getCategory()) : '', $this->getScore() > 0 ? 'score=' . (int) $this->getScore() : '', $this->getDescription() ? 'description=' . self::exportString($this->getDescription()) : '', $this->getWhitelist() == 0 ? 'whitelist=0' : '', ))) ); } public function evaluate() { $comparisons = $this->getComparisonGroup(); $waf = $this->getWAF(); if ($comparisons instanceof wfWAFRuleComparisonGroup && $waf instanceof wfWAF) { $comparisons->setRule($this); if ($comparisons->evaluate()) { $waf->tripRule($this); return true; } } return false; } public function debug() { return $this->getComparisonGroup()->debug(); } /** * For JSON. * * @return array */ public function toArray() { return array( 'ruleID' => $this->getRuleID(), 'type' => $this->getType(), 'category' => $this->getCategory(), 'score' => $this->getScore(), 'description' => $this->getDescription(), 'whitelist' => $this->getWhitelist(), 'action' => $this->getAction(), ); } /** * @return int */ public function getRuleID() { return $this->ruleID; } /** * @param int $ruleID */ public function setRuleID($ruleID) { $this->ruleID = $ruleID; } /** * @return string */ public function getType() { return $this->type; } /** * @param string $type */ public function setType($type) { $this->type = $type; } /** * @return string */ public function getCategory() { return $this->category; } /** * @param string $category */ public function setCategory($category) { $this->category = $category; } /** * @return int */ public function getScore() { return $this->score; } /** * @param int $score */ public function setScore($score) { $this->score = $score; } /** * @return string */ public function getDescription() { return $this->description; } /** * @param string $description */ public function setDescription($description) { $this->description = $description; } /** * @return int */ public function getWhitelist() { return $this->whitelist; } /** * @param string $whitelist */ public function setWhitelist($whitelist) { $this->whitelist = $whitelist; } /** * @return string */ public function getAction() { return $this->action; } /** * @param string $action */ public function setAction($action) { $this->action = $action; } /** * @return wfWAFRuleComparisonGroup */ public function getComparisonGroup() { return $this->comparisonGroup; } /** * @param wfWAFRuleComparisonGroup $comparisonGroup */ public function setComparisonGroup($comparisonGroup) { $this->comparisonGroup = $comparisonGroup; } /** * @return wfWAF */ public function getWAF() { return $this->waf; } /** * @param wfWAF $waf */ public function setWAF($waf) { $this->waf = $waf; if ($this->comparisonGroup) { $this->comparisonGroup->setWAF($waf); } } } class wfWAFRuleLogicalOperator implements wfWAFRuleInterface { /** * @var string */ private $operator; /** * @var array */ protected $validOperators = array( '||', '&&', 'and', 'or', 'xor', ); /** * @var bool */ private $currentValue = false; /** * @var wfWAFRuleInterface */ private $comparison; /** * @param string $operator * @param bool $currentValue * @param wfWAFRuleInterface $comparison */ public function __construct($operator, $currentValue = false, $comparison = null) { $this->setOperator($operator); $this->setCurrentValue($currentValue); $this->setComparison($comparison); } public function __sleep() { return array( 'operator', 'currentValue', 'comparison', ); } /** * @return string * @throws wfWAFRuleLogicalOperatorException */ public function render() { if (!$this->isValid()) { throw new wfWAFRuleLogicalOperatorException(sprintf('Invalid logical operator "%s", must be one of %s', $this->getOperator(), join(", ", $this->validOperators))); } return sprintf("new %s(%s)", get_class($this), var_export(trim(wfWAFUtils::strtoupper($this->getOperator())), true)); } /** * @return string * @throws wfWAFRuleLogicalOperatorException */ public function renderRule() { if (!$this->isValid()) { throw new wfWAFRuleLogicalOperatorException(sprintf('Invalid logical operator "%s", must be one of %s', $this->getOperator(), join(", ", $this->validOperators))); } return trim(wfWAFUtils::strtolower($this->getOperator())); } public function evaluate() { $currentValue = $this->getCurrentValue(); $comparison = $this->getComparison(); if (is_bool($currentValue) && $comparison instanceof wfWAFRuleInterface) { switch (wfWAFUtils::strtolower($this->getOperator())) { case '&&': case 'and': return $currentValue && $comparison->evaluate(); case '||': case 'or': return $currentValue || $comparison->evaluate(); case 'xor': return $currentValue xor $comparison->evaluate(); } } return false; } /** * @return bool */ public function isValid() { return in_array(wfWAFUtils::strtolower($this->getOperator()), $this->validOperators); } /** * @return string */ public function getOperator() { return $this->operator; } /** * @param string $operator */ public function setOperator($operator) { $this->operator = $operator; } /** * @return boolean */ public function getCurrentValue() { return $this->currentValue; } /** * @param boolean $currentValue */ public function setCurrentValue($currentValue) { $this->currentValue = $currentValue; } /** * @return wfWAFRuleInterface */ public function getComparison() { return $this->comparison; } /** * @param wfWAFRuleInterface $comparison */ public function setComparison($comparison) { $this->comparison = $comparison; } } class wfWAFPhpBlock { public $open = false; public $echoTag; public $shortTag; public $openParentheses = 0, $closedParentheses = 0; public $backtickCount = 0; public $badCharacter = false; public $mismatchedParentheses = false; public function __construct($echoTag = false, $shortTag = false) { $this->echoTag = $echoTag; $this->shortTag = $shortTag; } public function hasParentheses() { return $this->openParentheses > 0 && $this->closedParentheses === $this->openParentheses; } public function hasBacktickPair() { return $this->backtickCount > 0 && $this->backtickCount % 2 === 0; } public function hasParenthesesOrBacktickPair() { return $this->hasParentheses() || $this->hasBacktickPair(); } public function hasMismatchedParentheses() { return $this->mismatchedParentheses || $this->closedParentheses !== $this->openParentheses; } public function hasSyntaxError() { if (version_compare(phpversion(), '8.0.0', '>=')) { return $this->badCharacter; } return $this->hasMismatchedParentheses(); } public static function isValid($phpBlock) { return $phpBlock !== null && !$phpBlock->hasSyntaxError(); } public static function extend($phpBlock, $echoTag = false, $shortTag = false) { if ($phpBlock === null) $phpBlock = new self(); $phpBlock->open = true; $phpBlock->echoTag = $echoTag; $phpBlock->shortTag = $shortTag; return $phpBlock; } } class wfWAFRuleComparison implements wfWAFRuleInterface { private $matches; private $failedSubjects; private $result; /** * @var wfWAFRule */ private $rule; private static $scalarActions = array( 'contains', 'notcontains', 'match', 'notmatch', 'matchcount', 'containscount', 'equals', 'notequals', 'identical', 'notidentical', 'greaterthan', 'greaterthanequalto', 'lessthan', 'lessthanequalto', 'lengthgreaterthan', 'lengthlessthan', 'currentuseris', 'currentuserisnot', 'md5equals', 'filepatternsmatch', 'filehasphp', 'islocalurl', 'isremoteurl', 'isvalidurl', 'isnotvalidurl', 'urlhostequals', 'urlhostnotequals', 'urlhostmatches', 'urlhostnotmatches', 'urlschemeequals', 'urlschemenotequals', 'urlschemematches', 'urlschemenotmatches', 'versionequals', 'versionnotequals', 'versiongreaterthan', 'versiongreaterthanequalto', 'versionlessthan', 'versionlessthanequalto', 'exists' ); private static $arrayActions = array( 'keyexists', 'keymatches' ); private static $globalActions = array( 'hasuser', 'nothasuser', 'currentusercan', 'currentusercannot' ); const ACTION_TYPE_SCALAR=0; const ACTION_TYPE_ARRAY=1; const ACTION_TYPE_GLOBAL=2; /** * @var mixed */ private $expected; /** * @var mixed */ private $subjects; /** * @var string */ private $action; private $multiplier; /** * @var wfWAF */ private $waf; /** * @param wfWAF $waf * @param string $action * @param mixed $expected * @param mixed $subjects */ public function __construct($waf, $action, $expected, $subjects = null) { $this->setWAF($waf); $this->setAction($action); $this->setExpected($expected); $this->setSubjects($subjects); } public function __sleep() { return array( 'rule', 'action', 'expected', 'subjects', ); } public function __wakeup() { if (empty($this->getWAF())) { $this->setWAF(wfWAF::getInstance()); } } /** * @param string|array $subject * @return string */ public static function getSubjectKey($subject) { if (!is_array($subject)) { return (string) $subject; } $return = ''; $global = array_shift($subject); if ($global instanceof wfWAFRuleComparisonSubject) { $global = 'filtered'; } foreach ($subject as $key) { $return .= '[' . $key . ']'; } return $global . $return; } /** * @return string * @throws wfWAFRuleException */ public function render() { if (!$this->isActionValid()) { throw new wfWAFRuleException('Invalid action passed to ' . get_class($this) . ', action: ' . var_export($this->getAction(), true)); } $subjectExport = ''; /** @var wfWAFRuleComparisonSubject $subject */ foreach ($this->getSubjects() as $subject) { $subjectExport .= $subject->render() . ",\n"; } $subjectExport = 'array(' . wfWAFUtils::substr($subjectExport, 0, -2) . ')'; $expected = $this->getExpected(); return sprintf('new %s($this, %s, %s, %s)', get_class($this), var_export((string) $this->getAction(), true), ($expected instanceof wfWAFRuleVariable ? $expected->render() : var_export($expected, true)), $subjectExport); } /** * @return string * @throws wfWAFRuleException */ public function renderRule() { if (!$this->isActionValid()) { throw new wfWAFRuleException('Invalid action passed to ' . get_class($this) . ', action: ' . var_export($this->getAction(), true)); } $subjectExport = ''; /** @var wfWAFRuleComparisonSubject $subject */ foreach ($this->getSubjects() as $subject) { $subjectExport .= $subject->renderRule() . ", "; } $subjectExport = wfWAFUtils::substr($subjectExport, 0, -2); $expected = $this->getExpected(); return sprintf('%s(%s, %s)', $this->getAction(), ($expected instanceof wfWAFRuleVariable ? $expected->renderRule() : wfWAFRule::exportString($expected)), $subjectExport); } public function getActionType() { $action=wfWAFUtils::strtolower($this->getAction()); if (in_array($action, self::$scalarActions)) { return self::ACTION_TYPE_SCALAR; } else if(in_array($action, self::$arrayActions)) { return self::ACTION_TYPE_ARRAY; } else if(in_array($action, self::$globalActions)) { return self::ACTION_TYPE_GLOBAL; } else { return null; } } public function isActionValid() { return $this->getActionType() !== null; } public function hasSubject() { return $this->getActionType() !== self::ACTION_TYPE_GLOBAL; } private function isWhitelisted($subjectKey = '') { return $this->getWAF() && $this->getRule() && $this->getWAF()->isRuleParamWhitelisted($this->getRule()->getRuleID(), $this->getWAF()->getRequest()->getPath(), $subjectKey); } public function evaluate() { $type = $this->getActionType(); if ($type===null) { return false; } else if ($type===self::ACTION_TYPE_GLOBAL) { return (!$this->isWhitelisted()) && ($this->result=call_user_func(array($this, $this->getAction()))); } $subjects = $this->getSubjects(); if (!is_array($subjects)) { return false; } $this->result = false; /** @var wfWAFRuleComparisonSubject $subject */ foreach ($subjects as $subject) { $global = $subject->getValue(); $subjectKey = $subject->getKey(); if ($this->_evaluate(array($this, $this->getAction()), $global, $subjectKey, $type===self::ACTION_TYPE_SCALAR)) { $this->result = true; } } return $this->result; } /** * @param callback $callback * @param mixed $global * @param string $subjectKey * @param bool $iterate * @return bool */ private function _evaluate($callback, $global, $subjectKey, $iterate) { $result = false; if ($this->isWhitelisted($subjectKey)) { return $result; } if (is_array($global) && $iterate) { foreach ($global as $key => $value) { if ($this->_evaluate($callback, $value, $subjectKey . '[' . $key . ']', $iterate)) { $result = true; } } } else if (call_user_func($callback, $global)) { $result = true; $this->failedSubjects[] = array( 'subject' => $subjectKey, 'value' => is_string($global) ? $global : wfWAFUtils::json_encode($global), 'multiplier' => $this->getMultiplier(), 'matches' => $this->getMatches(), ); } return $result; } public function contains($subject) { if (is_array($this->getExpected())) { return in_array($this->getExpected(), $subject); } return wfWAFUtils::strpos((string) $subject, (string) $this->getExpected()) !== false; } public function notContains($subject) { return !$this->contains($subject); } public function match($subject) { return preg_match((string) $this->getExpected(), (string) $subject, $this->matches) > 0; } public function notMatch($subject) { return !$this->match($subject); } public function matchCount($subject) { $this->multiplier = preg_match_all((string) $this->getExpected(), (string) $subject, $this->matches); return $this->multiplier > 0; } public function containsCount($subject) { if (is_array($this->getExpected())) { $this->multiplier = 0; foreach ($this->getExpected() as $val) { if ($val == $subject) { $this->multiplier++; } } return $this->multiplier > 0; } $this->multiplier = wfWAFUtils::substr_count($subject, $this->getExpected()); return $this->multiplier > 0; } public function equals($subject) { return $this->getExpected() == $subject; } public function notEquals($subject) { return $this->getExpected() != $subject; } public function identical($subject) { return $this->getExpected() === $subject; } public function notIdentical($subject) { return $this->getExpected() !== $subject; } public function greaterThan($subject) { return $subject > $this->getExpected(); } public function greaterThanEqualTo($subject) { return $subject >= $this->getExpected(); } public function lessThan($subject) { return $subject < $this->getExpected(); } public function lessThanEqualTo($subject) { return $subject <= $this->getExpected(); } public function lengthGreaterThan($subject) { return wfWAFUtils::strlen(is_array($subject) ? join('', $subject) : (string) $subject) > $this->getExpected(); } public function lengthLessThan($subject) { return wfWAFUtils::strlen(is_array($subject) ? join('', $subject) : (string) $subject) < $this->getExpected(); } public function currentUserIs($subject) { if ($authCookie = $this->getWAF()->parseAuthCookie()) { return $authCookie['role'] === $this->getExpected(); } return false; } public function currentUserIsNot($subject) { return !$this->currentUserIs($subject); } public function hasUser() { return $this->getWAF()->parseAuthCookie()!==false; } public function notHasUser() { return !$this->hasUser(); } public function currentUserCan() { return $this->getWAF()->checkCapability($this->getExpected()); } public function currentUserCannot() { return !$this->currentUserCan(); } public function md5Equals($subject) { return md5((string) $subject) === $this->getExpected(); } public function filePatternsMatch($subject) { $request = $this->getWAF()->getRequest(); $files = $request->getFiles(); $patterns = $this->getWAF()->getMalwareSignatures(); $commonStrings = $this->getWAF()->getMalwareSignatureCommonStrings(); if (!is_array($patterns) || !is_array($files)) { return false; } $backtrackLimit = ini_get('pcre.backtrack_limit'); if (is_numeric($backtrackLimit)) { $backtrackLimit = (int) $backtrackLimit; if ($backtrackLimit > 10000000) { ini_set('pcre.backtrack_limit', 1000000); } } else { $backtrackLimit = false; } foreach ($files as $file) { if ($file['name'] == (string) $subject) { if (!is_file($file['tmp_name'])) { continue; } $fh = @fopen($file['tmp_name'], 'r'); if (!$fh) { continue; } $totalRead = 0; $first = true; $readsize = max(min(10 * 1024 * 1024, wfWAFUtils::iniSizeToBytes(ini_get('upload_max_filesize'))), 1 * 1024 * 1024); while (!feof($fh)) { $data = fread($fh, $readsize); $totalRead += strlen($data); if ($totalRead < 1) { return false; } $commonStringsChecked = array(); foreach ($patterns as $index => $rule) { if (@preg_match('/' . $rule . '/iS', '') === false) { continue; //This PCRE version can't compile the rule } if (!$first && substr($rule, 0, 1) == '^') { continue; //Signature only applies to file beginning } if (isset($commonStrings[$index])) { foreach ($commonStrings[$index] as $s) { if (!isset($commonStringsChecked[$s])) { $commonStringsChecked[$s] = (preg_match('/' . $s . '/iS', $data) == 1); } if (!$commonStringsChecked[$s]) { continue 2; } } } if (preg_match('/(' . $rule . ')/iS', $data, $matches)) { if ($backtrackLimit !== false) { ini_set('pcre.backtrack_limit', $backtrackLimit); } return true; } } $first = false; } } } if ($backtrackLimit !== false) { ini_set('pcre.backtrack_limit', $backtrackLimit); } return false; } private function checkForPhp($path) { if (!is_file($path)) return false; $fh = @fopen($path, 'r'); if ($fh === false) return false; //T_BAD_CHARACTER is only available since PHP 7.4.0 and before 7.0.0 $T_BAD_CHARACTER = defined('T_BAD_CHARACTER') ? constant('T_BAD_CHARACTER') : 10001; $phpBlock = null; $wrappedTokenCheckBytes = ''; $maxTokenSize = 15; //__halt_compiler $possibleWrappedTokens = array('', 'exit', 'new', 'clone', 'echo', 'print', 'require', 'include', 'require_once', 'include_once', '__halt_compiler'); $readsize = 1024 * 1024; //1MB chunks $iteration = 0; $shortOpenTagEnabled = (bool) ini_get('short_open_tag'); do { $data = fread($fh, $readsize); $actualReadsize = strlen($data); if ($actualReadsize === 0) break; //Make sure we didn't miss PHP split over a chunking boundary $wrappedCheckLength = strlen($wrappedTokenCheckBytes); if ($wrappedCheckLength > 0) { $testBytes = $wrappedTokenCheckBytes . substr($data, 0, min($maxTokenSize, $actualReadsize)); foreach ($possibleWrappedTokens as $t) { $position = strpos($testBytes, $t); if ($position !== false && $position < $wrappedCheckLength && $position + strlen($t) >= $wrappedCheckLength) { //Found a token that starts before this segment of data and ends within it $data = substr($wrappedTokenCheckBytes, $position) . $data; break; } } } $prepended = NULL; //Make sure it tokenizes correctly if chunked if ($phpBlock !== null) { if ($phpBlock->echoTag) { $data = '_resetErrors(); $tokens = @token_get_all($data); $error = error_get_last(); if ($error !== null && feof($fh) && stripos($error['message'], 'Unterminated comment') !== false) break; $firstToken = reset($tokens); if (is_array($firstToken) && $firstToken[0] === $prepended) array_shift($tokens); //Ignore the prepended token; it is only relevant for token_get_all $offset = 0; foreach ($tokens as $token) { if (is_array($token)) { $offset += strlen($token[1]); switch ($token[0]) { case T_OPEN_TAG: $phpBlock = wfWAFPhpBlock::extend($phpBlock, false, $token[1] === 'echoTag || $phpBlock->hasParenthesesOrBacktickPair())) { fclose($fh); return true; } $phpBlock->open = false; break; case T_NEW: case T_CLONE: case T_ECHO: case T_PRINT: case T_REQUIRE: case T_INCLUDE: case T_REQUIRE_ONCE: case T_INCLUDE_ONCE: case T_HALT_COMPILER: case T_EXIT: if (wfWAFPhpBlock::isValid($phpBlock)) { fclose($fh); return true; } break; case $T_BAD_CHARACTER: if ($phpBlock !== null) $phpBlock->badCharacter = true; break; case T_STRING: if (!$phpBlock->shortTag && preg_match('/^[A-z0-9_]{3,}$/', $token[1]) && function_exists($token[1])) { fclose($fh); return true; } break; } } else { $offset += strlen($token); if ($phpBlock !== null) { switch ($token) { case '(': $phpBlock->openParentheses++; break; case ')': if ($phpBlock->openParentheses > $phpBlock->closedParentheses) $phpBlock->closedParentheses++; else $phpBlock->mismatchedParentheses = true; break; case '`': $phpBlock->backtickCount++; break; } } } } if (wfWAFPhpBlock::isValid($phpBlock) && $phpBlock->hasParenthesesOrBacktickPair()) { fclose($fh); return true; } $wrappedTokenCheckBytes = substr($data, - min($maxTokenSize, $actualReadsize)); } while (!feof($fh)); fclose($fh); return false; } public function fileHasPHP($subject) { $request = $this->getWAF()->getRequest(); $files = $request->getFiles(); if (!is_array($files)) { return false; } foreach ($files as $file) { if ($file['name'] === (string) $subject && $this->checkForPhp($file['tmp_name'])) return true; } return false; } private function _resetErrors() { if (function_exists('error_clear_last')) { error_clear_last(); } else { // set error_get_last() to defined state by forcing an undefined variable error set_error_handler(array($this, '_resetErrorsHandler'), 0); @$undefinedVariable; restore_error_handler(); } } public function _resetErrorsHandler($errno, $errstr, $errfile, $errline) { //Do nothing } public function isLocalURL($subject) { if (empty($subject)) { return false; } $parsed = wfWAFUtils::parse_url((string) $subject); if (!isset($parsed['host'])) { return true; } $guessSiteURL = sprintf('%s://%s/', wfWAF::getInstance()->getRequest()->getProtocol(), wfWAF::getInstance()->getRequest()->getHost()); $siteURL = wfWAF::getInstance()->getStorageEngine()->getConfig('siteURL', null, 'synced') ? wfWAF::getInstance()->getStorageEngine()->getConfig('siteURL', null, 'synced') : $guessSiteURL; $homeURL = wfWAF::getInstance()->getStorageEngine()->getConfig('homeURL', null, 'synced') ? wfWAF::getInstance()->getStorageEngine()->getConfig('homeURL', null, 'synced') : $guessSiteURL; $siteHost = wfWAFUtils::parse_url($siteURL, PHP_URL_HOST); $homeHost = wfWAFUtils::parse_url($homeURL, PHP_URL_HOST); return (is_string($siteHost) && strtolower($parsed['host']) == strtolower($siteHost)) || (is_string($homeHost) && strtolower($parsed['host']) == strtolower($homeHost)); } public function isRemoteURL($subject) { if (empty($subject)) { return false; } return !$this->isLocalURL($subject); } public function isValidURL($subject) { if ($subject === null) { return false; } return wfWAFUtils::validate_url((string) $subject) !== false; } public function isNotValidURL($subject) { if ($subject === null) { return false; } return !$this->isValidURL($subject); } public function urlHostEquals($subject) { if ($subject === null) { return false; } $host = wfWAFUtils::parse_url((string) $subject, PHP_URL_HOST); if (!is_string($host)) { return wfWAFUtils::strlen($this->getExpected()) == 0; } return strtolower($host) == strtolower($this->getExpected()); } public function urlHostNotEquals($subject) { if ($subject === null) { return false; } return !$this->urlHostEquals($subject); } public function urlHostMatches($subject) { if ($subject === null) { return false; } $host = wfWAFUtils::parse_url((string) $subject, PHP_URL_HOST); if (!is_string($host)) { return false; } return preg_match((string) $this->getExpected(), $host, $this->matches) > 0; } public function urlHostNotMatches($subject) { if ($subject === null) { return false; } return !$this->urlHostMatches($subject); } public function urlSchemeEquals($subject) { if ($subject === null) { return false; } $scheme = wfWAFUtils::parse_url((string) $subject, PHP_URL_SCHEME); if (!is_string($scheme)) { return wfWAFUtils::strlen($this->getExpected()) == 0; } return strtolower($scheme) == strtolower($this->getExpected()); } public function urlSchemeNotEquals($subject) { if ($subject === null) { return false; } return !$this->urlSchemeEquals($subject); } public function urlSchemeMatches($subject) { if ($subject === null) { return false; } $scheme = wfWAFUtils::parse_url((string) $subject, PHP_URL_SCHEME); if (!is_string($scheme)) { return false; } return preg_match((string) $this->getExpected(), $scheme, $this->matches) > 0; } public function urlSchemeNotMatches($subject) { if ($subject === null) { return false; } return !$this->urlSchemeMatches($subject); } public function versionEquals($subject) { if ($subject === null) { return false; } return version_compare($subject, $this->getExpected(), '=='); } public function versionNotEquals($subject) { if ($subject === null) { return false; } return version_compare($subject, $this->getExpected(), '!='); } public function versionGreaterThan($subject) { if ($subject === null) { return false; } return version_compare($subject, $this->getExpected(), '>'); } public function versionGreaterThanEqualTo($subject) { if ($subject === null) { return false; } return version_compare($subject, $this->getExpected(), '>='); } public function versionLessThan($subject) { if ($subject === null) { return false; } return version_compare($subject, $this->getExpected(), '<'); } public function versionLessThanEqualTo($subject) { if ($subject === null) { return false; } return version_compare($subject, $this->getExpected(), '<='); } public function keyExists($subject) { if (!is_array($subject)) { return false; } return array_key_exists($this->getExpected(), $subject); } public function keyMatches($subject) { if (!is_array($subject)) { return false; } foreach($subject as $key=>$value) { if (preg_match($this->getExpected(), $key)) return true; } return false; } public function exists($subject) { return isset($subject); } /** * @return mixed */ public function getAction() { return $this->action; } /** * @param mixed $action */ public function setAction($action) { $this->action = $action; } /** * @return mixed */ public function getExpected() { return $this->expected; } /** * @param mixed $expected */ public function setExpected($expected) { $this->expected = $expected; } /** * @return mixed */ public function getSubjects() { return $this->subjects; } /** * @param mixed $subjects * @return $this */ public function setSubjects($subjects) { $this->subjects = $subjects; return $this; } /** * @return mixed */ public function getMatches() { return $this->matches; } /** * @return mixed */ public function getFailedSubjects() { return (array)$this->failedSubjects; } /** * @return mixed */ public function getResult() { return $this->result; } /** * @return mixed */ public function getMultiplier() { return $this->multiplier; } /** * @return wfWAF */ public function getWAF() { return $this->waf; } /** * @param wfWAF $waf */ public function setWAF($waf) { $this->waf = $waf; if (is_array($this->subjects)) { foreach ($this->subjects as $subject) { if (is_object($subject) && method_exists($subject, 'setWAF')) { $subject->setWAF($waf); } } } if (is_object($this->expected) && method_exists($this->expected, 'setWAF')) { $this->expected->setWAF($waf); } } /** * @return wfWAFRule */ public function getRule() { return $this->rule; } /** * @param wfWAFRule $rule */ public function setRule($rule) { $this->rule = $rule; } } class wfWAFRuleComparisonGroup implements wfWAFRuleInterface { private $items = array(); private $failedComparisons = array(); private $result = false; private $waf; /** * @var wfWAFRule */ private $rule; public function __construct() { $args = func_get_args(); foreach ($args as $arg) { $this->add($arg); } } public function __sleep() { return array( 'items', ); } public function add($item) { $this->items[] = $item; } public function remove($item) { $key = array_search($item, $this->items); if ($key !== false) { unset($this->items[$key]); } } /** * * @throws wfWAFRuleException */ public function evaluate() { if (count($this->items) % 2 != 1) { throw new wfWAFRuleException('Invalid number of rules and logical operators. Should be odd number of rules and logical operators.'); } $this->result = false; $operator = null; /** @var wfWAFRuleComparison|wfWAFRuleLogicalOperator|wfWAFRuleComparisonGroup $comparison */ for ($i = 0; $i < count($this->items); $i++) { $comparison = $this->items[$i]; if ($i % 2 == 1 && !($comparison instanceof wfWAFRuleLogicalOperator)) { throw new wfWAFRuleException('Invalid WAF rule format, expected wfWAFRuleLogicalOperator, got ' . get_class($comparison)); } if ($i % 2 == 0 && !($comparison instanceof wfWAFRuleComparison || $comparison instanceof wfWAFRuleComparisonGroup)) { throw new wfWAFRuleException('Invalid WAF rule format, expected wfWAFRuleComparison or wfWAFRuleComparisonGroup, got ' . get_class($comparison)); } if ($comparison instanceof wfWAFRuleLogicalOperator) { $operator = $comparison; continue; } if ($comparison instanceof wfWAFRuleComparison || $comparison instanceof wfWAFRuleComparisonGroup) { $comparison->setRule($this->getRule()); if ($operator instanceof wfWAFRuleLogicalOperator) { $operator->setCurrentValue($this->result); $operator->setComparison($comparison); $this->result = $operator->evaluate(); } else { $this->result = $comparison->evaluate(); } } if ($comparison instanceof wfWAFRuleComparison && $comparison->getResult()) { if ($comparison->hasSubject()) { foreach ($comparison->getFailedSubjects() as $failedSubject) { $this->failedComparisons[] = new wfWAFRuleComparisonFailure( $failedSubject['subject'], $failedSubject['value'], $comparison->getExpected(), $comparison->getAction(), $failedSubject['multiplier'], $failedSubject['matches'] ); } } else { $this->failedComparisons[] = new wfWAFRuleComparisonFailure( '', '', $comparison->getExpected(), $comparison->getAction(), 1, array() ); } } if ($comparison instanceof wfWAFRuleComparisonGroup && $comparison->getResult()) { foreach ($comparison->getFailedComparisons() as $comparisonFail) { $this->failedComparisons[] = $comparisonFail; } } } return $this->result; } /** * @return string * @throws wfWAFRuleException */ public function render() { if (count($this->items) % 2 != 1) { throw new wfWAFRuleException('Invalid number of rules and logical operators. Should be odd number of rules and logical operators.'); } $return = array(); /** * @var wfWAFRuleInterface $item */ for ($i = 0; $i < count($this->items); $i++) { $item = $this->items[$i]; if ($i % 2 == 1 && !($item instanceof wfWAFRuleLogicalOperator)) { throw new wfWAFRuleException('Invalid WAF rule format, expected wfWAFRuleLogicalOperator, got ' . get_class($item)); } if ($i % 2 == 0 && !($item instanceof wfWAFRuleComparison || $item instanceof wfWAFRuleComparisonGroup)) { throw new wfWAFRuleException('Invalid WAF rule format, expected wfWAFRule or wfWAFRuleComparisonGroup, got ' . get_class($item)); } $return[] = $item->render(); } return sprintf('new %s(%s)', get_class($this), join(', ', $return)); } /** * @return string * @throws wfWAFRuleException */ public function renderRule() { if (count($this->items) % 2 != 1) { throw new wfWAFRuleException('Invalid number of rules and logical operators. Should be odd number of rules and logical operators.'); } $return = array(); /** * @var wfWAFRuleInterface $item */ for ($i = 0; $i < count($this->items); $i++) { $item = $this->items[$i]; if ($i % 2 == 1 && !($item instanceof wfWAFRuleLogicalOperator)) { throw new wfWAFRuleException('Invalid WAF rule format, expected wfWAFRuleLogicalOperator, got ' . get_class($item)); } if ($i % 2 == 0 && !($item instanceof wfWAFRuleComparison || $item instanceof wfWAFRuleComparisonGroup)) { throw new wfWAFRuleException('Invalid WAF rule format, expected wfWAFRule or wfWAFRuleComparisonGroup, got ' . get_class($item)); } $return[] = $item->renderRule(); } return sprintf('(%s)', join(' ', $return)); } public function debug() { $debug = ''; /** @var wfWAFRuleComparisonFailure $failedComparison */ foreach ($this->getFailedComparisons() as $failedComparison) { $debug .= $failedComparison->getParamKey() . ' ' . $failedComparison->getAction() . ' ' . $failedComparison->getExpected() . "\n"; } return $debug; } /** * @return array */ public function getItems() { return $this->items; } /** * @param array $items */ public function setItems($items) { $this->items = $items; } /** * @return mixed */ public function getFailedComparisons() { return $this->failedComparisons; } /** * @return boolean */ public function getResult() { return $this->result; } /** * @return wfWAFRule */ public function getRule() { return $this->rule; } /** * @param wfWAFRule $rule */ public function setRule($rule) { $this->rule = $rule; } /** * @return mixed */ public function getWAF() { return $this->waf; } /** * @param mixed $waf */ public function setWAF($waf) { $this->waf = $waf; foreach ($this->items as $item) { if (is_object($item) && method_exists($item, 'setWAF')) { $item->setWAF($waf); } } } } class wfWAFRuleComparisonFailure { private $paramKey; private $expected; private $action; /** * @var null|int */ private $multiplier; /** * @var string */ private $paramValue; /** * @var mixed */ private $matches; /** * @param string $paramKey * @param string $paramValue * @param string $expected * @param string $action * @param mixed $multiplier * @param mixed $matches */ public function __construct($paramKey, $paramValue, $expected, $action, $multiplier = null, $matches = null) { $this->setParamKey($paramKey); $this->setExpected($expected); $this->setAction($action); $this->setMultiplier($multiplier); $this->setParamValue($paramValue); $this->setMatches($matches); } public function __sleep() { return array( 'paramKey', 'expected', 'action', 'multiplier', 'paramValue', 'matches', ); } /** * @return mixed */ public function getParamKey() { return $this->paramKey; } /** * @param mixed $paramKey */ public function setParamKey($paramKey) { $this->paramKey = $paramKey; } /** * @return mixed */ public function getExpected() { return $this->expected; } /** * @param mixed $expected */ public function setExpected($expected) { $this->expected = $expected; } /** * @return mixed */ public function getAction() { return $this->action; } /** * @param mixed $action */ public function setAction($action) { $this->action = $action; } /** * @return int|null */ public function getMultiplier() { return $this->multiplier; } /** * @param int|null $multiplier */ public function setMultiplier($multiplier) { $this->multiplier = $multiplier; } /** * @return bool */ public function hasMultiplier() { return $this->getMultiplier() > 1; } /** * @return string */ public function getParamValue() { return $this->paramValue; } /** * @param string $paramValue */ public function setParamValue($paramValue) { $this->paramValue = $paramValue; } /** * @return mixed */ public function getMatches() { return $this->matches; } /** * @param mixed $matches */ public function setMatches($matches) { $this->matches = $matches; } } class wfWAFRuleComparisonSubject { /** * @var array */ private $subject; /** * @var array */ private $filters; /** @var wfWAF */ private $waf; public static function create($waf, $subject, $filters) { return new self($waf, $subject, $filters); } /** * wfWAFRuleComparisonSubject constructor. * @param wfWAF $waf * @param array $subject * @param array $filters */ public function __construct($waf, $subject, $filters) { $this->waf = $waf; $this->subject = $subject; $this->filters = $filters; } public function __sleep() { return array( 'subject', 'filters', ); } private function getRootValue($subject) { if ($subject instanceof wfWAFRuleComparisonSubject) { return $subject->getValue(); } else { return $this->getWAF()->getGlobal($subject); } } /** * @return mixed|null */ public function getValue() { $subject = $this->getSubject(); if (!is_array($subject)) { return $this->runFilters($this->getRootValue($subject), $subject); } else if (count($subject) > 0) { $globalKey = array_shift($subject); return $this->runFilters($this->_getValue($subject, $this->getRootValue($globalKey))); } return null; } /** * @param array $subjectKey * @param array $global * @return null */ private function _getValue($subjectKey, $global) { if (!is_array($global) || !is_array($subjectKey)) { return null; } $key = array_shift($subjectKey); if (array_key_exists($key, $global)) { if (count($subjectKey) > 0) { return $this->_getValue($subjectKey, $global[$key]); } else { return $global[$key]; } } return null; } /** * @return string */ public function getKey() { return wfWAFRuleComparison::getSubjectKey($this->getSubject()); } /** * @param mixed $value * @return mixed */ private function runFilters($value) { $filters = $this->getFilters(); if (is_array($filters)) { foreach ($filters as $filterArgs) { if (method_exists($this, 'filter' . $filterArgs[0])) { $value = call_user_func_array(array($this, 'filter' . $filterArgs[0]), array_merge(array($value), array_slice($filterArgs, 1))); } } } return $value; } /** * @param mixed $value * @return string */ public function filterBase64decode($value) { if (is_string($value)) { return base64_decode($value); } return $value; } public function filterReplace($value, $find, $replace) { return str_replace($find, $replace, $value); } public function filterPregReplace($value, $pattern, $replacement, $limit=-1) { return preg_replace($pattern, $replacement, $value, $limit); } private function getMatchingKeys($array, $patterns) { if (!is_array($array)) return array(); $filtered = array(); $pattern = array_shift($patterns); foreach ($array as $key=>$value) { if (preg_match($pattern, $key)) { if (empty($patterns)) { $filtered[] = $value; } else { $filtered = array_merge($filtered, $this->getMatchingKeys($value, $patterns)); } } } return $filtered; } public function filterFilterKeys($values) { $patterns = array_slice(func_get_args(), 1); return $this->getMatchingKeys($values, $patterns); } public function filterJson($value) { return wfWAFUtils::json_decode(@(string)$value, true); } private function renderSubject() { $subjects = $this->getSubject(); if (is_array($subjects)) { $rendered = array(); foreach ($subjects as $subject) { if ($subject instanceof wfWAFRuleComparisonSubject) { array_push($rendered, $subject->render()); } else { array_push($rendered, var_export($subject, true)); } } return sprintf('array(%s)', implode(', ', $rendered)); } else { return var_export($subjects, true); } } /** * @return string */ public function render() { return sprintf('%s::create($this, %s, %s)', get_class($this), $this->renderSubject(), var_export($this->getFilters(), true)); } /** * @return string */ public function renderRule() { $subjects = $this->getSubject(); if (is_array($subjects)) { if (strpos($subjects[0], '.') !== false) { list($superGlobal, $global) = explode('.', $subjects[0], 2); unset($subjects[0]); $subjects = array_merge(array($superGlobal, $global), $subjects); } $rule = ''; foreach ($subjects as $subject) { if (preg_match("/^[a-zA-Z_][a-zA-Z0-9_]*$/", $subject)) { $rule .= "$subject."; } else { $rule = rtrim($rule, '.'); $rule .= sprintf("['%s']", str_replace("'", "\\'", $subject)); } } $rule = rtrim($rule, '.'); } else { $rule = $this->getSubject(); } foreach ($this->getFilters() as $filter) { $rule = $filter[0] . '(' . implode(',', array_merge(array($rule), array_slice($filter, 1))) . ')'; } return $rule; } /** * @return array */ public function getSubject() { return $this->subject; } /** * @param array $subject */ public function setSubject($subject) { $this->subject = $subject; } /** * @return array */ public function getFilters() { return $this->filters; } /** * @param array $filters */ public function setFilters($filters) { $this->filters = $filters; } /** * @return wfWAF */ public function getWAF() { return $this->waf; } private static function setWafForSubject($subject, $waf) { if (is_array($subject)) { foreach ($subject as $child) { self::setWafForSubject($child, $waf); } } else if ($subject instanceof wfWAFRuleComparisonSubject) { $subject->setWAF($waf); } } /** * @param wfWAF $waf */ public function setWAF($waf) { $this->waf = $waf; self::setWafForSubject($this->subject, $waf); } } }