Overview

Namespaces

  • Jyxo
    • Beholder
      • TestCase
    • Gettext
      • Parser
    • Input
      • Chain
      • Filter
      • Validator
    • Mail
      • Email
        • Attachment
      • Parser
      • Sender
    • Rpc
      • Json
      • Xml
    • Shell
    • Spl
    • Svn
    • Time
    • Webdav
  • PHP

Classes

  • Charset
  • Color
  • Css
  • ErrorHandler
  • ErrorMail
  • FirePhp
  • Html
  • HtmlTag
  • SpamFilter
  • String
  • Timer
  • XmlReader

Exceptions

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