Verzeichnisstruktur phpBB-3.1.0
- Veröffentlicht
- 27.10.2014
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
php_exporter.php
001 <?php
002 /**
003 *
004 * This file is part of the phpBB Forum Software package.
005 *
006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
007 * @license GNU General Public License, version 2 (GPL-2.0)
008 *
009 * For full copyright and license information, please see
010 * the docs/CREDITS.txt file.
011 *
012 */
013
014 namespace phpbb\event;
015
016 /**
017 * Class php_exporter
018 * Crawls through a list of files and grabs all php-events
019 */
020 class php_exporter
021 {
022 /** @var string Path where we look for files*/
023 protected $path;
024
025 /** @var string phpBB Root Path */
026 protected $root_path;
027
028 /** @var string */
029 protected $current_file;
030
031 /** @var string */
032 protected $current_event;
033
034 /** @var int */
035 protected $current_event_line;
036
037 /** @var array */
038 protected $events;
039
040 /** @var array */
041 protected $file_lines;
042
043 /**
044 * @param string $phpbb_root_path
045 * @param mixed $extension String 'vendor/ext' to filter, null for phpBB core
046 */
047 public function __construct($phpbb_root_path, $extension = null)
048 {
049 $this->root_path = $phpbb_root_path;
050 $this->path = $phpbb_root_path;
051 $this->events = $this->file_lines = array();
052 $this->current_file = $this->current_event = '';
053 $this->current_event_line = 0;
054
055 $this->path = $this->root_path;
056 if ($extension)
057 {
058 $this->path .= 'ext/' . $extension . '/';
059 }
060 }
061
062 /**
063 * Get the list of all events
064 *
065 * @return array Array with events: name => details
066 */
067 public function get_events()
068 {
069 return $this->events;
070 }
071
072 /**
073 * Set current event data
074 *
075 * @param string $name Name of the current event (used for error messages)
076 * @param int $line Line where the current event is placed in
077 * @return null
078 */
079 public function set_current_event($name, $line)
080 {
081 $this->current_event = $name;
082 $this->current_event_line = $line;
083 }
084
085 /**
086 * Set the content of this file
087 *
088 * @param array $content Array with the lines of the file
089 * @return null
090 */
091 public function set_content($content)
092 {
093 $this->file_lines = $content;
094 }
095
096 /**
097 * Crawl the phpBB/ directory for php events
098 * @return int The number of events found
099 */
100 public function crawl_phpbb_directory_php()
101 {
102 $files = $this->get_recursive_file_list();
103 $this->events = array();
104 foreach ($files as $file)
105 {
106 $this->crawl_php_file($file);
107 }
108 ksort($this->events);
109
110 return sizeof($this->events);
111 }
112
113 /**
114 * Returns a list of files in $dir
115 *
116 * @return array List of files (including the path)
117 */
118 public function get_recursive_file_list()
119 {
120 try
121 {
122 $iterator = new \RecursiveIteratorIterator(
123 new \phpbb\event\recursive_event_filter_iterator(
124 new \RecursiveDirectoryIterator(
125 $this->path,
126 \FilesystemIterator::SKIP_DOTS
127 ),
128 $this->path
129 ),
130 \RecursiveIteratorIterator::LEAVES_ONLY
131 );
132 }
133 catch (\Exception $e)
134 {
135 return array();
136 }
137
138 $files = array();
139 foreach ($iterator as $file_info)
140 {
141 /** @var \RecursiveDirectoryIterator $file_info */
142 $relative_path = $iterator->getInnerIterator()->getSubPathname();
143 $files[] = str_replace(DIRECTORY_SEPARATOR, '/', $relative_path);
144 }
145
146 return $files;
147 }
148
149 /**
150 * Format the php events as a wiki table
151 * @return string
152 */
153 public function export_events_for_wiki()
154 {
155 $wiki_page = '= PHP Events (Hook Locations) =' . "\n";
156 $wiki_page .= '{| class="sortable zebra" cellspacing="0" cellpadding="5"' . "\n";
157 $wiki_page .= '! Identifier !! Placement !! Arguments !! Added in Release !! Explanation' . "\n";
158 foreach ($this->events as $event)
159 {
160 $wiki_page .= '|- id="' . $event['event'] . '"' . "\n";
161 $wiki_page .= '| [[#' . $event['event'] . '|' . $event['event'] . ']] || ' . $event['file'] . ' || ' . implode(', ', $event['arguments']) . ' || ' . $event['since'] . ' || ' . $event['description'] . "\n";
162 }
163 $wiki_page .= '|}' . "\n";
164
165 return $wiki_page;
166 }
167
168 /**
169 * @param string $file
170 * @return int Number of events found in this file
171 * @throws \LogicException
172 */
173 public function crawl_php_file($file)
174 {
175 $this->current_file = $file;
176 $this->file_lines = array();
177 $content = file_get_contents($this->path . $this->current_file);
178 $num_events_found = 0;
179
180 if (strpos($content, "dispatcher->trigger_event('") || strpos($content, "dispatcher->dispatch('"))
181 {
182 $this->set_content(explode("\n", $content));
183 for ($i = 0, $num_lines = sizeof($this->file_lines); $i < $num_lines; $i++)
184 {
185 $event_line = false;
186 $found_trigger_event = strpos($this->file_lines[$i], "dispatcher->trigger_event('");
187 $arguments = array();
188 if ($found_trigger_event !== false)
189 {
190 $event_line = $i;
191 $this->set_current_event($this->get_event_name($event_line, false), $event_line);
192
193 // Find variables of the event
194 $arguments = $this->get_vars_from_array();
195 $doc_vars = $this->get_vars_from_docblock();
196 $this->validate_vars_docblock_array($arguments, $doc_vars);
197 }
198 else
199 {
200 $found_dispatch = strpos($this->file_lines[$i], "dispatcher->dispatch('");
201 if ($found_dispatch !== false)
202 {
203 $event_line = $i;
204 $this->set_current_event($this->get_event_name($event_line, true), $event_line);
205 }
206 }
207
208 if ($event_line)
209 {
210 // Validate @event
211 $event_line_num = $this->find_event();
212 $this->validate_event($this->current_event, $this->file_lines[$event_line_num]);
213
214 // Validate @since
215 $since_line_num = $this->find_since();
216 $since = $this->validate_since($this->file_lines[$since_line_num]);
217
218 // Find event description line
219 $description_line_num = $this->find_description();
220 $description = substr(trim($this->file_lines[$description_line_num]), strlen('* '));
221
222 if (isset($this->events[$this->current_event]))
223 {
224 throw new \LogicException("The event '{$this->current_event}' from file "
225 . "'{$this->current_file}:{$event_line_num}' already exists in file "
226 . "'{$this->events[$this->current_event]['file']}'", 10);
227 }
228
229 sort($arguments);
230 $this->events[$this->current_event] = array(
231 'event' => $this->current_event,
232 'file' => $this->current_file,
233 'arguments' => $arguments,
234 'since' => $since,
235 'description' => $description,
236 );
237 $num_events_found++;
238 }
239 }
240 }
241
242 return $num_events_found;
243 }
244
245 /**
246 * Find the name of the event inside the dispatch() line
247 *
248 * @param int $event_line
249 * @param bool $is_dispatch Do we look for dispatch() or trigger_event() ?
250 * @return string Name of the event
251 * @throws \LogicException
252 */
253 public function get_event_name($event_line, $is_dispatch)
254 {
255 $event_text_line = $this->file_lines[$event_line];
256 $event_text_line = ltrim($event_text_line, "\t ");
257
258 if ($is_dispatch)
259 {
260 $regex = '#\$([a-z](?:[a-z0-9_]|->)*)';
261 $regex .= '->dispatch\(';
262 $regex .= '\'' . $this->preg_match_event_name() . '\'';
263 $regex .= '\);#';
264 }
265 else
266 {
267 $regex = '#extract\(\$([a-z](?:[a-z0-9_]|->)*)';
268 $regex .= '->trigger_event\(';
269 $regex .= '\'' . $this->preg_match_event_name() . '\'';
270 $regex .= ', compact\(\$vars\)\)\);#';
271 }
272
273 $match = array();
274 preg_match($regex, $event_text_line, $match);
275 if (!isset($match[2]))
276 {
277 throw new \LogicException("Can not find event name in line '{$event_text_line}' "
278 . "in file '{$this->current_file}:{$event_line}'", 1);
279 }
280
281 return $match[2];
282 }
283
284 /**
285 * Returns a regex match for the event name
286 *
287 * @return string
288 */
289 protected function preg_match_event_name()
290 {
291 return '([a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+)';
292 }
293
294 /**
295 * Find the $vars array
296 *
297 * @return array List of variables
298 * @throws \LogicException
299 */
300 public function get_vars_from_array()
301 {
302 $line = ltrim($this->file_lines[$this->current_event_line - 1], "\t");
303 if ($line === ');')
304 {
305 $vars_array = $this->get_vars_from_multi_line_array();
306 }
307 else
308 {
309 $vars_array = $this->get_vars_from_single_line_array($line);
310 }
311
312 foreach ($vars_array as $var)
313 {
314 if (!preg_match('#^([a-zA-Z_][a-zA-Z0-9_]*)$#', $var))
315 {
316 throw new \LogicException("Found invalid var '{$var}' in array for event '{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 3);
317 }
318 }
319
320 sort($vars_array);
321 return $vars_array;
322 }
323
324 /**
325 * Find the variables in single line array
326 *
327 * @param string $line
328 * @param bool $throw_multiline Throw an exception when there are too
329 * many arguments in one line.
330 * @return array List of variables
331 * @throws \LogicException
332 */
333 public function get_vars_from_single_line_array($line, $throw_multiline = true)
334 {
335 $match = array();
336 preg_match('#^\$vars = array\(\'([a-zA-Z0-9_\' ,]+)\'\);$#', $line, $match);
337
338 if (isset($match[1]))
339 {
340 $vars_array = explode("', '", $match[1]);
341 if ($throw_multiline && sizeof($vars_array) > 6)
342 {
343 throw new \LogicException('Should use multiple lines for $vars definition '
344 . "for event '{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 2);
345 }
346 return $vars_array;
347 }
348 else
349 {
350 throw new \LogicException("Can not find '\$vars = array();'-line for event '{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 1);
351 }
352 }
353
354 /**
355 * Find the variables in single line array
356 *
357 * @return array List of variables
358 * @throws \LogicException
359 */
360 public function get_vars_from_multi_line_array()
361 {
362 $current_vars_line = 2;
363 $var_lines = array();
364 while (ltrim($this->file_lines[$this->current_event_line - $current_vars_line], "\t") !== '$vars = array(')
365 {
366 $var_lines[] = substr(trim($this->file_lines[$this->current_event_line - $current_vars_line]), 0, -1);
367
368 $current_vars_line++;
369 if ($current_vars_line > $this->current_event_line)
370 {
371 // Reached the start of the file
372 throw new \LogicException("Can not find end of \$vars array for event '{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 2);
373 }
374 }
375
376 return $this->get_vars_from_single_line_array('$vars = array(' . implode(", ", $var_lines) . ');', false);
377 }
378
379 /**
380 * Find the $vars array
381 *
382 * @return array List of variables
383 * @throws \LogicException
384 */
385 public function get_vars_from_docblock()
386 {
387 $doc_vars = array();
388 $current_doc_line = 1;
389 $found_comment_end = false;
390 while (ltrim($this->file_lines[$this->current_event_line - $current_doc_line], "\t") !== '/**')
391 {
392 if (ltrim($this->file_lines[$this->current_event_line - $current_doc_line], "\t ") === '*/')
393 {
394 $found_comment_end = true;
395 }
396
397 if ($found_comment_end)
398 {
399 $var_line = trim($this->file_lines[$this->current_event_line - $current_doc_line]);
400 $var_line = preg_replace('!\s+!', ' ', $var_line);
401 if (strpos($var_line, '* @var ') === 0)
402 {
403 $doc_line = explode(' ', $var_line, 5);
404 if (sizeof($doc_line) !== 5)
405 {
406 throw new \LogicException("Found invalid line '{$this->file_lines[$this->current_event_line - $current_doc_line]}' "
407 . "for event '{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 1);
408 }
409 $doc_vars[] = $doc_line[3];
410 }
411 }
412
413 $current_doc_line++;
414 if ($current_doc_line > $this->current_event_line)
415 {
416 // Reached the start of the file
417 throw new \LogicException("Can not find end of docblock for event '{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 2);
418 }
419 }
420
421 if (empty($doc_vars))
422 {
423 // Reached the start of the file
424 throw new \LogicException("Can not find @var lines for event '{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 3);
425 }
426
427 foreach ($doc_vars as $var)
428 {
429 if (!preg_match('#^([a-zA-Z_][a-zA-Z0-9_]*)$#', $var))
430 {
431 throw new \LogicException("Found invalid @var '{$var}' in docblock for event "
432 . "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 4);
433 }
434 }
435
436 sort($doc_vars);
437 return $doc_vars;
438 }
439
440 /**
441 * Find the "@since" Information line
442 *
443 * @return int Absolute line number
444 * @throws \LogicException
445 */
446 public function find_since()
447 {
448 return $this->find_tag('since', array('event', 'var'));
449 }
450
451 /**
452 * Find the "@event" Information line
453 *
454 * @return int Absolute line number
455 */
456 public function find_event()
457 {
458 return $this->find_tag('event', array());
459 }
460
461 /**
462 * Find a "@*" Information line
463 *
464 * @param string $find_tag Name of the tag we are trying to find
465 * @param array $disallowed_tags List of tags that must not appear between
466 * the tag and the actual event
467 * @return int Absolute line number
468 * @throws \LogicException
469 */
470 public function find_tag($find_tag, $disallowed_tags)
471 {
472 $find_tag_line = 0;
473 $found_comment_end = false;
474 while (strpos(ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t "), '* @' . $find_tag . ' ') !== 0)
475 {
476 if ($found_comment_end && ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t") === '/**')
477 {
478 // Reached the start of this doc block
479 throw new \LogicException("Can not find '@{$find_tag}' information for event "
480 . "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 1);
481 }
482
483 foreach ($disallowed_tags as $disallowed_tag)
484 {
485 if ($found_comment_end && strpos(ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t "), '* @' . $disallowed_tag) === 0)
486 {
487 // Found @var after the @since
488 throw new \LogicException("Found '@{$disallowed_tag}' information after '@{$find_tag}' for event "
489 . "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 3);
490 }
491 }
492
493 if (ltrim($this->file_lines[$this->current_event_line - $find_tag_line], "\t ") === '*/')
494 {
495 $found_comment_end = true;
496 }
497
498 $find_tag_line++;
499 if ($find_tag_line >= $this->current_event_line)
500 {
501 // Reached the start of the file
502 throw new \LogicException("Can not find '@{$find_tag}' information for event "
503 . "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 2);
504 }
505 }
506
507 return $this->current_event_line - $find_tag_line;
508 }
509
510 /**
511 * Find a "@*" Information line
512 *
513 * @return int Absolute line number
514 * @throws \LogicException
515 */
516 public function find_description()
517 {
518 $find_desc_line = 0;
519 while (ltrim($this->file_lines[$this->current_event_line - $find_desc_line], "\t") !== '/**')
520 {
521 $find_desc_line++;
522 if ($find_desc_line > $this->current_event_line)
523 {
524 // Reached the start of the file
525 throw new \LogicException("Can not find a description for event "
526 . "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 1);
527 }
528 }
529
530 $find_desc_line = $this->current_event_line - $find_desc_line + 1;
531
532 $desc = trim($this->file_lines[$find_desc_line]);
533 if (strpos($desc, '* @') === 0 || $desc[0] !== '*' || substr($desc, 1) == '')
534 {
535 // First line of the doc block is a @-line, empty or only contains "*"
536 throw new \LogicException("Can not find a description for event "
537 . "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 2);
538 }
539
540 return $find_desc_line;
541 }
542
543 /**
544 * Validate "@since" Information
545 *
546 * @param string $line
547 * @return string
548 * @throws \LogicException
549 */
550 public function validate_since($line)
551 {
552 $match = array();
553 preg_match('#^\* @since (\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?)$#', ltrim($line, "\t "), $match);
554 if (!isset($match[1]))
555 {
556 throw new \LogicException("Invalid '@since' information for event "
557 . "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'");
558 }
559
560 return $match[1];
561 }
562
563 /**
564 * Validate "@event" Information
565 *
566 * @param string $event_name
567 * @param string $line
568 * @return string
569 * @throws \LogicException
570 */
571 public function validate_event($event_name, $line)
572 {
573 $event = substr(ltrim($line, "\t "), strlen('* @event '));
574
575 if ($event !== trim($event))
576 {
577 throw new \LogicException("Invalid '@event' information for event "
578 . "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 1);
579 }
580
581 if ($event !== $event_name)
582 {
583 throw new \LogicException("Event name does not match '@event' tag for event "
584 . "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 2);
585 }
586
587 return $event;
588 }
589
590 /**
591 * Validates that two arrays contain the same strings
592 *
593 * @param array $vars_array Variables found in the array line
594 * @param array $vars_docblock Variables found in the doc block
595 * @return null
596 * @throws \LogicException
597 */
598 public function validate_vars_docblock_array($vars_array, $vars_docblock)
599 {
600 $vars_array = array_unique($vars_array);
601 $vars_docblock = array_unique($vars_docblock);
602 $sizeof_vars_array = sizeof($vars_array);
603
604 if ($sizeof_vars_array !== sizeof($vars_docblock) || $sizeof_vars_array !== sizeof(array_intersect($vars_array, $vars_docblock)))
605 {
606 throw new \LogicException("\$vars array does not match the list of '@var' tags for event "
607 . "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'");
608 }
609 }
610 }
611