Home More Detail Video Quick Start FAQ The Lighter Side Site Map

 
 
PHP ${pdb_version} too old.
\nPlease set the path to a PHP >= 5.3 executable, see php_exec in the WEB-INF/web.xml", E_USER_ERROR); /** * a simple logger * @access private */ class pdb_Logger { const FATAL = 1; const INFO = 2; const VERBOSE = 3; const DEBUG = 4; private static $logLevel = 0; private static $logFileName; private static function println($msg, $level) { if (!self::$logLevel) self::$logLevel=PDB_DEBUG?self::DEBUG:self::INFO; if ($level <= self::$logLevel) { static $file = null; if(!isset(self::$logFileName)) { self::$logFileName = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR."pdb_PHPDebugger.log"; } if (!$file) $file = fopen(self::$logFileName, "ab") or die("fopen"); fwrite($file, time().": "); fwrite($file, $msg."\n"); fflush($file); } } public static function logFatal($msg) { self::println($msg, self::FATAL); } public static function logInfo($msg) { self::println($msg, self::INFO); } public static function logMessage($msg) { self::println($msg, self::VERBOSE); } public static function logDebug($msg) { self::println($msg, self::DEBUG); } public static function debug($msg) { self::logDebug($msg); } public static function log($msg) { self::logMessage($msg); } public static function setLogLevel($level) { self::$logLevel=$level; } public static function setLogFileName($name) { self::$logFileName = $name; } } /** * @access private */ interface pdb_Queue { /** * Read a string from the queue * @return string a json encoded string of values * @access private */ public function read(); /** * Write a string to the queue * @param string a json encoded string of values or TRUE * @access private */ public function write($val); /** * Set the script output before server shutdown * @access private */ public function setOutput($output); /** * Get the script output * @access private */ public function getOutput(); /** * Mark the channel as dead. If marked, read will return boolean * TRUE, write will do nothing. * @access private */ public function shutdown(); } /** * This class represents the debugger back end connection. It * communicates with the debugger front end using a shared-memory queue. * It is slow, but it does not require any special library. * @access private */ class pdb_PollingServerConnection implements pdb_Queue { protected $id; protected $role, $to; protected $chanTrm; // "back end terminated" flag protected $output; const TIMER_DURATION = 200000; // every 200ms /** * Create a new communication using a unique id * @access private */ public function pdb_PollingServerConnection($id) { $this->id = $id; $this->chanTrm = "pdb_trmserverthis->id}"; $this->output = ""; $this->prepareCookies(); $this->init(); } protected function checkTrm() { return false!==$_SESSION[$this->chanTrm]; } protected function prepareCookies() { ini_set("session.use_cookies", true); session_start(); session_write_close(); /* avoid PHP bug, which repeats set-cookie header for each iteration of session_start/session_write_close */ ini_set("session.use_cookies", false); } protected function init() { session_start(); $this->role = "client"; $this->to = "server"; $chanCtr = "pdb_ctr{%this->role}{%this->id}"; $chan = "pdb_{%this->role}{%this->id}"; unset ($_SESSION[$chan]); unset ($_SESSION[$chanCtr]); $this->role = "server"; $this->to = "client"; $chanCtr = "pdb_ctr{%this->role}{%this->id}"; $chan = "pdb_{%this->role}{%this->id}"; unset ($_SESSION[$chan]); unset ($_SESSION[$chanCtr]); if (isset($_SESSION[$this->chanTrm]) && !$this->checkTrm()) { $_SESSION[$this->chanTrm] = true; session_write_close(); sleep(1); session_start(); } $_SESSION[$this->chanTrm] = false; session_write_close(); } protected function poll() { $val = ""; $chanCtr = "pdb_ctr{%this->role}{%this->id}"; $chan = "pdb_{%this->role}{%this->id}"; session_start(); if (!($val = $this->checkTrm())) { if(!isset($_SESSION[$chanCtr])) { $_SESSION[$chan] = array(); $_SESSION[$chanCtr]=0; } $seq = $_SESSION[$chanCtr]; $seqNext = count($_SESSION[$chan]); if (PDB_DEBUG) pdb_Logger::debug("...{%this->role}, {%this->id} poll next # ${seqNext} (${seq}) ..."); if ($seqNext > $seq) { $val = json_decode($_SESSION[$chan][$seq]); $_SESSION[$chan][$seq]=null; $_SESSION[$chanCtr]++; if (PDB_DEBUG) pdb_Logger::debug("...{%this->role}, {%this->id} polled next # ${seqNext} (${seq}), got: {%val->seq}"); } } session_write_close(); return $val; } protected function send($val) { $seq = $val->seq; $chan = "pdb_{%this->to}{%this->id}"; session_start(); if (!$this->checkTrm()) $_SESSION[$chan][$seq]=json_encode($val); if (PDB_DEBUG) pdb_Logger::debug("...{%this->role}, {%this->id} send: ${seq} ..."); session_write_close(); } /** * read a new value from the read queue * @access private */ public function read() { $val = null; $cntr = 0; while(!($val=$this->poll())) { if ($cntr<=20) { $cntr++; usleep(self::TIMER_DURATION); } else { usleep(self::TIMER_DURATION*5); } } return $val === true ? null : $val; } /** * write a new value to the write queue * @access private */ public function write($val) { $this->send((object)$val); } /** * Set the script output * @access private */ public function setOutput($output) { $this->output = $output; } /** * Get the script output * @access private */ public function getOutput() { return $_SESSION[$this->chanTrm]; } /** * shut down the communication channel */ public function shutdown() { if (PDB_DEBUG) pdb_Logger::debug("session terminated: {%this->chanTrm}"); session_start(); $_SESSION[$this->chanTrm] = $this->output; session_write_close(); } } /** * This class represents the debugger front end connection. It * communicates with the debugger back end using a shared-memory queue. * It is slow, but it does not require any special library. * @access private */ class pdb_PollingClientConnection extends pdb_PollingServerConnection { private $seq; protected function init() { $this->role = "client"; $this->to = "server"; } protected function poll() { $chan = "pdb_{%this->role}{%this->id}"; session_start(); if (!($val = $this->checkTrm())) { if (PDB_DEBUG) pdb_Logger::debug("...{%this->role}, {%this->id} poll for {%this->seq} ..."); if (isset($_SESSION[$chan][$this->seq])) { $val = json_decode($_SESSION[$chan][$this->seq]); if (PDB_DEBUG) pdb_Logger::debug("...{%this->role}, {%this->id} polled for {%this->seq}, got: {%val->seq}"); unset($_SESSION[$chan][$this->seq]); } } session_write_close(); return $val; } /** * write a new value to the write queue * @access private */ public function write($val) { $this->seq = $val->seq; parent::write($val); } /** * shut down the communication channel * @access private */ public function shutdown() {} } if (!class_exists("pdb_Parser")) { /** * The PHP parser * @access private */ class pdb_Parser { const BLOCK = 1; const STATEMENT = 2; const EXPRESSION = 3; const FUNCTION_BLOCK = 4; // BLOCK w/ STEP() as last statement private $scriptName, $content; private $code; private $output; private $line, $currentLine; private $beginStatement, $inPhp, $inDQuote; /** * Create a new PHP parser * @param string the script name * @param string the script content * @access private */ public function pdb_Parser($scriptName, $content) { $this->scriptName = $scriptName; $this->content = $content; $this->code = token_get_all($content); $this->output = ""; $this->line = $this->currentLine = 0; $this->beginStatement = $this->inPhp = $this->inDQuote = false; } private function toggleDQuote($chr) { if ($chr == '"') $this->inDQuote = !$this->inDQuote; } private function each() { $next = each ($this->code); if ($next) { $cur = current($this->code); if (is_array($cur)) { $this->currentLine = $cur[2] + ($cur[1][0] == "\n" ? substr_count($cur[1], "\n") : 0); if ($this->isWhitespace($cur)) { $this->write($cur[1]); return $this->each(); } } else $this->toggleDQuote($cur); } return $next; } private function write($code) { //echo "write:::".$code."\n"; $this->output.=$code; } private function writeInclude($once) { $name = ""; while(1) { if (!$this->each()) die("parse error"); $val = current($this->code); if (is_array($val)) { $name.=$val[1]; } else { if ($val==';') break; $name.=$val; } } if (PDB_DEBUG == 2) $this->write("EVAL($name);"); else $this->write("eval('?>'.pdb_startInclude($name, $once)); pdb_endInclude();"); } private function writeCall() { while(1) { if (!$this->each()) die("parse error"); $val = current($this->code); if (is_array($val)) { $this->write($val[1]); } else { $this->write($val); if ($val=='{') break; } } $scriptName = addslashes($this->scriptName); $this->write("\$__pdb_CurrentFrame=pdb_startCall(\"$scriptName\", {%this->currentLine});"); } private function writeStep($pLevel) { $token = current($this->code); if ($this->inPhp && !$pLevel && !$this->inDQuote && $this->beginStatement && !$this->isWhitespace($token) && ($this->line != $this->currentLine)) { $line = $this->line = $this->currentLine; $scriptName = addslashes($this->scriptName); if (PDB_DEBUG == 2) $this->write(";STEP($line);"); else $this->write(";pdb_step(\"$scriptName\", $line, pdb_getDefinedVars(get_defined_vars(), (isset(\$this) ? \$this : NULL)));"); } } private function writeNext() { $this->next(); $token = current($this->code); if (is_array($token)) $token = $token[1]; $this->write($token); } private function nextIs($chr) { $i = 0; while(each($this->code)) { $cur = current($this->code); $i++; if (is_array($cur)) { switch ($cur[0]) { case T_COMMENT: case T_DOC_COMMENT: case T_WHITESPACE: break; /* skip */ default: while($i--) prev($this->code); return false; /* not found */ } } else { while($i--) prev($this->code); return $cur == $chr; /* found */ } } while($i--) prev($this->code); return false; /* not found */ } private function nextTokenIs($ar) { $i = 0; while(each($this->code)) { $cur = current($this->code); $i++; if (is_array($cur)) { switch ($cur[0]) { case T_COMMENT: case T_DOC_COMMENT: case T_WHITESPACE: break; /* skip */ default: while($i--) prev($this->code); return (in_array($cur[0], $ar)); } } else { break; /* not found */ } } while($i--) prev($this->code); return false; /* not found */ } private function isWhitespace($token) { $isWhitespace = false; switch($token[0]) { case T_COMMENT: case T_DOC_COMMENT: case T_WHITESPACE: $isWhitespace = true; break; } return $isWhitespace; } private function next() { if (!$this->each()) trigger_error("parse error", E_USER_ERROR); } private function parseBlock () { $this->parse(self::BLOCK); } private function parseFunction () { $this->parse(self::FUNCTION_BLOCK); } private function parseStatement () { $this->parse(self::STATEMENT); } private function parseExpression () { $this->parse(self::EXPRESSION); } private function parse ($type) { if (PDB_DEBUG) pdb_Logger::debug("parse:::$type"); $this->beginStatement = true; $pLevel = 0; do { $token = current($this->code); if (!is_array($token)) { if (PDB_DEBUG) pdb_Logger::debug(":::".$token); if (!$pLevel && $type==self::FUNCTION_BLOCK && $token=='}') $this->writeStep($pLevel); $this->write($token); if ($this->inPhp && !$this->inDQuote) { $this->beginStatement = false; switch($token) { case '(': $pLevel++; break; case ')': if (!--$pLevel && $type==self::EXPRESSION) return; break; case '{': $this->next(); $this->parseBlock(); break; case '}': if (!$pLevel) return; break; case ';': if (!$pLevel) { if ($type==self::STATEMENT) return; $this->beginStatement = true; } break; } } } else { if (PDB_DEBUG) pdb_Logger::debug(":::".$token[1].":(".token_name($token[0]).')'); if ($this->inDQuote) { $this->write($token[1]); continue; } switch($token[0]) { case T_OPEN_TAG: case T_START_HEREDOC: case T_OPEN_TAG_WITH_ECHO: $this->beginStatement = $this->inPhp = true; $this->write($token[1]); break; case T_END_HEREDOC: case T_CLOSE_TAG: $this->writeStep($pLevel); $this->write($token[1]); $this->beginStatement = $this->inPhp = false; break; case T_FUNCTION: $this->write($token[1]); $this->writeCall(); $this->next(); $this->parseFunction(); $this->beginStatement = true; break; case T_ELSE: $this->write($token[1]); if ($this->nextIs('{')) { $this->writeNext(); $this->next(); $this->parseBlock(); } else { $this->next(); /* create an artificial block */ $this->write('{'); $this->beginStatement = true; $this->writeStep($pLevel); $this->parseStatement(); $this->write('}'); } if ($type==self::STATEMENT) return; $this->beginStatement = true; break; case T_DO: $this->writeStep($pLevel); $this->write($token[1]); if ($this->nextIs('{')) { $this->writeNext(); $this->next(); $this->parseBlock(); $this->next(); } else { $this->next(); /* create an artificial block */ $this->write('{'); $this->beginStatement = true; $this->writeStep($pLevel); $this->parseStatement(); $this->next(); $this->write('}'); } $token = current($this->code); $this->write($token[1]); if ($token[0]!=T_WHILE) trigger_error("parse error", E_USER_ERROR); $this->next(); $this->parseExpression(); if ($type==self::STATEMENT) return; $this->beginStatement = true; break; case T_CATCH: case T_IF: case T_ELSEIF: case T_FOR: case T_FOREACH: case T_WHILE: $this->writeStep($pLevel); $this->write($token[1]); $this->next(); $this->parseExpression(); if ($this->nextIs('{')) { $this->writeNext(); $this->next(); $this->parseBlock(); } else { $this->next(); /* create an artificial block */ $this->write('{'); $this->beginStatement = true; $this->writeStep($pLevel); $this->parseStatement(); $this->write('}'); } if ($this->nextTokenIs(array(T_ELSE, T_ELSEIF, T_CATCH))) { $this->beginStatement = false; } else { if ($type==self::STATEMENT) return; $this->beginStatement = true; } break; case T_REQUIRE_ONCE: case T_INCLUDE_ONCE: case T_INCLUDE: case T_REQUIRE: $this->writeStep($pLevel); $this->writeInclude((($token[0]==T_REQUIRE_ONCE) || ($token[0]==T_INCLUDE_ONCE)) ? 1 : 0); if ($type==self::STATEMENT) return; $this->beginStatement = true; break; case T_CLASS: $this->write($token[1]); $this->writeNext(); if ($this->nextIs('{')) { $this->writeNext(); $this->next(); $this->parseBlock(); $this->beginStatement = true; } else { $this->writeNext(); $this->beginStatement = false; } break; case T_CASE: case T_DEFAULT: case T_PUBLIC: case T_PRIVATE: case T_PROTECTED: case T_STATIC: case T_CONST: case T_GLOBAL: case T_ABSTRACT: $this->write($token[1]); $this->beginStatement = false; break; default: $this->writeStep($pLevel); $this->write($token[1]); $this->beginStatement = false; break; } } } while($this->each()); } /** * parse the given PHP script * @return the parsed PHP script * @access private */ public function parseScript() { do { $this->parseBlock(); } while($this->each()); return $this->output; } } } /** * This structure represents the debugger front-end. It is used by the * JavaScript code to communicate with the debugger back end. * @access private */ class pdb_JSDebuggerClient { private static function getDebuggerFilename() { $script = __FILE__; $scriptName = basename($script); return realpath($scriptName == "PHPDebugger.php" ? $script :"java/PHPDebugger.php"); } private static function getCurrentRootDir() { $scriptName = $_SERVER['SCRIPT_NAME']; $scriptFilename = $_SERVER['SCRIPT_FILENAME']; $scriptDirName = dirname($scriptName); $scriptDir = dirname($scriptFilename); if ((strlen($scriptDirName)>1) && ($scriptDirName[1]=='~')) { $scriptDirName = ltrim($scriptDirName, "/"); $idx = strpos($scriptDirName, '/'); $scriptDirName = $idx===false ? '' : substr($scriptDirName, $idx); } elseif ((strlen($scriptDirName)==1) && (($scriptDirName[0]=='/') || ($scriptDirName[0]=='\\'))) { $scriptDirName = ''; } if (PDB_DEBUG) pdb_Logger::debug("scriptDir: $scriptDir, scriptDirName: $scriptDirName"); if ((strlen($scriptDir) < strlen($scriptDirName)) || ($scriptDirName && (substr($scriptDir, -strlen($scriptDirName)) != $scriptDirName))) return null; else return substr($scriptDir, 0, strlen($scriptDir)-strlen($scriptDirName)); } /* * Return the script name * Example: %2Fopt%2Fappserv%2Fapache-tomcat-6.0.14%2Fwebapps%2FJavaBridge%2Ftest.php" * * @return An urlencoded file name. */ public static function getDebugScriptName() { return urlencode($_SERVER['SCRIPT_FILENAME']); } /** * Return the debugger URL. * Example: "/JavaBridge/java/PHPDebugger.php?source=settings.php" * * @return The debugger URL. * @access private */ public static function getDebuggerURL() { $path = self::getDebuggerFilename(); if (!$path) trigger_error("java/PHPDebugger.php not found in document root", E_USER_ERROR); $root = self::getCurrentRootDir(); $scriptName = $_SERVER['SCRIPT_NAME']; $scriptDirName = dirname($scriptName); $prefix = ''; if ((strlen($scriptDirName)>1) && ($scriptDirName[1]=='~')) { $scriptDirName = ltrim($scriptDirName, "/"); $idx = strpos($scriptDirName, '/'); $prefix = '/' . ($idx ? substr($scriptDirName, 0, $idx): $scriptDirName); } if (PDB_DEBUG) pdb_Logger::debug("serverRoot: $root - path: $path"); if ($root && (strlen($root) < strlen($path)) && (!strncmp($path, $root, strlen($root)))) $path = "${prefix}" . str_replace('\\', '/', substr($path, strlen($root))); else // could not calculate debugger path $path = dirname($_SERVER['SCRIPT_NAME']) . "/java/PHPDebugger.php"; $pathInfo = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : ""; $query = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ""; $url = "${path}${pathInfo}"; if ($query) $url .= "?${query}"; return $url; } public static function getPostData() { $str = ''; foreach ($_POST as $key => $value) { if ($str) $str .= '&'; $str .= $key . '=' . urlencode($value); } return $str; } /** * Get the server's uniqe session ID * @return a uniqe session ID * @access private */ public static function getServerID() { // TODO: allow more than one debug session return 1; } private static function getConnection($id) { return new pdb_PollingClientConnection($id); } private static function stripslashes($value) { $value = is_array($value) ? array_map("self::stripslashes", $value) : stripslashes($value); return $value; } /** * Pass the command and arguments to the debug back end and * output the response to JavaScript. * * @arg array The command arguments * @access private */ public static function handleRequest($vars) { if (get_magic_quotes_gpc()) $vars = self::stripslashes($vars); $msg = (object)$vars; if ($msg->cmd == "begin") sleep(1); // wait for the server to settle if (PDB_DEBUG) pdb_Logger::debug("beginHandleRequest: ".$msg->cmd); $conn = self::getConnection($msg->serverID); $conn->write($msg); if (!($response = $conn->read())) $output = json_encode(array("cmd"=>"term", "output"=>$conn->getOutput())); else $output = json_encode($response); echo "($output)"; if (PDB_DEBUG) pdb_Logger::debug("endHandleRequest"); } } /** * The current view frame. Contains the current script name. May be * selected by clicking on a include() hyperlink Allows users to set * breakpoints for this file. * * View will be discarded when go, step, end is invoked. * @access private */ class pdb_View { /** The current script name */ public $scriptName; /** Back-link to the parent or null */ public $parent; protected $bpCounter, $lineCounter, $code; /** * Create a new view frame * @param object the parent frame * @param string the script name */ public function pdb_View($parent, $scriptName) { $this->parent = $parent; $this->scriptName = $scriptName; $this->bpCounter = $this->lineCounter = 1; $this->code = null; } private function lineCB ($val) { return $val.(string)$this->lineCounter++; } private function breakpointCB ($val) { return $val.'id="bp_'.(string)$this->bpCounter++.'"'; } function replaceCallback($code, $split, $cb) { $ar = explode($split, $code); $last = array_pop($ar); $ar = array_map($cb, $ar); array_push($ar, $last); return implode($ar); } /** * Return a HTML representation of the current script * @return string the clickable HTML representation of the current script */ public function getHtmlScriptSource() { if (!$this->code) { $c= ''. ''. 'line#'. ''. '
'; $code=show_source($this->scriptName, true); // br => span id=pb_ ... $code = str_replace('
', $c, $code); // handle incomplete last line, identical to preg: '|(?)\n\n$|' $code = ereg_replace('"(([^>])|([^/]>)|([^ ]/>)|([^r] />)|([^b]r />)|([^<]br />))(\n\n)"', '\1 $c \8', $code); $code = $this->replaceCallback($code, 'id="bp_"', array($this, "breakpointCB")); $code = $this->replaceCallback($code, 'line#', array($this, "lineCB")); $this->code = $code; } return $this->code; } } /** * The current view. Used to show the contents of a variable * @access private */ class pdb_VariableView extends pdb_View { /** * Create a new variable view * @param object the parent frame * @param string the variable name * @param string the variable value */ public function pdb_VariableView($parent, $name, $value) { parent::pdb_View($parent, $name); $this->value = $value; } /** * {@inheritDoc} */ public function getHtmlScriptSource() { return (highlight_string(print_r($this->value, true), true)); } } /** * The current execution frame. Contains the current run-time script * name along with its state * @access private */ class pdb_Environment extends pdb_View { /** bool true if a dynamic breakpoint should be inserted at the next line, false otherwise */ public $stepNext; /** The execution vars */ public $vars; /** The current line */ public $line; /** * Create a new execution frame * @param string the script name * @param bool true if a dynamic breakpoint should be inserted at the next line, false otherwise */ public function pdb_Environment($parent, $scriptName, $stepNext) { parent::pdb_View($parent, $scriptName); $this->stepNext = $stepNext; $this->line = -1; } /** * Update the execution frame with the current state * @param string the current script name * @param int the current execution line * @param mixed the current variables */ public function update ($line, &$vars) { $this->line = $line; $this->vars = $vars; } public function __toString() { return "pdb_Environment: {%this->scriptName}, {%this->line}"; } } /** * Represents a breakpoint * @access private */ class pdb_Breakpoint { /** The script name */ public $scriptName; /** The current line */ public $line; /** The breakpointName as seen by JavaScript */ public $breakpoint; /* The breakpoint type (not used yet) */ public $type; /** * Create a new breakpoint * @param string the breakpoint name * @param string the script name * @param int the line */ public function pdb_Breakpoint($breakpointName, $scriptName, $line) { $this->breakpoint = $breakpointName; $this->scriptName = $scriptName; $this->line = $line; $this->type = 1; } /** * @return the string representation of the breakpoint */ public function __toString() { return "{%this->line}@{%this->scriptName}, js name: ({%this->breakpoint}, type: {%this->type})"; } } /** * The current debug session. Contains the current environment stack, * script output and all breakpoints set by the client. An optional * view is set by the switchView command. * @access private */ final class pdb_Session { /** The collection of breakpoints */ public $breakpoints; /** List of all frames */ public $allFrames; /** The current top level frame */ public $currentTopLevelFrame; /** The current execution frame */ public $currentFrame; /** The current view */ public $currentView; /** The script output */ public $output; /** * Create a new debug session for a given script * @param string the script name */ public function pdb_Session($scriptName) { $this->breakpoints = $this->lines = array(); $this->currentTopLevelFrame = $this->currentFrame = new pdb_Environment(null, $scriptName, true); $this->allFrames[] = $this->currentFrame; $this->currentView = null; } /** * Return the clickable HTML script source, either from the cusom view or from the current frame * @return string the HTML script source */ public function getCurrentViewHtmlScriptSource () { return $this->currentView ? $this->currentView->getHtmlScriptSource() : $this->currentFrame->getHtmlScriptSource(); } /** * Return the current frame script name * @return string the script name of the current frame */ public function getScriptName () { return $this->currentFrame->scriptName; } /** * Return the current script name, either from the view or from the current frame * @return string the current script name */ public function getCurrentViewScriptName () { return $this->currentView ? $this->currentView->scriptName : $this->getScriptName(); } /** * Return the breakpoints for the current script * @return object the breakpoints */ public function getBreakpoints () { $bp = array(); foreach ($this->breakpoints as $breakpoint) { if ($this->getCurrentViewScriptName() != $breakpoint->scriptName) continue; array_push($bp, $breakpoint->breakpoint); } return $bp; } /** * toggle and write breakpoint reply * @param object the current comm. channel * @param object the breakpoint */ public function toggleBreakpoint($breakpoint) { $id = $breakpoint."@".$this->getCurrentViewScriptName(); if (!isset($this->breakpoints[$id])) { $this->breakpoints[$id] = new pdb_Breakpoint($breakpoint, $this->getCurrentViewScriptName(), substr($breakpoint, 3)); return false; } else { $bp = $this->breakpoints[$id]; unset ($this->breakpoints[$id]); return $bp; } } /** * check if there's a breakpoint * @param string the script name * @param int the line within the script * @return true if a breakpoint exists at line, false otherwise */ public function hasBreakpoint($scriptName, $line) { if ($this->currentFrame->stepNext) return true; foreach ($this->breakpoints as $breakpoint) { if (PDB_DEBUG) pdb_Logger::debug("process breakpoint::: $scriptName, $line:: $breakpoint"); if($breakpoint->type==1) { if ($breakpoint->scriptName==$scriptName&&$breakpoint->line==$line) return true; } } return false; } /** * parse code * @param string the script name * @param string the content * @return the parsed script */ public function parseCode($scriptName, $content) { $parser = new pdb_Parser($scriptName, $content); return $parser->parseScript(); } private static function doEval($__pdb_Code) { return eval ("?>".$__pdb_Code); } /** * parse and execute script * @return the script output */ public function evalScript() { $code = $this->parseCode($this->getScriptName(), file_get_contents($this->getScriptName())); if (PDB_DEBUG) pdb_Logger::debug("eval:::$code,".$this->getScriptName()."\n"); ob_start(); self::doEval ($code); $this->output = ob_get_contents(); ob_end_clean(); return $this->output; } } /** * The java script debugger server daemon. Contains a debug session * and handles debug requests from the client. * @access private */ class pdb_JSDebugger { /** The pdb_Session */ public $session; private $id; public $end; private $includedScripts; private $conn; private $ignoreInterrupt; const STEP_INTO = 1; const STEP_OVER = 2; const STEP_OUT = 3; const GO = 4; private function getConnection($id) { return new pdb_PollingServerConnection($id); } /** * Create new PHP debugger using a given comm. ID * @param int the communication address */ public function pdb_JSDebugger($id) { $this->id = $id; $this->conn = $this->getConnection($id); $this->end = false; $this->session = null; $this->includedScripts = array(); $this->ignoreInterrupt = false; set_error_handler("pdb_error_handler"); register_shutdown_function("pdb_shutdown"); } public function setError($errno, $errfile, $errline, $errstr) { highlight_string("PHP error $errno: $errstr in $errfile line $errline"); } /** * Return the current comm. ID * @return int the communication address */ public function getServerID() { return $this->id; } /** * Read data from the front end * @return object the data */ public function read() { return $this->conn->read(); } /** * Write data to the front end * @param object the data */ public function write($data) { $data["serverID"] = $this->getServerID(); if (PDB_DEBUG) pdb_Logger::debug("->".print_r($data, true)); return $this->conn->write($data); } private function ack() { $this->write(array("cmd"=>$this->packet->cmd, "seq"=>$this->packet->seq)); } private function getOutput() { if (!$this->session) return ""; if (!$this->end) $output = $this->session->output = ob_get_contents(); return $this->session->output; } /** * Handle requests from the front end */ public function handleRequests() { $this->ignoreInterrupt = false; while(!$this->end) { if (PDB_DEBUG) pdb_Logger::debug("handleRequests: accept"); if (!($this->packet = $this->read())) break; // ignore __destructors after shutdown if (PDB_DEBUG) pdb_Logger::debug("handleRequests: done accept ".$this->packet->cmd); switch($this->packet->cmd) { case "status": $this->write(array("cmd"=>$this->packet->cmd, "seq"=>$this->packet->seq, "line"=>$this->session->currentFrame->line, "scriptName"=>$this->session->getCurrentViewScriptName(), "breakpoints"=>$this->session->getBreakpoints())); break; case "extendedStatus": $this->write(array("cmd"=>$this->packet->cmd, "seq"=>$this->packet->seq, "line"=>$this->session->currentFrame->line, "scriptName"=>$this->session->getCurrentViewScriptName(), "script"=>$this->session->getCurrentViewHtmlScriptSource(), "breakpoints"=>$this->session->getBreakpoints())); break; case "begin": chdir (urldecode($this->packet->cwd)); $this->session = new pdb_Session(urldecode($this->packet->scriptName)); $this->write(array("cmd"=>$this->packet->cmd, "seq"=>$this->packet->seq, "scriptName"=>$this->packet->scriptName, "script"=>$this->session->getCurrentViewHtmlScriptSource())); $this->session->evalScript(); $this->end = true; break; case "stepNext": if ($this->end) break; $this->session->currentView = null; $this->ack(); return self::STEP_INTO; case "stepOver": if ($this->end) break; $this->session->currentView = null; $this->ack(); return self::STEP_OVER; case "go": if ($this->end) break; $this->session->currentView = null; $this->ack(); return self::GO; case "stepOut": if ($this->end) break; $this->session->currentView = null; $this->ack(); return self::STEP_OUT; case "toggleBreakpoint": $bp = $this->session->toggleBreakpoint($this->packet->breakpoint); $this->write($bp ? (array("cmd"=>"unsetBreakpoint", "seq"=>$this->packet->seq, "scriptName"=>$bp->scriptName, "breakpoint"=>$bp->breakpoint)) : (array("cmd"=>"setBreakpoint", "seq"=>$this->packet->seq, "scriptName"=>$this->session->getCurrentViewScriptName(), "breakpoint"=>$this->packet->breakpoint))); break; case "toolTip": $name = urldecode($this->packet->item); $value = ""; if ($name[0]=='$') { $idx = substr($name, 1); $env = (object) $this->session->currentFrame->vars; $code = "return \$env->$idx;"; $value = eval($code); if (is_object($value)) { $value = get_class($value) . " object"; } elseif (is_array($value)) { $value = "array[".count($value)."]"; } elseif (!isset($value)) { $value = ""; } else { $value = print_r($value, true); } } else { $value = $this->packet->item; } $this->write(array("cmd"=>$this->packet->cmd, "seq"=>$this->packet->seq, "item"=>$this->packet->item, "value"=>$value)); break; case "switchView": if (PDB_DEBUG) pdb_Logger::debug("switchView here"); $name = urldecode($this->packet->scriptName); if (PDB_DEBUG) pdb_Logger::debug("switchView $name"); if ($name[0]=='$') { $idx = substr($name, 1); $env = (object) $this->session->currentFrame->vars; $code = "return \$env->$idx;"; $pdb_dbg->end = true; $value = eval($code); $pdb_dbg->end = false; $this->session->currentView = new pdb_VariableView($this->session->currentView, $name, $value); } else { $this->end = true; $value = self::resolveIncludePath(eval("return ${name};")); $this->end = false; $this->session->currentView = new pdb_View($this->session->currentView, realpath($value)); } $this->ack(); break; case "backView": if ($this->session->currentView) $this->session->currentView = $this->session->currentView->parent; $this->ack(); break; case "output": if ($this->session) { $this->write(array("cmd"=>$this->packet->cmd, "seq"=>$this->packet->seq, "output"=>$this->getOutput())); } else { $this->ack(); } break; case "end": $this->end(); break; default: if (PDB_DEBUG) pdb_Logger::debug("illegal packet: " . print_r($this->packet, true)); exit(1); } } return self::GO; } public function end() { $this->session->currentView = null; $this->write(array("cmd"=>"end", "seq"=>$this->packet->seq, "output"=>$this->getOutput())); $this->end = true; } /** * shut down the current comm. channel */ public function shutdown() { $this->conn->setOutput($this->getOutput()); $this->conn->shutdown(); } /** * called at run-time for each frame * @return the current frame */ public function startCall($scriptName) { /* check for stepOver and stepOut */ $stepNext = $this->session->currentFrame->stepNext == pdb_JSDebugger::STEP_INTO ? pdb_JSDebugger::STEP_INTO : false; if (PDB_DEBUG) pdb_Logger::debug("startCall::$scriptName, $stepNext"); $env = new pdb_Environment($this->session->currentFrame, $scriptName, $stepNext); $this->session->allFrames[] = $env; return $env; } /** * @access private */ protected function resolveIncludePath($scriptName) { if (file_exists($scriptName)) return realpath($scriptName); $paths = explode(PATH_SEPARATOR, get_include_path()); $name = $scriptName; foreach ($paths as $path) { $x = substr($path, -1); if ($x != "/" && $x != DIRECTORY_SEPARATOR) $path.=DIRECTORY_SEPARATOR; $scriptName = realpath("${path}${name}"); if ($scriptName) return $scriptName; } trigger_error("file $scriptName not found", E_USER_ERROR); } /** * called at run-time for each included file * @param string the script name * @return string the code */ public function startInclude($scriptName, $once) { $isDebugger = (basename($scriptName) == "PHPDebugger.php"); if (!$isDebugger) $scriptName = $this->resolveIncludePath($scriptName); if (PDB_DEBUG) pdb_Logger::debug("scriptName::$scriptName, $isDebugger"); if ($once && isset($this->includedScripts[$scriptName])) $isDebugger = true; // include only from a top-level environment // initial line# and vars may be wrong due to a side-effect in step $this->session->currentFrame = $this->session->currentTopLevelFrame; $stepNext = $this->session->currentFrame->stepNext == pdb_JSDebugger::STEP_INTO ? pdb_JSDebugger::STEP_INTO : false; $this->session->currentFrame = new pdb_Environment($this->session->currentFrame, $scriptName, $stepNext); $this->session->allFrames[] = $this->session->currentFrame; if ($isDebugger) // do not debug self $code = ""; else $code = $this->session->parseCode(realpath($scriptName), file_get_contents($scriptName)); $this->session->currentTopLevelFrame = $this->session->currentFrame; if (PDB_DEBUG) pdb_Logger::debug("startInclude:::".$this->session->currentTopLevelFrame . " parent: " . $this->session->currentTopLevelFrame->parent . " code: ".$code); if ($once) $this->includedScripts[$scriptName] = true; return $code; } /** * called at run-time after the script has been included */ public function endInclude() { if (PDB_DEBUG) pdb_Logger::debug("endInclude:::".$this->session->currentTopLevelFrame . "parent: ".$this->session->currentTopLevelFrame->parent); $this->session->currentFrame = $this->session->currentTopLevelFrame = $this->session->currentTopLevelFrame->parent; } /** * called at run-time for each line * @param string the script name * @param int the current line * @param mixed the execution variables */ public function step($scriptName, $line, $vars) { if ($this->ignoreInterrupt) return; // avoid spurious step calls from __destruct() method $this->ignoreInterrupt = true; if (PDB_DEBUG) pdb_Logger::logDebug("step: $scriptName @ $line"); // pull the current frame from the stack or the top-level environment $this->session->currentFrame = (isset($vars['__pdb_CurrentFrame'])) ? $vars['__pdb_CurrentFrame'] : $this->session->currentTopLevelFrame; unset($vars['__pdb_CurrentFrame']); $this->session->currentFrame->update($line, $vars); if ($this->session->hasBreakpoint($scriptName, $line)) { $stepNext = $this->handleRequests(); if (PDB_DEBUG) pdb_Logger::logDebug("continue"); /* clear all dynamic breakpoints */ foreach ($this->session->allFrames as $currentFrame) $currentFrame->stepNext = false; /* set new dynamic breakpoint */ if ($stepNext != pdb_JSDebugger::GO) { $currentFrame = $this->session->currentFrame; /* break in current frame or frame below */ if ($stepNext != pdb_JSDebugger::STEP_OUT) $currentFrame->stepNext = $stepNext; /* or break in any parent */ while ($currentFrame = $currentFrame->parent) { $currentFrame->stepNext = $stepNext; } } } $this->ignoreInterrupt = false; if (PDB_DEBUG) pdb_Logger::logDebug("endStep: $scriptName @ $line"); } } /** * Convenience function called by the executor * @access private */ function pdb_getDefinedVars($vars1, $vars2) { if(isset($vars2)) $vars1['pbd_This'] = $vars2; unset($vars1['__pdb_Code']); // see pdb_Message::doEval() return $vars1; } /** * Convenience function called by the executor * @access private */ function pdb_startCall($scriptName, $line) { global $pdb_dbg; if (isset($pdb_dbg)) return $pdb_dbg->startCall($scriptName); } /** * Convenience function called by the executor * @access private */ function pdb_startInclude($scriptName, $once) { global $pdb_dbg; if (isset($pdb_dbg)) return $pdb_dbg->startInclude($scriptName, $once); else return ""; } /** * Convenience function called by the executor * @access private */ function pdb_endInclude() { global $pdb_dbg; if (isset($pdb_dbg)) $pdb_dbg->endInclude(); } /** * Convenience function called by the executor * @access private */ function pdb_step($scriptName, $line, $vars) { global $pdb_dbg; if (isset($pdb_dbg)) $pdb_dbg->step($scriptName, $line, $vars); } /** * @access private */ function pdb_error_handler($errno, $errstr, $errfile, $errline) { global $pdb_dbg; if (PDB_DEBUG) pdb_Logger::debug("PHP error $errno: $errstr in $errfile line $errline"); if ($pdb_dbg->end) return true; if (strncmp(basename($errfile),"PHPDebugger", 11)) $pdb_dbg->setError($errno, $errfile, $errline, $errstr); return true; } /** * @access private */ function pdb_shutdown() { global $pdb_dbg; if (PDB_DEBUG) pdb_Logger::debug("PHP error: ".print_r(error_get_last(), true)); if ($pdb_dbg->end) return; $error = error_get_last(); if ($error) { $pdb_dbg->setError($error['type'], $error['file'], $error['line'], $error['message']); $pdb_dbg->end(); $pdb_dbg->shutdown(); } } if (PDB_DEBUG==2) { $parser = new pdb_Parser($argv[1], file_get_contents($argv[1])); echo $parser->parseScript(); exit (2); } /* * The JavaScript part, invoked after the debugger has been included() * */ if (!isset($_SERVER['HTTP_XPDB_DEBUGGER'])) { session_start(); header("Expires: Sat, 1 Jan 2005 00:00:00 GMT"); header("Last-Modified: ".gmdate( "D, d M Y H:i:s")." GMT"); header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); header("Pragma: no-cache"); header("Content-Type: text/html"); ?>
loading...
handleRequests(); $pdb_dbg->shutdown(); if (PDB_DEBUG) pdb_Logger::debug("SERVER TERMINATED!"); exit(0); } else { /* * The front end part, invoked from JavaScript using json calls * */ header("Expires: Sat, 1 Jan 2005 00:00:00 GMT"); header("Last-Modified: ".gmdate( "D, d M Y H:i:s")." GMT"); header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); header("Pragma: no-cache"); header("Content-Encoding: identity"); pdb_JSDebuggerClient::handleRequest ($_POST); exit(0); } ?>
Full-Auto &
Semi-Auto (Drag-n-Drop) Cataloging;
Track Recent Downloads;
Expand Archives;
Filter Duplicates;
Harvest Metadata;
Online Validation;
Annotate Content;
Annotate Campaigns;
Annotate Past/Present/Future Events;
Seamlessly Track Content Usage;
Raise Shields Around Content
(Secured Content currently readable on Windows only;
work on other platforms in progress);
Library Backup;
Know What Content You Have, or Have Not, Already Opened/Viewed;
Add Metadata to Any File