├── README.markdown ├── classes ├── Console.php ├── MySqlDatabase.php ├── PhpQuickProfiler.php └── PqpDatabase.Interface.php ├── css └── pQp.css ├── display.php ├── images ├── overlay.gif └── side.png ├── index.php └── pqp.tpl /README.markdown: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in 9 | all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | 19 | ##PHP Quick Profiler README 20 | [http://particletree.com/features/php-quick-profiler/](http://particletree.com/features/php-quick-profiler/) 21 | 22 | ### On This Page 23 | 24 | 1. License 25 | 2. Introduction and Overview of Files 26 | 3. Getting the Example Working 27 | 4. Setting up the Database Class 28 | 5. Using Smarty instead of PHP echos 29 | 30 | #### 1. License 31 | 32 | Created by Ryan Campbell. Designed by Kevin Hale. 33 | 34 | Copyright (c) 2009 Infinity Box Inc. 35 | 36 | All code and designs are provided under a 37 | Creative Commons Attribution 3.0 License. 38 | 39 | http://creativecommons.org/licenses/by/3.0/us/ 40 | 41 | #### 2. Introduction and Overview of Files 42 | 43 | PHP Quick Profiler (PQP) is a helper class that outputs to the screen information 44 | useful for debugging when the page has finished executing. If you haven't already, 45 | definitely read the article over at our blog introducing the profiler at: 46 | 47 | http://particletree.com/features/php-quick-profiler/ 48 | 49 | This zip package contains a functional example project that utilizes the helper classes. 50 | Here's a breakdown of the files: 51 | 52 | - index.php : Contains example code utilizing PQP. Open this in your browser to see the demo. 53 | - display.php : Contains the markup for PQP. 54 | - display.tpl : A Smarty variation of the PQP markup. 55 | - /css/ : The stylesheets used by PQP. 56 | - /images/ : The images used by PQP. 57 | - /classes/PhpQuickProfiler : The core class that compiles the data before outputting to the browser. 58 | - /classes/Console.php : The class used to log items to the PQP display. 59 | - /classes/MySqlDatabase : A sample database wrapper to show how database logging can be implemented with PQP. 60 | 61 | #### 3. Getting the Example Working 62 | 63 | For the most part, the example should work once you drop it in your root directory. 64 | There are a few settings you might want to check if it doesn't. 65 | 66 | - In index.php, set the $config member variable to the path relative to your root. 67 | 68 | - If PQP does not appear after navigating to index.php in your browser, locate the destructor 69 | of the PQPExample class (at the bottom). Rename the function from __destruct() to display(). 70 | Then, manually call the function display() just underneath the class after the call to init(). 71 | The reason this would happen is because the destructor is not firing on your server configuration. 72 | 73 | - At this point, everything should work except for the database tab. 74 | 75 | #### 4. Setting up the Database Class 76 | 77 | *NOTE!* 78 | This step requires knowledge of your PHP / Database interactions. 79 | There is, unfortunately, no copy/paste solution. 80 | 81 | Logging database data is by far the hardest part of integrating PQP into your own project. 82 | It requires that you have some sort of database wrapper around your code. If you do, it 83 | should be easy to implement. To show you how it works, follow these steps with the 84 | sample database class we've provided with the code. 85 | 86 | - Create a database named 'test' and run the following query on it. 87 | 88 | CREATE TABLE `Posts` ( 89 | `PostId` int(11) unsigned NOT NULL default '0', 90 | PRIMARY KEY (`PostId`) 91 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1 92 | 93 | - In index.php, uncomment out the second include, which includes the database class. 94 | - In index.php, uncomment out the function sampleDatabaseData(). 95 | - In the sampleDatabaseData(), supply your database host, username, password, and database name. 96 | 97 | Given those steps, database logging will be enabled. If you would like to transition this 98 | to your own database class, open /classes/MySqlDatabase.php and note the following: 99 | 100 | - $queryCount and $queries member variables declared on initialization 101 | - When a query is run, the following is executed: 102 | 103 | $start = $this->getTime(); 104 | $rs = mysql_query($sql, $this->conn); 105 | $this->queryCount += 1; 106 | $this->logQuery($sql, $start); 107 | 108 | - Everything in /classes/MySqlDatabase.php under the section comment "Debugging" 109 | must be available for the above snippet to work. 110 | 111 | #### 5. Using Smarty instead of PHP echos 112 | 113 | We love Smarty and hate using echos to spit out markup, but to make PQP work for as many people 114 | as possible we set the default to use the echo version. To show love to the Smarty users out 115 | there, we have included a display.tpl file for PQP. To make it work, you need to change 116 | the following in /classes/PhpQuickProfiler.php: 117 | 118 | - Add a require_once to your Smarty Library. 119 | - In the constructor, declare an instance of Smarty: $this->smarty = new Smarty(...); 120 | - Everywhere in in the code you see $this->output[... change it to a smarty assign. For example: 121 | 122 | $this->output['logs'] = $logs; 123 | 124 | ... becomes ... 125 | 126 | $this->smarty->assign('logs', $logs); 127 | 128 | After doing it once, you'll see the pattern and can probably use a find/replace to do the rest quickly. 129 | 130 | - Locate the display() function at the bottom. Remove the last 2 lines, and add: 131 | 132 | $this->smarty->display('pathToDisplay.tpl'); 133 | 134 | And then you're all set after that! Have fun and happy debugging! -------------------------------------------------------------------------------- /classes/Console.php: -------------------------------------------------------------------------------- 1 | array(), 21 | 'logCount' => 0, 22 | 'memoryCount' => 0, 23 | 'errorCount' => 0, 24 | 'speedCount' => 0); 25 | } 26 | 27 | /*----------------------------------- 28 | LOG A VARIABLE TO CONSOLE 29 | ------------------------------------*/ 30 | 31 | public static function log($data) { 32 | $logItem = array( 33 | "data" => $data, 34 | "type" => 'log' 35 | ); 36 | self::addToConsoleAndIncrement('logCount', $logItem); 37 | } 38 | 39 | /*--------------------------------------------------- 40 | LOG MEMORY USAGE OF VARIABLE OR ENTIRE SCRIPT 41 | -----------------------------------------------------*/ 42 | 43 | public static function logMemory($object = false, $name = 'PHP') { 44 | $memory = memory_get_usage(); 45 | if($object) $memory = strlen(serialize($object)); 46 | $logItem = array( 47 | "data" => $memory, 48 | "type" => 'memory', 49 | "name" => $name, 50 | "dataType" => gettype($object) 51 | ); 52 | self::addToConsoleAndIncrement('memoryCount', $logItem); 53 | } 54 | 55 | /*----------------------------------- 56 | LOG A PHP EXCEPTION OBJECT 57 | ------------------------------------*/ 58 | 59 | public static function logError($exception, $message) { 60 | $logItem = array( 61 | "data" => $message, 62 | "type" => 'error', 63 | "file" => $exception->getFile(), 64 | "line" => $exception->getLine() 65 | ); 66 | self::addToConsoleAndIncrement('errorCount', $logItem); 67 | } 68 | 69 | /*------------------------------------ 70 | POINT IN TIME SPEED SNAPSHOT 71 | -------------------------------------*/ 72 | 73 | public static function logSpeed($name = 'Point in Time') { 74 | $logItem = array( 75 | "data" => PhpQuickProfiler::getMicroTime(), 76 | "type" => 'speed', 77 | "name" => $name 78 | ); 79 | self::addToConsoleAndIncrement('speedCount', $logItem); 80 | } 81 | 82 | /*----------------------------------- 83 | RETURN & MODIFY LOGS 84 | ------------------------------------*/ 85 | 86 | public static function addToConsoleAndIncrement($log, $item) { 87 | if(!isset($GLOBALS['pqp_logs'])) self::init(); 88 | $GLOBALS['pqp_logs']['console'][] = $item; 89 | $GLOBALS['pqp_logs'][$log] += 1; 90 | } 91 | 92 | public function getLogs() { 93 | if(!isset($GLOBALS['pqp_logs'])) self::init(); 94 | return $GLOBALS['pqp_logs']; 95 | } 96 | 97 | } 98 | 99 | ?> -------------------------------------------------------------------------------- /classes/MySqlDatabase.php: -------------------------------------------------------------------------------- 1 | host = $host; 34 | $this->user = $user; 35 | $this->password = $password; 36 | } 37 | 38 | function connect($new = false) { 39 | $this->conn = mysql_connect($this->host, $this->user, $this->password, $new); 40 | if(!$this->conn) { 41 | throw new Exception('We\'re working on a few connection issues.'); 42 | } 43 | } 44 | 45 | function changeDatabase($database) { 46 | $this->database = $database; 47 | if($this->conn) { 48 | if(!mysql_select_db($database, $this->conn)) { 49 | throw new CustomException('We\'re working on a few connection issues.'); 50 | } 51 | } 52 | } 53 | 54 | function lazyLoadConnection() { 55 | $this->connect(true); 56 | if($this->database) $this->changeDatabase($this->database); 57 | } 58 | 59 | /*----------------------------------- 60 | QUERY 61 | ------------------------------------*/ 62 | 63 | function query($sql) { 64 | if(!$this->conn) $this->lazyLoadConnection(); 65 | $start = $this->getTime(); 66 | $rs = mysql_query($sql, $this->conn); 67 | $this->queryCount += 1; 68 | $this->logQuery($sql, $start); 69 | if(!$rs) { 70 | throw new Exception('Could not execute query.'); 71 | } 72 | return $rs; 73 | } 74 | 75 | /*----------------------------------- 76 | DEBUGGING 77 | ------------------------------------*/ 78 | 79 | public function logQuery($sql, $start) { 80 | $query = array( 81 | 'sql' => $sql, 82 | 'time' => ($this->getTime() - $start)*1000 83 | ); 84 | array_push($this->queries, $query); 85 | } 86 | 87 | public function getTime() { 88 | $time = microtime(); 89 | $time = explode(' ', $time); 90 | $time = $time[1] + $time[0]; 91 | $start = $time; 92 | return $start; 93 | } 94 | 95 | public function getReadableTime($time) { 96 | $ret = $time; 97 | $formatter = 0; 98 | $formats = array('ms', 's', 'm'); 99 | if($time >= 1000 && $time < 60000) { 100 | $formatter = 1; 101 | $ret = ($time / 1000); 102 | } 103 | if($time >= 60000) { 104 | $formatter = 2; 105 | $ret = ($time / 1000) / 60; 106 | } 107 | $ret = number_format($ret,3,'.','') . ' ' . $formats[$formatter]; 108 | return $ret; 109 | } 110 | 111 | function __destruct() { 112 | @mysql_close($this->conn); 113 | } 114 | 115 | } 116 | 117 | ?> 118 | -------------------------------------------------------------------------------- /classes/PhpQuickProfiler.php: -------------------------------------------------------------------------------- 1 | startTime = $startTime; 25 | $this->config = $config; 26 | require_once($_SERVER['DOCUMENT_ROOT'].$config.'classes/Console.php'); 27 | } 28 | 29 | /*------------------------------------------- 30 | FORMAT THE DIFFERENT TYPES OF LOGS 31 | -------------------------------------------*/ 32 | 33 | public function gatherConsoleData() { 34 | $logs = Console::getLogs(); 35 | if($logs['console']) { 36 | foreach($logs['console'] as $key => $log) { 37 | if($log['type'] == 'log') { 38 | $logs['console'][$key]['data'] = print_r($log['data'], true); 39 | } 40 | elseif($log['type'] == 'memory') { 41 | $logs['console'][$key]['data'] = $this->getReadableFileSize($log['data']); 42 | } 43 | elseif($log['type'] == 'speed') { 44 | $logs['console'][$key]['data'] = $this->getReadableTime(($log['data'] - $this->startTime)*1000); 45 | } 46 | } 47 | } 48 | $this->output['logs'] = $logs; 49 | } 50 | 51 | /*------------------------------------------- 52 | AGGREGATE DATA ON THE FILES INCLUDED 53 | -------------------------------------------*/ 54 | 55 | public function gatherFileData() { 56 | $files = get_included_files(); 57 | $fileList = array(); 58 | $fileTotals = array( 59 | "count" => count($files), 60 | "size" => 0, 61 | "largest" => 0, 62 | ); 63 | 64 | foreach($files as $key => $file) { 65 | $size = filesize($file); 66 | $fileList[] = array( 67 | 'name' => $file, 68 | 'size' => $this->getReadableFileSize($size) 69 | ); 70 | $fileTotals['size'] += $size; 71 | if($size > $fileTotals['largest']) $fileTotals['largest'] = $size; 72 | } 73 | 74 | $fileTotals['size'] = $this->getReadableFileSize($fileTotals['size']); 75 | $fileTotals['largest'] = $this->getReadableFileSize($fileTotals['largest']); 76 | $this->output['files'] = $fileList; 77 | $this->output['fileTotals'] = $fileTotals; 78 | } 79 | 80 | /*------------------------------------------- 81 | MEMORY USAGE AND MEMORY AVAILABLE 82 | -------------------------------------------*/ 83 | 84 | public function gatherMemoryData() { 85 | $memoryTotals = array(); 86 | $memoryTotals['used'] = $this->getReadableFileSize(memory_get_peak_usage()); 87 | $memoryTotals['total'] = ini_get("memory_limit"); 88 | $this->output['memoryTotals'] = $memoryTotals; 89 | } 90 | 91 | /*-------------------------------------------------------- 92 | QUERY DATA -- DATABASE OBJECT WITH LOGGING REQUIRED 93 | ----------------------------------------------------------*/ 94 | 95 | public function gatherQueryData() { 96 | $queryTotals = array(); 97 | $queryTotals['count'] = 0; 98 | $queryTotals['time'] = 0; 99 | $queries = array(); 100 | 101 | if($this->db != '') { 102 | $queryTotals['count'] += $this->db->queryCount; 103 | foreach($this->db->queries as $key => $query) { 104 | $query = $this->attemptToExplainQuery($query); 105 | $queryTotals['time'] += $query['time']; 106 | $query['time'] = $this->getReadableTime($query['time']); 107 | $queries[] = $query; 108 | } 109 | } 110 | 111 | $queryTotals['time'] = $this->getReadableTime($queryTotals['time']); 112 | $this->output['queries'] = $queries; 113 | $this->output['queryTotals'] = $queryTotals; 114 | } 115 | 116 | /*-------------------------------------------------------- 117 | CALL SQL EXPLAIN ON THE QUERY TO FIND MORE INFO 118 | ----------------------------------------------------------*/ 119 | 120 | function attemptToExplainQuery($query) { 121 | try { 122 | $sql = 'EXPLAIN '.$query['sql']; 123 | $rs = $this->db->query($sql); 124 | } 125 | catch(Exception $e) {} 126 | if($rs) { 127 | $row = mysql_fetch_array($rs, MYSQL_ASSOC); 128 | $query['explain'] = $row; 129 | } 130 | return $query; 131 | } 132 | 133 | /*------------------------------------------- 134 | SPEED DATA FOR ENTIRE PAGE LOAD 135 | -------------------------------------------*/ 136 | 137 | public function gatherSpeedData() { 138 | $speedTotals = array(); 139 | $speedTotals['total'] = $this->getReadableTime(($this->getMicroTime() - $this->startTime)*1000); 140 | $speedTotals['allowed'] = ini_get("max_execution_time"); 141 | $this->output['speedTotals'] = $speedTotals; 142 | } 143 | 144 | /*------------------------------------------- 145 | HELPER FUNCTIONS TO FORMAT DATA 146 | -------------------------------------------*/ 147 | 148 | function getMicroTime() { 149 | $time = microtime(); 150 | $time = explode(' ', $time); 151 | return $time[1] + $time[0]; 152 | } 153 | 154 | public function getReadableFileSize($size, $retstring = null) { 155 | // adapted from code at http://aidanlister.com/repos/v/function.size_readable.php 156 | $sizes = array('bytes', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); 157 | 158 | if ($retstring === null) { $retstring = '%01.2f %s'; } 159 | 160 | $lastsizestring = end($sizes); 161 | 162 | foreach ($sizes as $sizestring) { 163 | if ($size < 1024) { break; } 164 | if ($sizestring != $lastsizestring) { $size /= 1024; } 165 | } 166 | if ($sizestring == $sizes[0]) { $retstring = '%01d %s'; } // Bytes aren't normally fractional 167 | return sprintf($retstring, $size, $sizestring); 168 | } 169 | 170 | public function getReadableTime($time) { 171 | $ret = $time; 172 | $formatter = 0; 173 | $formats = array('ms', 's', 'm'); 174 | if($time >= 1000 && $time < 60000) { 175 | $formatter = 1; 176 | $ret = ($time / 1000); 177 | } 178 | if($time >= 60000) { 179 | $formatter = 2; 180 | $ret = ($time / 1000) / 60; 181 | } 182 | $ret = number_format($ret,3,'.','') . ' ' . $formats[$formatter]; 183 | return $ret; 184 | } 185 | 186 | /*--------------------------------------------------------- 187 | DISPLAY TO THE SCREEN -- CALL WHEN CODE TERMINATING 188 | -----------------------------------------------------------*/ 189 | 190 | public function display($db = '') { 191 | $this->db = $db; 192 | $this->gatherConsoleData(); 193 | $this->gatherFileData(); 194 | $this->gatherMemoryData(); 195 | $this->gatherQueryData(); 196 | $this->gatherSpeedData(); 197 | require_once($_SERVER['DOCUMENT_ROOT'].$this->config.'display.php'); 198 | displayPqp($this->output, $this->config); 199 | } 200 | 201 | } 202 | 203 | ?> -------------------------------------------------------------------------------- /classes/PqpDatabase.Interface.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /css/pQp.css: -------------------------------------------------------------------------------- 1 | /* - - - - - - - - - - - - - - - - - - - - - 2 | 3 | Title : PHP Quick Profiler CSS 4 | Author : Designed by Kevin Hale. 5 | URL : http://particletree.com 6 | 7 | Last Updated : April 21, 2009 8 | 9 | - - - - - - - - - - - - - - - - - - - - - */ 10 | 11 | .pQp{ 12 | width:100%; 13 | text-align:center; 14 | position:fixed; 15 | bottom:0; 16 | } 17 | * html .pQp{ 18 | position:absolute; 19 | } 20 | .pQp *{ 21 | margin:0; 22 | padding:0; 23 | border:none; 24 | } 25 | #pQp{ 26 | margin:0 auto; 27 | width:85%; 28 | min-width:960px; 29 | background-color:#222; 30 | border:12px solid #000; 31 | border-bottom:none; 32 | font-family:"Lucida Grande", Tahoma, Arial, sans-serif; 33 | -webkit-border-top-left-radius:15px; 34 | -webkit-border-top-right-radius:15px; 35 | -moz-border-radius-topleft:15px; 36 | -moz-border-radius-topright:15px; 37 | } 38 | #pQp .pqp-box h3{ 39 | font-weight:normal; 40 | line-height:200px; 41 | padding:0 15px; 42 | color:#fff; 43 | } 44 | .pQp, .pQp td{ 45 | color:#444; 46 | } 47 | 48 | /* ----- IDS ----- */ 49 | 50 | #pqp-metrics{ 51 | background:#000; 52 | width:100%; 53 | } 54 | #pqp-console, #pqp-speed, #pqp-queries, #pqp-memory, #pqp-files{ 55 | background:url(../images/overlay.gif); 56 | border-top:1px solid #ccc; 57 | height:200px; 58 | overflow:auto; 59 | } 60 | 61 | /* ----- Colors ----- */ 62 | 63 | .pQp .green{color:#588E13 !important;} 64 | .pQp .blue{color:#3769A0 !important;} 65 | .pQp .purple{color:#953FA1 !important;} 66 | .pQp .orange{color:#D28C00 !important;} 67 | .pQp .red{color:#B72F09 !important;} 68 | 69 | /* ----- Logic ----- */ 70 | 71 | #pQp, #pqp-console, #pqp-speed, #pqp-queries, #pqp-memory, #pqp-files{ 72 | display:none; 73 | } 74 | .pQp .console, .pQp .speed, .pQp .queries, .pQp .memory, .pQp .files{ 75 | display:block !important; 76 | } 77 | .pQp .console #pqp-console, .pQp .speed #pqp-speed, .pQp .queries #pqp-queries, 78 | .pQp .memory #pqp-memory, .pQp .files #pqp-files{ 79 | display:block; 80 | } 81 | .console td.green, .speed td.blue, .queries td.purple, .memory td.orange, .files td.red{ 82 | background:#222 !important; 83 | border-bottom:6px solid #fff !important; 84 | cursor:default !important; 85 | } 86 | 87 | .tallDetails #pQp .pqp-box{ 88 | height:500px; 89 | } 90 | .tallDetails #pQp .pqp-box h3{ 91 | line-height:500px; 92 | } 93 | .hideDetails #pQp .pqp-box{ 94 | display:none !important; 95 | } 96 | .hideDetails #pqp-footer{ 97 | border-top:1px dotted #444; 98 | } 99 | .hideDetails #pQp #pqp-metrics td{ 100 | height:50px; 101 | background:#000 !important; 102 | border-bottom:none !important; 103 | cursor:default !important; 104 | } 105 | .hideDetails #pQp var{ 106 | font-size:18px; 107 | margin:0 0 2px 0; 108 | } 109 | .hideDetails #pQp h4{ 110 | font-size:10px; 111 | } 112 | .hideDetails .heightToggle{ 113 | visibility:hidden; 114 | } 115 | 116 | /* ----- Metrics ----- */ 117 | 118 | #pqp-metrics td{ 119 | height:80px; 120 | width:20%; 121 | text-align:center; 122 | cursor:pointer; 123 | border:1px solid #000; 124 | border-bottom:6px solid #444; 125 | -webkit-border-top-left-radius:10px; 126 | -moz-border-radius-topleft:10px; 127 | -webkit-border-top-right-radius:10px; 128 | -moz-border-radius-topright:10px; 129 | } 130 | #pqp-metrics td:hover{ 131 | background:#222; 132 | border-bottom:6px solid #777; 133 | } 134 | #pqp-metrics .green{ 135 | border-left:none; 136 | } 137 | #pqp-metrics .red{ 138 | border-right:none; 139 | } 140 | 141 | #pqp-metrics h4{ 142 | text-shadow:#000 1px 1px 1px; 143 | } 144 | .side var{ 145 | text-shadow:#444 1px 1px 1px; 146 | } 147 | 148 | .pQp var{ 149 | font-size:23px; 150 | font-weight:bold; 151 | font-style:normal; 152 | margin:0 0 3px 0; 153 | display:block; 154 | } 155 | .pQp h4{ 156 | font-size:12px; 157 | color:#fff; 158 | margin:0 0 4px 0; 159 | } 160 | 161 | /* ----- Main ----- */ 162 | 163 | .pQp .main{ 164 | width:80%; 165 | } 166 | *+html .pQp .main{ 167 | width:78%; 168 | } 169 | * html .pQp .main{ 170 | width:77%; 171 | } 172 | .pQp .main td{ 173 | padding:7px 15px; 174 | text-align:left; 175 | background:#151515; 176 | border-left:1px solid #333; 177 | border-right:1px solid #333; 178 | border-bottom:1px dotted #323232; 179 | color:#FFF; 180 | } 181 | .pQp .main td, pre{ 182 | font-family:Monaco, "Consolas", "Lucida Console", "Courier New", monospace; 183 | font-size:11px; 184 | } 185 | .pQp .main td.alt{ 186 | background:#111; 187 | } 188 | .pQp .main tr.alt td{ 189 | background:#2E2E2E; 190 | border-top:1px dotted #4E4E4E; 191 | } 192 | .pQp .main tr.alt td.alt{ 193 | background:#333; 194 | } 195 | .pQp .main td b{ 196 | float:right; 197 | font-weight:normal; 198 | color:#E6F387; 199 | } 200 | .pQp .main td:hover{ 201 | background:#2E2E2E; 202 | } 203 | 204 | /* ----- Side ----- */ 205 | 206 | .pQp .side{ 207 | float:left; 208 | width:20%; 209 | background:#000; 210 | color:#fff; 211 | -webkit-border-bottom-left-radius:30px; 212 | -moz-border-radius-bottomleft:30px; 213 | text-align:center; 214 | } 215 | .pQp .side td{ 216 | padding:10px 0 5px 0; 217 | background:url(../images/side.png) repeat-y right; 218 | } 219 | .pQp .side var{ 220 | color:#fff; 221 | font-size:15px; 222 | } 223 | .pQp .side h4{ 224 | font-weight:normal; 225 | color:#F4FCCA; 226 | font-size:11px; 227 | } 228 | 229 | /* ----- Console ----- */ 230 | 231 | #pqp-console .side td{ 232 | padding:12px 0; 233 | } 234 | #pqp-console .side td.alt1{ 235 | background:#588E13; 236 | width:51%; 237 | } 238 | #pqp-console .side td.alt2{ 239 | background-color:#B72F09; 240 | } 241 | #pqp-console .side td.alt3{ 242 | background:#D28C00; 243 | border-bottom:1px solid #9C6800; 244 | border-left:1px solid #9C6800; 245 | -webkit-border-bottom-left-radius:30px; 246 | -moz-border-radius-bottomleft:30px; 247 | } 248 | #pqp-console .side td.alt4{ 249 | background-color:#3769A0; 250 | border-bottom:1px solid #274B74; 251 | } 252 | 253 | #pqp-console .main table{ 254 | width:100%; 255 | } 256 | #pqp-console td div{ 257 | width:100%; 258 | overflow:hidden; 259 | } 260 | #pqp-console td.type{ 261 | font-family:"Lucida Grande", Tahoma, Arial, sans-serif; 262 | text-align:center; 263 | text-transform: uppercase; 264 | font-size:9px; 265 | padding-top:9px; 266 | color:#F4FCCA; 267 | vertical-align:top; 268 | width:40px; 269 | } 270 | .pQp .log-log td.type{ 271 | background:#47740D !important; 272 | } 273 | .pQp .log-error td.type{ 274 | background:#9B2700 !important; 275 | } 276 | .pQp .log-memory td.type{ 277 | background:#D28C00 !important; 278 | } 279 | .pQp .log-speed td.type{ 280 | background:#2B5481 !important; 281 | } 282 | 283 | .pQp .log-log pre{ 284 | color:#999; 285 | } 286 | .pQp .log-log td:hover pre{ 287 | color:#fff; 288 | } 289 | 290 | .pQp .log-memory em, .pQp .log-speed em{ 291 | float:left; 292 | font-style:normal; 293 | display:block; 294 | color:#fff; 295 | } 296 | .pQp .log-memory pre, .pQp .log-speed pre{ 297 | float:right; 298 | white-space: normal; 299 | display:block; 300 | color:#FFFD70; 301 | } 302 | 303 | /* ----- Speed ----- */ 304 | 305 | #pqp-speed .side td{ 306 | padding:12px 0; 307 | } 308 | #pqp-speed .side{ 309 | background-color:#3769A0; 310 | } 311 | #pqp-speed .side td.alt{ 312 | background-color:#2B5481; 313 | border-bottom:1px solid #1E3C5C; 314 | border-left:1px solid #1E3C5C; 315 | -webkit-border-bottom-left-radius:30px; 316 | -moz-border-radius-bottomleft:30px; 317 | } 318 | 319 | /* ----- Queries ----- */ 320 | 321 | #pqp-queries .side{ 322 | background-color:#953FA1; 323 | border-bottom:1px solid #662A6E; 324 | border-left:1px solid #662A6E; 325 | } 326 | #pqp-queries .side td.alt{ 327 | background-color:#7B3384; 328 | } 329 | #pqp-queries .main b{ 330 | float:none; 331 | } 332 | #pqp-queries .main em{ 333 | display:block; 334 | padding:2px 0 0 0; 335 | font-style:normal; 336 | color:#aaa; 337 | } 338 | 339 | /* ----- Memory ----- */ 340 | 341 | #pqp-memory .side td{ 342 | padding:12px 0; 343 | } 344 | #pqp-memory .side{ 345 | background-color:#C48200; 346 | } 347 | #pqp-memory .side td.alt{ 348 | background-color:#AC7200; 349 | border-bottom:1px solid #865900; 350 | border-left:1px solid #865900; 351 | -webkit-border-bottom-left-radius:30px; 352 | -moz-border-radius-bottomleft:30px; 353 | } 354 | 355 | /* ----- Files ----- */ 356 | 357 | #pqp-files .side{ 358 | background-color:#B72F09; 359 | border-bottom:1px solid #7C1F00; 360 | border-left:1px solid #7C1F00; 361 | } 362 | #pqp-files .side td.alt{ 363 | background-color:#9B2700; 364 | } 365 | 366 | /* ----- Footer ----- */ 367 | 368 | #pqp-footer{ 369 | width:100%; 370 | background:#000; 371 | font-size:11px; 372 | border-top:1px solid #ccc; 373 | } 374 | #pqp-footer td{ 375 | padding:0 !important; 376 | border:none !important; 377 | } 378 | #pqp-footer strong{ 379 | color:#fff; 380 | } 381 | #pqp-footer a{ 382 | color:#999; 383 | padding:5px 10px; 384 | text-decoration:none; 385 | } 386 | #pqp-footer .credit{ 387 | width:20%; 388 | text-align:left; 389 | } 390 | #pqp-footer .actions{ 391 | width:80%; 392 | text-align:right; 393 | } 394 | #pqp-footer .actions a{ 395 | float:right; 396 | width:auto; 397 | } 398 | #pqp-footer a:hover, #pqp-footer a:hover strong, #pqp-footer a:hover b{ 399 | background:#fff; 400 | color:blue !important; 401 | text-decoration:underline; 402 | } 403 | #pqp-footer a:active, #pqp-footer a:active strong, #pqp-footer a:active b{ 404 | background:#ECF488; 405 | color:green !important; 406 | } -------------------------------------------------------------------------------- /display.php: -------------------------------------------------------------------------------- 1 | 24 | 128 | JAVASCRIPT; 129 | 130 | echo ''; 347 | 348 | } 349 | 350 | ?> -------------------------------------------------------------------------------- /images/overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wufoo/PHP-Quick-Profiler/331be5072f0b6e6fc924c119c6f4b4d7fd9f7116/images/overlay.gif -------------------------------------------------------------------------------- /images/side.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wufoo/PHP-Quick-Profiler/331be5072f0b6e6fc924c119c6f4b4d7fd9f7116/images/side.png -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | profiler = new PhpQuickProfiler(PhpQuickProfiler::getMicroTime()); 28 | } 29 | 30 | public function init() { 31 | $this->sampleConsoleData(); 32 | $this->sampleDatabaseData(); 33 | $this->sampleMemoryLeak(); 34 | $this->sampleSpeedComparison(); 35 | } 36 | 37 | /*------------------------------------------- 38 | EXAMPLES OF THE 4 CONSOLE FUNCTIONS 39 | -------------------------------------------*/ 40 | 41 | public function sampleConsoleData() { 42 | try { 43 | Console::log('Begin logging data'); 44 | Console::logMemory($this, 'PQP Example Class : Line '.__LINE__); 45 | Console::logSpeed('Time taken to get to line '.__LINE__); 46 | Console::log(array('Name' => 'Ryan', 'Last' => 'Campbell')); 47 | Console::logSpeed('Time taken to get to line '.__LINE__); 48 | Console::logMemory($this, 'PQP Example Class : Line '.__LINE__); 49 | Console::log('Ending log below with a sample error.'); 50 | throw new Exception('Unable to write to log!'); 51 | } 52 | catch(Exception $e) { 53 | Console::logError($e, 'Sample error logging.'); 54 | } 55 | } 56 | 57 | /*------------------------------------- 58 | DATABASE OBJECT TO LOG QUERIES 59 | --------------------------------------*/ 60 | 61 | public function sampleDatabaseData() { 62 | /*$this->db = new MySqlDatabase( 63 | 'your DB host', 64 | 'your DB user', 65 | 'your DB password'); 66 | $this->db->connect(true); 67 | $this->db->changeDatabase('your db name'); 68 | 69 | $sql = 'SELECT PostId FROM Posts WHERE PostId > 2'; 70 | $rs = $this->db->query($sql); 71 | 72 | $sql = 'SELECT COUNT(PostId) FROM Posts'; 73 | $rs = $this->db->query($sql); 74 | 75 | $sql = 'SELECT COUNT(PostId) FROM Posts WHERE PostId != 1'; 76 | $rs = $this->db->query($sql);*/ 77 | } 78 | 79 | /*----------------------------------- 80 | EXAMPLE MEMORY LEAK DETECTED 81 | ------------------------------------*/ 82 | 83 | public function sampleMemoryLeak() { 84 | $ret = ''; 85 | $longString = 'This is a really long string that when appended with the . symbol 86 | will cause memory to be duplicated in order to create the new string.'; 87 | for($i = 0; $i < 10; $i++) { 88 | $ret = $ret . $longString; 89 | Console::logMemory($ret, 'Watch memory leak -- iteration '.$i); 90 | } 91 | } 92 | 93 | /*----------------------------------- 94 | POINT IN TIME SPEED MARKS 95 | ------------------------------------*/ 96 | 97 | public function sampleSpeedComparison() { 98 | Console::logSpeed('Time taken to get to line '.__LINE__); 99 | Console::logSpeed('Time taken to get to line '.__LINE__); 100 | Console::logSpeed('Time taken to get to line '.__LINE__); 101 | Console::logSpeed('Time taken to get to line '.__LINE__); 102 | Console::logSpeed('Time taken to get to line '.__LINE__); 103 | Console::logSpeed('Time taken to get to line '.__LINE__); 104 | } 105 | 106 | public function __destruct() { 107 | $this->profiler->display($this->db); 108 | } 109 | 110 | } 111 | 112 | $pqp = new PQPExample(); 113 | $pqp->init(); 114 | 115 | ?> 116 | 117 | 119 | 120 | 121 | 122 | 123 | 124 | PHP Quick Profiler Demo 125 | 126 | 127 | 128 | 129 | 130 | 161 | 162 | 163 | 164 |
165 |

On this Page You Can See How to
Use the PHP Quick Profiler to...

166 | 167 | 174 | 175 | Return to Particletree. 176 |
177 | 178 | 179 | -------------------------------------------------------------------------------- /pqp.tpl: -------------------------------------------------------------------------------- 1 | 2 | {literal} 3 | 107 | {/literal} 108 | 109 | --------------------------------------------------------------------------------