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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

php_exporter.php

Zuletzt modifiziert: 09.10.2024, 12:51 - Dateigröße: 16.72 KiB


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