PageRenderTime 41ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/bin/wantedpages.php

http://github.com/splitbrain/dokuwiki
PHP | 186 lines | 128 code | 20 blank | 38 comment | 29 complexity | 907bed645e3a3a4900e7f424dddc3fd2 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  1. #!/usr/bin/php
  2. <?php
  3. use splitbrain\phpcli\CLI;
  4. use splitbrain\phpcli\Options;
  5. if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
  6. define('NOSESSION', 1);
  7. require_once(DOKU_INC . 'inc/init.php');
  8. /**
  9. * Find wanted pages
  10. */
  11. class WantedPagesCLI extends CLI {
  12. const DIR_CONTINUE = 1;
  13. const DIR_NS = 2;
  14. const DIR_PAGE = 3;
  15. private $skip = false;
  16. private $sort = 'wanted';
  17. private $result = array();
  18. /**
  19. * Register options and arguments on the given $options object
  20. *
  21. * @param Options $options
  22. * @return void
  23. */
  24. protected function setup(Options $options) {
  25. $options->setHelp(
  26. 'Outputs a list of wanted pages (pages that do not exist yet) and their origin pages ' .
  27. ' (the pages that are linkin to these missing pages).'
  28. );
  29. $options->registerArgument(
  30. 'namespace',
  31. 'The namespace to lookup. Defaults to root namespace',
  32. false
  33. );
  34. $options->registerOption(
  35. 'sort',
  36. 'Sort by wanted or origin page',
  37. 's',
  38. '(wanted|origin)'
  39. );
  40. $options->registerOption(
  41. 'skip',
  42. 'Do not show the second dimension',
  43. 'k'
  44. );
  45. }
  46. /**
  47. * Your main program
  48. *
  49. * Arguments and options have been parsed when this is run
  50. *
  51. * @param Options $options
  52. * @return void
  53. */
  54. protected function main(Options $options) {
  55. $args = $options->getArgs();
  56. if($args) {
  57. $startdir = dirname(wikiFN($args[0] . ':xxx'));
  58. } else {
  59. $startdir = dirname(wikiFN('xxx'));
  60. }
  61. $this->skip = $options->getOpt('skip');
  62. $this->sort = $options->getOpt('sort');
  63. $this->info("searching $startdir");
  64. foreach($this->getPages($startdir) as $page) {
  65. $this->internalLinks($page);
  66. }
  67. ksort($this->result);
  68. foreach($this->result as $main => $subs) {
  69. if($this->skip) {
  70. print "$main\n";
  71. } else {
  72. $subs = array_unique($subs);
  73. sort($subs);
  74. foreach($subs as $sub) {
  75. printf("%-40s %s\n", $main, $sub);
  76. }
  77. }
  78. }
  79. }
  80. /**
  81. * Determine directions of the search loop
  82. *
  83. * @param string $entry
  84. * @param string $basepath
  85. * @return int
  86. */
  87. protected function dirFilter($entry, $basepath) {
  88. if($entry == '.' || $entry == '..') {
  89. return WantedPagesCLI::DIR_CONTINUE;
  90. }
  91. if(is_dir($basepath . '/' . $entry)) {
  92. if(strpos($entry, '_') === 0) {
  93. return WantedPagesCLI::DIR_CONTINUE;
  94. }
  95. return WantedPagesCLI::DIR_NS;
  96. }
  97. if(preg_match('/\.txt$/', $entry)) {
  98. return WantedPagesCLI::DIR_PAGE;
  99. }
  100. return WantedPagesCLI::DIR_CONTINUE;
  101. }
  102. /**
  103. * Collects recursively the pages in a namespace
  104. *
  105. * @param string $dir
  106. * @return array
  107. * @throws DokuCLI_Exception
  108. */
  109. protected function getPages($dir) {
  110. static $trunclen = null;
  111. if(!$trunclen) {
  112. global $conf;
  113. $trunclen = strlen($conf['datadir'] . ':');
  114. }
  115. if(!is_dir($dir)) {
  116. throw new DokuCLI_Exception("Unable to read directory $dir");
  117. }
  118. $pages = array();
  119. $dh = opendir($dir);
  120. while(false !== ($entry = readdir($dh))) {
  121. $status = $this->dirFilter($entry, $dir);
  122. if($status == WantedPagesCLI::DIR_CONTINUE) {
  123. continue;
  124. } else if($status == WantedPagesCLI::DIR_NS) {
  125. $pages = array_merge($pages, $this->getPages($dir . '/' . $entry));
  126. } else {
  127. $page = array(
  128. 'id' => pathID(substr($dir . '/' . $entry, $trunclen)),
  129. 'file' => $dir . '/' . $entry,
  130. );
  131. $pages[] = $page;
  132. }
  133. }
  134. closedir($dh);
  135. return $pages;
  136. }
  137. /**
  138. * Parse instructions and add the non-existing links to the result array
  139. *
  140. * @param array $page array with page id and file path
  141. */
  142. protected function internalLinks($page) {
  143. global $conf;
  144. $instructions = p_get_instructions(file_get_contents($page['file']));
  145. $cns = getNS($page['id']);
  146. $exists = false;
  147. $pid = $page['id'];
  148. foreach($instructions as $ins) {
  149. if($ins[0] == 'internallink' || ($conf['camelcase'] && $ins[0] == 'camelcaselink')) {
  150. $mid = $ins[1][0];
  151. resolve_pageid($cns, $mid, $exists);
  152. if(!$exists) {
  153. list($mid) = explode('#', $mid); //record pages without hashes
  154. if($this->sort == 'origin') {
  155. $this->result[$pid][] = $mid;
  156. } else {
  157. $this->result[$mid][] = $pid;
  158. }
  159. }
  160. }
  161. }
  162. }
  163. }
  164. // Main
  165. $cli = new WantedPagesCLI();
  166. $cli->run();