PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 3.1.0
Defender Security – Malware Scanner, Login Security & Firewall v3.1.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / framework / base / component.php

component.php in Defender Security – Malware Scanner, Login Security & Firewall 3.1.0, at framework/base/component.php

388 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Author: Hoang Ngo
4 */
5
6 namespace Calotes\Base;
7
8 use Calotes\Component\Behavior;
9 use Calotes\Component\Event;
10
11 /**
12 * Class Component
13 *
14 * Class should extend this if behavior and event required
15 *
16 * @package Calotes\Base
17 */
18 class Component extends Base {
19 /**
20 * Contains array of behaviors
21 *
22 * @var array
23 */
24 protected $behaviors = array();
25
26 /**
27 * Store events array
28 *
29 * @var array
30 */
31 protected $events = array();
32
33 /**
34 * Internal use only
35 *
36 * @var array
37 */
38 protected $cached_object = array();
39
40 /**
41 * Cache the annotations of properties
42 *
43 * @var array
44 */
45 public $annotations = array();
46
47 /**
48 * Defined a list of events and handler
49 *
50 * @return array
51 */
52 public function events() {
53 return array();
54 }
55
56 /**
57 * @param $name
58 *
59 * @return bool
60 */
61 public function has_event( $name ) {
62 if ( isset( $this->events[ $name ] ) && count( $this->events[ $name ] ) ) {
63 return true;
64 }
65
66 return false;
67 }
68
69 /**
70 * Queue an event
71 *
72 * @param string $name Event name
73 * @param callable $handler
74 * @param null|mixed $data
75 * @param bool $append If this is true, append the handler at the end, if not put at top
76 */
77 public function on( $name, $handler, $data = null, $append = true ) {
78 if ( true === $append ) {
79 $this->events[ $name ][] = array( $handler, $data );
80 } else {
81 $this->events[ $name ] = array( $handler, $data ) + array( $this->events[ $name ] );
82 }
83 }
84
85 /**
86 * Dequeue an event
87 *
88 * @param string $name
89 * @param callable|null $handler if this is null, this event will be remove, else only remove the handler
90 *
91 * @return bool
92 */
93 public function off( $name, $handler = null ) {
94 if ( empty( $this->events ) ) {
95 return false;
96 }
97
98 if ( null === $handler ) {
99 unset( $this->events[ $name ] );
100
101 return true;
102 }
103
104 $removed = false;
105
106 foreach ( $this->events[ $name ] as $i => $event ) {
107 if ( $event[0] === $handler ) {
108 unset( $this->events[ $name ][ $i ] );
109 $removed = true;
110 }
111 }
112
113 if ( true === $removed ) {
114 // reset order
115 $this->events[ $name ] = array_values( $this->events[ $name ] );
116 }
117
118 return $removed;
119 }
120
121 /**
122 * Trigger an event
123 *
124 * @param string $name
125 * @param null|Event $event
126 *
127 * @return void
128 */
129 public function trigger( $name, $event = null ) {
130 // merge with the info we get from events() function
131 $events = array_merge( $this->events, $this->events() );
132
133 if ( ! isset( $events[ $name ] ) || empty( $events[ $name ] )
134 ) {
135 return;
136 }
137
138 if ( null === $event ) {
139 $event = new Event();
140 }
141
142 $event->sender = $this;
143 $event->handled = false;
144 foreach ( $events[ $name ] as $e ) {
145 if ( isset( $e[1] ) ) {
146 $event->message = $e[1];
147 }
148 if ( ! is_array( $e[0] ) ) {
149 call_user_func( $e[0], $event );
150 } else {
151 $ref_method = new \ReflectionMethod( $e[0][0], $e[0][1] );
152 $ref_method->invoke( new $e[0][0](), $event );
153 }
154 }
155 }
156
157 /**
158 * Attach a behavior to current class, a behavior is a mixins, which useful in case of pro/free version
159 *
160 * @param string $name
161 * @param Behavior|string $behavior
162 */
163 public function attach_behavior( $name, $behavior ) {
164 // make a fast init
165 if ( ! $behavior instanceof Behavior ) {
166 $behavior = new $behavior();
167 }
168 $behavior->owner = $this;
169 $this->behaviors[ $name ] = $behavior;
170 }
171
172 /**
173 * Detach a behavior
174 *
175 * @param string $name
176 *
177 * @return mixed
178 */
179 public function detach_behavior( $name ) {
180 if ( ! isset( $this->behaviors[ $name ] ) ) {
181 return null;
182 }
183
184 $behavior = $this->behaviors[ $name ];
185 $behavior->owner = null;
186 unset( $this->behaviors[ $name ] );
187
188 return $behavior;
189 }
190
191 /**
192 * @param $name
193 *
194 * @return bool
195 */
196 public function has_behavior( $name ) {
197 return isset( $this->behaviors[ $name ] );
198 }
199
200 /**
201 * @param $method
202 *
203 * @return bool
204 * @throws \ReflectionException
205 */
206 public function has_method( $method ) {
207 $ref_class = new \ReflectionClass( $this );
208 if ( $ref_class->hasMethod( $method ) ) {
209 return true;
210 }
211
212 foreach ( $this->behaviors as $key => $behavior ) {
213 $ref_class = new \ReflectionClass( $behavior );
214 if ( $ref_class->hasMethod( $method ) ) {
215 return true;
216 }
217 }
218
219 return false;
220 }
221
222 /**
223 * @param $name
224 *
225 * @return mixed
226 * @throws \Exception
227 */
228 public function __get( $name ) {
229 // priority to current class properties
230 if ( $this->has_property( $name ) ) {
231 return $this->$name;
232 }
233 // check if behaviors already have
234 foreach ( $this->behaviors as $key => $behavior ) {
235 $ref_class = new \ReflectionClass( $behavior );
236
237 if ( $ref_class->hasProperty( $name ) ) {
238 return $ref_class->getProperty( $name )->getValue( $behavior );
239 }
240 }
241
242 throw new \Exception( 'Getting unknown property: ' . get_class( $this ) . '::' . $name );
243 }
244
245 /**
246 * @param $name
247 * @param $arguments
248 *
249 * @return mixed
250 * @throws \Exception
251 */
252 public function __call( $name, $arguments ) {
253 $ref_class = new \ReflectionClass( $this );
254 if ( $ref_class->hasMethod( $name ) ) {
255 $ref_method = new \ReflectionMethod( $this, $name );
256
257 return $ref_method->invokeArgs( $this, $arguments );
258 }
259 foreach ( $this->behaviors as $key => $behavior ) {
260 $ref_class = new \ReflectionClass( $behavior );
261 if ( $ref_class->hasMethod( $name ) ) {
262 $ref_method = new \ReflectionMethod( $behavior, $name );
263
264 return $ref_method->invokeArgs( $behavior, $arguments );
265 }
266 }
267
268 throw new \Exception( 'Getting unknown property: ' . get_class( $this ) . '::' . $name );
269 }
270
271 /**
272 * Do not call this directly, magic method for assign value to property, if property is not exist for this component, we will
273 * check its behavior
274 *
275 * @param $name
276 * @param $value
277 *
278 * @throws \Exception
279 */
280 public function __set( $name, $value ) {
281 $ref_class = new \ReflectionClass( $this );
282 if ( $ref_class->hasProperty( $name ) ) {
283 $ref_class->getProperty( $name )->setValue( $value );
284
285 return;
286 }
287
288 foreach ( $this->behaviors as $key => $behavior ) {
289 $ref_class = new \ReflectionClass( $behavior );
290 if ( $ref_class->hasProperty( $name ) ) {
291 $ref_class->getProperty( $name )->setValue( $behavior, $value );
292
293 return;
294 }
295 }
296
297 throw new \Exception( 'Setting unknown property: ' . get_class( $this ) . '::' . $name );
298 }
299
300 /**
301 * Parse the annotations of the class, and cache it. The list should be
302 * - type: for casting
303 * - sanitize_*: the list of sanitize_ functions, which should be run on this property
304 * - rule: the rule that we use for validation
305 */
306 protected function parse_annotations() {
307 $class = new \ReflectionClass( static::class );
308 $properties = $class->getProperties( \ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED );
309 foreach ( $properties as $property ) {
310 $doc_block = $property->getDocComment();
311 if ( ! stristr( $doc_block, '@defender_property' ) ) {
312 continue;
313 }
314 $this->annotations[ $property->getName() ] = array(
315 'type' => $this->parse_annotations_var( $doc_block ),
316 'sanitize' => $this->parse_annotation_sanitize( $doc_block ),
317 'rule' => $this->parse_annotation_rule( $doc_block ),
318 );
319 }
320 }
321
322 /**
323 * Get the variable type
324 *
325 * @param $docblock
326 *
327 * @return false|mixed
328 */
329 private function parse_annotations_var( $docblock ) {
330 $pattern = '/@var\s(.+)/';
331 if ( preg_match( $pattern, $docblock, $matches ) ) {
332 $type = trim( $matches[1] );
333
334 // only allow right type
335 if ( in_array(
336 $type,
337 array(
338 'boolean',
339 'bool',
340 'integer',
341 'int',
342 'float',
343 'double',
344 'string',
345 'array',
346 'object',
347 )
348 ) ) {
349 return $type;
350 }
351 }
352
353 return false;
354 }
355
356 /**
357 * Get the sanitize function
358 *
359 * @param $docblock
360 *
361 * @return false|mixed
362 */
363 private function parse_annotation_sanitize( $docblock ) {
364 $pattern = '/@(sanitize_.+)/';
365 if ( preg_match( $pattern, $docblock, $matches ) ) {
366 return trim( $matches[1] );
367 }
368
369 return false;
370 }
371
372 /**
373 * Get the validation rule
374 *
375 * @param $docblock
376 *
377 * @return false|mixed
378 */
379 private function parse_annotation_rule( $docblock ) {
380 $pattern = '/@(rule_.+)/';
381 if ( preg_match( $pattern, $docblock, $matches ) ) {
382 return trim( $matches[1] );
383 }
384
385 return false;
386 }
387 }
388