StringHashParser.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. <?php
  2. /**
  3. * Parses string hash files. File format is as such:
  4. *
  5. * DefaultKeyValue
  6. * KEY: Value
  7. * KEY2: Value2
  8. * --MULTILINE-KEY--
  9. * Multiline
  10. * value.
  11. *
  12. * Which would output something similar to:
  13. *
  14. * array(
  15. * 'ID' => 'DefaultKeyValue',
  16. * 'KEY' => 'Value',
  17. * 'KEY2' => 'Value2',
  18. * 'MULTILINE-KEY' => "Multiline\nvalue.\n",
  19. * )
  20. *
  21. * We use this as an easy to use file-format for configuration schema
  22. * files, but the class itself is usage agnostic.
  23. *
  24. * You can use ---- to forcibly terminate parsing of a single string-hash;
  25. * this marker is used in multi string-hashes to delimit boundaries.
  26. */
  27. class HTMLPurifier_StringHashParser
  28. {
  29. /**
  30. * @type string
  31. */
  32. public $default = 'ID';
  33. /**
  34. * Parses a file that contains a single string-hash.
  35. * @param string $file
  36. * @return array
  37. */
  38. public function parseFile($file)
  39. {
  40. if (!file_exists($file)) {
  41. return false;
  42. }
  43. $fh = fopen($file, 'r');
  44. if (!$fh) {
  45. return false;
  46. }
  47. $ret = $this->parseHandle($fh);
  48. fclose($fh);
  49. return $ret;
  50. }
  51. /**
  52. * Parses a file that contains multiple string-hashes delimited by '----'
  53. * @param string $file
  54. * @return array
  55. */
  56. public function parseMultiFile($file)
  57. {
  58. if (!file_exists($file)) {
  59. return false;
  60. }
  61. $ret = array();
  62. $fh = fopen($file, 'r');
  63. if (!$fh) {
  64. return false;
  65. }
  66. while (!feof($fh)) {
  67. $ret[] = $this->parseHandle($fh);
  68. }
  69. fclose($fh);
  70. return $ret;
  71. }
  72. /**
  73. * Internal parser that acepts a file handle.
  74. * @note While it's possible to simulate in-memory parsing by using
  75. * custom stream wrappers, if such a use-case arises we should
  76. * factor out the file handle into its own class.
  77. * @param resource $fh File handle with pointer at start of valid string-hash
  78. * block.
  79. * @return array
  80. */
  81. protected function parseHandle($fh)
  82. {
  83. $state = false;
  84. $single = false;
  85. $ret = array();
  86. do {
  87. $line = fgets($fh);
  88. if ($line === false) {
  89. break;
  90. }
  91. $line = rtrim($line, "\n\r");
  92. if (!$state && $line === '') {
  93. continue;
  94. }
  95. if ($line === '----') {
  96. break;
  97. }
  98. if (strncmp('--#', $line, 3) === 0) {
  99. // Comment
  100. continue;
  101. } elseif (strncmp('--', $line, 2) === 0) {
  102. // Multiline declaration
  103. $state = trim($line, '- ');
  104. if (!isset($ret[$state])) {
  105. $ret[$state] = '';
  106. }
  107. continue;
  108. } elseif (!$state) {
  109. $single = true;
  110. if (strpos($line, ':') !== false) {
  111. // Single-line declaration
  112. list($state, $line) = explode(':', $line, 2);
  113. $line = trim($line);
  114. } else {
  115. // Use default declaration
  116. $state = $this->default;
  117. }
  118. }
  119. if ($single) {
  120. $ret[$state] = $line;
  121. $single = false;
  122. $state = false;
  123. } else {
  124. $ret[$state] .= "$line\n";
  125. }
  126. } while (!feof($fh));
  127. return $ret;
  128. }
  129. }
  130. // vim: et sw=4 sts=4