source: branches/1.2/workflow/inc/nano/NanoSanitizer.class.php @ 1349

Revision 1349, 23.4 KB checked in by niltonneto, 15 years ago (diff)

Ticket #561 - Inclusão do módulo Workflow faltante nessa versão.

  • Property svn:executable set to *
Line 
1<?php
2
3/**
4 * NanoSanitizer
5 *
6 * @package NanoAjax
7 *
8 */
9class NanoSanitizer
10{
11
12    /**
13     * Enter description here...
14     *
15     * @access protected
16     * @var array
17     */
18    protected $_mArrSignaturePresets       = array();
19
20    /**
21     * Enter description here...
22     *
23     * @access protected
24     * @var boolean
25     */
26    protected $_mBlnMagicQuotes            = false;
27
28    /**
29     * Enter description here...
30     *
31     * @access protected
32     * @var array
33     */
34    protected $_mArrUnSecureVariables      = array();
35
36    /**
37     * Enter description here...
38     *
39     * @access protected
40     * @var array
41     */
42    protected $_mArrSignatures             = array();
43
44    /**
45     * Enter description here...
46     *
47     * @access protected
48     * @var integer
49     */
50    protected $_mIntCountUnSecureVariables = 0;
51
52    /**
53     * Enter description here...
54     *
55     * @access protected
56     * @var integer
57     */
58    protected $_mIntCountSignature         = 0;
59
60    /**
61     * Enter description here...
62     *
63     * @access protected
64     * @var array
65     */
66    protected $_mArrSanitizedVariables     = array();
67
68    /**
69     * Enter description here...
70     *
71     * @access protected
72     * @var string
73     */
74    protected $_mStrSignaturePreset        = '';
75
76    /**
77     * Enter description here...
78     *
79     * @access protected
80     * @var boolean
81     */
82    protected $_mBlnReportErrors           = false;
83
84    /**
85     * Enter description here...
86     *
87     * @access protected
88     * @var boolean
89     */
90    protected $_mBlnStopOnError            = false;
91
92    protected $logger;
93
94
95    /**
96     * Constructor, initializes object
97     *
98     * @access public
99     * @return NanoSanitizer
100     */
101    public function __construct($logger)
102    {
103        $this->logger           = $logger;
104        $this->_mBlnMagicQuotes = (bool) get_magic_quotes_gpc();
105    }
106
107    /**
108     * Enter description here...
109     *
110     * @param unknown_type $preset_file
111     */
112    public function loadPresets( $preset_file = '' )
113    {
114        $this->_mArrSignaturePresets = ( '' != $preset_file && is_file($preset_file) && is_readable($preset_file) )
115                                            ? include($preset_file)
116                                            : include(dirname(__FILE__).'/include/NanoSanitizer.presets.inc.php');
117    }
118
119    /**
120     * Enter description here...
121     *
122     * @param string $signature_preset
123     */
124    public function setSignaturePreset( $signature_preset = '' )
125    {
126        $this->logger->rawAdd('setting signature preset...');
127
128        if( NanoUtil::isNotEmptyString($signature_preset) && array_key_exists($signature_preset,$this->_mArrSignaturePresets) )
129        {
130            $this->_mStrSignaturePreset = $signature_preset;
131            $this->logger->add('done.');
132        }
133        else
134        {
135            $this->_throw( __METHOD__,
136                           ' signatur preset ('.$signature_preset.') {'.
137                           gettype($signature_preset).'} NOT valid!' );
138        }
139    }
140
141
142    /**
143     * Sets the signature array with paramters for later verification
144     *
145     * @param array $signature_array
146     */
147    public function setSignatures( $signatures_array )
148    {
149        $this->logger->rawAdd('setting signatures...');
150
151        if( NanoUtil::isNotEmptyArray($signatures_array) )
152        {
153            $this->_mArrSignatures     = $signatures_array;
154            $this->_mIntCountSignature = count($signatures_array);
155            $this->logger->add('done.');
156        }
157        else
158        {
159            $this->_throw( __METHOD__,
160                           ' signatur array ('.implode('|',$signatures_array).
161                           'is NOT valid!' );
162        }
163    }
164
165    /**
166     * Set variables which will be sanitized
167     *
168     * @param array $variables_array
169     */
170    public function setUnSecureData( $unsecure_variables_array )
171    {
172        $this->logger->rawAdd('setting unsecure variable array...');
173
174        if( is_array($unsecure_variables_array) && count( $unsecure_variables_array ) > 0 )
175        {
176            $this->logger->add('done.');
177            $this->_mArrUnSecureVariables      = $unsecure_variables_array;
178            $this->_mIntCountUnSecureVariables = count($unsecure_variables_array);
179        }
180        else
181        {
182            $this->_throw( __METHOD__, ' unsecure variables array is NOT valid!' );
183        }
184    }
185
186    /**
187     * sets reporting of variable unequality
188     *
189     * @param boolean $bln_switch
190     */
191    public function setErrorReporting( $bln_switch )
192    {
193        if( is_bool($bln_switch) )
194        {
195            $this->_mBlnReportErrors = $bln_switch;
196        }
197    }
198
199    /**
200     * sets reporting of variable unequality
201     *
202     * @param boolean $bln_switch
203     */
204    public function setStopOnError( $bln_switch )
205    {
206        if( is_bool($bln_switch) )
207        {
208            $this->_mBlnStopOnError = $bln_switch;
209        }
210    }
211
212
213    /**
214     * Executes sanitization
215     *
216     */
217    public function executeSanitization()
218    {
219        $this->logger->rawAdd('checking all parameters...');
220        if( false == $this->_areParemetersValid() )
221        {
222            $this->_throw( __METHOD__,
223                           'Signature / Input Variables Error !!! [S:'.
224                           $this->_mIntCountSignature.'|I:'.
225                           $this->_mIntCountUnSecureVariables.']' );
226        }
227        $this->logger->add('valid!');
228        $this->logger->add('<br/>iterating over all sigantures...');
229
230        foreach ($this->_mArrSignatures as $varname => $signature)
231        {
232            $this->logger->rawAdd('<br/>checking variable <b>'.$varname.'</b> is required but not present...');
233
234            if( $this->_isRequiredVariableNotPresent($varname,$signature) )
235            {
236                $this->_throw( __METHOD__,
237                               'Variable ['.$varname.'] is required, but NOT present!' );
238            }
239
240            $this->logger->add('OK. {'.(($this->_isVariableRequired($signature))?'required':'NOT required').'}');
241
242            $this->logger->rawAdd('checking variable exists in unsecure array...');
243
244            if( array_key_exists($varname,$this->_mArrUnSecureVariables) )
245            {
246                $this->logger->add('exists!');
247                $variable_container = trim($this->_mArrUnSecureVariables[$varname]);
248
249                $this->logger->rawAdd('searching for preset in signature...');
250
251                // -------------------------------------------------------------
252                // PRESET:
253                // is preset in signature ?
254                // set preset data to siganture
255                if( true === $this->_isSignaturePresetValid($signature) )
256                {
257                    $this->logger->add('found! {<b>'.NanoUtil::getParam($signature,'preset').'</b>}');
258                    $this->logger->rawAdd('setting signsture preset data to signature...');
259                    $signature = $this->_getSignaturePresetData($signature);
260                    $this->logger->add('done.');
261                }
262                else
263                {
264                    $this->logger->add('NOT found, using given signature.');
265                }
266
267                $this->logger->rawAdd('checking signature given type...');
268
269                // -------------------------------------------------------------
270                // TYPE:
271                // apply type (integer, string, array,...) to variable
272                // { brute force mode }
273                if( $this->_isSignatureVarTypeValid($signature) )
274                {
275                    $this->logger->rawAdd('valid. setting type [<b>'.$signature['type'].'</b>]...');
276                    settype( $variable_container, $signature['type'] );
277                    $this->logger->add('done.');
278                }
279
280                $this->logger->rawAdd('searching for (filter) methods in signature...');
281
282                // -------------------------------------------------------------
283                // METHODS:
284                // apply method(s) to variable
285                if( $this->_isSignatureMethodsValid($signature) )
286                {
287                    $this->logger->add('found.');
288
289                    // check if is not an array
290                    if( !is_array($signature['methods']) )
291                    {
292                        // put methodname into array for later iteration
293                        $signature['methods'] = array($signature['methods']);
294                    }
295
296                    $this->logger->add('iterating over given filter methods...');
297
298                    // iterate over method array
299                    foreach ( $signature['methods'] as $method_data )
300                    {
301                        $this->logger->rawAdd('executing method <b>'.$method_data['name'].'</b>...');
302
303                        if( method_exists( $this, $method_data['name'] ) )
304                        {
305                            // execute method with variable as parameter
306                            $variable_container = $this->$method_data['name']($variable_container,$method_data['limits']);
307                        }
308                        else
309                        {
310                            $logger_message = 'method ['.$method_data['name'].'] NOT found!!!';
311
312                            if( true == $this->_mBlnStopOnError )
313                            {
314                                $this->_throw( __METHOD__,'method ['.$method_data['name'].'] NOT found!!!');
315                            }
316                            else { $this->logger->add('method ['.$method_data['name'].'] NOT found!!!'); }
317                        }
318
319                        $this->logger->add('done.');
320                    }
321                }
322                else
323                {
324                    $this->logger->add('NOT found. (nothing to do)');
325                }
326
327                // -------------------------------------------------------------
328                // REPORTING (report variable change / stop if has changed)
329                if( true == $this->_mBlnReportErrors)
330                {
331                    // -------------------------------------------------------------
332                    // VERIFICATION (is variable changed in value (after sanitization)
333                    if( $this->_isVariableChanged($varname,$variable_container) )
334                    {
335                        $this->logger->add('NOT equal');
336
337                        $message = '~~ Variable <b>'.$varname.'</b> '. /* $logger */
338                        /* $logger */     'seems not to be same after sanitization '.
339                        /* $logger */     '<div style="border:1px solid #CC0000;'.
340                        /* $logger */     'background-color:#EEEEEE"><b>'.
341                        /* $logger */     htmlentities($this->_mArrUnSecureVariables[$varname]).
342                        /* $logger */     '</b>&nbsp;</div> {before} != <div style="'.
343                        /* $logger */     'border:1px solid #CC0000;background-color:'.
344                        /* $logger */     '#EEEEEE"><b>'.$variable_container.
345                        /* $logger */     '</b>&nbsp;</div> {after}';
346
347                        if( true == $this->_mBlnStopOnError )
348                        {
349                            $this->_throw( __METHOD__,$message);
350                        }
351                        else { $this->logger->add($message); }
352                    }
353                    else { $this->logger->add('IS equal'); }
354                }
355
356                // -------------------------------------------------------------
357                // ASSIGNMENT
358                $this->_assignCleanedVariable($varname,$variable_container);
359
360            }
361            else { $this->logger->add('not found! (continue with next)'); }
362        }
363
364        return $this->_mArrSanitizedVariables;
365    }
366
367    /**
368     * Enter description here...
369     *
370     * @param unknown_type $varname
371     * @param unknown_type $cleaned_variable
372     */
373    protected function _assignCleanedVariable( $varname, $cleaned_variable )
374    {
375        // -------------------------------------------------------------
376        // ASSIGNMENT
377        // set sanitized variable to new (output) array
378        $this->logger->rawAdd('assigning cleaned input variable to output array...');
379        $this->_mArrSanitizedVariables[$varname] = $cleaned_variable;
380        $this->logger->add('done.');
381    }
382
383    protected function _isVariableChanged( $varname, $new_variable )
384    {
385        $this->logger->rawAdd('checking variable has changed while sanitization [<b>'.
386                              htmlentities($this->_mArrUnSecureVariables[$varname]).'</b>] ?? [<b>'.
387                              $new_variable.'</b>]...');
388
389        return ( !empty($this->_mArrUnSecureVariables[$varname]) && $this->_mArrUnSecureVariables[$varname] != (string)$new_variable);
390    }
391
392    protected function _isRequiredVariableNotPresent( $varname, $signature )
393    {
394        return ( false == isset($this->_mArrUnSecureVariables[$varname])
395                 &&
396                 $this->_isVariableRequired($signature) );
397    }
398
399    protected function _isVariableRequired( $signature = array() )
400    {
401        return NanoUtil::getParam($signature,'required',false);
402    }
403
404    /**
405     * Enter description here...
406     *
407     * @param unknown_type $signature
408     * @return unknown
409     */
410    protected function _isSignaturePresetValid( $signature = array() )
411    {
412        return ( '' != NanoUtil::getParam($signature,'preset') && array_key_exists(NanoUtil::getParam($signature,'preset'),$this->_mArrSignaturePresets) )
413                    ? true
414                    : false;
415    }
416
417    /**
418     * Enter description here...
419     *
420     * @param unknown_type $signature
421     * @return unknown
422     */
423    protected function _getSignaturePresetData( $signature = array() )
424    {
425        $preset_signature = $this->_mArrSignaturePresets[$signature['preset']];
426
427        unset($signature['preset']);
428
429        return array_merge($signature,$preset_signature);
430    }
431
432    /**
433     * Enter description here...
434     *
435     * @param unknown_type $signature
436     * @return unknown
437     */
438    protected function _isSignatureVarTypeValid( $signature = array() )
439    {
440        return ( '' != NanoUtil::getParam($signature,'type') )
441                    ? true
442                    : false;
443    }
444
445    /**
446     * Enter description here...
447     *
448     * @param unknown_type $signature
449     * @return unknown
450     */
451    protected function _isSignatureMethodsValid( $signature = array() )
452    {
453        return ( '' != NanoUtil::getParam($signature,'methods') )
454                    ? true
455                    : false;
456    }
457
458    protected function _areParemetersValid()
459    {
460        // Check all needed parameter (arrays) are loaded, not empty
461        // and size of both is equal
462        return ( $this->_mIntCountSignature         > 0
463                 &&
464                 $this->_mIntCountUnSecureVariables > 0
465                 &&
466                 $this->_mIntCountSignature        == $this->_mIntCountUnSecureVariables )
467
468                    // check passed
469                    ? true
470                    // check failed
471                    : true;
472
473    }
474
475    // addslashes wrapper to check for gpc_magic_quotes
476    protected function _addNiceSlashes($string)
477    {
478        // if magic quotes is on the string is already quoted, just return it
479        return (MAGIC_QUOTES)
480
481                    // return raw string
482                    ? $string
483
484                    // add slashes and return new string
485                    : addslashes($string);
486    }
487
488    // internal function for utf8 decoding
489    // PHP's utf8_decode function is a little
490    // screwy
491    protected function _decodeUtf8($string)
492    {
493        return utf8_decode($string);
494        /*
495        return strtr($string,
496        "???????¥µÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿ",
497        "SOZsozYYuAAAAAAACEEEEIIIIDNOOOOOOUUUUYsaaaaaaaceeeeiiiionoooooouuuuyy");
498        */
499    }
500
501
502    // default string sanitization -- only let the alphanumeric set through
503    protected function _sanitizeDefaultAlphaNumericString($string, $limits = array() )
504    {
505        return $this->_getLimitedString(preg_replace("/[^a-zA-Z0-9_\-\ ]/", "", $string), $limits);
506    }
507
508
509    // paranoid sanitization -- only let the alphanumeric set through
510    protected function _sanitizeParanoidAlphaNumericString($string, $limits = array() )
511    {
512        return $this->_getLimitedString(preg_replace("/[^a-zA-Z0-9]/", "", $string), $limits);
513    }
514
515
516    // default string sanitization -- only let the alphanumeric set through
517    protected function _sanitizeDefaultGermanAlphaNumericString($string, $limits = array() )
518    {
519        return $this->_getLimitedString(preg_replace("/[^a-zA-Z0-9_\-\ äöüÄÖÜß]/", "", $string), $limits);
520    }
521
522
523    // paranoid sanitization -- only let the alphanumeric set through
524    protected function _sanitizeParanoidGermanAlphaNumericString($string, $limits = array() )
525    {
526        return $this->_getLimitedString(preg_replace("/[^a-zA-Z0-9äöüÄÖÜß]/", "", $string), $limits);
527    }
528
529    // sanitize a string in prep for passing a single argument to
530    // system() or exec() or passthru()
531    protected function _sanitizeSystemString($string, $min = null, $max = null )
532    {
533        // no piping, passing possible environment variables ($),
534        // seperate commands, nested execution, file redirection,
535        // background processing, special commands (backspace, etc.), quotes
536        // newlines, or some other special characters
537        $pattern = '/(;|\||`|>|<|&|^|"|'."\n|\r|'".'|{|}|[|]|\)|\()/i';
538
539        $string  = preg_replace($pattern, '', $string);
540
541        //make sure this is only interpretted as ONE argument
542
543        return $this->_getLimitedString('"'.preg_replace('/\$/', '\\\$', $string).'"', $min, $max);
544    }
545
546
547    // sanitize a string for SQL input (simple slash out quotes and slashes)
548    protected function _sanitizeDefaultSqlString($string, $min = null, $max = null)
549    {
550        return $this->_getLimitedString($this->_saveEscapeString($string), $min, $max);
551    }
552
553
554    // sanitize a string for SQL input (simple slash out quotes and slashes)
555    protected function _sanitizeParanoidSqlString($string, $min = null, $max = null)
556    {
557        return $this->_sanitizeDefaultSqlString(strip_tags($string), $min, $max);
558    }
559
560
561    // sanitize a string for HTML (make sure nothing gets interpretted!)
562    protected function _sanitizeHtmlString($string)
563    {
564        $pattern = array( '/\&/',   //  0
565                          '/</',    //  1
566                          "/>/",    //  2
567                          '/\n/',   //  3
568                          '/"/',    //  4
569                          "/'/",    //  5
570                          "/%/",    //  6
571                          '/\(/',   //  7
572                          '/\)/',   //  8
573                          '/\+/',   //  9
574                          '/-/'  ); // 10
575
576        $replace = array( '&amp;',  //  0
577                          '&lt;',   //  1
578                          '&gt;',   //  2
579                          '<br/>',  //  3
580                          '&quot;', //  4
581                          '&#39;',  //  5
582                          '&#37;',  //  6
583                          '&#40;',  //  7
584                          '&#41;',  //  8
585                          '&#43;',  //  9
586                          '&#45;' );// 10
587
588        return preg_replace($pattern, $replace, $string);
589    }
590
591    // make float float!
592    function _sanitizeFloat($float, $min='', $max='')
593    {
594        $float = floatval($float);
595        if((($min != '') && ($float < $min)) || (($max != '') && ($float > $max)))
596        return false;
597        return $float;
598    }
599
600
601    /**
602     * Enter description here...
603     *
604     * @param unknown_type $input
605     * @param unknown_type $min
606     * @param unknown_type $max
607     * @return unknown
608     */
609    function check_float($input, $min='', $max='')
610    {
611        if($input != _sanitizeFloat($input, $min, $max))
612        return false;
613        return true;
614    }
615
616
617    /**
618     * Enter description here...
619     *
620     * @param unknown_type $input
621     * @param unknown_type $min
622     * @param unknown_type $max
623     * @return unknown
624     */
625    function check_sql_string($input, $min='', $max='')
626    {
627        if($input != _sanitizeSqlString($input, $min, $max))
628        return false;
629        return true;
630    }
631
632    /**
633     * Enter description here...
634     *
635     * @param unknown_type $input
636     * @param unknown_type $min
637     * @param unknown_type $max
638     * @return unknown
639     */
640    function check_ldap_string($input, $min='', $max='')
641    {
642        if($input != sanitize_string($input, $min, $max))
643        return false;
644        return true;
645    }
646
647    /**
648     * Enter description here...
649     *
650     * @param unknown_type $input
651     * @param unknown_type $min
652     * @param unknown_type $max
653     * @return unknown
654     */
655    function check_system_string($input, $min='', $max='')
656    {
657        if($input != _sanitizeSystemString($input, $min, $max, true))
658        return false;
659        return true;
660    }
661
662
663    /**
664     * Enter description here...
665     *
666     * @param string $integer
667     * @param array $limits
668     * @return mixed
669     */
670    function _limitIntegerValue($integer, $limits = array() )
671    {
672        return ( $this->_isIntegerInRange($integer, $limits) )
673
674                    ? (( true == $this->_mBlnReportErrors )
675
676                          ? (( true == $this->_mBlnStopOnError )
677
678                                ? $this->_throw(__METHOD__,'Length limit applies!!!')
679                                : $this->logger->add('Length limit applies!!!'))
680
681                          : false)
682
683                    : $integer;
684    }
685
686
687    /**
688     * Enter description here...
689     *
690     * @param string $string
691     * @param array $limits
692     * @return mixed
693     */
694    protected function _getLimitedString( $string, $limits = array() )
695    {
696        return ( $this->_isStringInRange($string,$limits) )
697
698                    ? (( true == $this->_mBlnReportErrors )
699
700                          ? (( true == $this->_mBlnStopOnError )
701
702                                ? $this->_throw(__METHOD__,'Length limit applies!!!')
703                                : $this->logger->add('Length limit applies!!!'))
704
705                          : false)
706
707                    : $string;
708    }
709
710
711    /**
712     * Enter description here...
713     *
714     * @param string $string
715     * @param array $limits
716     * @return boolean
717     */
718    protected function _isStringInRange( $string, $limits = array() )
719    {
720        return ( ( isset($limits['min']) && strlen($string) < $limits['min'] )
721                   ||
722                 ( isset($limits['max']) && strlen($string) > $limits['max'] ) );
723    }
724
725
726    /**
727     * Enter description here...
728     *
729     * @param string $string
730     * @param array $limits
731     * @return boolean
732     */
733    protected function _isIntegerInRange( $integer, $limits = array() )
734    {
735        return ( ( isset($limits['min']) && $integer < $limits['min'] )
736                   ||
737                 ( isset($limits['max']) && $integer > $limits['max'] ) );
738    }
739
740
741    /**
742     * Enter description here...
743     *
744     * @param string $string
745     * @return string mysql escaped string
746     */
747    private function _saveEscapeString( $string )
748    {
749        if( true == $this->_mBlnMagicQuotes )
750        {
751            $string = stripslashes($string);
752        }
753
754        return mysql_real_escape_string($string);
755    }
756
757
758    /**
759     * Enter description here...
760     *
761     * @param string $method
762     * @param string $msg
763     */
764    private function _throw( $method, $msg )
765    {
766        throw new Exception("[".$method.']: '.$msg);
767    }
768}
769
770?>
Note: See TracBrowser for help on using the repository browser.