├── README.md ├── changelog.md ├── config.php ├── inc ├── codeSamples.php ├── markdown.php ├── raml.php ├── ramlDataObject.php ├── ramlPathObject.php └── spyc.php ├── index.php ├── raml ├── github.raml ├── githubrepo.raml ├── songs.raml └── twitter.raml └── templates ├── grey ├── _404.phtml ├── _action.phtml ├── _comments.phtml ├── _menu.phtml ├── _resources.phtml ├── _verbs.phtml └── index.phtml └── orange ├── _404.phtml ├── _action.phtml ├── _comments.phtml ├── _menu.phtml ├── _resources.phtml ├── _verbs.phtml └── index.phtml /README.md: -------------------------------------------------------------------------------- 1 | # RAML 2 HTML for PHP 2 | 3 | RAML 2 HTML for PHP is a simple application that makes use of multiple templates to allow you to build and customize your API Docs using RAML. 4 | 5 | ![Screenshot](http://www.mikestowe.com/wp-content/uploads/2014/05/raml2html.png?v=1) 6 | 7 | #### What all does RAML 2 HTML for PHP do? 8 | RAML 2 HTML for PHP builds out a multi-page documentation site for you based on your RAML spec. This lets users explore and understand how your API works, while letting you style the documentation (within the RAML spec) using HTML or markdown, and provide your users with automatically generated code samples while also letting you include community and commenting functionality within your documentation via Disqus. 9 | 10 | Of course, being templated, you can add additional features/ functionality to your site quickly and easily by setting up your own template (or copying the grey template) and modifying the HTML/CSS/PHP code. 11 | 12 | #### What version of PHP does RAML 2 HTML require? 13 | RAML 2 HTML for PHP versions 1.0 or greater require PHP 5.3+ 14 | 15 | If you are running an older version of PHP, it is highly recommend you upgrade, but if you are unable to do so, you can use RAML version 0.2 which supports PHP 5+. However, this version is extremely limited and is not being maintained or supported. 16 | 17 | No other external libraries, databases, or extensions are required to run RAML to HTML for PHP, although if APC is installed the script will take advantage of it for caching purposes. 18 | 19 | #### How do I set it up? 20 | Important setup information is stored in config.php. You can read setup instructions [here](http://www.mikestowe.com/2014/05/raml-2-html.php). 21 | 22 | #### Is there a Demo? 23 | Yes! You can find the latest stable demo and the latest development version demos [here](http://www.mikestowe.com/2014/05/raml-2-html.php). 24 | 25 | #### Does it support all RAML features? 26 | Not yet, although version 1.0 was a complete rewrite supports base, path variables, multi-level includes, resourceTypes, traits, and more. Other features will be added down the road! 27 | 28 | #### How Can I Help? 29 | Easy! Download and use RAML 2 HTML for PHP, tell your friends, if you find issues report them, or even better - feel free to contribute by forking and making pull requests! 30 | 31 | #### License 32 | RAML is covered under the GPL2 license. However, the included class Spyc falls under the MIT license. 33 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | #RAML2HTML for PHP 2 | ###version 1.3 changelog 3 | - Added in support for resourceTypes 4 | - Fixed isArray() bug 5 | 6 | 7 | ###version 1.2 changelog 8 | 9 | - Upgraded Spyc to fix spacing issues 10 | - Added in support for basic markdown 11 | - headers 12 | - bold and italic text 13 | - lists (ordered/unordered) 14 | - links and images 15 | - code blocks 16 | - Added in support for alerts 17 | - info 18 | - warning 19 | - alert 20 | - Added in Auto-generated Code Samples 21 | - JavaScript 22 | - PHP via Curl 23 | - Ruby on Rails 24 | - Added in comments via Disqus (optional) 25 | - Added in code and response formatting 26 | - Added "required" and "example" fields to Parameter boxes 27 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /inc/codeSamples.php: -------------------------------------------------------------------------------- 1 | 6 | * @link https://github.com/mikestowe/php-raml2html 7 | * @link http://www.mikestowe.com/2014/05/raml-2-html.php 8 | * @license http://www.gnu.org/licenses/gpl-2.0.html GPL v2 9 | */ 10 | 11 | namespace RAML2HTML; 12 | 13 | /** 14 | * Code Sample Generator 15 | * @package RAML2HTML 16 | */ 17 | class codeSamples 18 | { 19 | private $RAML = false; 20 | 21 | /** 22 | * Setup Class 23 | * @param RAML 24 | * @return void 25 | */ 26 | function __construct($object) { 27 | $this->RAML = $object; 28 | } 29 | 30 | /** 31 | * Create a Path for API Calls 32 | * @return string 33 | */ 34 | private function path() { 35 | $path = $this->RAML->baseUri . $this->RAML->getCurrentPath(); 36 | if ($this->RAML->getCurrentAction() == 'GET') { 37 | $path .= '?'; 38 | $opt = true; 39 | 40 | foreach ($this->RAML->action()->get('queryParameters')->toArray() as $k => $v) { 41 | if (isset($v['required']) && $v['required'] == 1) { 42 | $path .= $k . '='; 43 | if (isset($v['example'])) { 44 | $path .= urlencode($v['example']) . '&'; 45 | } else { 46 | $path .= '%' . $k . '%&'; 47 | } 48 | } elseif (isset($v['required']) && $opt && isset($v['example'])) { 49 | $path .= $k . '=' . urlencode($v['example']) . '&'; 50 | $opt = false; 51 | } 52 | } 53 | return substr($path, 0,-1); 54 | } 55 | 56 | return $path; 57 | } 58 | 59 | 60 | /** 61 | * Produce Code Sample for PHP 62 | * @return string 63 | */ 64 | public function php() { 65 | $template = '$ch = curl_init();' . "\n"; 66 | $template .= 'curl_setopt($ch, CURLOPT_URL, "'. $this->path() .'");' . "\n"; 67 | $template .= 'curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);' . "\n"; 68 | $template .= 'curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); ' . "\n"; 69 | $template .= '' . "\n"; 70 | 71 | $template .= '// Make sure you set the nessary headers as a $headers array' . "\n"; 72 | $template .= 'curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);' . "\n"; 73 | 74 | $template .= '' . "\n"; 75 | 76 | if ($this->RAML->getCurrentAction() != 'GET') { 77 | $template .= 'curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "'.strtolower($this->RAML->getCurrentAction()).'")' . "\n"; 78 | } 79 | 80 | if (in_array($this->RAML->getCurrentAction(), array('POST', 'PUT', 'PATCH'))) { 81 | if($this->RAML->get('body')->get('application/json')->get('example')) { 82 | $template .= '$body = \'' . str_replace("'", "\\'", $this->RAML->get('body')->get('application/json')->get('example')) . '\';' . "\n"; 83 | } else { 84 | $template .= '// $body is your JSON/ XML/ Text/ Form Query/ etc' . "\n"; 85 | } 86 | 87 | $template .= 'curl_setopt($ch, CURLOPT_POSTFIELDS, $body);' . "\n"; 88 | $template .= '' . "\n"; 89 | } 90 | 91 | $template .= '$response = curl_exec($ch);' . "\n"; 92 | $template .= '$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);' . "\n"; 93 | $template .= 'curl_close($ch);' . "\n"; 94 | 95 | return $template; 96 | } 97 | 98 | 99 | 100 | /** 101 | * Produce Code Sample for Rails 102 | * @return string 103 | */ 104 | public function rails() { 105 | $template = 'uri = URI.parse("'.$this->path().'")' . "\n"; 106 | $template .= 'http = Net::HTTP.new(uri.host, uri.port)' . "\n"; 107 | $template .= 'request = Net::HTTP::'.ucfirst(strtolower($this->RAML->getCurrentAction())).'.new(uri.request_uri)' . "\n\n"; 108 | $template .= '# Make sure you set the appropriate headers' . "\n"; 109 | $template .= 'request["header"] = "header value"' . "\n\n"; 110 | 111 | if ($this->RAML->getCurrentAction() != 'GET') { 112 | $template .= '# body is your JSON/ XML/ Text/ Form Query/ etc' . "\n"; 113 | $template .= 'request.set_form_data(body)' . "\n\n"; 114 | } 115 | 116 | $template .= 'response = http.request(request)' . "\n"; 117 | 118 | return $template; 119 | } 120 | 121 | 122 | 123 | /** 124 | * Produce Code Sample for JavaScript 125 | * @return string 126 | */ 127 | public function javascript() { 128 | $template = 'var xmlHttp = new XMLHttpRequest();' . "\n"; 129 | $template .= 'xmlHttp.open("'.strtoupper($this->RAML->getCurrentAction()).'", "'.$this->path().'", false);' . "\n"; 130 | $template .= "\n"; 131 | $template .= "// Make sure you set the appropriate headers\n"; 132 | $template .= 'xmlHttp.setRequestHeader("Header Key", "Header Value");' . "\n\n"; 133 | $send = 'null'; 134 | 135 | if ($this->RAML->getCurrentAction() != 'GET') { 136 | $template .= 'var data = "# body is your JSON/ XML/ Text/ Form Query/ etc"' . "\n"; 137 | $send = 'data'; 138 | } 139 | 140 | $template .= 'xmlHttp.send('.$send.');' . "\n\n"; 141 | $template .= 'var response = xmlHttp.responseText;' . "\n"; 142 | 143 | return $template; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /inc/markdown.php: -------------------------------------------------------------------------------- 1 | 6 | * @link https://github.com/mikestowe/php-raml2html 7 | * @link http://www.mikestowe.com/2014/05/raml-2-html.php 8 | * @license http://www.gnu.org/licenses/gpl-2.0.html GPL v2 9 | */ 10 | 11 | namespace RAML2HTML; 12 | 13 | /** 14 | * Simple Markdown Parser 15 | * @package RAML2HTML 16 | */ 17 | class markdown 18 | { 19 | 20 | static $patterns = array( 21 | '\n(\s)*-' => '
    • ', 22 | '\n(\s)*([0-9]+)\.?' => '
    $1. ', 23 | '\[(info|warning|alert)\]([^\]]+)\[\/(info|warning|alert)\]' => '
$2
', 24 | '^|\s(\*\*|__)([^\*\*|__]+)(\*\*|__)' => '$2', 25 | '^|\s(\*|_)([^\*|_]+)(\*|_)' => '$2', 26 | '!\[([^\]]+)\]\(([^\)]+)\)' => '$1', 27 | '\[([^\]]+)\]\(([^\)]+)\)' => '$1', 28 | '\#{6}([^\n]+)\n' => '
$1
', 29 | '\#{5}([^\n]+)\n' => '
$1
', 30 | '\#{4}([^\n]+)\n' => '

$1

', 31 | '\#{3}([^\n]+)\n' => '

$1

', 32 | '\##([^\n]+)\n' => '

$1

', 33 | '\#([^\n]+)\n' => '

$1

