[ Index ] |
PHP Cross Reference of PHK Manager |
[Summary view] [Print] [Text view]
1 <?php 2 //============================================================================= 3 // 4 // Copyright Francois Laupretre <phk@tekwire.net> 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); 7 // you may not use this file except in compliance with the License. 8 // You may obtain a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 // 18 //============================================================================= 19 /** 20 * @copyright Francois Laupretre <phk@tekwire.net> 21 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, V 2.0 22 * @category PHK 23 * @package PHK 24 *///========================================================================== 25 26 namespace PHK { 27 28 if (!class_exists('PHK\Backend',false)) 29 { 30 //============================================================================= 31 /** 32 * This class contains the non-accelerated runtime code. This code must 33 * never be accessed during 'fast path' scenarios. 34 * 35 * Each \PHK\Backend instance is associated with a 'front-end' PHK instance 36 * (accelerated or not). 37 * 38 * <Public API> 39 */ 40 41 class Backend 42 { 43 44 private $front; // PHK front-end 45 46 //-------------- 47 48 public function __construct($front) 49 { 50 $this->front=$front; 51 } 52 53 //--------------------------------- 54 55 public function __get($name) 56 { 57 return $this->front->$name(); 58 } 59 60 //--------------------------------- 61 62 public function __call($method,$args) 63 { 64 return \PHK\Tools\Util::callMethod($this->front,$method,$args); 65 } 66 67 //--------------------------------- 68 69 public function test() 70 { 71 // Remove E_NOTICE messages if the test script is a package - workaround 72 // to PHP bug #39903 ('__COMPILER_HALT_OFFSET__ already defined') 73 74 error_reporting(($errlevel=error_reporting()) & ~E_NOTICE); 75 76 if (!is_null($test_script=$this->option('test_script'))) 77 { 78 $test_uri=$this->uri($test_script); 79 require($test_uri); 80 } 81 elseif (!is_null($phpunit_test_package=$this->option('phpunit_test_package'))) 82 { 83 if (!is_null($phpunit_package=$this->option('phpunit_package'))) 84 { $phpunit_package_mnt=require $this->uri($phpunit_package); } 85 else $phpunit_package_mnt=null; 86 87 $phpunit_test_package_mnt=require $this->uri($phpunit_test_package); 88 89 \PHK\UnitTest\_phk_load_phpunit_interface(); 90 define('PHPUnit_MAIN_METHOD', 'PHPUnit_TextUI_\PHK::main'); 91 PHPUnit_TextUI_\PHK::main(); 92 93 if (!is_null($phpunit_package_mnt)) \PHK\Mgr::umount($phpunit_package_mnt); 94 95 if (!is_null($phpunit_test_package_mnt)) 96 \PHK\Mgr::umount($phpunit_test_package_mnt); 97 } 98 else echo "No unit tests\n"; 99 100 error_reporting($errlevel); 101 } 102 103 //--------------------------------- 104 // Display the environment 105 // This function cannot be cached 106 107 public function envinfo() 108 { 109 $html=\PHK\Tools\Util::envIsWeb(); 110 111 //-- Accelerator 112 113 self::infoSection($html,'PHK Accelerator'); 114 115 self::startInfoTable($html); 116 if (\PHK::acceleratorIsPresent()) \PHK::accelTechInfo(); 117 else self::showInfoLine($html,'PHK Accelerator','No'); 118 119 self::infoSection($html,'Cache'); 120 121 self::showInfoLine($html,'Cache system used',\PHK\Cache::cacheName()); 122 self::endInfoTable($html); 123 124 //-- Environment 125 126 self::infoSection($html,'Environment'); 127 128 self::startInfoTable($html); 129 self::showInfoLine($html,'PHP SAPI',php_sapi_name()); 130 self::showInfoLine($html,'Mount point',$this->mnt); 131 132 //-- Mount options 133 134 $string=''; 135 $class=new ReflectionClass('\PHK'); 136 foreach($class->getConstants() as $name => $value) 137 { 138 if ((strlen($name)>1) && (substr($name,0,2)=='F_') 139 && ($this->flags & $value)) $string .= ','.strtolower(substr($name,2)); 140 } 141 unset($class); 142 $string=trim($string,','); 143 self::showInfoLine($html,'Current mount options' 144 ,$string=='' ? '<none>' : $string); 145 self::endInfoTable($html); 146 } 147 148 //--------------------------------- 149 // Display the file tree 150 151 public function showfiles() 152 { 153 $this->proxy()->showfiles(); 154 } 155 156 //--------------------------------- 157 // Display map content or <empty> message 158 159 public function showmap($subfile_to_url_function=null) 160 { 161 if ($this->mapDefined()) 162 \Automap\Mgr::map($this->automapID)->show(null,$subfile_to_url_function); 163 else echo "This package does not contain a map\n"; 164 } 165 166 //----- 167 /** 168 * <Info> Displays information about the plugin 169 * 170 * If the plugin object defines a method name '_webinfo', this method is called 171 * with the $html parameter. 172 * 173 * If the plugin is not defined, just displays a small informative message 174 * 175 * @param boolean $html Whether to display in html or raw text 176 * @return void 177 */ 178 179 private function pluginInfo($html) 180 { 181 self::infoSection($html,'Plugin'); 182 183 if (is_null($class=$this->option('plugin_class'))) 184 { 185 echo ($html ? '<p>' : '')."Not defined\n"; 186 return; 187 } 188 189 if ($this->isCallablePluginMethod('_webinfo')) 190 { 191 $this->callPluginMethod('_webinfo',$html); 192 echo $html ? '<p>' : "\n"; 193 } 194 195 self::startInfoTable($html); 196 197 self::showInfoLine($html,'Class',$class); 198 199 $rc=new ReflectionClass($class); 200 201 foreach ($rc->getMethods() as $method) 202 { 203 if ((!$method->isPublic())||($method->isStatic()) 204 ||($method->isConstructor())||($method->isDestructor()) 205 ||($method->getName()==='_webinfo')) continue; 206 $name=$method->getName(); 207 $a=array(); 208 foreach($method->getParameters() as $param) 209 { 210 $s='$'.$param->getName(); 211 if ($param->isPassedByReference()) $s='&'.$s; 212 if ($param->isArray()) $s = 'Array '.$s; 213 if ($param->isOptional()) 214 { 215 if ($param->isDefaultValueAvailable()) 216 $s .= ' = '.var_export($param->getDefaultValue(),true); 217 $s = '['.$s.']'; 218 } 219 $a[]=$s; 220 } 221 self::showInfoLine($html,'Method',$name.' ( '.implode(', ',$a).' )'); 222 } 223 224 self::endInfoTable($html); 225 } 226 227 //----- 228 /** 229 * <Info> Displays an option and its value 230 * 231 * An URL can be set in an option. Syntax: 'text to display <url>' 232 * In HTML mode, only the text is displayed and an hyperlink is generated 233 * In text mode, it is displayed as-is. 234 * URLs starting with 'http://' are automatically recognized 235 236 * @param boolean $html Whether to display in html or raw text 237 * @param string $opt Option name 238 * @return void 239 */ 240 241 private function showOption($html,$opt,$default=null) 242 { 243 $str1=ucfirst(str_replace('_',' ',$opt)); 244 245 $url=null; 246 $newwin=true; 247 if (is_null($val=$this->option($opt))) $val=$default; 248 249 if ($html && preg_match('/^(.*)\s<(\S+)>.*$/',$val,$regs)) 250 { // If the value contains an URL 251 $str2=trim($regs[1]); 252 $url=$regs[2]; 253 if ($str2=='') $str2=$url; 254 } 255 else 256 { 257 $str2=$val; 258 $vlen=strlen($val); 259 if (($vlen>=7)&&(substr($val,0,7)=='http://')) $url=$val; 260 elseif (($vlen>=1) && ($val{0}=='/') && file_exists($this->uri($val))) 261 { 262 // Warning: We build an HTTP URL going to \PHK\Web\Info, not a stream wrapper URI. 263 $url=\PHK::subpathURL('/view/'.trim($val,'/')); 264 $newwin=false; 265 } 266 } 267 268 self::showInfoLine($html,$str1,$str2,$url,$newwin); 269 } 270 271 //----- 272 /** 273 * <Info> Start a new information section 274 * 275 * @param boolean $html Whether to display in html or raw text 276 * @param string $title The title to display 277 * @return void 278 */ 279 280 public static function infoSection($html,$title) 281 { 282 echo $html ? '<h2>'.htmlspecialchars($title).'</h2>' 283 : "\n==== ".str_pad($title.' ',70,'='). "\n\n"; 284 } 285 286 //----- 287 /** 288 * <Info> Displays an information line 289 * 290 * In html mode, the information is displayed in a table. This table must 291 * have been opened by a previous call to \PHK::startInfoTable(). 292 * 293 * Note: The URLs starting with a '/' char are internal (generated by \PHK\Web\Info 294 * ) and, so, are displayed in html mode only. 295 * 296 * @param boolean $html Whether to display in html or raw text 297 * @param string $string The left side (without ':') 298 * @param string|boolean $value The value to display. If boolean, displays 'Yes' 299 * or 'No'. 300 * @param string|null $url An URL to associate with this value. Null if no URL. 301 * @param boolean $newwin Used in html mode only. Whether the URL link opens 302 * a new window when clicked. 303 * @return void 304 * 305 * @see startInfoTable() 306 * @see endInfoTable() 307 */ 308 309 public static function showInfoLine($html,$string,$value,$url=null 310 ,$newwin=true) 311 { 312 if (is_null($value)) $value='<>'; 313 if (is_bool($value)) $value=\PHK\Tools\Util::bool2str($value); 314 315 if ($html) 316 { 317 echo '<tr><td>'.htmlspecialchars($string).': </td><td>'; 318 if ($url) 319 { 320 echo '<a href="'.$url.'"'; 321 if ($newwin) echo ' target="_blank"'; 322 echo '>'; 323 } 324 echo htmlspecialchars($value); 325 if ($url) echo '</a>'; 326 echo '</td></tr>'; 327 } 328 else 329 { 330 echo "$string: $value"; 331 if ((!is_null($url)) && ($url{0}!='/')) echo " <$url>"; 332 echo "\n"; 333 } 334 } 335 336 //----- 337 /** 338 * <Info> Starts an HTML table 339 * 340 * In text mode, does nothing. 341 * 342 * This function is public because it can be called from the plugin's _webinfo 343 * method. 344 * 345 * @param boolean $html Whether to display in html or raw text 346 * @return void 347 */ 348 349 public static function startInfoTable($html) 350 { 351 echo $html ? '<table border=0>' : ''; 352 } 353 354 //----- 355 356 public static function endInfoTable($html) 357 { 358 echo $html ? '</table>' : ''; 359 } 360 361 //----- 362 // Display non technical information 363 // Webinfo default welcome page 364 365 public function info() 366 { 367 $html=\PHK\Tools\Util::envIsWeb(); 368 369 if ($html && (!is_null($info_script=$this->option('info_script')))) 370 { require($this->uri($info_script)); } 371 else 372 { 373 self::startInfoTable($html); 374 $this->showOption($html,'name'); 375 $this->showOption($html,'summary'); 376 $this->showOption($html,'version'); 377 $this->showOption($html,'release'); 378 $this->showOption($html,'distribution'); 379 $this->showOption($html,'license'); 380 $this->showOption($html,'copyright'); 381 $this->showOption($html,'url'); 382 $this->showOption($html,'author'); 383 $this->showOption($html,'packager'); 384 $this->showOption($html,'requires'); 385 386 $req=implode(' ',\PHK\Tools\Util::mkArray($this->option('required_extensions'))); 387 if ($req=='') $req='<none>'; 388 self::showInfoLine($html,'Required extensions',$req); 389 390 self::endInfoTable($html); 391 } 392 } 393 394 //----- 395 396 public function techinfo() 397 { 398 $html=\PHK\Tools\Util::envIsWeb(); 399 400 self::infoSection($html,'Package'); 401 402 self::startInfoTable($html); 403 $this->showOption($html,'name'); 404 $this->showOption($html,'summary'); 405 $this->showOption($html,'version'); 406 $this->showOption($html,'release'); 407 $this->showOption($html,'distribution'); 408 $this->showOption($html,'license'); 409 $this->showOption($html,'copyright'); 410 $this->showOption($html,'url'); 411 $this->showOption($html,'author'); 412 $this->showOption($html,'packager'); 413 $this->showOption($html,'requires'); 414 self::showInfoLine($html,'Signed',$this->proxy()->signed()); 415 self::showInfoLine($html,'Automap defined',$this->mapDefined()); 416 self::showInfoLine($html,'File path',$this->path); 417 self::showInfoLine($html,'File size',filesize($this->path)); 418 419 $req=implode(', ',\PHK\Tools\Util::mkArray($this->option('required_extensions'))); 420 if ($req=='') $req='<none>'; 421 self::showInfoLine($html,'Required extensions',$req); 422 423 self::showInfoLine($html,'Build date' 424 ,\PHK\Tools\Util::timeString($this->buildInfo('build_timestamp'))); 425 $this->showOption($html,'icon'); 426 $this->showOption($html,'crc_check',false); 427 $this->showOption($html,'help_prefix'); 428 $this->showOption($html,'license_prefix'); 429 $this->showOption($html,'auto_umount',false); 430 $this->showOption($html,'no_cache',false); 431 $this->showOption($html,'no_opcode_cache',false); 432 $this->showOption($html,'prolog_code_creator',false); 433 $this->showOption($html,'plain_prolog',false); 434 self::showInfoLine($html,'File count',count($this->pathList())); 435 self::endInfoTable($html); 436 437 $this->pluginInfo($html); 438 439 self::infoSection($html,'Package scripts'); 440 441 self::startInfoTable($html); 442 $this->showOption($html,'cli_run_script'); 443 $this->showOption($html,'web_run_script'); 444 $this->showOption($html,'lib_run_script'); 445 $this->showOption($html,'info_script'); 446 $this->showOption($html,'mount_script'); 447 $this->showOption($html,'umount_script'); 448 $this->showOption($html,'test_script'); 449 $this->showOption($html,'phpunit_package'); 450 $this->showOption($html,'phpunit_test_package'); 451 452 self::endInfoTable($html); 453 454 self::infoSection($html,'Module versions'); 455 456 self::startInfoTable($html); 457 self::showInfoLine($html,'PHK Creator',$this->buildInfo('phk_creator_version')); 458 self::showInfoLine($html,'Automap Creator',$this->buildInfo('automap_creator_version')); 459 self::showInfoLine($html,'Automap min version',$this->buildInfo('automap_minVersion')); 460 self::endInfoTable($html); 461 462 self::infoSection($html,'Sub-packages'); 463 464 ob_start(); 465 $this->proxy()->displayPackages(); 466 $data=ob_get_clean(); 467 if ($data==='') echo ($html ? '<p>' : '')."None\n"; 468 else echo $data; 469 470 self::infoSection($html,'Web direct access'); 471 472 self::startInfoTable($html); 473 $list=\PHK\Tools\Util::mkArray($this->option('web_access')); 474 self::showInfoLine($html,'State',count($list) ? 'Enabled' : 'Disabled'); 475 $this->showOption($html,'web_main_redirect',false); 476 foreach($list as $path) self::showInfoLine($html,'Path',$path); 477 self::endInfoTable($html); 478 479 //-- Options 480 481 self::infoSection($html,'Package options'); 482 483 $a=$this->options(); 484 $data=(is_null($a) ? '<>' : print_r($a,true)); 485 echo ($html ? ('<pre>'.htmlspecialchars($data).'</pre>') : $data); 486 487 //-- Sections 488 489 self::infoSection($html,'Sections'); 490 $this->proxy()->stree()->display(false); 491 } 492 493 //----- 494 /** 495 * Returns a subfile content for a multi-type metafile 496 * 497 * File name : <prefix>.<type> - Type is 'txt' or 'htm'. 498 * 499 * A text file can be transformed to html, but the opposite is not possible. 500 * 501 * Type is determined by the SAPI type (CLI => txt, else => htm). 502 * 503 * @param string $prefix Prefix to search for 504 * @return string|null The requested content or null if not found 505 */ 506 507 public function autoFile($prefix) 508 { 509 $html=\PHK\Tools\Util::envIsWeb(); 510 $txt_suffixes=array('.txt',''); 511 $suffixes=($html ? array('.htm','.html') : $txt_suffixes); 512 513 $base_path=$this->uri($prefix); 514 foreach($suffixes as $suffix) 515 { 516 if (is_readable($base_path.$suffix)) 517 { 518 return \PHK\Tools\Util::readFile($base_path.$suffix); 519 break; 520 } 521 } 522 523 // If html requested and we only have a txt file, tranform it to html 524 525 if ($html) 526 { 527 foreach ($txt_suffixes as $suffix) 528 if (is_readable($base_path.$suffix)) 529 return '<pre>'.htmlspecialchars(\PHK\Tools\Util::readFile($base_path.$suffix)) 530 .'</pre>'; 531 } 532 533 return null; 534 } 535 536 //----- 537 /** 538 * Returns a multi-type content from an option name 539 * 540 * Option ($name.'_prefix') gives the prefix to send to autoFile() 541 * 542 * @param string $name Option prefix 543 * @return string Requested content or an informative error string. 544 */ 545 546 public function autoOption($name) 547 { 548 $data=null; 549 550 $prefix=$this->option($name.'_prefix'); 551 552 if (!is_null($prefix)) $data=$this->autoFile($prefix); 553 554 if (is_null($data)) 555 { 556 $data='<No '.$name.' file>'."\n"; 557 if (\PHK\Tools\Util::envIsWeb()) $data=htmlspecialchars($data); 558 } 559 560 return $data; 561 } 562 563 //----- 564 /** 565 * Checks if the plugin class is defined and contains a given method 566 * 567 * @param string $method 568 * @return boolean 569 */ 570 571 public function isCallablePluginMethod($method) 572 { 573 return (is_null($this->plugin)) ? false 574 : is_callable(array($this->plugin,$method)); 575 } 576 577 //----- 578 /** 579 * Calls a given method in the plugin object 580 * 581 * @param string method 582 * @return * the method's return value 583 * @throws \Exception if the plugin or the method does not exist 584 */ 585 586 public function callPluginMethod($method) 587 { 588 if (!$this->isCallablePluginMethod($method)) 589 throw new \Exception($method.': Undefined plugin method'); 590 591 $args=func_get_args(); 592 array_shift($args); 593 594 return call_user_func_array(array($this->plugin,$method),$args); 595 } 596 597 //----- 598 599 public function pathList() 600 { 601 return unserialize(file_get_contents($this->commandURI(__FUNCTION__))); 602 } 603 604 //----- 605 606 public function sectionList() 607 { 608 return unserialize(file_get_contents($this->commandURI(__FUNCTION))); 609 } 610 611 //----- 612 /** 613 * Check a package 614 * 615 * TODO: There's a lot more to check... 616 * 617 * @return array of error messages 618 */ 619 620 public function check() 621 { 622 $errors=array(); 623 624 // Check package CRC 625 626 try { $this->proxy()->crcCheck(); } 627 catch (\Exception $e) { $errors[]=$e->getMessage(); } 628 629 // Check symbol map 630 631 $id=$this->automapID(); 632 if ($id) 633 { 634 $map=\Automap\Mgr::map($id); 635 $errors=array_merge($errors,$map->check()); 636 } 637 638 return $errors; 639 } 640 641 //--------------------------------- 642 // Workaround for PHP bug/issue when trying to use PATH_INFO when PHP is 643 // run as an Apache CGI executable. In this mode, an url in the form of 644 // 'http://.../.../file.php/args' does not go to file.php but returns 645 // 'No input file specified'. There, we have to pass args the 'usual' 646 // way (via $_REQUEST). 647 // Drawback: as the URL now contains a '?' char, most browsers refuse to cache 648 // it, even with the appropriate header fields, causing some useless traffic 649 // when navigating in the tabs and flicking on the screen. So, the preferred 650 // method is via PATH_INFO. 651 // Allows a PHK package to become fully compatible with CGI mode by computing 652 // every relative URLs through this method. 653 654 public static function subpathURL($path) 655 { 656 if ($path{0}!='/') $path=\PHK::setSubpath().'/'.$path; //-- Make path absolute 657 $path=preg_replace(',//+,','/',$path); 658 659 return \PHK\Tools\Util::httpBaseURL().((php_sapi_name()=='cgi') 660 ? ('?_phk_path='.urlencode($path)) : $path); 661 } 662 663 //----- 664 665 private static function cmdUsage($msg=null) 666 { 667 if (!is_null($msg)) echo "** ERROR: $msg\n"; 668 669 echo "\nAvailable commands:\n\n"; 670 echo " - @help Display package help\n"; 671 echo " - @license Display license\n"; 672 echo " - @get <path> Display a subfile content\n"; 673 echo " - @showmap Display symbol map, if present\n"; 674 echo " - @showfiles List subfiles\n"; 675 echo " - @check Check package\n"; 676 echo " - @option <name> Display a package option\n"; 677 echo " - @set_interp <string> Set the first line of the PHK to '#!<string>'\n"; 678 echo " - @info Display information about the PHK file\n"; 679 echo " - @techinfo Display technical information\n"; 680 echo " - @dump <directory> Extracts the files\n"; 681 echo " - @test [switches] [UnitTest] Run the package's unit tests\n"; 682 683 if (!is_null($msg)) exit(1); 684 } 685 686 //----- 687 688 public function builtinProlog($file) 689 { 690 $retcode=0; 691 $args=$_SERVER['argv']; 692 693 try 694 { 695 $this->proxy()->crcCheck(); 696 697 $command=\PHK\Tools\Util::substr($args[1],1); 698 array_shift($args); 699 $param=isset($args[1]) ? $args[1] : null; 700 701 switch($command) 702 { 703 case 'get': 704 if (is_null($param)) 705 self::cmdUsage($command.": needs argument"); 706 $uri=$this->uri($param); 707 if (is_file($uri)) readfile($uri); 708 else throw new \Exception("$param: file not found"); 709 break; 710 711 case 'test': 712 case 'showmap': 713 case 'info': 714 case 'techinfo': 715 case 'showfiles': 716 $this->$command(); 717 break; 718 719 case 'check': 720 $errs=$this->check(); 721 if (count($errs)) 722 { 723 foreach($errs as $err) echo "$err\n"; 724 throw new \Exception("*** The check procedure found errors in $phk_path"); 725 } 726 echo "Check OK\n"; 727 break; 728 729 case 'option': 730 $res=$this->$command($param); 731 if (is_null($res)) throw new \Exception('Option not set'); 732 echo "$res\n"; 733 break; 734 735 case 'set_interp': 736 if (is_null($param)) 737 self::cmdUsage($command.": needs argument"); 738 739 //-- This is the only place in the runtime code where we write something 740 //-- into an existing PHK archive. 741 742 if (file_put_contents($file 743 ,\PHK\Proxy::setBufferInterp($file,$param))===false) 744 throw new \Exception('Cannot write file'); 745 break; 746 747 case 'license': 748 case 'licence': 749 echo $this->autoOption('license'); 750 break; 751 752 case 'help': 753 echo $this->autoOption($command); 754 break; 755 756 case 'dump': 757 if (is_null($param)) 758 self::cmdUsage($command.": needs argument"); 759 $this->proxy()->ftree()->dump($param); 760 break; 761 762 case '': 763 self::cmdUsage(); 764 break; 765 766 default: 767 self::cmdUsage($command.': Unknown command'); 768 } 769 770 \PHK\Tools\Util::displaySlowPath(); 771 } 772 catch (\Exception $e) 773 { 774 if (getenv('SHOW_EXCEPTION')!==false) throw $e; 775 echo "** ERROR: Command failed ($command) - ".$e->getMessage()."\n"; 776 $retcode=1; 777 } 778 779 return $retcode; 780 } 781 782 //--- 783 } // End of class 784 //=========================================================================== 785 } // End of class_exists 786 //=========================================================================== 787 } // End of namespace 788 //=========================================================================== 789 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jun 4 18:33:15 2015 | Cross-referenced by PHPXref 0.7.1 |