Overview

Packages

  • Jyxo_Beholder
  • Jyxo_Charset
  • Jyxo_Color
  • Jyxo_Css
  • Jyxo_ErrorHandling
  • Jyxo_FirePhp
  • Jyxo_Gettext
    • Parser
  • Jyxo_Html
  • Jyxo_Input
    • Chain
    • Filter
    • Validator
  • Jyxo_Mail
    • Email
    • Parser
    • Sender
  • Jyxo_Rpc
    • Json
    • Xml
  • Jyxo_Shell
  • Jyxo_SpamFilter
  • Jyxo_Spl
  • Jyxo_String
  • Jyxo_Svn
  • Jyxo_Time
  • Jyxo_Timer
  • Jyxo_Webdav
  • Jyxo_XmlReader
  • PHP

Classes

  • Jyxo_FirePhp
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * Jyxo PHP Library
  5:  *
  6:  * LICENSE
  7:  *
  8:  * This source file is subject to the new BSD license that is bundled
  9:  * with this package in the file license.txt.
 10:  * It is also available through the world-wide-web at this URL:
 11:  * https://github.com/jyxo/php/blob/master/license.txt
 12:  */
 13: 
 14: /**
 15:  * Class for sending information to FirePHP.
 16:  *
 17:  * @category Jyxo
 18:  * @package Jyxo_FirePhp
 19:  * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
 20:  * @license https://github.com/jyxo/php/blob/master/license.txt
 21:  * @author Jaroslav HanslĂ­k
 22:  */
 23: class Jyxo_FirePhp
 24: {
 25:     /**
 26:      * Type information.
 27:      *
 28:      * @var string
 29:      */
 30:     const INFO = 'INFO';
 31: 
 32:     /**
 33:      * Type warning.
 34:      *
 35:      * @var string
 36:      */
 37:     const WARNING = 'WARN';
 38: 
 39:     /**
 40:      * Type error.
 41:      *
 42:      * @var string
 43:      */
 44:     const ERROR = 'ERROR';
 45: 
 46:     /**
 47:      * Type log.
 48:      *
 49:      * @var string
 50:      */
 51:     const LOG = 'LOG';
 52: 
 53:     /**
 54:      * Type trace.
 55:      *
 56:      * @var string
 57:      */
 58:     const TRACE = 'TRACE';
 59: 
 60:     /**
 61:      * Type table.
 62:      *
 63:      * @var string
 64:      */
 65:     const TABLE = 'TABLE';
 66: 
 67:     /**
 68:      * Is logging enabled.
 69:      *
 70:      * @var boolean
 71:      */
 72:     private static $enabled = true;
 73: 
 74:     /**
 75:      * Sets if logging id enabled.
 76:      *
 77:      * @param boolean $flag Is logging enabled
 78:      */
 79:     public static function setEnabled($flag = true)
 80:     {
 81:         self::$enabled = (bool) $flag;
 82:     }
 83: 
 84:     /**
 85:      * Dumps a variable.
 86:      *
 87:      * @param mixed $variable Variable
 88:      * @param string $label Variable label
 89:      * @return boolean
 90:      */
 91:     public static function dump($variable, $label = '')
 92:     {
 93:         return self::log($variable, (string) $label);
 94:     }
 95: 
 96:     /**
 97:      * Sends an information message.
 98:      *
 99:      * @param string $message Message text
100:      * @param string $label Message label
101:      * @return boolean
102:      */
103:     public static function info($message, $label = '')
104:     {
105:         return self::log((string) $message, (string) $label, self::INFO);
106:     }
107: 
108:     /**
109:      * Sends a warning.
110:      *
111:      * @param string $message Message text
112:      * @param string $label Message label
113:      * @return boolean
114:      */
115:     public static function warning($message, $label = '')
116:     {
117:         return self::log((string) $message, (string) $label, self::WARNING);
118:     }
119: 
120:     /**
121:      * Sends an error.
122:      *
123:      * @param string $message Message text
124:      * @param string $label Message label
125:      * @return boolean
126:      */
127:     public static function error($message, $label = '')
128:     {
129:         return self::log((string) $message, (string) $label, self::ERROR);
130:     }
131: 
132:     /**
133:      * Sends a log message.
134:      *
135:      * @param mixed $message Message text
136:      * @param string $label Message label
137:      * @param string $type Message type
138:      * @return boolean
139:      */
140:     public static function log($message, $label = '', $type = self::LOG)
141:     {
142:         $output = array(
143:             array(
144:                 'Type' => $type,
145:                 'Label' => $label
146:             ),
147:             self::encodeVariable($message)
148:         );
149: 
150:         return self::send($output);
151:     }
152: 
153:     /**
154:      * Sends a trace.
155:      *
156:      * @param string $message Message text
157:      * @param string $file File name
158:      * @param integer $line File line
159:      * @param array $trace Trace
160:      * @return boolean
161:      */
162:     public static function trace($message, $file, $line, array $trace)
163:     {
164:         $output = array(
165:             array(
166:                 'Type' => self::TRACE,
167:                 'Label' => null
168:             ),
169:             array(
170:                 'Message' => Jyxo_Charset::fixUtf($message),
171:                 'File' => $file,
172:                 'Line' => $line,
173:                 'Trace' => self::replaceVariable($trace)
174:             )
175:         );
176: 
177:         return self::send($output);
178:     }
179: 
180:     /**
181:      * Sends a table.
182:      *
183:      * @param string $label Message label
184:      * @param array $header Table header
185:      * @param array $data Table data
186:      * @param string $ident Unique identifier
187:      * @return boolean
188:      */
189:     public static function table($label, array $header, array $data, $ident = '')
190:     {
191:         $output = array(
192:             array(
193:                 'Type' => self::TABLE,
194:                 'Label' => $label
195:             ),
196:             array_merge(array($header), $data)
197:         );
198: 
199:         return self::send($output, $ident);
200:     }
201: 
202:     /**
203:      * Logs an exception.
204:      *
205:      * @param Exception $e Exception to log
206:      * @return boolean First exception sending result
207:      */
208:     public static function exception(Exception $e)
209:     {
210:         $result = self::trace(
211:             'Exception: ' . $e->getMessage() . ' [' . $e->getCode() . ']',
212:             $e->getFile(),
213:             $e->getLine(),
214:             $e->getTrace()
215:         );
216:         while ($e = $e->getPrevious()) {
217:             self::trace(
218:                 'Previous exception: ' . $e->getMessage() . ' [' . $e->getCode() . ']',
219:                 $e->getFile(),
220:                 $e->getLine(),
221:                 $e->getTrace()
222:             );
223:         }
224:         return $result;
225:     }
226: 
227:     /**
228:      * Sends output.
229:      *
230:      * @param array $output Output
231:      * @param string $ident Message identifier
232:      * @return boolean
233:      */
234:     private static function send(array $output, $ident = '')
235:     {
236:         // Headers were already sent, can not proceed
237:         if (headers_sent()) {
238:             return false;
239:         }
240: 
241:         // Logging is disabled
242:         if (!self::$enabled) {
243:             return false;
244:         }
245: 
246:         // Sending only if FirePHP is installed
247:         if (!self::isInstalled()) {
248:             return false;
249:         }
250: 
251:         // Sent headers count
252:         static $no = 0;
253: 
254:         // Adding filename and line where logging was called
255:         $first = reset($output);
256:         if (empty($first['File'])) {
257:             // Cut message information
258:             $first = array_shift($output);
259: 
260:             // Find file
261:             $backtrace = debug_backtrace();
262:             $hop = array_shift($backtrace);
263: 
264:             // Remove Jyxo_FirePhp call
265:             while (__FILE__ === $hop['file']) {
266:                 $hop = array_shift($backtrace);
267:             }
268: 
269:             // Add file information
270:             $first['File'] = $hop['file'];
271:             $first['Line'] = $hop['line'];
272: 
273:             // And return altered information back
274:             array_unshift($output, $first);
275:         }
276: 
277:         // Splitting result
278:         $parts = str_split(json_encode($output), 5000);
279: 
280:         // If an identifier was provided, delete previous messages with that identifier
281:         if (!empty($ident)) {
282:             static $idents = array();
283: 
284:             // Delete previous send
285:             if (isset($idents[$ident])) {
286:                 for ($i = $idents[$ident][0]; $i <= $idents[$ident][1]; $i++) {
287:                     header_remove('X-Wf-Jyxo-1-1-Jyxo' . $i);
288:                 }
289:             }
290: 
291:             // Save identifiers of headers that will be actually used
292:             $idents[$ident] = array($no + 1, $no + count($parts));
293:         }
294: 
295:         // Sending
296:         header('X-Wf-Protocol-Jyxo: http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
297:         header('X-Wf-Jyxo-Structure-1: http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
298:         header('X-Wf-Jyxo-Plugin-1: http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3');
299:         foreach ($parts as $part) {
300:             $no++;
301:             header(sprintf('X-Wf-Jyxo-1-1-Jyxo%s: |%s|\\', $no, $part));
302:         }
303:         // Last one is sent again but without \
304:         header(sprintf('X-Wf-Jyxo-1-1-Jyxo%s: |%s|', $no, $part));
305: 
306:         return true;
307:     }
308: 
309:     /**
310:      * Checks if FirePHP extension is installed.
311:      *
312:      * @return boolean
313:      */
314:     private static function isInstalled()
315:     {
316:         // Header X-FirePHP-Version
317:         if (isset($_SERVER['HTTP_X_FIREPHP_VERSION'])) {
318:             return true;
319:         }
320: 
321:         // Header x-insight
322:         if (isset($_SERVER['HTTP_X_INSIGHT']) && 'activate' === $_SERVER['HTTP_X_INSIGHT']) {
323:             return true;
324:         }
325: 
326:         // Modified user-agent
327:         if (isset($_SERVER['HTTP_USER_AGENT']) && false !== strpos($_SERVER['HTTP_USER_AGENT'], 'FirePHP/')) {
328:             return true;
329:         }
330: 
331:         // Not installed
332:         return false;
333:     }
334: 
335:     /**
336:      * Replaces objects with appropriate names in variable.
337:      *
338:      * @param mixed $variable Variable where to replace objects
339:      * @return mixed
340:      */
341:     private static function replaceVariable($variable)
342:     {
343:         if (is_object($variable)) {
344:             return 'object ' . get_class($variable);
345:         } elseif (is_resource($variable)) {
346:             return (string) $variable;
347:         } elseif (is_array($variable)) {
348:             foreach ($variable as $k => $v) {
349:                 unset($variable[$k]);
350:                 $variable[$k] = self::replaceVariable($v);
351:             }
352:             return $variable;
353:         } else {
354:             return $variable;
355:         }
356:     }
357: 
358:     /**
359:      * Encodes a variable.
360:      *
361:      * @param mixed $variable Variable to be encoded
362:      * @param integer $objectDepth Current object traversal depth
363:      * @param integer $arrayDepth Current array traversal depth
364:      * @param integer $totalDepth Current total traversal depth
365:      * @return array
366:      */
367:     private static function encodeVariable($variable, $objectDepth = 1, $arrayDepth = 1, $totalDepth = 1)
368:     {
369:         static $maxObjectDepth = 5;
370:         static $maxArrayDepth = 5;
371:         static $maxTotalDepth = 10;
372:         static $stack = array();
373: 
374:         if ($totalDepth > $maxTotalDepth) {
375:             return sprintf('** Max Depth (%s) **', $maxTotalDepth);
376:         }
377: 
378:         if (is_resource($variable)) {
379:             return sprintf('** %s **', (string) $variable);
380:         } elseif (is_object($variable)) {
381:             if ($objectDepth > $maxObjectDepth) {
382:                 return sprintf('** Max Object Depth (%s) **', $maxObjectDepth);
383:             }
384: 
385:             $class = get_class($variable);
386: 
387:             // Check recursion
388:             foreach ($stack as $item) {
389:                 if ($item === $variable) {
390:                     return sprintf('** Recursion (%s) **', $class);
391:                 }
392:             }
393:             array_push($stack, $variable);
394: 
395:             // Add class name
396:             $return = array('__className' => $class);
397: 
398:             // Add properties
399:             $reflectionClass = new ReflectionClass($class);
400:             foreach ($reflectionClass->getProperties() as $property) {
401:                 $name = $property->getName();
402:                 $rawName = $name;
403: 
404:                 if ($property->isStatic()) {
405:                     $name = 'static:' . $name;
406:                 }
407: 
408:                 if ($property->isPublic()) {
409:                     $name = 'public:' . $name;
410:                 } elseif ($property->isProtected()) {
411:                     $name = 'protected:' . $name;
412:                     $rawName = "\0" . '*' . "\0" . $rawName;
413:                 } elseif ($property->isPrivate()) {
414:                     $name = 'private:' . $name;
415:                     $rawName = "\0" . $class . "\0" . $rawName;
416:                 }
417: 
418:                 if (!$property->isPublic()) {
419:                     $property->setAccessible(true);
420:                 }
421:                 $return[$name] = self::encodeVariable($property->getValue($variable), $objectDepth + 1, 1, $totalDepth + 1);
422:             }
423: 
424:             // Add members that are not defined in the class but exist in the object
425:             $members = (array) $variable;
426:             foreach ($members as $rawName => $member) {
427:                 $name = $rawName;
428:                 if ("\0" === $name[0]) {
429:                     $parts = explode("\0", $name);
430:                     $name = $parts[2];
431:                 }
432:                 if (!$reflectionClass->hasProperty($name)) {
433:                     $name = 'undeclared:' . $name;
434:                     $return[$name] = self::encodeVariable($member, $objectDepth + 1, 1, $totalDepth + 1);
435:                 }
436:             }
437:             unset($members);
438: 
439:             array_pop($stack);
440: 
441:             return $return;
442:         } elseif (is_array($variable)) {
443:             if ($arrayDepth > $maxArrayDepth) {
444:                 return sprintf('** Max Array Depth (%s) **', $maxArrayDepth);
445:             }
446: 
447:             $return = array();
448:             foreach ($variable as $k => $v) {
449:                 // Encoding the $GLOBALS PHP array causes an infinite loop as it contains a reference to itself
450:                 if ('GLOBALS' === $k && is_array($v) && array_key_exists('GLOBALS', $v)) {
451:                     $v['GLOBALS'] = '** Recursion (GLOBALS) **';
452:                 }
453:                 $return[$k] = self::encodeVariable($v, 1, $arrayDepth + 1, $totalDepth + 1);
454:             }
455: 
456:             return $return;
457:         } else {
458:             return $variable;
459:         }
460:     }
461: }
462: 
Jyxo PHP Library API documentation generated by ApiGen 2.3.0