├── .gitignore
├── .htaccess
├── FireLogger.php
├── composer.json
├── composer.lock
├── index.php
├── license.txt
├── readme.md
└── tests
├── ajax.php
├── backtrace.php
├── basic.php
├── iframe.php
├── issue_10.php
└── this_is_really_long_file_name.php
/.gitignore:
--------------------------------------------------------------------------------
1 | _layouts
2 | shared
3 | _site
4 | vendor
5 | composer.phar
6 |
--------------------------------------------------------------------------------
/.htaccess:
--------------------------------------------------------------------------------
1 | RewriteEngine on
2 | RewriteRule !^tests/ tests%{REQUEST_URI}
--------------------------------------------------------------------------------
/FireLogger.php:
--------------------------------------------------------------------------------
1 | log("info", "hello from ajax logger");
28 | // $ajax->log("have", "fun!");
29 | //
30 | // you may also use shortcut helper functions to log into default logger
31 | //
32 | // flog("Hello from PHP!");
33 | // fwarn("Warning, %s alert!", "gertruda");
34 | // ...
35 | //
36 | class FireLogger implements \Psr\Log\LoggerInterface {
37 | // global state kept under FireLogger "namespace"
38 | public static $enabled = true; // enabled by default, but see the code executed after class
39 | public static $counter = 0; // an aid for ordering log records on client
40 | public static $loggers = array(); // the array of all instantiated fire-loggers during request
41 | public static $default; // points to default logger
42 | public static $error; // points to error logger (for errors trigerred by PHP)
43 | public static $oldErrorHandler;
44 | public static $oldExceptionHandler;
45 | public static $clientVersion = '?';
46 | public static $recommendedClientVersion = '1.2';
47 |
48 | // logger instance data
49 | public $name; // [optional] logger name
50 | public $style; // [optional] CSS snippet for logger icon in FireLogger console
51 | public $logs = array(); // array of captured log records, this will be encoded into headers during
52 | public $levels = array('debug', 'warning', 'info', 'error', 'critical'); // well-known log levels (originated in Python)
53 |
54 | //------------------------------------------------------------------------------------------------------
55 | function __construct($name='logger', $style=null) {
56 | $this->name = $name;
57 | $this->style = $style;
58 | FireLogger::$loggers[] = $this;
59 | }
60 |
61 | public function error( $message, array $context = array() ) {
62 | $this->log(Psr\Log\LogLevel::ERROR, $message, $context);
63 | }
64 |
65 | public function alert( $message, array $context = array() ) {
66 | $this->log(Psr\Log\LogLevel::WARNING, $message, $context);
67 | }
68 |
69 | public function emergency( $message, array $context = array() ) {
70 | $this->log(Psr\Log\LogLevel::CRITICAL, $message, $context);
71 | }
72 |
73 | public function debug( $message, array $context = array() ) {
74 | $this->log(Psr\Log\LogLevel::DEBUG, $message, $context);
75 | }
76 |
77 | public function info( $message, array $context = array() ) {
78 | $this->log(Psr\Log\LogLevel::INFO, $message, $context);
79 | }
80 |
81 | public function critical( $message, array $context = array() ) {
82 | $this->log(Psr\Log\LogLevel::CRITICAL, $message, $context);
83 | }
84 |
85 | public function notice( $message, array $context = array() ) {
86 | $this->log(Psr\Log\LogLevel::INFO, $message, $context);
87 | }
88 |
89 | public function warning( $message, array $context = array() ) {
90 | $this->log(Psr\Log\LogLevel::WARNING, $message, $context);
91 | }
92 |
93 | public function log($level, $message, array $context = array() ) {
94 | switch($level) {
95 | case \Psr\Log\LogLevel::WARNING:
96 | case \Psr\Log\LogLevel::ALERT:
97 | $level = "warning";
98 | break;
99 | case \Psr\Log\LogLevel::EMERGENCY:
100 | case \Psr\Log\LogLevel::CRITICAL:
101 | $level = "critical";
102 | break;
103 | case \Psr\Log\LogLevel::DEBUG:
104 | $level = "debug";
105 | break;
106 | case \Psr\Log\LogLevel::ERROR:
107 | $level = "error";
108 | break;
109 | case \Psr\Log\LogLevel::INFO:
110 | $level = "info";
111 | break;
112 | case \Psr\Log\LogLevel::NOTICE:
113 | $level = "info";
114 | break;
115 | break;
116 | default:
117 | //throw new InvalidArgumentException("Level {$level} is not defined");
118 | }
119 |
120 | list($msg, $ctx) = $this->interpolate($message, $context);
121 | array_unshift($ctx, $level, $msg);
122 | call_user_func_array(array($this, 'firelog'), $ctx);
123 | }
124 |
125 | private function interpolate($message, array $context) {
126 | $fcontext = array();
127 |
128 | $fmessage = preg_replace_callback("/\{([\._A-Za-z0-9]+)\}/",
129 | function ($matches) use (&$context, &$fcontext) {
130 | if(isset($context[$matches[1]])) {
131 | $fcontext[] = $context[$matches[1]];
132 | return "%o";
133 | } else {
134 | return $matches[0];
135 | }
136 | },
137 | $message
138 | );
139 |
140 | return array($fmessage, $fcontext);
141 | }
142 |
143 | //------------------------------------------------------------------------------------------------------
144 | private function pickle($var, $level = 0) {
145 | if (is_bool($var) || is_null($var) || is_int($var) || is_float($var)) {
146 | return $var;
147 |
148 | } elseif (is_string($var)) {
149 | return @iconv('UTF-16', 'UTF-8//IGNORE', iconv(FIRELOGGER_ENCODING, 'UTF-16//IGNORE', $var)); // intentionally @
150 |
151 | } elseif (is_array($var)) {
152 | static $marker;
153 | if ($marker === NULL) $marker = uniqid("\x00", TRUE); // detects recursions
154 | if (isset($var[$marker])) {
155 | return '*RECURSION*';
156 |
157 | } elseif ($level < FIRELOGGER_MAX_PICKLE_DEPTH || !FIRELOGGER_MAX_PICKLE_DEPTH) {
158 | $var[$marker] = TRUE;
159 | $res = array();
160 | foreach ($var as $k => &$v) {
161 | if ($k !== $marker) $res[self::pickle($k)] = self::pickle($v, $level + 1);
162 | }
163 | unset($var[$marker]);
164 | return $res;
165 |
166 | } else {
167 | return '...';
168 | }
169 |
170 | } elseif (is_object($var)) {
171 | $arr = (array) $var;
172 | $arr['__class##'] = get_class($var);
173 |
174 | static $list = array(); // detects recursions
175 | if (in_array($var, $list, TRUE)) {
176 | return '*RECURSION*';
177 |
178 | } elseif ($level < FIRELOGGER_MAX_PICKLE_DEPTH || !FIRELOGGER_MAX_PICKLE_DEPTH) {
179 | $list[] = $var;
180 | $res = array();
181 | foreach ($arr as $k => &$v) {
182 | if ($k[0] === "\x00") {
183 | $k = substr($k, strrpos($k, "\x00") + 1);
184 | }
185 | $res[self::pickle($k)] = self::pickle($v, $level + 1);
186 | }
187 | array_pop($list);
188 | return $res;
189 |
190 | } else {
191 | return '...';
192 | }
193 |
194 | } elseif (is_resource($var)) {
195 | return '*' . get_resource_type($var) . ' resource*';
196 |
197 | } else {
198 | return '*unknown type*';
199 | }
200 | }
201 | //------------------------------------------------------------------------------------------------------
202 | private function extract_file_line($trace) {
203 | while (count($trace) && !array_key_exists('file', $trace[0])) array_shift($trace);
204 | $thisFile = $trace[0]['file'];
205 | while (count($trace) && (array_key_exists('file', $trace[0]) && $trace[0]['file']==$thisFile)) array_shift($trace);
206 | while (count($trace) && !array_key_exists('file', $trace[0])) array_shift($trace);
207 |
208 | if (count($trace)==0) return array("?", "0");
209 | $file = $trace[0]['file'];
210 | $line = $trace[0]['line'];
211 | return array($file, $line);
212 | }
213 | //------------------------------------------------------------------------------------------------------
214 | private function extract_trace($trace) {
215 | $t = array();
216 | $f = array();
217 | foreach ($trace as $frame) {
218 | // prevent notices about invalid indices, wasn't able to google smart solution, PHP is dumb ass
219 | $frame += array('file' => null, 'line' => null, 'class' => null, 'type' => null, 'function' => null, 'object' => null, 'args' => null);
220 | $t[] = array(
221 | $frame['file'],
222 | $frame['line'],
223 | $frame['class'].$frame['type'].$frame['function'],
224 | $frame['object']
225 | );
226 | $f[] = $frame['args'];
227 | };
228 | return array($t, $f);
229 | }
230 | //------------------------------------------------------------------------------------------------------
231 | function firelog(/*level, fmt, obj1, obj2, ...*/) {
232 | if (!FireLogger::$enabled) return; // no-op
233 |
234 | $args = func_get_args();
235 | $fmt = '';
236 | $level = 'debug';
237 | if (is_string($args[0]) && in_array($args[0], $this->levels)) {
238 | $level = array_shift($args);
239 | }
240 | if (is_string($args[0])) {
241 | $fmt = array_shift($args);
242 | }
243 |
244 | $time = microtime(true);
245 | $item = array(
246 | 'name' => $this->name,
247 | 'args' => array(),
248 | 'level' => $level,
249 | 'timestamp' => $time,
250 | 'order' => FireLogger::$counter++, // PHP is really fast, timestamp has insufficient resolution for log records ordering
251 | 'time' => gmdate('H:i:s', (int)$time).'.'.substr(fmod($time, 1.0), 2, 3), // '23:53:13.396'
252 | 'template' => $fmt,
253 | 'message' => $fmt // TODO: render reasonable plain text message
254 | );
255 | if ($this->style) $item['style'] = $this->style;
256 | if (count($args) && $args[0] instanceof Exception) {
257 | // exception with backtrace
258 | $e = $args[0];
259 | $trace = $e->getTrace();
260 | $ti = $this->extract_trace($trace);
261 | $item['exc_info'] = array(
262 | $e->getMessage(),
263 | $e->getFile(),
264 | $ti[0]
265 | );
266 | $item['exc_frames'] = $ti[1];
267 | $item['exc_text'] = 'exception';
268 | $item['template'] = $e->getMessage();
269 | $item['code'] = $e->getCode();
270 | $item['pathname'] = $e->getFile();
271 | $item['lineno'] = $e->getLine();
272 | } else {
273 | // rich log record
274 | $trace = debug_backtrace();
275 | list($file, $line) = $this->extract_file_line($trace);
276 | $data = array();
277 | $item['pathname'] = $file;
278 | $item['lineno'] = $line;
279 | foreach ($args as $arg) {
280 | // override file/line in case we've got passed FireLoggerFileLine
281 | if ($arg instanceof FireLoggerFileLine) {
282 | $item['pathname'] = $arg->file;
283 | $item['lineno'] = $arg->line;
284 | continue; // do not process this arg
285 | }
286 | // override backtrace in case we've got passed FireLoggerBacktrace
287 | if ($arg instanceof FireLoggerBacktrace) {
288 | $ti = $this->extract_trace($arg->trace);
289 | $item['exc_info'] = array(
290 | '',
291 | '',
292 | $ti[0]
293 | );
294 | $item['exc_frames'] = $ti[1];
295 | continue; // do not process this arg
296 | }
297 | $data[] = $arg;
298 | }
299 | $item['args'] = $data;
300 | }
301 |
302 | $this->logs[] = self::pickle($item);
303 | }
304 | //------------------------------------------------------------------------------------------------------
305 | static function firelogger_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
306 | if (headers_sent()) {
307 | return false; // calls default error handler
308 | }
309 |
310 | if (!defined('FIRELOGGER_NO_ERROR_FILTERING')) {
311 | // FIRELOGGER_NO_ERROR_FILTERING causes error_reporting() settings will have no effect
312 | if (!($errno & error_reporting())) return;
313 | }
314 |
315 | $errors = array(
316 | E_WARNING => 'Warning',
317 | E_USER_WARNING => 'Warning',
318 | E_NOTICE => 'Notice',
319 | E_USER_NOTICE => 'Notice',
320 | E_STRICT => 'Strict standards',
321 | E_DEPRECATED => 'Deprecated',
322 | E_USER_DEPRECATED => 'Deprecated',
323 | );
324 | $no = isset($errors[$errno]) ? $errors[$errno] : 'Unknown error';
325 | FireLogger::$error->firelog('warning', "$no: $errstr", new FireLoggerFileLine($errfile, $errline), new FireLoggerBacktrace(debug_backtrace()));
326 | }
327 | //------------------------------------------------------------------------------------------------------
328 | //
329 | // Encoding handler
330 | // * collects all log messages from all FireLogger instances
331 | // * encodes them into HTTP headers
332 | //
333 | // see protocol specs at http://wiki.github.com/darwin/firelogger
334 | //
335 | static function handler() {
336 | if (headers_sent($file, $line)) {
337 | trigger_error("Cannot send FireLogger headers after output have been sent" . ($file ? " (output started at $file:$line)." : "."), E_USER_WARNING);
338 | return;
339 | }
340 |
341 | // detector for fatal errors
342 | if (function_exists('error_get_last')) {
343 | $error = error_get_last();
344 | if (in_array($error['type'], array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE))) {
345 | FireLogger::$default->firelog(new ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']));
346 | }
347 | }
348 |
349 | $logs = array();
350 | foreach (FireLogger::$loggers as $logger) {
351 | $logs = array_merge($logs, $logger->logs);
352 | }
353 |
354 | // final encoding
355 | $id = dechex(mt_rand(0, 0xFFFF)).dechex(mt_rand(0, 0xFFFF)); // mt_rand is not working with 0xFFFFFFFF
356 | $json = json_encode(array('logs' => $logs));
357 | $res = str_split(base64_encode($json), 76); // RFC 2045
358 |
359 | foreach($res as $k=>$v) {
360 | header("FireLogger-$id-$k:$v");
361 | }
362 | }
363 | }
364 |
365 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
366 | // helper class for passing file/line override into log methods
367 | class FireLoggerFileLine {
368 | public $file;
369 | public $line;
370 | function __construct($file, $line) {
371 | $this->file = $file;
372 | $this->line = $line;
373 | }
374 | }
375 |
376 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
377 | // helper class for passing backtrace override into log methods
378 | class FireLoggerBacktrace {
379 | public $trace;
380 | function __construct($trace) {
381 | $this->trace = $trace;
382 | }
383 | }
384 |
385 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
386 | // decide if firelogger should be enabled
387 | if (!defined('FIRELOGGER_NO_VERSION_CHECK')) {
388 | if (!isset($_SERVER['HTTP_X_FIRELOGGER'])) {
389 | FireLogger::$enabled = false;
390 | } else {
391 | FireLogger::$clientVersion = $_SERVER['HTTP_X_FIRELOGGER'];
392 | if (FireLogger::$clientVersion!=FireLogger::$recommendedClientVersion) {
393 | error_log("FireLogger for PHP (v".FIRELOGGER_VERSION.") works best with FireLogger extension of version ".FireLogger::$recommendedClientVersion.". You are currently using extension v".FireLogger::$clientVersion.". Please visit the homepage and install matching versions => http://firelogger.binaryage.com/php");
394 | }
395 | }
396 | }
397 |
398 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
399 | // test if firelogger password matches
400 | if (!defined('FIRELOGGER_NO_PASSWORD_CHECK') && defined('FIRELOGGER_PASSWORD') && FireLogger::$enabled) {
401 | if (isset($_SERVER['HTTP_X_FIRELOGGERAUTH'])) {
402 | $clientHash = $_SERVER['HTTP_X_FIRELOGGERAUTH'];
403 | $serverHash = md5("#FireLoggerPassword#".FIRELOGGER_PASSWORD."#");
404 | if ($clientHash!==$serverHash) { // passwords do not match
405 | FireLogger::$enabled = false;
406 | trigger_error("FireLogger password do not match. Have you specified correct password FireLogger extension?");
407 | }
408 | } else {
409 | FireLogger::$enabled = false; // silently disable firelogger in case client didn't provide requested password
410 | }
411 | }
412 |
413 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
414 | // register default logger for convenience
415 | if (!defined('FIRELOGGER_NO_OUTPUT_HANDLER')) {
416 | if (FireLogger::$enabled) ob_start(); // start output buffering (in case firelogger should be enabled)
417 | }
418 |
419 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
420 | // register default logger for convenience
421 | if (!defined('FIRELOGGER_NO_DEFAULT_LOGGER')) {
422 | FireLogger::$default = new FireLogger('php', 'background-color: #767ab6'); // register default firelogger with official PHP logo color :-)
423 | }
424 |
425 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
426 | // shortcut functions for convenience
427 | if (!defined('FIRELOGGER_NO_CONFLICT')) {
428 | function flog(/*fmt, obj1, obj2, ...*/) {
429 | $args = func_get_args();
430 | call_user_func_array(array(FireLogger::$default, 'firelog'), $args);
431 | }
432 | function fwarn(/*fmt, obj1, obj2, ...*/) {
433 | $args = func_get_args();
434 | array_unshift($args, 'warning');
435 | call_user_func_array(array(FireLogger::$default, 'firelog'), $args);
436 | }
437 | function ferror(/*fmt, obj1, obj2, ...*/) {
438 | $args = func_get_args();
439 | array_unshift($args, 'error');
440 | call_user_func_array(array(FireLogger::$default, 'firelog'), $args);
441 | }
442 | function finfo(/*fmt, obj1, obj2, ...*/) {
443 | $args = func_get_args();
444 | array_unshift($args, 'info');
445 | call_user_func_array(array(FireLogger::$default, 'firelog'), $args);
446 | }
447 | function fcritical(/*fmt, obj1, obj2, ...*/) {
448 | $args = func_get_args();
449 | array_unshift($args, 'critical');
450 | call_user_func_array(array(FireLogger::$default, 'firelog'), $args);
451 | }
452 | }
453 |
454 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
455 | // register global handler for uncaught exceptions
456 | if (!defined('FIRELOGGER_NO_EXCEPTION_HANDLER')) {
457 | FireLogger::$oldExceptionHandler = set_exception_handler(array(FireLogger::$default, 'firelog'));
458 | }
459 |
460 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
461 | // register global handler for errors
462 | if (!defined('FIRELOGGER_NO_ERROR_HANDLER')) {
463 | FireLogger::$error = new FireLogger('error', 'background-color: #f00');
464 | FireLogger::$oldErrorHandler = set_error_handler(array('FireLogger', 'firelogger_error_handler'));
465 | }
466 |
467 | // enable encoding handler
468 | if (FireLogger::$enabled) register_shutdown_function(array('FireLogger', 'handler'));
469 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "binaryage/firelogger",
3 | "version": "0.0.1",
4 | "require" : {
5 | "psr/log": "1.0.0"
6 | },
7 | "autoload" : {
8 | "psr-0": { "FireLogger": "" }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
5 | ],
6 | "hash": "c42d195722b9106eed38be9045afeb3d",
7 | "packages": [
8 | {
9 | "name": "psr/log",
10 | "version": "1.0.0",
11 | "source": {
12 | "type": "git",
13 | "url": "https://github.com/php-fig/log",
14 | "reference": "1.0.0"
15 | },
16 | "dist": {
17 | "type": "zip",
18 | "url": "https://github.com/php-fig/log/archive/1.0.0.zip",
19 | "reference": "1.0.0",
20 | "shasum": ""
21 | },
22 | "type": "library",
23 | "autoload": {
24 | "psr-0": {
25 | "Psr\\Log\\": ""
26 | }
27 | },
28 | "notification-url": "https://packagist.org/downloads/",
29 | "license": [
30 | "MIT"
31 | ],
32 | "authors": [
33 | {
34 | "name": "PHP-FIG",
35 | "homepage": "http://www.php-fig.org/"
36 | }
37 | ],
38 | "description": "Common interface for logging libraries",
39 | "keywords": [
40 | "log",
41 | "psr",
42 | "psr-3"
43 | ],
44 | "time": "2012-12-21 11:40:51"
45 | }
46 | ],
47 | "packages-dev": [
48 |
49 | ],
50 | "aliases": [
51 |
52 | ],
53 | "minimum-stability": "stable",
54 | "stability-flags": [
55 |
56 | ],
57 | "platform": [
58 |
59 | ],
60 | "platform-dev": [
61 |
62 | ]
63 | }
64 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | Software License Agreement (BSD License)
2 |
3 | Copyright (c) 2009, Antonin Hildebrand
4 | All rights reserved.
5 |
6 | Redistribution and use of this software in source and binary forms, with or without modification,
7 | are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above
10 | copyright notice, this list of conditions and the
11 | following disclaimer.
12 |
13 | * Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the
15 | following disclaimer in the documentation and/or other
16 | materials provided with the distribution.
17 |
18 | * Neither the name of Antonin Hildebrand nor the names of its
19 | contributors may be used to endorse or promote products
20 | derived from this software without specific prior
21 | written permission of Antonin Hildebrand.
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
24 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
25 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
26 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # FireLogger for PHP
2 |
3 | FireLogger is a sexy PHP logger console integrated into Firebug (an alternative to FirePHP).
4 |
5 |
6 |
7 | ## Visit [firelogger.binaryage.com](http://firelogger.binaryage.com)
--------------------------------------------------------------------------------
/tests/ajax.php:
--------------------------------------------------------------------------------
1 |
7 | Hello World! #
8 |
9 | exit;
10 | }
11 | ?>
12 |
13 |
14 |
$code"; 61 | 62 | eval($code); 63 | ?> 64 | 65 | -------------------------------------------------------------------------------- /tests/iframe.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 |
$code"; 20 | eval($code); 21 | ?> 22 | 23 | 24 | 25 | 32 | 33 | 34 |