', 34 | ); 35 | 36 | 37 | static function parse($input) { 38 | foreach (self::$patterns as $search => $replace) { 39 | $input = preg_replace('/'.$search.'/i', $replace, $input); 40 | } 41 | 42 | // Handle Code 43 | $input = preg_replace_callback('/`([^`]+)`/i', function($matches) { 44 | return '
'.htmlentities($matches[1]).'
'; 45 | }, $input); 46 | 47 | // Handle line breaks 48 | return str_replace("\n", "
", $input); 49 | } 50 | 51 | 52 | static function clean($input) { 53 | foreach (self::$patterns as $search => $replace) { 54 | if (strpos($replace, '$2')) { 55 | $replace = '$2'; 56 | } elseif (strpos($replace, '$1')) { 57 | $replace = '$1'; 58 | } else { 59 | $replace = ''; 60 | } 61 | 62 | $input = preg_replace('/'.$search.'/i', $replace, $input); 63 | } 64 | 65 | return str_replace("\n", " ", $input); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /inc/raml.php: -------------------------------------------------------------------------------- 1 | 6 | * @link https://github.com/mikestowe/php-raml2html 7 | * @link http://www.mikestowe.com/2014/05/raml-2-html.php 8 | * @license http://www.gnu.org/licenses/gpl-2.0.html GPL v2 9 | */ 10 | 11 | namespace RAML2HTML; 12 | 13 | /** 14 | * RAML Class 15 | * @package RAML2HTML 16 | */ 17 | class RAML extends RAMLDataObject 18 | { 19 | 20 | private $keys = array( 21 | 'traits', 22 | ); 23 | 24 | private $verbs = array(); 25 | private $paths = array(); 26 | private $traits = array(); 27 | private $base = array(); 28 | private $resources = array(); 29 | private $schemas = array(); 30 | private $examples = array(); 31 | private $currentPath = '/'; 32 | private $currentVerb = null; 33 | private $includePath = '../raml/'; 34 | 35 | 36 | /** 37 | * Constructing Method 38 | * Setups class properties 39 | * @param array $verbs 40 | * @return void 41 | */ 42 | public function __construct($verbs = array()) 43 | { 44 | $this->setMaster($this); 45 | $this->verbs = $verbs; 46 | parent::__construct(); 47 | } 48 | 49 | 50 | /** 51 | * Build RAML Object from Array 52 | * Used to take a parsed array and build the RAML Object 53 | * @param array $array 54 | * @return void 55 | */ 56 | public function buildFromArray($array) 57 | { 58 | $array = $this->handleIncludes($array); 59 | $this->paths['/'] = new RAMLPathObject($this, '/'); 60 | 61 | // Handle Base Data 62 | foreach ($array as $key => $value) { 63 | if (is_array($value) && substr($key, 0, 1) == '/') { 64 | continue; 65 | } elseif ($key == 'resourceTypes') { 66 | foreach ($value as $v) { 67 | $this->resources[key($v)] = $v[key($v)]; 68 | } 69 | } elseif ($key == 'traits') { 70 | foreach ($value as $v) { 71 | $this->traits[key($v)] = $v[key($v)]; 72 | } 73 | } elseif ($key == 'schemas') { 74 | foreach ($value as $v) { 75 | $this->schemas[key($v)] = $v[key($v)]; 76 | } 77 | } elseif (in_array(strtoupper($key), $this->verbs)) { 78 | $this->paths[$key]->addVerb($key); 79 | $this->set(strtoupper($key), $value); 80 | } else { 81 | $this->set($key, $value); 82 | } 83 | 84 | unset($array[$key]); 85 | } 86 | 87 | $this->formatResourceTypes(); 88 | 89 | foreach ($this->base as $key => $value) { 90 | $cleanKey = str_replace('?', '', $key); 91 | if (in_array($cleanKey, $this->verbs)) { 92 | $cleanKey = strtoupper($cleanKey); 93 | $cleanV = array(); 94 | 95 | if (isset($value['responses'])) { 96 | foreach ($value['responses'] as $k => $v) { 97 | $cleanV['c' . $k] = $v; 98 | } 99 | unset($value['responses']); 100 | $value['responses'] = $cleanV; 101 | } 102 | 103 | } 104 | unset($this->base[$key]); 105 | $this->base[$cleanKey] = $value; 106 | } 107 | 108 | // Handle Paths 109 | foreach ($array as $key => $value) { 110 | $this->paths['/']->addChild('/' . $key, $key); 111 | $this->generatePathData($key, $value); 112 | } 113 | } 114 | 115 | 116 | /** 117 | * Format ResourceTypes 118 | * Prevent Collisions 119 | * @return void 120 | */ 121 | 122 | private function formatResourceTypes() { 123 | foreach ($this->resources as $rtk => $rtv) { 124 | foreach ($rtv as $rtmtk => $rtmtv) { 125 | if (in_array($rtmtk, $this->verbs) || in_array(substr($rtmtk, 0, -1), $this->verbs)) { 126 | // Fix responses first 127 | if (isset($rtmtv['responses'])) { 128 | foreach ($rtmtv['responses'] as $k => $v) { 129 | unset($rtmtv['responses'][$k]); 130 | $rtmtv['responses']['c'.$k] = $v; 131 | } 132 | } 133 | unset($this->resources[$rtk][$rtmtk]); 134 | $this->resources[$rtk][strtoupper($rtmtk)] = $rtmtv; 135 | } 136 | } 137 | } 138 | } 139 | 140 | 141 | /** 142 | * Generata Path Data 143 | * Build Path Objects 144 | * @param string $key 145 | * @param mixed $value 146 | * @return void 147 | */ 148 | public function generatePathData($key, $value) { 149 | $key = $this->handlePlaceHolders($key); 150 | 151 | $this->paths[$key] = new RAMLPathObject($this, $key); 152 | 153 | foreach ($value as $skey => $svalue) { 154 | $skey = $this->handlePlaceHolders($skey); 155 | 156 | if (is_array($svalue) && substr($skey, 0, 1) == '/') { 157 | $this->paths[$key]->addChild($this->formatParentPath($key) . $skey, $skey); 158 | $this->generatePathData($this->formatParentPath($key) . $skey, $svalue); 159 | unset($value[$skey]); 160 | } elseif ($skey == 'is') { 161 | if (is_array($svalue)) { 162 | foreach($svalue as $ivalue) { 163 | if (!isset($value[$ivalue])) { 164 | $value[$ivalue] = $this->traits[$ivalue]; 165 | } elseif (is_array($this->traits[$ivalue])) { 166 | $value[$ivalue] = array_merge($value[$ivalue], $this->traits[$ivalue]); 167 | } 168 | } 169 | } else { 170 | if (!isset($value[$svalue])) { 171 | $value[$svalue] = $this->traits[$svalue]; 172 | } elseif (is_array($this->traits[$svalue])) { 173 | $value[$svalue] = array_merge($value[$svalue], $this->traits[$svalue]); 174 | } 175 | } 176 | } elseif (in_array($skey, $this->verbs)) { 177 | $this->paths[$key]->addVerb($skey); 178 | $cleanV = array(); 179 | 180 | if (isset($svalue['responses'])) { 181 | foreach ($svalue['responses'] as $k => $v) { 182 | $cleanV['c' . $k] = $v; 183 | } 184 | unset($svalue['responses']); 185 | $svalue['responses'] = $cleanV; 186 | } 187 | 188 | unset($value[$skey]); 189 | $value[strtoupper($skey)] = $svalue; 190 | } 191 | } 192 | 193 | // Add in base first 194 | $value = array_merge_recursive($value, $this->base); 195 | 196 | // Handle resourceTypes 197 | if(isset($value['type'])) { 198 | $tempRT = $this->resources[$value['type']]; 199 | foreach ($this->paths[$key]->getVerbs() as $verb) { 200 | if (isset($tempRT[$verb.'?'])) { 201 | $tempRT[$verb] = $tempRT[$verb.'?']; 202 | unset($tempRT[$verb.'?']); 203 | } 204 | } 205 | 206 | foreach($this->verbs as $verb) { 207 | $verb = strtoupper($verb); 208 | if (isset($tempRT[$verb]) && !isset($value[$verb])) { 209 | $this->paths[$key]->addVerb($verb); 210 | } 211 | } 212 | 213 | $value = array_merge_recursive($value, $tempRT); 214 | } 215 | 216 | $this->paths[$key]->setData($value); 217 | } 218 | 219 | 220 | /** 221 | * Dump 222 | * Debug Method - TBR 223 | * @return array 224 | */ 225 | public function dump() 226 | { 227 | var_dump($this->paths); 228 | } 229 | 230 | 231 | /** 232 | * SetVerbs 233 | * Sets the list of allowable verbs 234 | * @param array $verbs 235 | * @return RAML 236 | */ 237 | public function setVerbs(array $verbs) 238 | { 239 | array_change_key_case ($verbs, ARRAY_KEY_UPPERCASE); 240 | $this->verbs = $verbs; 241 | return $this; 242 | } 243 | 244 | 245 | /** 246 | * GetVerbs 247 | * Returns a list of allowable verbs 248 | * @return array 249 | */ 250 | public function getVerbs() 251 | { 252 | return $this->verbs; 253 | } 254 | 255 | 256 | /** 257 | * IsActionValid 258 | * Returns whether or not an action can be performed on a path 259 | * @param string $action 260 | * @return bool 261 | */ 262 | public function isActionValid($action) 263 | { 264 | // Path must be valid before testing action 265 | if(!$this->isPathValid($this->getCurrentPath())) { 266 | return false; 267 | } 268 | 269 | $t = strtoupper($action); 270 | if (in_array($t, $this->path()->getVerbs())) { 271 | return true; 272 | } 273 | return false; 274 | } 275 | 276 | 277 | /** 278 | * SetCurrentAction 279 | * Sets the Current Action for use by RAML Object 280 | * @param string 281 | * @return RAML 282 | */ 283 | public function setCurrentAction($action) 284 | { 285 | if ($this->isActionValid($action)) { 286 | $this->currentVerb = strtoupper($action); 287 | return $this; 288 | } 289 | 290 | throw new Exception('Invalid Verb'); 291 | } 292 | 293 | 294 | /** 295 | * GetCurrentAction 296 | * Returns the current action as set by setCurrentAction 297 | * @return string 298 | */ 299 | public function getCurrentAction() 300 | { 301 | return $this->currentVerb; 302 | } 303 | 304 | 305 | /** 306 | * Action 307 | * Shortcut for accessing the CurrentAction Object 308 | * @return RAMLDataObject 309 | */ 310 | public function action() 311 | { 312 | return $this->path()->get($this->getCurrentAction()); 313 | } 314 | 315 | 316 | /** 317 | * IsPathValid 318 | * Determines whether or not a path is valid 319 | * @param string $path 320 | * @return bool 321 | */ 322 | public function isPathValid($path) 323 | { 324 | return isset($this->paths[$path]); 325 | } 326 | 327 | 328 | /** 329 | * GetPathObject 330 | * Gets a RAMLPathObject for the defined Path 331 | * @param string $path 332 | * @return RAMLPathObject | bool 333 | */ 334 | public function getPathObject($path) 335 | { 336 | if (isset($this->paths[$path])) { 337 | return $this->paths[$path]; 338 | } 339 | return false; 340 | } 341 | 342 | 343 | /** 344 | * SetCurrentPath 345 | * Set the current path 346 | * @param string 347 | * @return RAML 348 | */ 349 | public function setCurrentPath($path) 350 | { 351 | $this->currentPath = $path; 352 | return $this; 353 | } 354 | 355 | 356 | /** 357 | * GetCurrentPath 358 | * Returns the current path as defined in string type 359 | * @return string 360 | */ 361 | public function getCurrentPath() 362 | { 363 | return $this->currentPath; 364 | } 365 | 366 | 367 | /** 368 | * GetChildPaths 369 | * Returns a paths children paths as strings 370 | * @param string $path 371 | * @return array 372 | */ 373 | public function getChildPaths($path) 374 | { 375 | return $this->paths[$path]->getChildren(); 376 | } 377 | 378 | 379 | /** 380 | * Path 381 | * Gets the current path object 382 | * @return RAMLPathObject 383 | */ 384 | public function path() 385 | { 386 | return $this->getPathObject($this->getCurrentPath()); 387 | } 388 | 389 | 390 | /** 391 | * FormatParentPath 392 | * Removes unwanted extensions from parent path 393 | * @param string 394 | * @return string 395 | */ 396 | public function formatParentPath($string) 397 | { 398 | return preg_replace('/\.[a-z]{3,4}$/i', '', $string); 399 | } 400 | 401 | 402 | /** 403 | * HandlePlaceHolders 404 | * Replaces {} with defined text 405 | * @param string 406 | * @return string 407 | */ 408 | public function handlePlaceHolders($string) 409 | { 410 | if (is_string($string) && preg_match('/.*({(.+)}).*/', $string, $matches)) { 411 | if ($this->get($matches[2], false)) { 412 | $t = str_replace($matches[1], $this->get($matches[2]), $string); 413 | return $t; 414 | } elseif ($this->get('base', false) && $this->get('base')->get($matches[2], false)) { 415 | $t = str_replace($matches[1], $this->get('base')->get($matches[2]), $string); 416 | return $t; 417 | } 418 | } 419 | 420 | return $string; 421 | } 422 | 423 | 424 | /** 425 | * Handle Schemas 426 | * Replaces Schema references 427 | * @param string 428 | * @return string 429 | */ 430 | public function handleSchemas($string) 431 | { 432 | if (!isset($this->schemas[$string])) { 433 | return $string; 434 | } 435 | 436 | return $this->schemas[$string]; 437 | } 438 | 439 | 440 | /** 441 | * Handle Traits 442 | * Replaces Traits references 443 | * @param string 444 | * @return string 445 | */ 446 | public function handleTraits($string) 447 | { 448 | // Placeholder 449 | } 450 | 451 | 452 | /** 453 | * Handle Resources 454 | * Replaces ResouceType references 455 | * @param string 456 | * @return string 457 | */ 458 | public function handleResourceTypes($string) 459 | { 460 | // Placeholder 461 | } 462 | 463 | 464 | /** 465 | * Handle Includes 466 | * Handles the Includes within the Array 467 | * @param array $array 468 | * @return array 469 | */ 470 | public function handleIncludes($array) 471 | { 472 | foreach($array as $key => $value) { 473 | if (is_array($value)) { 474 | $array[$key] = $this->handleIncludes($value); 475 | 476 | } elseif (is_string($value) && preg_match('/^\!include ([a-z0-9_\.\/\-]+)/i', $value, $matches)) { 477 | $ext_t = explode('.', $matches[1]); 478 | $ext = strtolower(array_pop($ext_t)); 479 | 480 | if (in_array($ext, array('yaml', 'raml'))) { 481 | $array[$key] = $this->handleIncludes(spyc_load_file($this->includePath . $matches[1])); 482 | } else { 483 | $array[$key] = file_get_contents($this->includePath . $matches[1]); 484 | } 485 | } 486 | } 487 | 488 | return $array; 489 | } 490 | 491 | 492 | /** 493 | * Ping Status 494 | * Ping the Server to find out if it's online or not 495 | * ##### SHOULD BE A GET REQUEST ##### 496 | * @param string $url defaults to baseUri 497 | * @Param array $headers defaults to empty array 498 | * @param int $expire defaults to 300 seconds or 5 minutes 499 | * @return string (online | offline) 500 | */ 501 | public function pingStatus($url = 'default', $headers = array(), $expire = 300, $notifyEmail = false) 502 | { 503 | global $cacheTimeLimit; 504 | 505 | if ($url == 'default') { 506 | $url = $this->get('baseUri'); 507 | } 508 | 509 | $status = false; 510 | if ($cacheTimeLimit && function_exists('apc_fetch')) { 511 | $status = apc_fetch('RAMLStatus' . md5($url)); 512 | } 513 | 514 | if ($status) { 515 | return $status; 516 | } 517 | 518 | // Insert CURL with Optional Headers 519 | $ch = curl_init($url); 520 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 521 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 522 | curl_setopt($ch, CURLOPT_TIMEOUT, 3); 523 | $output = curl_exec($ch); 524 | $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE); 525 | curl_close($ch); 526 | 527 | $status = 'offline'; 528 | if (substr($http_status, 0, 1) == '2') { 529 | $status = 'online'; 530 | } 531 | 532 | if ($notifyEmail && $status == 'offline') { 533 | mail($notifyEmail, $this->title . ' API is Down!', 'The server at ' . $url . ' failed to be queried successfully.', 'FROM: ' . $notifyEmail); 534 | } 535 | 536 | if ($cacheTimeLimit && function_exists('apc_store')) { 537 | apc_store('RAMLStatus' . md5($url), $status, $cacheTimeLimit); 538 | } 539 | 540 | return $status; 541 | } 542 | 543 | 544 | /** 545 | * Set Include Path 546 | * Required for multi-directory RAML files 547 | * @param string $path path of the RAML files 548 | * @return RAML 549 | */ 550 | public function setIncludePath($path) 551 | { 552 | $this->includePath = realpath($path) . '/'; 553 | return $this; 554 | } 555 | } 556 | -------------------------------------------------------------------------------- /inc/ramlDataObject.php: -------------------------------------------------------------------------------- 1 | 6 | * @link https://github.com/mikestowe/php-raml2html 7 | * @link http://www.mikestowe.com/2014/05/raml-2-html.php 8 | * @license http://www.gnu.org/licenses/gpl-2.0.html GPL v2 9 | */ 10 | 11 | namespace RAML2HTML; 12 | 13 | /** 14 | * RAML Data Object Class 15 | * @package RAML2HTML 16 | */ 17 | class RAMLDataObject 18 | { 19 | protected $master; 20 | private $data = array(); 21 | 22 | public function __construct(array $data = array()) 23 | { 24 | $this->data = $data; 25 | } 26 | 27 | public function setMaster($master) 28 | { 29 | $this->master = $master; 30 | } 31 | 32 | public function setData($data = array()) 33 | { 34 | $this->data = $data; 35 | } 36 | 37 | public function set($key, $value) 38 | { 39 | $this->data[$key] = $value; 40 | } 41 | 42 | /** 43 | * Get 44 | * Get Value based on Key 45 | * @param string $dataKey 46 | * @return mixed 47 | */ 48 | public function get($dataKey, $default = '[RAMLDataObject]') 49 | { 50 | if (!isset($this->data[$dataKey])) { 51 | $dataKey = strtoupper($dataKey); 52 | } 53 | 54 | if (!isset($this->data[$dataKey])) { 55 | if ($default != '[RAMLDataObject]') { 56 | return $default; 57 | } 58 | return new RAMLDataObject(); 59 | // shoudl return false 60 | } elseif (is_array($this->data[$dataKey])) { 61 | $t = new RAMLDataObject($this->data[$dataKey]); 62 | $t->setMaster($this->master); 63 | return $t; 64 | // convert to preg_match_all 65 | } elseif (is_string($this->data[$dataKey]) && preg_match('/^\!include ([a-z_\.\/]+)/i', $this->data[$dataKey], $matches)) { 66 | $ext = array_pop(explode('.', $matches[1])); 67 | if (in_array($ext, array('yaml', 'raml'))) { 68 | $t = new RAMLDataObject(spyc_load_file($matches[1])); 69 | $t->setMaster($this); 70 | return $t; 71 | } 72 | 73 | return file_get_contents($matches[1]); 74 | } elseif ($dataKey == 'schema') { 75 | $this->data[$dataKey] = $this->master->handleSchema($this->data[$dataKey]); 76 | } 77 | 78 | return $this->master->handlePlaceHolders($this->data[$dataKey]); 79 | } 80 | 81 | public function toArray() 82 | { 83 | return $this->data; 84 | } 85 | 86 | public function toString() 87 | { 88 | return (string) current($this->data); 89 | } 90 | 91 | public function isArray() 92 | { 93 | if ((is_array($this->data) || is_object($this->data)) && count($this->data) > 0) { 94 | return true; 95 | } 96 | return false; 97 | } 98 | 99 | public function isString() 100 | { 101 | if (count($this->data) == 1 && is_string(current($this->data))) { 102 | return true; 103 | } 104 | return false; 105 | } 106 | 107 | public function isInt() 108 | { 109 | if (count($this->data) == 1 && is_int(current($this->data))) { 110 | return true; 111 | } 112 | return false; 113 | } 114 | 115 | public function __get($key) 116 | { 117 | return $this->get($key); 118 | } 119 | 120 | public function __set($key, $value) 121 | { 122 | $this->set($key, $value); 123 | } 124 | 125 | public function __toString() 126 | { 127 | return $this->toString(); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /inc/ramlPathObject.php: -------------------------------------------------------------------------------- 1 | 6 | * @link https://github.com/mikestowe/php-raml2html 7 | * @link http://www.mikestowe.com/2014/05/raml-2-html.php 8 | * @license http://www.gnu.org/licenses/gpl-2.0.html GPL v2 9 | */ 10 | 11 | namespace RAML2HTML; 12 | 13 | /** 14 | * RAML Path Object Class 15 | * @package RAML2HTML 16 | */ 17 | class RAMLPathObject extends RAMLDataObject 18 | { 19 | 20 | private $path; 21 | private $children = array(); 22 | private $verbs = array(); 23 | 24 | public function __construct($master, $path) 25 | { 26 | $this->master = $master; 27 | $this->path = $path; 28 | parent::__construct(); 29 | } 30 | 31 | private function getProperties() 32 | { 33 | return $this->master->getPathObject($this->path); 34 | } 35 | 36 | private function getActionProperties() 37 | { 38 | return $this->master->action(); 39 | } 40 | 41 | public function addChild($absolutePath, $relativePath) 42 | { 43 | $absolutePath = $this->master->handlePlaceHolders(str_replace('//', '/', $absolutePath)); 44 | $relativePath = $this->master->handlePlaceHolders(str_replace('//', '/', $relativePath)); 45 | $this->children[$absolutePath] = $relativePath; 46 | return $this; 47 | } 48 | 49 | public function getChildren() 50 | { 51 | return $this->children; 52 | } 53 | 54 | 55 | public function addVerb($key) 56 | { 57 | $this->verbs[] = strtoupper($key); 58 | } 59 | 60 | public function getVerbs() 61 | { 62 | return $this->verbs; 63 | } 64 | 65 | 66 | // Handle Responses More Effectively 67 | public function getResponses() 68 | { 69 | $responses = array(); 70 | 71 | foreach ($this->getActionProperties()->get('responses')->toArray() as $code => $value) { 72 | $code = ltrim($code, 'c'); 73 | 74 | if (isset($value['description']) && count($value) == 1) { 75 | $responses[$code][] = array('type' => $value['description']); 76 | } 77 | 78 | if (isset($value['body']['example'])) { 79 | $responses[$code][] = array('type' => 'Standard Response', 'example' => $value['body']['example'], 'schema' => array()); 80 | } 81 | 82 | if (isset($value['body']['application/json']) && is_string($value['body']['application/json'])) { 83 | $responses[$code][] = array('type' => 'application/json', 'example' => $value['body']['application/json']); 84 | } 85 | 86 | if (isset($value['body']['application/xml']) && is_string($value['body']['application/xml'])) { 87 | $responses[$code][] = array('type' => 'application/xml', 'example' => $value['body']['application/xml']); 88 | } elseif (isset($value['body'])) { 89 | $t = 0; 90 | foreach ($value['body'] as $rkey => $rvalue) { 91 | $rexample = isset($rvalue['example']) ? $rvalue['example'] : null; 92 | $rschema = isset($rvalue['schema']) ? $rvalue['schema'] : null; 93 | $responses[$code][] = array('type' => $rkey, 'example' => $rexample, 'schema' => $rschema); 94 | } 95 | } 96 | } 97 | 98 | return $responses; 99 | } 100 | 101 | 102 | } 103 | -------------------------------------------------------------------------------- /inc/spyc.php: -------------------------------------------------------------------------------- 1 | 6 | * @author Chris Wanstrath 7 | * @link https://github.com/mustangostang/spyc/ 8 | * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen 9 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 10 | * @package Spyc 11 | */ 12 | 13 | if (!function_exists('spyc_load')) { 14 | /** 15 | * Parses YAML to array. 16 | * @param string $string YAML string. 17 | * @return array 18 | */ 19 | function spyc_load($string) { 20 | return Spyc::YAMLLoadString($string); 21 | } 22 | 23 | } 24 | 25 | if (!function_exists('spyc_load_file')) { 26 | /** 27 | * Parses YAML to array. 28 | * @param string $file Path to YAML file. 29 | * @return array 30 | */ 31 | function spyc_load_file($file) { 32 | return Spyc::YAMLLoad($file); 33 | } 34 | 35 | } 36 | 37 | if (!function_exists('spyc_dump')) { 38 | /** 39 | * Dumps array to YAML. 40 | * @param array $data Array. 41 | * @return string 42 | */ 43 | function spyc_dump($data) { 44 | return Spyc::YAMLDump($data, false, false, true); 45 | } 46 | 47 | } 48 | 49 | /** 50 | * The Simple PHP YAML Class. 51 | * 52 | * This class can be used to read a YAML file and convert its contents 53 | * into a PHP array. It currently supports a very limited subsection of 54 | * the YAML spec. 55 | * 56 | * Usage: 57 | * 58 | * $Spyc = new Spyc; 59 | * $array = $Spyc->load($file); 60 | * 61 | * or: 62 | * 63 | * $array = Spyc::YAMLLoad($file); 64 | * 65 | * or: 66 | * 67 | * $array = spyc_load_file($file); 68 | * 69 | * @package Spyc 70 | */ 71 | class Spyc { 72 | 73 | // SETTINGS 74 | 75 | const REMPTY = "\0\0\0\0\0"; 76 | 77 | /** 78 | * Setting this to true will force YAMLDump to enclose any string value in 79 | * quotes. False by default. 80 | * 81 | * @var bool 82 | */ 83 | public $setting_dump_force_quotes = false; 84 | 85 | /** 86 | * Setting this to true will forse YAMLLoad to use syck_load function when 87 | * possible. False by default. 88 | * @var bool 89 | */ 90 | public $setting_use_syck_is_possible = false; 91 | 92 | /**#@+ 93 | * @access private 94 | * @var mixed 95 | */ 96 | private $_dumpIndent; 97 | private $_dumpWordWrap; 98 | private $_containsGroupAnchor = false; 99 | private $_containsGroupAlias = false; 100 | private $path; 101 | private $result; 102 | private $LiteralPlaceHolder = '___YAML_Literal_Block___'; 103 | private $SavedGroups = array(); 104 | private $indent; 105 | /** 106 | * Path modifier that should be applied after adding current element. 107 | * @var array 108 | */ 109 | private $delayedPath = array(); 110 | 111 | /**#@+ 112 | * @access public 113 | * @var mixed 114 | */ 115 | public $_nodeId; 116 | 117 | /** 118 | * Load a valid YAML string to Spyc. 119 | * @param string $input 120 | * @return array 121 | */ 122 | public function load($input) { 123 | return $this -> __loadString($input); 124 | } 125 | 126 | /** 127 | * Load a valid YAML file to Spyc. 128 | * @param string $file 129 | * @return array 130 | */ 131 | public function loadFile($file) { 132 | return $this -> __load($file); 133 | } 134 | 135 | /** 136 | * Load YAML into a PHP array statically 137 | * 138 | * The load method, when supplied with a YAML stream (string or file), 139 | * will do its best to convert YAML in a file into a PHP array. Pretty 140 | * simple. 141 | * Usage: 142 | * 143 | * $array = Spyc::YAMLLoad('lucky.yaml'); 144 | * print_r($array); 145 | * 146 | * @access public 147 | * @return array 148 | * @param string $input Path of YAML file or string containing YAML 149 | */ 150 | public static function YAMLLoad($input) { 151 | $Spyc = new Spyc; 152 | return $Spyc -> __load($input); 153 | } 154 | 155 | /** 156 | * Load a string of YAML into a PHP array statically 157 | * 158 | * The load method, when supplied with a YAML string, will do its best 159 | * to convert YAML in a string into a PHP array. Pretty simple. 160 | * 161 | * Note: use this function if you don't want files from the file system 162 | * loaded and processed as YAML. This is of interest to people concerned 163 | * about security whose input is from a string. 164 | * 165 | * Usage: 166 | * 167 | * $array = Spyc::YAMLLoadString("---\n0: hello world\n"); 168 | * print_r($array); 169 | * 170 | * @access public 171 | * @return array 172 | * @param string $input String containing YAML 173 | */ 174 | public static function YAMLLoadString($input) { 175 | $Spyc = new Spyc; 176 | return $Spyc -> __loadString($input); 177 | } 178 | 179 | /** 180 | * Dump YAML from PHP array statically 181 | * 182 | * The dump method, when supplied with an array, will do its best 183 | * to convert the array into friendly YAML. Pretty simple. Feel free to 184 | * save the returned string as nothing.yaml and pass it around. 185 | * 186 | * Oh, and you can decide how big the indent is and what the wordwrap 187 | * for folding is. Pretty cool -- just pass in 'false' for either if 188 | * you want to use the default. 189 | * 190 | * Indent's default is 2 spaces, wordwrap's default is 40 characters. And 191 | * you can turn off wordwrap by passing in 0. 192 | * 193 | * @access public 194 | * @return string 195 | * @param array $array PHP array 196 | * @param int $indent Pass in false to use the default, which is 2 197 | * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) 198 | * @param int $no_opening_dashes Do not start YAML file with "---\n" 199 | */ 200 | public static function YAMLDump($array, $indent = false, $wordwrap = false, $no_opening_dashes = false) { 201 | $spyc = new Spyc; 202 | return $spyc -> dump($array, $indent, $wordwrap, $no_opening_dashes); 203 | } 204 | 205 | /** 206 | * Dump PHP array to YAML 207 | * 208 | * The dump method, when supplied with an array, will do its best 209 | * to convert the array into friendly YAML. Pretty simple. Feel free to 210 | * save the returned string as tasteful.yaml and pass it around. 211 | * 212 | * Oh, and you can decide how big the indent is and what the wordwrap 213 | * for folding is. Pretty cool -- just pass in 'false' for either if 214 | * you want to use the default. 215 | * 216 | * Indent's default is 2 spaces, wordwrap's default is 40 characters. And 217 | * you can turn off wordwrap by passing in 0. 218 | * 219 | * @access public 220 | * @return string 221 | * @param array $array PHP array 222 | * @param int $indent Pass in false to use the default, which is 2 223 | * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40) 224 | */ 225 | public function dump($array, $indent = false, $wordwrap = false, $no_opening_dashes = false) { 226 | // Dumps to some very clean YAML. We'll have to add some more features 227 | // and options soon. And better support for folding. 228 | 229 | // New features and options. 230 | if ($indent === false or !is_numeric($indent)) { 231 | $this -> _dumpIndent = 2; 232 | } else { 233 | $this -> _dumpIndent = $indent; 234 | } 235 | 236 | if ($wordwrap === false or !is_numeric($wordwrap)) { 237 | $this -> _dumpWordWrap = 40; 238 | } else { 239 | $this -> _dumpWordWrap = $wordwrap; 240 | } 241 | 242 | // New YAML document 243 | $string = ""; 244 | if (!$no_opening_dashes) 245 | $string = "---\n"; 246 | 247 | // Start at the base of the array and move through it. 248 | if ($array) { 249 | $array = (array)$array; 250 | $previous_key = -1; 251 | foreach ($array as $key => $value) { 252 | if (!isset($first_key)) 253 | $first_key = $key; 254 | $string .= $this -> _yamlize($key, $value, 0, $previous_key, $first_key, $array); 255 | $previous_key = $key; 256 | } 257 | } 258 | return $string; 259 | } 260 | 261 | /** 262 | * Attempts to convert a key / value array item to YAML 263 | * @access private 264 | * @return string 265 | * @param $key The name of the key 266 | * @param $value The value of the item 267 | * @param $indent The indent of the current node 268 | */ 269 | private function _yamlize($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) { 270 | if (is_array($value)) { 271 | if (empty($value)) 272 | return $this -> _dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array); 273 | // It has children. What to do? 274 | // Make it the right kind of item 275 | $string = $this -> _dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array); 276 | // Add the indent 277 | $indent += $this -> _dumpIndent; 278 | // Yamlize the array 279 | $string .= $this -> _yamlizeArray($value, $indent); 280 | } elseif (!is_array($value)) { 281 | // It doesn't have children. Yip. 282 | $string = $this -> _dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array); 283 | } 284 | return $string; 285 | } 286 | 287 | /** 288 | * Attempts to convert an array to YAML 289 | * @access private 290 | * @return string 291 | * @param $array The array you want to convert 292 | * @param $indent The indent of the current level 293 | */ 294 | private function _yamlizeArray($array, $indent) { 295 | if (is_array($array)) { 296 | $string = ''; 297 | $previous_key = -1; 298 | foreach ($array as $key => $value) { 299 | if (!isset($first_key)) 300 | $first_key = $key; 301 | $string .= $this -> _yamlize($key, $value, $indent, $previous_key, $first_key, $array); 302 | $previous_key = $key; 303 | } 304 | return $string; 305 | } else { 306 | return false; 307 | } 308 | } 309 | 310 | /** 311 | * Returns YAML from a key and a value 312 | * @access private 313 | * @return string 314 | * @param $key The name of the key 315 | * @param $value The value of the item 316 | * @param $indent The indent of the current node 317 | */ 318 | private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) { 319 | // do some folding here, for blocks 320 | if (is_string($value) && ((strpos($value, "\n") !== false || strpos($value, ": ") !== false || strpos($value, "- ") !== false || strpos($value, "*") !== false || strpos($value, "#") !== false || strpos($value, "<") !== false || strpos($value, ">") !== false || strpos($value, '%') !== false || strpos($value, ' ') !== false || strpos($value, "[") !== false || strpos($value, "]") !== false || strpos($value, "{") !== false || strpos($value, "}") !== false) || strpos($value, "&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 || substr($value, -1, 1) == ':')) { 321 | $value = $this -> _doLiteralBlock($value, $indent); 322 | } else { 323 | $value = $this -> _doFolding($value, $indent); 324 | } 325 | 326 | if ($value === array()) 327 | $value = '[ ]'; 328 | if ($value === "") 329 | $value = '""'; 330 | if (self::isTranslationWord($value)) { 331 | $value = $this -> _doLiteralBlock($value, $indent); 332 | } 333 | if (trim($value) != $value) 334 | $value = $this -> _doLiteralBlock($value, $indent); 335 | 336 | if (is_bool($value)) { 337 | $value = $value ? "true" : "false"; 338 | } 339 | 340 | if ($value === null) 341 | $value = 'null'; 342 | if ($value === "'" . self::REMPTY . "'") 343 | $value = null; 344 | 345 | $spaces = str_repeat(' ', $indent); 346 | 347 | //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) { 348 | if (is_array($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) { 349 | // It's a sequence 350 | $string = $spaces . '- ' . $value . "\n"; 351 | } else { 352 | // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"'); 353 | // It's mapped 354 | if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; 355 | } 356 | $string = rtrim($spaces . $key . ': ' . $value) . "\n"; 357 | } 358 | return $string; 359 | } 360 | 361 | /** 362 | * Creates a literal block for dumping 363 | * @access private 364 | * @return string 365 | * @param $value 366 | * @param $indent int The value of the indent 367 | */ 368 | private function _doLiteralBlock($value, $indent) { 369 | if ($value === "\n") 370 | return '\n'; 371 | if (strpos($value, "\n") === false && strpos($value, "'") === false) { 372 | return sprintf("'%s'", $value); 373 | } 374 | if (strpos($value, "\n") === false && strpos($value, '"') === false) { 375 | return sprintf('"%s"', $value); 376 | } 377 | $exploded = explode("\n", $value); 378 | $newValue = '|'; 379 | if (isset($exploded[0]) && ($exploded[0] == "|" || $exploded[0] == "|-" || $exploded[0] == ">")) { 380 | $newValue = $exploded[0]; 381 | unset($exploded[0]); 382 | } 383 | $indent += $this -> _dumpIndent; 384 | $spaces = str_repeat(' ', $indent); 385 | foreach ($exploded as $line) { 386 | $line = trim($line); 387 | if (strpos($line, '"') === 0 && strrpos($line, '"') == (strlen($line) - 1) || strpos($line, "'") === 0 && strrpos($line, "'") == (strlen($line) - 1)) { 388 | $line = substr($line, 1, -1); 389 | } 390 | $newValue .= "\n" . $spaces . ($line); 391 | } 392 | return $newValue; 393 | } 394 | 395 | /** 396 | * Folds a string of text, if necessary 397 | * @access private 398 | * @return string 399 | * @param $value The string you wish to fold 400 | */ 401 | private function _doFolding($value, $indent) { 402 | // Don't do anything if wordwrap is set to 0 403 | 404 | if ($this -> _dumpWordWrap !== 0 && is_string($value) && strlen($value) > $this -> _dumpWordWrap) { 405 | $indent += $this -> _dumpIndent; 406 | $indent = str_repeat(' ', $indent); 407 | $wrapped = wordwrap($value, $this -> _dumpWordWrap, "\n$indent"); 408 | $value = ">\n" . $indent . $wrapped; 409 | } else { 410 | if ($this -> setting_dump_force_quotes && is_string($value) && $value !== self::REMPTY) 411 | $value = '"' . $value . '"'; 412 | if (is_numeric($value) && is_string($value)) 413 | $value = '"' . $value . '"'; 414 | } 415 | 416 | return $value; 417 | } 418 | 419 | private function isTrueWord($value) { 420 | $words = self::getTranslations(array('true', 'on', 'yes', 'y')); 421 | return in_array($value, $words, true); 422 | } 423 | 424 | private function isFalseWord($value) { 425 | $words = self::getTranslations(array('false', 'off', 'no', 'n')); 426 | return in_array($value, $words, true); 427 | } 428 | 429 | private function isNullWord($value) { 430 | $words = self::getTranslations(array('null', '~')); 431 | return in_array($value, $words, true); 432 | } 433 | 434 | private function isTranslationWord($value) { 435 | return (self::isTrueWord($value) || self::isFalseWord($value) || self::isNullWord($value)); 436 | } 437 | 438 | /** 439 | * Coerce a string into a native type 440 | * Reference: http://yaml.org/type/bool.html 441 | * TODO: Use only words from the YAML spec. 442 | * @access private 443 | * @param $value The value to coerce 444 | */ 445 | private function coerceValue(&$value) { 446 | if (self::isTrueWord($value)) { 447 | $value = true; 448 | } else if (self::isFalseWord($value)) { 449 | $value = false; 450 | } else if (self::isNullWord($value)) { 451 | $value = null; 452 | } 453 | } 454 | 455 | /** 456 | * Given a set of words, perform the appropriate translations on them to 457 | * match the YAML 1.1 specification for type coercing. 458 | * @param $words The words to translate 459 | * @access private 460 | */ 461 | private static function getTranslations(array $words) { 462 | $result = array(); 463 | foreach ($words as $i) { 464 | $result = array_merge($result, array(ucfirst($i), strtoupper($i), strtolower($i))); 465 | } 466 | return $result; 467 | } 468 | 469 | // LOADING FUNCTIONS 470 | 471 | private function __load($input) { 472 | $Source = $this -> loadFromSource($input); 473 | return $this -> loadWithSource($Source); 474 | } 475 | 476 | private function __loadString($input) { 477 | $Source = $this -> loadFromString($input); 478 | return $this -> loadWithSource($Source); 479 | } 480 | 481 | private function loadWithSource($Source) { 482 | if (empty($Source)) 483 | return array(); 484 | if ($this -> setting_use_syck_is_possible && function_exists('syck_load')) { 485 | $array = syck_load(implode("\n", $Source)); 486 | return is_array($array) ? $array : array(); 487 | } 488 | 489 | $this -> path = array(); 490 | $this -> result = array(); 491 | 492 | $cnt = count($Source); 493 | for ($i = 0; $i < $cnt; $i++) { 494 | $line = $Source[$i]; 495 | 496 | $this -> indent = strlen($line) - strlen(ltrim($line)); 497 | $tempPath = $this -> getParentPathByIndent($this -> indent); 498 | $line = self::stripIndent($line, $this -> indent); 499 | if (self::isComment($line)) 500 | continue; 501 | if (self::isEmpty($line)) 502 | continue; 503 | $this -> path = $tempPath; 504 | 505 | $literalBlockStyle = self::startsLiteralBlock($line); 506 | if ($literalBlockStyle) { 507 | $line = rtrim($line, $literalBlockStyle . " \n"); 508 | $literalBlock = ''; 509 | $line .= ' ' . $this -> LiteralPlaceHolder; 510 | $literal_block_indent = strlen($Source[$i + 1]) - strlen(ltrim($Source[$i + 1])); 511 | while (++$i < $cnt && $this -> literalBlockContinues($Source[$i], $this -> indent)) { 512 | $literalBlock = $this -> addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent); 513 | } 514 | $i--; 515 | } 516 | 517 | // Strip out comments 518 | if (strpos($line, '#')) { 519 | $line = preg_replace('/\s*#([^"\']+)$/', '', $line); 520 | } 521 | 522 | while (++$i < $cnt && self::greedilyNeedNextLine($line)) { 523 | $line = rtrim($line, " \n\t\r") . ' ' . ltrim($Source[$i], " \t"); 524 | } 525 | $i--; 526 | 527 | $lineArray = $this -> _parseLine($line); 528 | 529 | if ($literalBlockStyle) 530 | $lineArray = $this -> revertLiteralPlaceHolder($lineArray, $literalBlock); 531 | 532 | $this -> addArray($lineArray, $this -> indent); 533 | 534 | foreach ($this->delayedPath as $indent => $delayedPath) 535 | $this -> path[$indent] = $delayedPath; 536 | 537 | $this -> delayedPath = array(); 538 | 539 | } 540 | return $this -> result; 541 | } 542 | 543 | private function loadFromSource($input) { 544 | if (!empty($input) && strpos($input, "\n") === false && file_exists($input)) 545 | $input = file_get_contents($input); 546 | 547 | return $this -> loadFromString($input); 548 | } 549 | 550 | private function loadFromString($input) { 551 | $lines = explode("\n", $input); 552 | foreach ($lines as $k => $_) { 553 | $lines[$k] = rtrim($_, "\r"); 554 | } 555 | return $lines; 556 | } 557 | 558 | /** 559 | * Parses YAML code and returns an array for a node 560 | * @access private 561 | * @return array 562 | * @param string $line A line from the YAML file 563 | */ 564 | private function _parseLine($line) { 565 | if (!$line) 566 | return array(); 567 | $line = trim($line); 568 | if (!$line) 569 | return array(); 570 | 571 | $array = array(); 572 | 573 | $group = $this -> nodeContainsGroup($line); 574 | if ($group) { 575 | $this -> addGroup($line, $group); 576 | $line = $this -> stripGroup($line, $group); 577 | } 578 | 579 | if ($this -> startsMappedSequence($line)) 580 | return $this -> returnMappedSequence($line); 581 | 582 | if ($this -> startsMappedValue($line)) 583 | return $this -> returnMappedValue($line); 584 | 585 | if ($this -> isArrayElement($line)) 586 | return $this -> returnArrayElement($line); 587 | 588 | if ($this -> isPlainArray($line)) 589 | return $this -> returnPlainArray($line); 590 | 591 | return $this -> returnKeyValuePair($line); 592 | 593 | } 594 | 595 | /** 596 | * Finds the type of the passed value, returns the value as the new type. 597 | * @access private 598 | * @param string $value 599 | * @return mixed 600 | */ 601 | private function _toType($value) { 602 | if ($value === '') 603 | return ""; 604 | $first_character = $value[0]; 605 | $last_character = substr($value, -1, 1); 606 | 607 | $is_quoted = false; 608 | do { 609 | if (!$value) 610 | break; 611 | if ($first_character != '"' && $first_character != "'") 612 | break; 613 | if ($last_character != '"' && $last_character != "'") 614 | break; 615 | $is_quoted = true; 616 | } while (0); 617 | 618 | if ($is_quoted) { 619 | $value = str_replace('\n', "\n", $value); 620 | return strtr(substr($value, 1, -1), array('\\"' => '"', '\'\'' => '\'', '\\\'' => '\'')); 621 | } 622 | 623 | if (strpos($value, ' #') !== false && !$is_quoted) 624 | $value = preg_replace('/\s+#(.+)$/', '', $value); 625 | 626 | if ($first_character == '[' && $last_character == ']') { 627 | // Take out strings sequences and mappings 628 | $innerValue = trim(substr($value, 1, -1)); 629 | if ($innerValue === '') 630 | return array(); 631 | $explode = $this -> _inlineEscape($innerValue); 632 | // Propagate value array 633 | $value = array(); 634 | foreach ($explode as $v) { 635 | $value[] = $this -> _toType($v); 636 | } 637 | return $value; 638 | } 639 | 640 | if (strpos($value, ': ') !== false && $first_character != '{') { 641 | $array = explode(': ', $value); 642 | $key = trim($array[0]); 643 | array_shift($array); 644 | $value = trim(implode(': ', $array)); 645 | $value = $this -> _toType($value); 646 | return array($key => $value); 647 | } 648 | 649 | if ($first_character == '{' && $last_character == '}') { 650 | $innerValue = trim(substr($value, 1, -1)); 651 | if ($innerValue === '') 652 | return array(); 653 | // Inline Mapping 654 | // Take out strings sequences and mappings 655 | $explode = $this -> _inlineEscape($innerValue); 656 | // Propagate value array 657 | $array = array(); 658 | foreach ($explode as $v) { 659 | $SubArr = $this -> _toType($v); 660 | if (empty($SubArr)) 661 | continue; 662 | if (is_array($SubArr)) { 663 | $array[key($SubArr)] = $SubArr[key($SubArr)]; 664 | continue; 665 | } 666 | $array[] = $SubArr; 667 | } 668 | return $array; 669 | } 670 | 671 | if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') { 672 | return null; 673 | } 674 | 675 | if (is_numeric($value) && preg_match('/^(-|)[1-9]+[0-9]*$/', $value)) { 676 | $intvalue = (int)$value; 677 | if ($intvalue != PHP_INT_MAX) 678 | $value = $intvalue; 679 | return $value; 680 | } 681 | 682 | if (is_numeric($value) && preg_match('/^0[xX][0-9a-fA-F]+$/', $value)) { 683 | // Hexadecimal value. 684 | return hexdec($value); 685 | } 686 | 687 | $this -> coerceValue($value); 688 | 689 | if (is_numeric($value)) { 690 | if ($value === '0') 691 | return 0; 692 | if (rtrim($value, 0) === $value) 693 | $value = (float)$value; 694 | return $value; 695 | } 696 | 697 | return $value; 698 | } 699 | 700 | /** 701 | * Used in inlines to check for more inlines or quoted strings 702 | * @access private 703 | * @return array 704 | */ 705 | private function _inlineEscape($inline) { 706 | // There's gotta be a cleaner way to do this... 707 | // While pure sequences seem to be nesting just fine, 708 | // pure mappings and mappings with sequences inside can't go very 709 | // deep. This needs to be fixed. 710 | 711 | $seqs = array(); 712 | $maps = array(); 713 | $saved_strings = array(); 714 | $saved_empties = array(); 715 | 716 | // Check for empty strings 717 | $regex = '/("")|(\'\')/'; 718 | if (preg_match_all($regex, $inline, $strings)) { 719 | $saved_empties = $strings[0]; 720 | $inline = preg_replace($regex, 'YAMLEmpty', $inline); 721 | } 722 | unset($regex); 723 | 724 | // Check for strings 725 | $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/'; 726 | if (preg_match_all($regex, $inline, $strings)) { 727 | $saved_strings = $strings[0]; 728 | $inline = preg_replace($regex, 'YAMLString', $inline); 729 | } 730 | unset($regex); 731 | 732 | // echo $inline; 733 | 734 | $i = 0; 735 | do { 736 | 737 | // Check for sequences 738 | while (preg_match('/\[([^{}\[\]]+)\]/U', $inline, $matchseqs)) { 739 | $seqs[] = $matchseqs[0]; 740 | $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1); 741 | } 742 | 743 | // Check for mappings 744 | while (preg_match('/{([^\[\]{}]+)}/U', $inline, $matchmaps)) { 745 | $maps[] = $matchmaps[0]; 746 | $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1); 747 | } 748 | 749 | if ($i++ >= 10) 750 | break; 751 | 752 | } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false); 753 | 754 | $explode = explode(',', $inline); 755 | $explode = array_map('trim', $explode); 756 | $stringi = 0; 757 | $i = 0; 758 | 759 | while (1) { 760 | 761 | // Re-add the sequences 762 | if (!empty($seqs)) { 763 | foreach ($explode as $key => $value) { 764 | if (strpos($value, 'YAMLSeq') !== false) { 765 | foreach ($seqs as $seqk => $seq) { 766 | $explode[$key] = str_replace(('YAMLSeq' . $seqk . 's'), $seq, $value); 767 | $value = $explode[$key]; 768 | } 769 | } 770 | } 771 | } 772 | 773 | // Re-add the mappings 774 | if (!empty($maps)) { 775 | foreach ($explode as $key => $value) { 776 | if (strpos($value, 'YAMLMap') !== false) { 777 | foreach ($maps as $mapk => $map) { 778 | $explode[$key] = str_replace(('YAMLMap' . $mapk . 's'), $map, $value); 779 | $value = $explode[$key]; 780 | } 781 | } 782 | } 783 | } 784 | 785 | // Re-add the strings 786 | if (!empty($saved_strings)) { 787 | foreach ($explode as $key => $value) { 788 | while (strpos($value, 'YAMLString') !== false) { 789 | $explode[$key] = preg_replace('/YAMLString/', $saved_strings[$stringi], $value, 1); 790 | unset($saved_strings[$stringi]); 791 | ++$stringi; 792 | $value = $explode[$key]; 793 | } 794 | } 795 | } 796 | 797 | // Re-add the empties 798 | if (!empty($saved_empties)) { 799 | foreach ($explode as $key => $value) { 800 | while (strpos($value, 'YAMLEmpty') !== false) { 801 | $explode[$key] = preg_replace('/YAMLEmpty/', '', $value, 1); 802 | $value = $explode[$key]; 803 | } 804 | } 805 | } 806 | 807 | $finished = true; 808 | foreach ($explode as $key => $value) { 809 | if (strpos($value, 'YAMLSeq') !== false) { 810 | $finished = false; 811 | break; 812 | } 813 | if (strpos($value, 'YAMLMap') !== false) { 814 | $finished = false; 815 | break; 816 | } 817 | if (strpos($value, 'YAMLString') !== false) { 818 | $finished = false; 819 | break; 820 | } 821 | if (strpos($value, 'YAMLEmpty') !== false) { 822 | $finished = false; 823 | break; 824 | } 825 | } 826 | if ($finished) 827 | break; 828 | 829 | $i++; 830 | if ($i > 10) 831 | break; 832 | // Prevent infinite loops. 833 | } 834 | 835 | return $explode; 836 | } 837 | 838 | private function literalBlockContinues($line, $lineIndent) { 839 | if (!trim($line)) 840 | return true; 841 | if (strlen($line) - strlen(ltrim($line)) > $lineIndent) 842 | return true; 843 | return false; 844 | } 845 | 846 | private function referenceContentsByAlias($alias) { 847 | do { 848 | if (!isset($this -> SavedGroups[$alias])) { echo "Bad group name: $alias."; 849 | break; 850 | } 851 | $groupPath = $this -> SavedGroups[$alias]; 852 | $value = $this -> result; 853 | foreach ($groupPath as $k) { 854 | $value = $value[$k]; 855 | } 856 | } while (false); 857 | return $value; 858 | } 859 | 860 | private function addArrayInline($array, $indent) { 861 | $CommonGroupPath = $this -> path; 862 | if (empty($array)) 863 | return false; 864 | 865 | foreach ($array as $k => $_) { 866 | $this -> addArray(array($k => $_), $indent); 867 | $this -> path = $CommonGroupPath; 868 | } 869 | return true; 870 | } 871 | 872 | private function addArray($incoming_data, $incoming_indent) { 873 | 874 | // print_r ($incoming_data); 875 | 876 | if (count($incoming_data) > 1) 877 | return $this -> addArrayInline($incoming_data, $incoming_indent); 878 | 879 | $key = key($incoming_data); 880 | $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null; 881 | if ($key === '__!YAMLZero') 882 | $key = '0'; 883 | 884 | if ($incoming_indent == 0 && !$this -> _containsGroupAlias && !$this -> _containsGroupAnchor) {// Shortcut for root-level values. 885 | if ($key || $key === '' || $key === '0') { 886 | $this -> result[$key] = $value; 887 | } else { 888 | $this -> result[] = $value; 889 | end($this -> result); 890 | $key = key($this -> result); 891 | } 892 | $this -> path[$incoming_indent] = $key; 893 | return; 894 | } 895 | 896 | $history = array(); 897 | // Unfolding inner array tree. 898 | $history[] = $_arr = $this -> result; 899 | foreach ($this->path as $k) { 900 | $history[] = $_arr = $_arr[$k]; 901 | } 902 | 903 | if ($this -> _containsGroupAlias) { 904 | $value = $this -> referenceContentsByAlias($this -> _containsGroupAlias); 905 | $this -> _containsGroupAlias = false; 906 | } 907 | 908 | // Adding string or numeric key to the innermost level or $this->arr. 909 | if (is_string($key) && $key == '<<') { 910 | if (!is_array($_arr)) { $_arr = array(); 911 | } 912 | 913 | $_arr = array_merge($_arr, $value); 914 | } else if ($key || $key === '' || $key === '0') { 915 | if (!is_array($_arr)) 916 | $_arr = array($key => $value); 917 | else 918 | $_arr[$key] = $value; 919 | } else { 920 | if (!is_array($_arr)) { $_arr = array($value); 921 | $key = 0; 922 | } else { $_arr[] = $value; 923 | end($_arr); 924 | $key = key($_arr); 925 | } 926 | } 927 | 928 | $reverse_path = array_reverse($this -> path); 929 | $reverse_history = array_reverse($history); 930 | $reverse_history[0] = $_arr; 931 | $cnt = count($reverse_history) - 1; 932 | for ($i = 0; $i < $cnt; $i++) { 933 | $reverse_history[$i + 1][$reverse_path[$i]] = $reverse_history[$i]; 934 | } 935 | $this -> result = $reverse_history[$cnt]; 936 | 937 | $this -> path[$incoming_indent] = $key; 938 | 939 | if ($this -> _containsGroupAnchor) { 940 | $this -> SavedGroups[$this -> _containsGroupAnchor] = $this -> path; 941 | if (is_array($value)) { 942 | $k = key($value); 943 | if (!is_int($k)) { 944 | $this -> SavedGroups[$this -> _containsGroupAnchor][$incoming_indent + 2] = $k; 945 | } 946 | } 947 | $this -> _containsGroupAnchor = false; 948 | } 949 | 950 | } 951 | 952 | private static function startsLiteralBlock($line) { 953 | $lastChar = substr(trim($line), -1); 954 | if ($lastChar != '>' && $lastChar != '|') 955 | return false; 956 | if ($lastChar == '|') 957 | return $lastChar; 958 | // HTML tags should not be counted as literal blocks. 959 | if (preg_match('#<.*?>$#', $line)) 960 | return false; 961 | return $lastChar; 962 | } 963 | 964 | private static function greedilyNeedNextLine($line) { 965 | $line = trim($line); 966 | if (!strlen($line)) 967 | return false; 968 | if (substr($line, -1, 1) == ']') 969 | return false; 970 | if ($line[0] == '[') 971 | return true; 972 | if (preg_match('#^[^:]+?:\s*\[#', $line)) 973 | return true; 974 | return false; 975 | } 976 | 977 | private function addLiteralLine($literalBlock, $line, $literalBlockStyle, $indent = -1) { 978 | $line = self::stripIndent($line, $indent); 979 | if ($literalBlockStyle !== '|') { 980 | $line = self::stripIndent($line); 981 | } 982 | $line = rtrim($line, "\r\n\t ") . "\n"; 983 | if ($literalBlockStyle == '|') { 984 | return $literalBlock . $line; 985 | } 986 | if (strlen($line) == 0) 987 | return rtrim($literalBlock, ' ') . "\n"; 988 | if ($line == "\n" && $literalBlockStyle == '>') { 989 | return rtrim($literalBlock, " \t") . "\n"; 990 | } 991 | if ($line != "\n") 992 | $line = trim($line, "\r\n ") . " "; 993 | return $literalBlock . $line; 994 | } 995 | 996 | function revertLiteralPlaceHolder($lineArray, $literalBlock) { 997 | foreach ($lineArray as $k => $_) { 998 | if (is_array($_)) 999 | $lineArray[$k] = $this -> revertLiteralPlaceHolder($_, $literalBlock); 1000 | else if (substr($_, -1 * strlen($this -> LiteralPlaceHolder)) == $this -> LiteralPlaceHolder) 1001 | $lineArray[$k] = rtrim($literalBlock, " \r\n"); 1002 | } 1003 | return $lineArray; 1004 | } 1005 | 1006 | private static function stripIndent($line, $indent = -1) { 1007 | if ($indent == -1) 1008 | $indent = strlen($line) - strlen(ltrim($line)); 1009 | return substr($line, $indent); 1010 | } 1011 | 1012 | private function getParentPathByIndent($indent) { 1013 | if ($indent == 0) 1014 | return array(); 1015 | $linePath = $this -> path; 1016 | do { 1017 | end($linePath); 1018 | $lastIndentInParentPath = key($linePath); 1019 | if ($indent <= $lastIndentInParentPath) 1020 | array_pop($linePath); 1021 | } while ($indent <= $lastIndentInParentPath); 1022 | return $linePath; 1023 | } 1024 | 1025 | private function clearBiggerPathValues($indent) { 1026 | 1027 | if ($indent == 0) 1028 | $this -> path = array(); 1029 | if (empty($this -> path)) 1030 | return true; 1031 | 1032 | foreach ($this->path as $k => $_) { 1033 | if ($k > $indent) 1034 | unset($this -> path[$k]); 1035 | } 1036 | 1037 | return true; 1038 | } 1039 | 1040 | private static function isComment($line) { 1041 | if (!$line) 1042 | return false; 1043 | if ($line[0] == '#') 1044 | return true; 1045 | if (trim($line, " \r\n\t") == '---') 1046 | return true; 1047 | return false; 1048 | } 1049 | 1050 | private static function isEmpty($line) { 1051 | return (trim($line) === ''); 1052 | } 1053 | 1054 | private function isArrayElement($line) { 1055 | if (!$line || !is_scalar($line)) 1056 | return false; 1057 | if (substr($line, 0, 2) != '- ') 1058 | return false; 1059 | if (strlen($line) > 3) 1060 | if (substr($line, 0, 3) == '---') 1061 | return false; 1062 | 1063 | return true; 1064 | } 1065 | 1066 | private function isHashElement($line) { 1067 | return strpos($line, ':'); 1068 | } 1069 | 1070 | private function isLiteral($line) { 1071 | if ($this -> isArrayElement($line)) 1072 | return false; 1073 | if ($this -> isHashElement($line)) 1074 | return false; 1075 | return true; 1076 | } 1077 | 1078 | private static function unquote($value) { 1079 | if (!$value) 1080 | return $value; 1081 | if (!is_string($value)) 1082 | return $value; 1083 | if ($value[0] == '\'') 1084 | return trim($value, '\''); 1085 | if ($value[0] == '"') 1086 | return trim($value, '"'); 1087 | return $value; 1088 | } 1089 | 1090 | private function startsMappedSequence($line) { 1091 | return (substr($line, 0, 2) == '- ' && substr($line, -1, 1) == ':'); 1092 | } 1093 | 1094 | private function returnMappedSequence($line) { 1095 | $array = array(); 1096 | $key = self::unquote(trim(substr($line, 1, -1))); 1097 | $array[$key] = array(); 1098 | $this -> delayedPath = array(strpos($line, $key) + $this -> indent => $key); 1099 | return array($array); 1100 | } 1101 | 1102 | private function checkKeysInValue($value) { 1103 | if (strchr('[{"\'', $value[0]) === false) { 1104 | if (strchr($value, ': ') !== false) { 1105 | throw new Exception('Too many keys: ' . $value); 1106 | } 1107 | } 1108 | } 1109 | 1110 | private function returnMappedValue($line) { 1111 | $this -> checkKeysInValue($line); 1112 | $array = array(); 1113 | $key = self::unquote(trim(substr($line, 0, -1))); 1114 | $array[$key] = ''; 1115 | return $array; 1116 | } 1117 | 1118 | private function startsMappedValue($line) { 1119 | return (substr($line, -1, 1) == ':'); 1120 | } 1121 | 1122 | private function isPlainArray($line) { 1123 | return ($line[0] == '[' && substr($line, -1, 1) == ']'); 1124 | } 1125 | 1126 | private function returnPlainArray($line) { 1127 | return $this -> _toType($line); 1128 | } 1129 | 1130 | private function returnKeyValuePair($line) { 1131 | $array = array(); 1132 | $key = ''; 1133 | if (strpos($line, ': ')) { 1134 | // It's a key/value pair most likely 1135 | // If the key is in double quotes pull it out 1136 | if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/', $line, $matches)) { 1137 | $value = trim(str_replace($matches[1], '', $line)); 1138 | $key = $matches[2]; 1139 | } else { 1140 | // Do some guesswork as to the key and the value 1141 | $explode = explode(': ', $line); 1142 | $key = trim(array_shift($explode)); 1143 | $value = trim(implode(': ', $explode)); 1144 | $this -> checkKeysInValue($value); 1145 | } 1146 | // Set the type of the value. Int, string, etc 1147 | $value = $this -> _toType($value); 1148 | if ($key === '0') 1149 | $key = '__!YAMLZero'; 1150 | $array[$key] = $value; 1151 | } else { 1152 | $array = array($line); 1153 | } 1154 | return $array; 1155 | 1156 | } 1157 | 1158 | private function returnArrayElement($line) { 1159 | if (strlen($line) <= 1) 1160 | return array( array()); 1161 | // Weird %) 1162 | $array = array(); 1163 | $value = trim(substr($line, 1)); 1164 | $value = $this -> _toType($value); 1165 | if ($this -> isArrayElement($value)) { 1166 | $value = $this -> returnArrayElement($value); 1167 | } 1168 | $array[] = $value; 1169 | return $array; 1170 | } 1171 | 1172 | private function nodeContainsGroup($line) { 1173 | $symbolsForReference = 'A-z0-9_\-'; 1174 | if (strpos($line, '&') === false && strpos($line, '*') === false) 1175 | return false; 1176 | // Please die fast ;-) 1177 | if ($line[0] == '&' && preg_match('/^(&[' . $symbolsForReference . ']+)/', $line, $matches)) 1178 | return $matches[1]; 1179 | if ($line[0] == '*' && preg_match('/^(\*[' . $symbolsForReference . ']+)/', $line, $matches)) 1180 | return $matches[1]; 1181 | if (preg_match('/(&[' . $symbolsForReference . ']+)$/', $line, $matches)) 1182 | return $matches[1]; 1183 | if (preg_match('/(\*[' . $symbolsForReference . ']+$)/', $line, $matches)) 1184 | return $matches[1]; 1185 | if (preg_match('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) 1186 | return $matches[1]; 1187 | return false; 1188 | 1189 | } 1190 | 1191 | private function addGroup($line, $group) { 1192 | if ($group[0] == '&') 1193 | $this -> _containsGroupAnchor = substr($group, 1); 1194 | if ($group[0] == '*') 1195 | $this -> _containsGroupAlias = substr($group, 1); 1196 | //print_r ($this->path); 1197 | } 1198 | 1199 | private function stripGroup($line, $group) { 1200 | $line = trim(str_replace($group, '', $line)); 1201 | return $line; 1202 | } 1203 | 1204 | } 1205 | 1206 | // Enable use of Spyc from command line 1207 | // The syntax is the following: php Spyc.php spyc.yaml 1208 | 1209 | do { 1210 | if (PHP_SAPI != 'cli') 1211 | break; 1212 | if (empty($_SERVER['argc']) || $_SERVER['argc'] < 2) 1213 | break; 1214 | if (empty($_SERVER['PHP_SELF']) || FALSE === strpos($_SERVER['PHP_SELF'], 'Spyc.php')) 1215 | break; 1216 | $file = $argv[1]; 1217 | echo json_encode(spyc_load_file($file)); 1218 | } while (0); 1219 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 6 | * @link https://github.com/mikestowe/php-raml2html 7 | * @link http://www.mikestowe.com/2014/05/raml-2-html.php 8 | * @license http://www.gnu.org/licenses/gpl-2.0.html GPL v2 9 | */ 10 | 11 | require_once('inc/spyc.php'); 12 | require_once('inc/ramlDataObject.php'); 13 | require_once('inc/raml.php'); 14 | require_once('inc/ramlPathObject.php'); 15 | require_once('inc/markdown.php'); 16 | require_once('inc/codeSamples.php'); 17 | require_once('config.php'); 18 | 19 | 20 | // Dangling Function 21 | function formatResponse($text) { 22 | return str_replace(array(" ", "\n"), array(" ", "
"), htmlspecialchars($text, ENT_QUOTES)); 23 | } 24 | 25 | // Handle Caching and Build 26 | $RAML = false; 27 | if ($cacheTimeLimit && function_exists('apc_fetch')) { 28 | $RAML = apc_fetch('RAML' . md5($RAMLsource)); 29 | } elseif (!$cacheTimeLimit && function_exists('apc_fetch')) { 30 | // Remove existing cache files 31 | apc_delete('RAML' . md5($RAMLsource)); 32 | } 33 | 34 | if (!$RAML) { 35 | $RAMLarray = spyc_load(file_get_contents($RAMLsource)); 36 | $RAML = new RAML2HTML\RAML($RAMLactionVerbs); 37 | 38 | $RAML->setIncludePath(dirname($RAMLsource) . '/'); 39 | $RAML->buildFromArray($RAMLarray); 40 | 41 | if ($cacheTimeLimit && function_exists('apc_store')) { 42 | apc_store('RAML' . md5($RAMLsource), $RAML, $cacheTimeLimit); 43 | } 44 | } 45 | 46 | 47 | // Set Current Path 48 | if (isset($_GET['path'])) { 49 | $RAML->setCurrentPath($_GET['path']); 50 | unset($_GET['path']); 51 | } 52 | 53 | 54 | // Set Current Action 55 | if (isset($_GET['action']) && $RAML->isActionValid($_GET['action'])) { 56 | $RAML->setCurrentAction($_GET['action']); 57 | unset($_GET['action']); 58 | } 59 | 60 | // Render Template 61 | require_once($docsTheme); 62 | 63 | ?> 64 | -------------------------------------------------------------------------------- /raml/githubrepo.raml: -------------------------------------------------------------------------------- 1 | #%RAML 0.8 2 | title: Mike's Github Repo 3 | baseUri: http://mikesgitapi.cloudhub.io 4 | version: v0.1 5 | description:

Welcome to my API!

Be sure to check out my site at http://www.mikestowe.com. 6 | /followers: 7 | description: Get a list of followers for mikestowe 8 | get: 9 | description: returns a list of followers 10 | post: 11 | description: doesn't work 12 | 13 | /following: 14 | description: Get a list of who mikestowe is following on Github 15 | get: 16 | description: returns a list of following 17 | post: 18 | description: stop trying to update my stuff... 19 | put: 20 | description: stop trying to update my stuff... 21 | patch: 22 | description: stop trying to update my stuff... 23 | delete: 24 | description: stop trying to update my stuff... 25 | connect: 26 | description: stop trying to update my stuff... 27 | trace: 28 | description: stop trying to update my stuff... 29 | 30 | /htmle: 31 | description: the HTML repo 32 | get: 33 | description: returns a list of commits 34 | connect: 35 | description: what are you doing??? 36 | 37 | /branches/{userId}: 38 | description: Gets branches! 39 | displayName: HTMLe Branches! 40 | get: 41 | description: returns a list of branches 42 | delete: 43 | description: acts like get... but its pinkish red 44 | 45 | /forks: 46 | get: 47 | description: returnsa list of forks 48 | options: 49 | description: acts like get... but its light green 50 | 51 | /evalscanner: 52 | get: 53 | description: returns a list of commits 54 | patch: 55 | description: throws an error because you shouldn't be doing that... 56 | /branches: 57 | get: 58 | description: returns a list of branches 59 | trace: 60 | description: doesn't do jack... 61 | /forks: 62 | get: 63 | description: returnsa list of forks 64 | 65 | /phpscanner: 66 | get: 67 | description: returns a list of commits 68 | 69 | /branches: 70 | get: 71 | description: returns a list of branches 72 | 73 | /forks: 74 | get: 75 | description: returnsa list of forks 76 | 77 | /smrtclass: 78 | get: 79 | description: returns a list of commits 80 | 81 | /branches: 82 | get: 83 | description: returns a list of branches 84 | 85 | /forks: 86 | get: 87 | description: returnsa list of forks 88 | 89 | /formbuilder: 90 | get: 91 | description: returns a list of commits 92 | 93 | /branches: 94 | get: 95 | description: returns a list of branches 96 | 97 | /forks: 98 | get: 99 | description: returnsa list of forks -------------------------------------------------------------------------------- /raml/songs.raml: -------------------------------------------------------------------------------- 1 | #%RAML 0.8 2 | 3 | title: World Music API 4 | baseUri: http://example.api.com/{version} 5 | version: v1 6 | traits: 7 | - paged: 8 | queryParameters: 9 | pages: 10 | description: The number of pages to return 11 | type: number 12 | - secured: !include raml/githubrepo.raml 13 | /songs: 14 | is: [ paged, secured ] 15 | get: 16 | queryParameters: 17 | genre: 18 | description: filter the songs by genre 19 | post: 20 | /{songId}: 21 | get: 22 | responses: 23 | 200: 24 | body: 25 | application/json: 26 | schema: !include raml/githubrepo.raml 27 | application/xml: !include raml/githubrepo.raml 28 | delete: 29 | description: | 30 | This method will *delete* an **individual song** -------------------------------------------------------------------------------- /templates/grey/_404.phtml: -------------------------------------------------------------------------------- 1 |

2 | The page you are trying to access does not exist. Please select a parent endpoint from the menu to your right. 3 |

4 | -------------------------------------------------------------------------------- /templates/grey/_action.phtml: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | getCurrentAction(); ?> 5 | baseUri . $RAML->getCurrentPath(); ?> 6 | 7 |
8 | 9 |

action()->get('description')); ?>

10 | 11 | 12 | action()->get('queryParameters')->isArray()): ?> 13 | 14 | Try It 15 | 16 |

Query Parameters

17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | action()->get('queryParameters')->toArray() as $param => $details) { 26 | ?> 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
ParameterTypeRequiredDescription
Example: ' . $details['example'] . '' : ''); ?>
35 | 36 | 37 | 38 | action()->get('body')->get('application/x-www-form-urlencoded')->get('formParameters')->isArray()): ?> 39 |

Form Parameters

40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | action()->get('body')->get('application/x-www-form-urlencoded')->get('formParameters')->toArray() as $param => $details) { 49 | ?> 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
ParameterTypeRequiredDescription
Example: ' . $details['example'] . '' : ''); ?>
58 | 59 | 60 | 61 | action()->get('body')->get('application/json')->get('schema')->get('properties')->isArray()): ?> 62 |

JSON Parameters

63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | action()->get('body')->get('application/json')->get('schema')->toArray(); 72 | if ($RAML->action()->get('body')->get('application/json')->get('schema')->isString()) { 73 | $tmp = json_decode($RAML->action()->get('body')->get('application/json')->get('schema')->toString(), true); 74 | } 75 | 76 | foreach ($tmp['properties'] as $param => $details) { 77 | ?> 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 |
ParameterTypeRequiredDescription
Example: ' . $details['example'] . '' : ''); ?>
86 | 87 | 88 | 89 |

Code Samples

90 | JavaScript 91 | PHP 92 | Rails 93 |
", $codeSamples->javascript()); ?>
94 |
", $codeSamples->php()); ?>
95 |
", $codeSamples->rails()); ?>
96 | 97 | 109 | 110 |

Response

111 | 112 | path()->getResponses() as $code => $responses) { ?> 113 | :

114 | 115 | ' . (is_array($response['type']) ? array_shift($response['type']) : $response['type']) . ''; 122 | 123 | if (isset($response['example'])): 124 | ?> 125 |
126 | 127 |
128 | 129 |

 

130 | 133 | 134 | 135 | 136 | path()->getVerbs()) > 1): ?> 137 |

Other Endpoint Actions

138 | path()->getVerbs() as $verb) { 140 | if ($verb == $RAML->getCurrentAction()) { 141 | continue; 142 | } 143 | ?> 144 |
145 | 146 |
147 | 148 | 149 | 150 | 151 | 152 | 153 | 215 | 216 | 240 | -------------------------------------------------------------------------------- /templates/grey/_comments.phtml: -------------------------------------------------------------------------------- 1 |
2 | 13 | 14 | -------------------------------------------------------------------------------- /templates/grey/_menu.phtml: -------------------------------------------------------------------------------- 1 |

Documentation

2 | 3 | 10 | 11 |

 

12 | 13 |

14 | Server Status: 15 | 16 | pingStatus(); 18 | if ($status == 'online'): ?> 19 | Online 20 | 21 | Offline 22 | 23 |

24 | 25 | Updated every 5 minutes 26 | -------------------------------------------------------------------------------- /templates/grey/_resources.phtml: -------------------------------------------------------------------------------- 1 |

Available Endpoints

2 | 17 | -------------------------------------------------------------------------------- /templates/grey/_verbs.phtml: -------------------------------------------------------------------------------- 1 |

Available Actions

2 | 3 | 17 | -------------------------------------------------------------------------------- /templates/grey/index.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | <?php echo $RAML->title; ?>: <?php echo $RAML->getCurrentPath(); ?> 4 | 5 | 6 | 7 | 8 | 9 | 10 | 19 | 20 | 262 | 263 | 264 | 265 | 266 |
267 |

get('title'); ?>

268 |

version get('version'); ?>           get('baseUri'); ?>

269 |
270 | 271 | 272 |
273 | 274 | 279 | 280 |
281 | getCurrentPath() != '/'): ?> 282 |

getCurrentPath(); ?>

283 | path()->description): ?> 284 | 285 | 286 | 287 | 288 | isPathValid($RAML->getCurrentPath()); ?> 289 | 290 | 291 | getCurrentAction() && $RAML->path()->description): 292 | echo RAML2HTML\markdown::parse($RAML->path()->description); 293 | endif; ?> 294 | 295 | 296 | 301 | 302 | 303 | path()->getVerbs() && !$RAML->getCurrentAction()): 305 | include('_verbs.phtml'); 306 | endif; 307 | ?> 308 | 309 | 310 | 311 | getChildPaths($RAML->getCurrentPath()) && !$RAML->getCurrentAction()): 313 | include('_resources.phtml'); 314 | endif; 315 | ?> 316 | 317 | 318 | getCurrentAction()): 320 | include('_action.phtml'); 321 | if ($disqus && $disqus_shortname): 322 | include('_comments.phtml'); 323 | endif; 324 | endif; 325 | ?> 326 | 327 | 328 |
329 | 330 |
331 | 332 |
333 | 334 | 337 | 338 | 339 | -------------------------------------------------------------------------------- /templates/orange/_404.phtml: -------------------------------------------------------------------------------- 1 |

2 | The page you are trying to access does not exist. Please select a parent endpoint from the menu to your right. 3 |

4 | -------------------------------------------------------------------------------- /templates/orange/_action.phtml: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | getCurrentAction(); ?> 5 | baseUri . $RAML->getCurrentPath(); ?> 6 | 7 |
8 | 9 |

action()->get('description')); ?>

10 | 11 | 12 | action()->get('queryParameters')->isArray()): ?> 13 | 14 | Try It 15 | 16 |

Query Parameters

17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | action()->get('queryParameters')->toArray() as $param => $details) { 26 | ?> 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
ParameterTypeRequiredDescription
Example: ' . $details['example'] . '' : ''); ?>
35 | 36 | 37 | 38 | action()->get('body')->get('application/x-www-form-urlencoded')->get('formParameters')->isArray()): ?> 39 |

Form Parameters

40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | action()->get('body')->get('application/x-www-form-urlencoded')->get('formParameters')->toArray() as $param => $details) { 49 | ?> 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
ParameterTypeRequiredDescription
Example: ' . $details['example'] . '' : ''); ?>
58 | 59 | 60 | 61 | action()->get('body')->get('application/json')->get('schema')->get('properties')->isArray()): ?> 62 |

JSON Parameters

63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | action()->get('body')->get('application/json')->get('schema')->toArray(); 72 | if ($RAML->action()->get('body')->get('application/json')->get('schema')->isString()) { 73 | $tmp = json_decode($RAML->action()->get('body')->get('application/json')->get('schema')->toString(), true); 74 | } 75 | 76 | foreach ($tmp['properties'] as $param => $details) { 77 | ?> 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 |
ParameterTypeRequiredDescription
Example: ' . $details['example'] . '' : ''); ?>
86 | 87 | 88 | 89 |

Code Samples

90 |
91 | JavaScript 92 | PHP 93 | Rails 94 |
", $codeSamples->javascript()); ?>
95 |
", $codeSamples->php()); ?>
96 |
", $codeSamples->rails()); ?>
97 | 98 | 110 | 111 |

Response

112 | 113 | path()->getResponses() as $code => $responses) { ?> 114 |
:
115 | 116 | ' . (is_array($response['type']) ? array_shift($response['type']) : $response['type']) . ''; 123 | 124 | if (isset($response['example'])): 125 | ?> 126 |

127 |
128 | 129 |
130 | 131 |

 

132 | 135 | 136 | 137 | 138 | path()->getVerbs()) > 1): ?> 139 |

Other Endpoint Actions

140 | path()->getVerbs() as $verb) { 142 | if ($verb == $RAML->getCurrentAction()) { 143 | continue; 144 | } 145 | ?> 146 |
147 | 148 |
149 | 150 | 151 | 152 | 153 | 154 | 155 | 217 | 218 | 242 | -------------------------------------------------------------------------------- /templates/orange/_comments.phtml: -------------------------------------------------------------------------------- 1 |
2 | 13 | 14 | -------------------------------------------------------------------------------- /templates/orange/_menu.phtml: -------------------------------------------------------------------------------- 1 | 8 | 9 |

10 | Server Status: 11 | 12 | pingStatus(); 14 | if ($status == 'online'): ?> 15 | Online 16 | 17 | Offline 18 | 19 |

20 | 21 | Updated every 5 minutes 22 | -------------------------------------------------------------------------------- /templates/orange/_resources.phtml: -------------------------------------------------------------------------------- 1 |

Available Endpoints

2 | 17 | -------------------------------------------------------------------------------- /templates/orange/_verbs.phtml: -------------------------------------------------------------------------------- 1 |

Available Actions

2 | 3 | 17 | -------------------------------------------------------------------------------- /templates/orange/index.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <?php echo $RAML->title; ?> | <?php echo $RAML->getCurrentPath(); ?> 6 | 7 | 8 | 9 | 10 | 19 | 249 | 250 | 251 | 252 | 253 |
254 | 255 |
256 |

get('title'); ?>

257 | version get('version'); ?>get('baseUri'); ?> 258 |
259 | 260 | 265 | 266 |
267 | getCurrentPath() != '/'): ?> 268 |

getCurrentPath(); ?>

269 | path()->description): ?> 270 | 271 | 272 | 273 | 274 | isPathValid($RAML->getCurrentPath()); ?> 275 | 276 | 277 | getCurrentAction() && $RAML->path()->description): 278 | echo RAML2HTML\markdown::parse($RAML->path()->description); 279 | endif; ?> 280 | 281 | 282 | 287 | 288 | 289 | path()->getVerbs() && !$RAML->getCurrentAction()): 291 | include('_verbs.phtml'); 292 | endif; 293 | ?> 294 | 295 | 296 | 297 | getChildPaths($RAML->getCurrentPath()) && !$RAML->getCurrentAction()): 299 | include('_resources.phtml'); 300 | endif; 301 | ?> 302 | 303 | 304 | getCurrentAction()): 306 | include('_action.phtml'); 307 | if ($disqus && $disqus_shortname): 308 | include('_comments.phtml'); 309 | endif; 310 | endif; 311 | ?> 312 |
313 | 314 |
315 | 316 | 319 | 320 |
321 | 322 | 323 | 324 | 325 | --------------------------------------------------------------------------------