diff --git a/application/controllers/adif.php b/application/controllers/adif.php
index 197a6f40..7671e1e4 100644
--- a/application/controllers/adif.php
+++ b/application/controllers/adif.php
@@ -66,7 +66,8 @@ class adif extends CI_Controller {
}
}
- public function import() {
+ public function import() {
+
$data['page_title'] = "ADIF Import";
$config['upload_path'] = './uploads/';
diff --git a/application/controllers/logbook.php b/application/controllers/logbook.php
index 67025562..49d148f6 100644
--- a/application/controllers/logbook.php
+++ b/application/controllers/logbook.php
@@ -224,6 +224,7 @@ class Logbook extends CI_Controller {
if(!$this->user_model->authorize($this->config->item('auth_mode'))) { return; }
$this->db->like('COL_CALL', $id);
+ $this->db->order_by("COL_TIME_ON", "desc");
$this->db->limit(16);
$query = $this->db->get($this->config->item('table_name'));
@@ -270,6 +271,7 @@ class Logbook extends CI_Controller {
$this->db->like('COL_CALL', $id);
$this->db->or_like('COL_GRIDSQUARE', $id);
+ $this->db->order_by("COL_TIME_ON", "desc");
$query = $this->db->get($this->config->item('table_name'));
if ($query->num_rows() > 0)
diff --git a/application/libraries/Frequency.php b/application/libraries/Frequency.php
index b21c17eb..bf699dfc 100644
--- a/application/libraries/Frequency.php
+++ b/application/libraries/Frequency.php
@@ -218,6 +218,69 @@ class Frequency {
}
}
+
+public function GetBand($Frequency) {
+ $Band = NULL;
+
+ if ($Frequency > 1000000 && $Frequency < 2000000) {
+ $Band = "160m";
+ } else if ($Frequency > 3000000 && $Frequency < 4000000) {
+ $Band = "80m";
+ } else if ($Frequency > 6000000 && $Frequency < 8000000) {
+ $Band = "40m";
+ } else if ($Frequency > 9000000 && $Frequency < 11000000) {
+ $Band = "30m";
+ } else if ($Frequency > 13000000 && $Frequency < 15000000) {
+ $Band = "20m";
+ } else if ($Frequency > 17000000 && $Frequency < 19000000) {
+ $Band = "17m";
+ } else if ($Frequency > 20000000 && $Frequency < 22000000) {
+ $Band = "15m";
+ } else if ($Frequency > 23000000 && $Frequency < 25000000) {
+ $Band = "12m";
+ } else if ($Frequency > 27000000 && $Frequency < 30000000) {
+ $Band = "10m";
+ } else if ($Frequency > 49000000 && $Frequency < 52000000) {
+ $Band = "6m";
+ } else if ($Frequency > 69000000 && $Frequency < 71000000) {
+ $Band = "4m";
+ } else if ($Frequency > 140000000 && $Frequency < 150000000) {
+ $Band = "2m";
+ } else if ($Frequency > 218000000 && $Frequency < 226000000) {
+ $Band = "1.25m";
+ } else if ($Frequency > 430000000 && $Frequency < 440000000) {
+ $Band = "70cm";
+ } else if ($Frequency > 900000000 && $Frequency < 930000000) {
+ $Band = "33cm";
+ } else if ($Frequency > 1200000000 && $Frequency < 1300000000) {
+ $Band = "23cm";
+ } else if ($Frequency > 2200000000 && $Frequency < 2600000000) {
+ $Band = "13cm";
+ } else if ($Frequency > 3000000000 && $Frequency < 4000000000) {
+ $Band = "9cm";
+ } else if ($Frequency > 5000000000 && $Frequency < 6000000000) {
+ $Band = "6cm";
+ } else if ($Frequency > 9000000000 && $Frequency < 11000000000) {
+ $Band = "3cm";
+ } else if ($Frequency > 23000000000 && $Frequency < 25000000000) {
+ $Band = "1.2cm";
+ } else if ($Frequency > 46000000000 && $Frequency < 55000000000) {
+ $Band = "6mm";
+ } else if ($Frequency > 75000000000 && $Frequency < 82000000000) {
+ $Band = "4mm";
+ } else if ($Frequency > 120000000000 && $Frequency < 125000000000) {
+ $Band = "2.5mm";
+ } else if ($Frequency > 133000000000 && $Frequency < 150000000000) {
+ $Band = "2mm";
+ } else if ($Frequency > 240000000000 && $Frequency < 250000000000) {
+ $Band = "1mm";
+ } else if ($Frequency >= 250000000000) {
+ $Band = "<1mm";
+ }
+
+ return $Band;
+ }
+
}
/* End of file Frequency.php */
\ No newline at end of file
diff --git a/application/models/logbook_model.php b/application/models/logbook_model.php
index ce773717..d90cd410 100644
--- a/application/models/logbook_model.php
+++ b/application/models/logbook_model.php
@@ -678,6 +678,8 @@ class Logbook_model extends CI_Model {
}
function import($record) {
+ $CI =& get_instance();
+ $CI->load->library('frequency');
// Join date+time
//$datetime = date('Y-m-d') ." ". $this->input->post('start_time');
//$myDate = date('Y-m-d', $record['qso_date']);
@@ -783,7 +785,9 @@ class Logbook_model extends CI_Model {
if(isset($record['band'])) {
$band = $record['band'];
} else {
- $band = null;
+ $myfreq = str_replace(array('.', ','), '' , $record['freq'].'0');
+
+ $band = $CI->frequency->GetBand($myfreq);
}
// Store IOTA Ref if available
@@ -833,6 +837,16 @@ class Logbook_model extends CI_Model {
} else {
$srx = null;
}
+
+ // Filter Modes if not apart of ADIF spec
+ if($record['mode'] == "RTTY75") {
+ // Set RTTY75 to just RTTY
+ $mode = "RTTY";
+ } else {
+ // If no other rules just plain mode that adif includes
+ $mode = $record['mode'];
+ }
+
$this->db->where('COL_CALL', $record['call']);
$this->db->where('COL_TIME_ON', $time_on);
@@ -845,9 +859,9 @@ class Logbook_model extends CI_Model {
'COL_TIME_ON' => $time_on,
'COL_TIME_OFF' => $time_off,
'COL_CALL' => strtoupper($record['call']),
- 'COL_BAND' => $record['band'],
+ 'COL_BAND' => $band,
'COL_FREQ' => $freq,
- 'COL_MODE' => $record['mode'],
+ 'COL_MODE' => $mode,
'COL_RST_RCVD' => $rst_rx,
'COL_RST_SENT' => $rst_tx,
'COL_NAME' => $name,
diff --git a/application/php_error.php b/application/php_error.php
deleted file mode 100644
index fa55cd5e..00000000
--- a/application/php_error.php
+++ /dev/null
@@ -1,4411 +0,0 @@
- nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Uses:
- * JSMin-php https://github.com/rgrove/jsmin-php/
- * jQuery http://jquery.com/
- */
-
- /**
- * PHP Error
- *
- * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
- *
- * WARNING! It is downright _DANGEROUS_ to use this in production, on
- * a live website. It should *ONLY* be used for development.
- *
- * PHP Error will kill your environment at will, clear the output
- * buffers, and allows HTML injection from exceptions.
- *
- * In future versions it plans to do far more then that.
- *
- * If you use it in development, awesome! If you use it in production,
- * you're an idiot.
- *
- * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
- *
- * = Info
- *
- * A small API for replacing the standard PHP errors, with prettier
- * error reporting. This will change the error reporting level, and this
- * is deliberate, as I believe in strict development errors.
- *
- * simple usage:
- *
- * \php_error\reportErrors();
- *
- * Advanced example:
- *
- * There is more too it if you want more customized error handling. You
- * can pass in options, to customize the setup, and you get back a
- * handler you can alter at runtime.
- *
- * $handler = new \php_error\ErrorHandler( $myOptions );
- * $handler->turnOn();
- *
- * There should only ever be one handler! This is an (underdstandable)
- * limitation in PHP. It's because if an exception or error is raised,
- * then there is a single point of handling it.
- *
- * = INI Options
- *
- * - php_error.force_disabled When set to a true value (such as on),
- * this forces this to be off.
- * This is so you can disable this script
- * in your production servers ini file,
- * incase you accidentally upload this there.
- *
- * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
- *
- * @author Joseph Lenton | https://github.com/josephlenton
- */
-
- namespace php_error;
-
- use \php_error\ErrorException,
- \php_error\FileLinesSet,
- \php_error\ErrorHandler,
-
- \php_error\JSMin,
- \php_error\JSMinException;
-
- use \Closure,
- \Exception,
- \InvalidArgumentException;
-
- use \ReflectionMethod,
- \ReflectionFunction,
- \ReflectionParameter;
-
- global $_php_error_already_setup,
- $_php_error_global_handler,
- $_php_error_is_ini_enabled;
-
- /*
- * Avoid being run twice.
- */
- if ( empty($_php_error_already_setup) ) {
- $_php_error_already_setup = true;
-
- /*
- * These are used as token identifiers by PHP.
- *
- * If they are missing, then they should never pop out of PHP,
- * so we just give them their future value.
- *
- * They are primarily here so I don't have to alter the 5.3
- * compliant code. Instead I can delete pre-5.3 code (this
- * code), in the future.
- *
- * As long as the value is unique, and does not clash with PHP,
- * then any number could be used. That is why they start counting
- * at 100,000.
- */
- if ( ! defined('T_DIR') ) {
- define( 'T_DIR', 100001 );
- }
- if ( ! defined('T_GOTO') ) {
- define( 'T_GOTO', 100002 );
- }
- if ( ! defined('T_NAMESPACE') ) {
- define( 'T_NAMESPACE', 100003 );
- }
- if ( ! defined('T_NS_C') ) {
- define( 'T_NS_C', 100004 );
- }
- if ( ! defined('T_NS_SEPARATOR') ) {
- define( 'T_NS_SEPARATOR', 100005 );
- }
- if ( ! defined('T_USE') ) {
- define( 'T_USE', 100006 );
- }
-
- /*
- * Check if it's empty, in case this file is loaded multiple times.
- */
- if ( ! isset($_php_error_global_handler) ) {
- $_php_error_global_handler = null;
-
- $_php_error_is_ini_enabled = false;
-
- /*
- * check both 'disable' and 'disabled' incase it's mispelt
- * check that display errors is on
- * and ensure we are *not* a command line script.
- */
- $_php_error_is_ini_enabled =
- ! @get_cfg_var( 'php_error.force_disabled' ) &&
- ! @get_cfg_var( 'php_error.force_disable' ) &&
- @ini_get('display_errors') === '1' &&
- PHP_SAPI !== 'cli'
- ;
- }
-
- /**
- * This is shorthand for turning off error handling,
- * calling a block of code, and then turning it on.
- *
- * However if 'reportErrors' has not been called,
- * then this will silently do nothing.
- *
- * @param callback A PHP function to call.
- * @return The result of calling the callback.
- */
- function withoutErrors( $callback ) {
- global $_php_error_global_handler;
-
- if ( $_php_error_global_handler !== null ) {
- return $_php_error_global_handler->withoutErrors( $callback );
- } else {
- return $callback();
- }
- }
-
- /**
- * Turns on error reporting, and returns the handler.
- *
- * If you just want error reporting on, then don't bother
- * catching the handler. If you're building something
- * clever, like a framework, then you might want to grab
- * and use it.
- *
- * Note that calling this a second time will replace the
- * global error handling with a new error handler.
- * The existing one will be turned off, and the new one
- * turned on.
- *
- * You can't use two at once!
- *
- * @param options Optional, options declaring how PHP Error should be setup and used.
- * @return The ErrorHandler used for reporting errors.
- */
- function reportErrors( $options=null ) {
- $handler = new ErrorHandler( $options );
- return $handler->turnOn();
- }
-
- /**
- * The actual handler. There can only ever be one.
- */
- class ErrorHandler
- {
- const REGEX_DOCTYPE = '/<( )*!( *)DOCTYPE([^>]+)>/';
-
- const REGEX_PHP_IDENTIFIER = '\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*';
- const REGEX_PHP_CONST_IDENTIFIER = '/\b[A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*/';
-
- /**
- * Matches:
- * {closure}()
- * blah::foo()
- * foo()
- *
- * It is:
- * a closure
- * or a method or function
- * followed by parenthesis '()'
- *
- * a function is 'namespace function'
- * a method is 'namespace class::function', or 'namespace class->function'
- * the whole namespace is optional
- * namespace is made up of an '\' and then repeating 'namespace\'
- * both the first slash, and the repeating 'namespace\', are optional
- *
- * 'END' matches it at the end of a string, the other one does not.
- */
- const REGEX_METHOD_OR_FUNCTION_END = '/(\\{closure\\})|(((\\\\)?(\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\\\\)*)?\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(::[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)?)\\(\\)$/';
- const REGEX_METHOD_OR_FUNCTION = '/(\\{closure\\})|(((\\\\)?(\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\\\\)*)?\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(::[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)?)\\(\\)/';
-
- const REGEX_VARIABLE = '/\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/';
-
- const REGEX_MISSING_SEMI_COLON_FOLLOWING_LINE = '/^ *(return|}|if|while|foreach|for|switch)/';
-
- /**
- * The number of lines to take from the file,
- * where the error is reported. This is the number
- * of lines around the line in question,
- * including that line.
- *
- * So '9' will be the error line + 4 lines above + 4 lines below.
- */
- const NUM_FILE_LINES = 13;
-
- const FILE_TYPE_APPLICATION = 1;
- const FILE_TYPE_IGNORE = 2;
- const FILE_TYPE_ROOT = 3;
-
- const PHP_ERROR_MAGIC_HEADER_KEY = 'PHP_ERROR_MAGIC_HEADER';
- const PHP_ERROR_MAGIC_HEADER_VALUE = 'php_stack_error';
- const MAGIC_IS_PRETTY_ERRORS_MARKER = '';
-
- const PHP_ERROR_INI_PREFIX = 'php_error';
-
- /**
- * At the time of writing, scalar type hints are unsupported.
- * By scalar, I mean 'string' and 'integer'.
- *
- * If they do get added, this is here as a trap to turn scalar
- * type hint warnings on and off.
- */
- private static $IS_SCALAR_TYPE_HINTING_SUPPORTED = false;
-
- private static $SCALAR_TYPES = array(
- 'string', 'integer', 'float', 'boolean',
- 'bool', 'int', 'number'
- );
-
- /**
- * A mapping of PHP internal symbols,
- * mapped to descriptions of them.
- */
- private static $PHP_SYMBOL_MAPPINGS = array(
- '$end' => 'end of file',
- 'T_ABSTRACT' => 'abstract',
- 'T_AND_EQUAL' => "'&='",
- 'T_ARRAY' => 'array',
- 'T_ARRAY_CAST' => 'array cast',
- 'T_AS' => "'as'",
- 'T_BOOLEAN_AND' => "'&&'",
- 'T_BOOLEAN_OR' => "'||'",
- 'T_BOOL_CAST' => 'boolean cast',
- 'T_BREAK' => 'break',
- 'T_CASE' => 'case',
- 'T_CATCH' => 'catch',
- 'T_CLASS' => 'class',
- 'T_CLASS_C' => '__CLASS__',
- 'T_CLONE' => 'clone',
- 'T_CLOSE_TAG' => 'closing PHP tag',
- 'T_CONCAT_EQUAL' => "'.='",
- 'T_CONST' => 'const',
- 'T_CONSTANT_ENCAPSED_STRING' => 'string',
- 'T_CONTINUE' => 'continue',
- 'T_CURLY_OPEN' => '\'{$\'',
- 'T_DEC' => '-- (decrement)',
- 'T_DECLARE' => 'declare',
- 'T_DEFAULT' => 'default',
- 'T_DIR' => '__DIR__',
- 'T_DIV_EQUAL' => "'/='",
- 'T_DNUMBER' => 'number',
- 'T_DOLLAR_OPEN_CURLY_BRACES' => '\'${\'',
- 'T_DO' => "'do'",
- 'T_DOUBLE_ARROW' => "'=>'",
- 'T_DOUBLE_CAST' => 'double cast',
- 'T_DOUBLE_COLON' => "'::'",
- 'T_ECHO' => 'echo',
- 'T_ELSE' => 'else',
- 'T_ELSEIF' => 'elseif',
- 'T_EMPTY' => 'empty',
- 'T_ENCAPSED_AND_WHITESPACE' => 'non-terminated string',
- 'T_ENDDECLARE' => 'enddeclare',
- 'T_ENDFOR' => 'endfor',
- 'T_ENDFOREACH' => 'endforeach',
- 'T_ENDIF' => 'endif',
- 'T_ENDSWITCH' => 'endswitch',
- 'T_ENDWHILE' => 'endwhile',
- 'T_EVAL' => 'eval',
- 'T_EXIT' => 'exit call',
- 'T_EXTENDS' => 'extends',
- 'T_FILE' => '__FILE__',
- 'T_FINAL' => 'final',
- 'T_FOR' => 'for',
- 'T_FOREACH' => 'foreach',
- 'T_FUNCTION' => 'function',
- 'T_FUNC_C' => '__FUNCTION__',
- 'T_GLOBAL' => 'global',
- 'T_GOTO' => 'goto',
- 'T_HALT_COMPILER' => '__halt_compiler',
- 'T_IF' => 'if',
- 'T_IMPLEMENTS' => 'implements',
- 'T_INC' => '++ (increment)',
- 'T_INCLUDE' => 'include',
- 'T_INCLUDE_ONCE' => 'include_once',
- 'T_INSTANCEOF' => 'instanceof',
- 'T_INT_CAST' => 'int cast',
- 'T_INTERFACE' => 'interface',
- 'T_ISSET' => 'isset',
- 'T_IS_EQUAL' => "'=='",
- 'T_IS_GREATER_OR_EQUAL' => "'>='",
- 'T_IS_IDENTICAL' => "'==='",
- 'T_IS_NOT_EQUAL' => "'!=' or '<>'",
- 'T_IS_NOT_IDENTICAL' => "'!=='",
- 'T_IS_SMALLER_OR_EQUAL' => "'<='",
- 'T_LINE' => '__LINE__',
- 'T_LIST' => 'list',
- 'T_LNUMBER' => 'number',
- 'T_LOGICAL_AND' => "'and'",
- 'T_LOGICAL_OR' => "'or'",
- 'T_LOGICAL_XOR' => "'xor'",
- 'T_METHOD_C' => '__METHOD__',
- 'T_MINUS_EQUAL' => "'-='",
- 'T_MOD_EQUAL' => "'%='",
- 'T_MUL_EQUAL' => "'*='",
- 'T_NAMESPACE' => 'namespace',
- 'T_NEW' => 'new',
- 'T_NUM_STRING' => 'array index in a string',
- 'T_NS_C' => '__NAMESPACE__',
- 'T_NS_SEPARATOR' => 'namespace seperator',
- 'T_OBJECT_CAST' => 'object cast',
- 'T_OBJECT_OPERATOR' => "'->'",
- 'T_OLD_FUNCTION' => 'old_function',
- 'T_OPEN_TAG' => "' "' "'|='",
- 'T_PAAMAYIM_NEKUDOTAYIM' => "'::'",
- 'T_PLUS_EQUAL' => "'+='",
- 'T_PRINT' => 'print',
- 'T_PRIVATE' => 'private',
- 'T_PUBLIC' => 'public',
- 'T_PROTECTED' => 'protected',
- 'T_REQUIRE' => 'require',
- 'T_REQUIRE_ONCE' => 'require_once',
- 'T_RETURN' => 'return',
- 'T_SL' => "'<<'",
- 'T_SL_EQUAL' => "'<<='",
- 'T_SR' => "'>>'",
- 'T_SR_EQUAL' => "'>>='",
- 'T_START_HEREDOC' => "'<<<'",
- 'T_STATIC' => 'static',
- 'T_STRING' => 'string',
- 'T_STRING_CAST' => 'string cast',
- 'T_SWITCH' => 'switch',
- 'T_THROW' => 'throw',
- 'T_TRY' => 'try',
- 'T_UNSET' => 'unset',
- 'T_UNSET_CAST' => 'unset cast',
- 'T_USE' => 'use',
- 'T_VAR' => 'var',
- 'T_VARIABLE' => 'variable',
- 'T_WHILE' => 'while',
- 'T_WHITESPACE' => 'whitespace',
- 'T_XOR_EQUAL' => "'^='"
- );
-
- private static $syntaxMap = array(
- 'const' => 'syntax-literal',
- 'reference_ampersand' => 'syntax-function',
-
- T_COMMENT => 'syntax-comment',
- T_DOC_COMMENT => 'syntax-comment',
-
- T_ABSTRACT => 'syntax-keyword',
- T_AS => 'syntax-keyword',
- T_BREAK => 'syntax-keyword',
- T_CASE => 'syntax-keyword',
- T_CATCH => 'syntax-keyword',
- T_CLASS => 'syntax-keyword',
-
- T_CONST => 'syntax-keyword',
-
- T_CONTINUE => 'syntax-keyword',
- T_DECLARE => 'syntax-keyword',
- T_DEFAULT => 'syntax-keyword',
- T_DO => 'syntax-keyword',
-
- T_ELSE => 'syntax-keyword',
- T_ELSEIF => 'syntax-keyword',
- T_ENDDECLARE => 'syntax-keyword',
- T_ENDFOR => 'syntax-keyword',
- T_ENDFOREACH => 'syntax-keyword',
- T_ENDIF => 'syntax-keyword',
- T_ENDSWITCH => 'syntax-keyword',
- T_ENDWHILE => 'syntax-keyword',
- T_EXTENDS => 'syntax-keyword',
-
- T_FINAL => 'syntax-keyword',
- T_FOR => 'syntax-keyword',
- T_FOREACH => 'syntax-keyword',
- T_FUNCTION => 'syntax-keyword',
- T_GLOBAL => 'syntax-keyword',
- T_GOTO => 'syntax-keyword',
-
- T_IF => 'syntax-keyword',
- T_IMPLEMENTS => 'syntax-keyword',
- T_INSTANCEOF => 'syntax-keyword',
- T_INTERFACE => 'syntax-keyword',
-
- T_LOGICAL_AND => 'syntax-keyword',
- T_LOGICAL_OR => 'syntax-keyword',
- T_LOGICAL_XOR => 'syntax-keyword',
- T_NAMESPACE => 'syntax-keyword',
- T_NEW => 'syntax-keyword',
- T_PRIVATE => 'syntax-keyword',
- T_PUBLIC => 'syntax-keyword',
- T_PROTECTED => 'syntax-keyword',
- T_RETURN => 'syntax-keyword',
- T_STATIC => 'syntax-keyword',
- T_SWITCH => 'syntax-keyword',
- T_THROW => 'syntax-keyword',
- T_TRY => 'syntax-keyword',
- T_USE => 'syntax-keyword',
- T_VAR => 'syntax-keyword',
- T_WHILE => 'syntax-keyword',
-
- // __VAR__ type magic constants
- T_CLASS_C => 'syntax-literal',
- T_DIR => 'syntax-literal',
- T_FILE => 'syntax-literal',
- T_FUNC_C => 'syntax-literal',
- T_LINE => 'syntax-literal',
- T_METHOD_C => 'syntax-literal',
- T_NS_C => 'syntax-literal',
-
- T_DNUMBER => 'syntax-literal',
- T_LNUMBER => 'syntax-literal',
-
- T_CONSTANT_ENCAPSED_STRING => 'syntax-string',
- T_VARIABLE => 'syntax-variable',
-
- // this is for unescaped strings, which appear differently
- // this includes function names
- T_STRING => 'syntax-function',
-
- // in build keywords, which work like functions
- T_ARRAY => 'syntax-function',
- T_CLONE => 'syntax-function',
- T_ECHO => 'syntax-function',
- T_EMPTY => 'syntax-function',
- T_EVAL => 'syntax-function',
- T_EXIT => 'syntax-function',
- T_HALT_COMPILER => 'syntax-function',
- T_INCLUDE => 'syntax-function',
- T_INCLUDE_ONCE => 'syntax-function',
- T_ISSET => 'syntax-function',
- T_LIST => 'syntax-function',
- T_REQUIRE_ONCE => 'syntax-function',
- T_PRINT => 'syntax-function',
- T_REQUIRE => 'syntax-function',
- T_UNSET => 'syntax-function'
- );
-
- /**
- * A list of methods which are known to call the autoloader,
- * but should not error, if the class is not found.
- *
- * They are allowed to fail, so we don't store a class not
- * found exception if they do.
- */
- private static $SAFE_AUTOLOADER_FUNCTIONS = array(
- 'class_exists',
- 'interface_exists',
- 'method_exists',
- 'property_exists',
- 'is_subclass_of'
- );
-
- /**
- * When returning values, if a mime type is set,
- * then PHP Error should only output if the mime type
- * is one of these.
- */
- private static $ALLOWED_RETURN_MIME_TYPES = array(
- 'text/html',
- 'application/xhtml+xml'
- );
-
- private static function isIIS() {
- return (
- isset($_SERVER['SERVER_SOFTWARE']) &&
- strpos($_SERVER['SERVER_SOFTWARE'], 'IIS/') !== false
- ) || (
- isset($_SERVER['_FCGI_X_PIPE_']) &&
- strpos($_SERVER['_FCGI_X_PIPE_'], 'IISFCGI') !== false
- );
- }
-
- /**
- * This attempts to state if this is *not* a PHP request,
- * but it cannot say if it *is* a PHP request. It achieves
- * this by looking for a mime type.
- *
- * For example if the mime type is JavaScript, then we
- * know it's not PHP. However there is no "yes, this is
- * definitely a normal HTML response" flag we can check.
- */
- private static function isNonPHPRequest() {
- /*
- * Check if we are a mime type that isn't allowed.
- *
- * Anything other than 'text/html' or similar will cause
- * this to turn off.
- */
- $response = ErrorHandler::getResponseHeaders();
-
- foreach ( $response as $key => $value ) {
- if ( strtolower($key) === 'content-type' ) {
- $found = true;
-
- foreach ( ErrorHandler::$ALLOWED_RETURN_MIME_TYPES as $type ) {
- if ( stripos($value, $type) !== false ) {
- $found = true;
- break;
- }
- }
-
- if ( ! $found ) {
- return true;
- }
-
- break;
- }
- }
-
- return false;
- }
-
- /**
- * Looks up a description for the symbol given,
- * and if found, it is returned.
- *
- * If it's not found, then the symbol given is returned.
- */
- private static function phpSymbolToDescription( $symbol ) {
- if ( isset(ErrorHandler::$PHP_SYMBOL_MAPPINGS[$symbol]) ) {
- return ErrorHandler::$PHP_SYMBOL_MAPPINGS[$symbol];
- } else {
- return "'$symbol'";
- }
- }
-
- /**
- * Attempts to syntax highlight the code snippet done.
- *
- * This is then returned as HTML, ready to be dumped to the screen.
- *
- * @param code An array of code lines to syntax highlight.
- * @return HTML version of the code given, syntax highlighted.
- */
- private static function syntaxHighlight( $code ) {
- $syntaxMap = ErrorHandler::$syntaxMap;
-
- // @supress invalid code raises a warning
- $tokens = @token_get_all( "" );
- $html = array();
- $len = count($tokens)-1;
- $inString = false;
- $stringBuff = null;
- $skip = false;
-
- for ( $i = 1; $i < $len; $i++ ) {
- $token = $tokens[$i];
-
- if ( is_array($token) ) {
- $type = $token[0];
- $code = $token[1];
- } else {
- $type = null;
- $code = $token;
- }
-
- // work out any whitespace padding
- if ( strpos($code, "\n") !== false && trim($code) === '' ) {
- if ( $inString ) {
- $html[]= "" . join('', $stringBuff);
- $stringBuff = array();
- }
- } else if ( $code === '&' ) {
- if ( $i < $len ) {
- $next = $tokens[$i+1];
-
- if ( is_array($next) && $next[0] === T_VARIABLE ) {
- $type = 'reference_ampersand';
- }
- }
- } else if ( $code === '"' || $code === "'" ) {
- if ( $inString ) {
- $html[]= "" . join('', $stringBuff) . htmlspecialchars($code) . "";
- $stringBuff = null;
- $skip = true;
- } else {
- $stringBuff = array();
- }
-
- $inString = !$inString;
- } else if ( $type === T_STRING ) {
- $matches = array();
- preg_match(ErrorHandler::REGEX_PHP_CONST_IDENTIFIER, $code, $matches);
-
- if ( $matches && strlen($matches[0]) === strlen($code) ) {
- $type = 'const';
- }
- }
-
- if ( $skip ) {
- $skip = false;
- } else {
- $code = htmlspecialchars( $code );
-
- if ( $type !== null && isset($syntaxMap[$type]) ) {
- $class = $syntaxMap[$type];
-
- if ( $type === T_CONSTANT_ENCAPSED_STRING && strpos($code, "\n") !== false ) {
- $append = "" .
- join(
- "\n",
- explode( "\n", $code )
- ) .
- "" ;
- } else if ( strrpos($code, "\n") === strlen($code)-1 ) {
- $append = "" . substr($code, 0, strlen($code)-1) . "\n";
- } else {
- $append = "$code";
- }
- } else if ( $inString && $code !== '"' ) {
- $append = "$code";
- } else {
- $append = $code;
- }
-
- if ( $inString ) {
- $stringBuff[]= $append;
- } else {
- $html[]= $append;
- }
- }
- }
-
- if ( $stringBuff !== null ) {
- $html[]= "" . join('', $stringBuff) . '';
- $stringBuff = null;
- }
-
- return join( '', $html );
- }
-
- /**
- * Splits a given function name into it's 'class, function' parts.
- * If there is no class, then null is returned.
- *
- * It also returns these parts in an array of: array( $className, $functionName );
- *
- * Usage:
- *
- * list( $class, $function ) = ErrorHandler::splitFunction( $name );
- *
- * @param name The function name to split.
- * @return An array containing class and function name.
- */
- private static function splitFunction( $name ) {
- $name = preg_replace( '/\\(\\)$/', '', $name );
-
- if ( strpos($name, '::') !== false ) {
- $parts = explode( '::', $name );
- $className = $parts[0];
- $type = '::';
- $functionName = $parts[1];
- } else if ( strpos($name, '->') !== false ) {
- $parts = explode( '->', $name );
- $className = $parts[0];
- $type = '->';
- $functionName = $parts[1];
- } else {
- $className = null;
- $type = null;
- $functionName = $name;
- }
-
- return array( $className, $type, $functionName );
- }
-
- private static function newArgument( $name, $type=false, $isPassedByReference=false, $isOptional=false, $optionalValue=null, $highlight=false ) {
- if ( $name instanceof ReflectionParameter ) {
- $highlight = func_num_args() > 1 ?
- $highlight = $type :
- false;
-
- $klass = $name->getDeclaringClass();
- $functionName = $name->getDeclaringFunction()->name;
- if ( $klass !== null ) {
- $klass = $klass->name;
- }
-
- $export = ReflectionParameter::export(
- ( $klass ?
- array( "\\$klass", $functionName ) :
- $functionName ),
- $name->name,
- true
- );
-
- $paramType = preg_replace('/.*?(\w+)\s+\$'.$name->name.'.*/', '\\1', $export);
- if ( strpos($paramType, '[') !== false || strlen($paramType) === 0 ) {
- $paramType = null;
- }
-
- return ErrorHandler::newArgument(
- $name->name,
- $paramType,
- $name->isPassedByReference(),
- $name->isDefaultValueAvailable(),
- ( $name->isDefaultValueAvailable() ?
- var_export( $name->getDefaultValue(), true ) :
- null ),
- ( func_num_args() > 1 ?
- $type :
- false )
- );
- } else {
- return array(
- 'name' => $name,
- 'has_type' => ( $type !== false ),
- 'type' => $type,
- 'is_reference' => $isPassedByReference,
- 'has_default' => $isOptional,
- 'default_val' => $optionalValue,
- 'is_highlighted' => $highlight
- );
- }
- }
-
- private static function syntaxHighlightFunctionMatch( $match, &$stackTrace, $highlightArg=null, &$numHighlighted=0 ) {
- list( $className, $type, $functionName ) = ErrorHandler::splitFunction( $match );
-
- // is class::method()
- if ( $className !== null ) {
- $reflectFun = new ReflectionMethod( $className, $functionName );
- // is a function
- } else if ( $functionName === '{closure}' ) {
- return '$closure';
- } else {
- $reflectFun = new ReflectionFunction( $functionName );
- }
-
- if ( $reflectFun ) {
- $params = $reflectFun->getParameters();
-
- if ( $params ) {
- $args = array();
- $min = 0;
- foreach( $params as $i => $param ) {
- $arg = ErrorHandler::newArgument( $param );
-
- if ( ! $arg['has_default'] ) {
- $min = $i;
- }
-
- $args[]= $arg;
- }
-
- if ( $highlightArg !== null ) {
- for ( $i = $highlightArg; $i <= $min; $i++ ) {
- $args[$i]['is_highlighted'] = true;
- }
-
- $numHighlighted = $min-$highlightArg;
- }
-
- if ( $className !== null ) {
- if ( $stackTrace && isset($stackTrace[1]) && isset($stackTrace[1]['type']) ) {
- $type = htmlspecialchars( $stackTrace[1]['type'] );
- }
- } else {
- $type = null;
- }
-
- return ErrorHandler::syntaxHighlightFunction( $className, $type, $functionName, $args );
- }
- }
-
- return null;
- }
-
- /**
- * Returns the values given, as HTML, syntax highlighted.
- * It's a shorter, slightly faster, more no-nonsense approach
- * then 'syntaxHighlight'.
- *
- * This is for syntax highlighting:
- * - fun( [args] )
- * - class->fun( [args] )
- * - class::fun( [args] )
- *
- * Class and type can be null, to denote no class, but are not optional.
- */
- private static function syntaxHighlightFunction( $class, $type, $fun, &$args=null ) {
- $info = array();
-
- // set the info
- if ( isset($class) && $class && isset($type) && $type ) {
- if ( $type === '->' ) {
- $type = '->';
- }
-
- $info []= "$class$type";
- }
-
- if ( isset($fun) && $fun ) {
- $info []= "$fun";
- }
-
- if ( $args ) {
- $info []= '( ';
-
- foreach ($args as $i => $arg) {
- if ( $i > 0 ) {
- $info[]= ', ';
- }
-
- if ( is_string($arg) ) {
- $info[]= $arg;
- } else {
- $highlight = $arg['is_highlighted'];
- $name = $arg['name'];
-
- if ( $highlight ) {
- $info[]= '';
- }
-
- if ( $name === '_' ) {
- $info[]= '';
- }
-
- if ( $arg['has_type'] ) {
- $info []= "";
- $info []= $arg['type'];
- $info []= ' ';
- }
-
- if ( $arg['is_reference'] ) {
- $info []= '&';
- }
-
- $info []= "\$$name";
-
- if ( $arg['has_default'] ) {
- $info []= '=' . $arg['default_val'] . '';
- }
-
- if ( $name === '_' ) {
- $info[]= '';
- }
- if ( $highlight ) {
- $info[]= '';
- }
- }
- }
-
- $info []= ' )';
- } else {
- $info []= '()';
- }
-
- return join( '', $info );
- }
-
- /**
- * Checks if the item is in options, and if it is, then it is removed and returned.
- *
- * If it is not found, or if options is not an array, then the alt is returned.
- */
- private static function optionsPop( &$options, $key, $alt=null ) {
- if ( $options && isset($options[$key]) ) {
- $val = $options[$key];
- unset( $options[$key] );
-
- return $val;
- } else {
- $iniAlt = @get_cfg_var( ErrorHandler::PHP_ERROR_INI_PREFIX . '.' . $key );
-
- if ( $iniAlt !== false ) {
- return $iniAlt;
- } else {
- return $alt;
- }
- }
- }
-
- private static function folderTypeToCSS( $type ) {
- if ( $type === ErrorHandler::FILE_TYPE_ROOT ) {
- return 'file-root';
- } else if ( $type === ErrorHandler::FILE_TYPE_IGNORE ) {
- return 'file-ignore';
- } else if ( $type === ErrorHandler::FILE_TYPE_APPLICATION ) {
- return 'file-app';
- } else {
- return 'file-common';
- }
- }
-
- private static function isFolderType( &$folders, $longest, $file ) {
- $parts = explode( '/', $file );
-
- $len = min( count($parts), $longest );
-
- for ( $i = $len; $i > 0; $i-- ) {
- if ( isset($folders[$i]) ) {
- $folderParts = &$folders[ $i ];
-
- $success = false;
- for ( $j = 0; $j < count($folderParts); $j++ ) {
- $folderNames = $folderParts[$j];
-
- for ( $k = 0; $k < count($folderNames); $k++ ) {
- if ( $folderNames[$k] === $parts[$k] ) {
- $success = true;
- } else {
- $success = false;
- break;
- }
- }
- }
-
- if ( $success ) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- private static function setFolders( &$origFolders, &$longest, $folders ) {
- $newFolders = array();
- $newLongest = 0;
-
- if ( $folders ) {
- if ( is_array($folders) ) {
- foreach ( $folders as $folder ) {
- ErrorHandler::setFoldersInner( $newFolders, $newLongest, $folder );
- }
- } else if ( is_string($folders) ) {
- ErrorHandler::setFoldersInner( $newFolders, $newLongest, $folders );
- } else {
- throw new Exception( "Unknown value given for folder: " . $folders );
- }
- }
-
- $origFolders = $newFolders;
- $longest = $newLongest;
- }
-
- private static function setFoldersInner( &$newFolders, &$newLongest, $folder ) {
- $folder = str_replace( '\\', '/', $folder );
- $folder = preg_replace( '/(^\\/+)|(\\/+$)/', '', $folder );
- $parts = explode( '/', $folder );
- $count = count( $parts );
-
- $newLongest = max( $newLongest, $count );
-
- if ( isset($newFolders[$count]) ) {
- $folds = &$newFolders[$count];
- $folds[]= $parts;
- } else {
- $newFolders[$count] = array( $parts );
- }
- }
-
- private static function getRequestHeaders() {
- if ( function_exists('getallheaders') ) {
- return getallheaders();
- } else {
- $headers = array();
-
- foreach ( $_SERVER as $key => $value ) {
- if ( strpos($key, 'HTTP_') === 0 ) {
- $key = str_replace( " ", "-", ucwords(strtolower( str_replace("_", " ", substr($key, 5)) )) );
- $headers[ $key ] = $value;
- }
- }
-
- return $headers;
- }
- }
-
- private static function getResponseHeaders() {
- $headers = function_exists('apache_response_headers') ?
- apache_response_headers() :
- array() ;
-
- /*
- * Merge the headers_list into apache_response_headers.
- *
- * This is because sometimes things are in one, which are
- * not present in the other.
- */
- if ( function_exists('headers_list') ) {
- $hList = headers_list();
-
- foreach ($hList as $header) {
- $header = explode(":", $header);
- $headers[ array_shift($header) ] = trim( implode(":", $header) );
- }
- }
-
- return $headers;
- }
-
- public static function identifyTypeHTML( $arg, $recurseLevels=1 ) {
- if ( ! is_array($arg) && !is_object($arg) ) {
- if ( is_string($arg) ) {
- return """ . htmlentities($arg) . """;
- } else {
- return "" . var_export( $arg, true ) . '';
- }
- } else if ( is_array($arg) ) {
- if ( count($arg) === 0 ) {
- return "[]";
- } else if ( $recurseLevels > 0 ) {
- $argArr = array();
-
- foreach ($arg as $ag) {
- $argArr[]= ErrorHandler::identifyTypeHTML( $ag, $recurseLevels-1 );
- }
-
- if ( ($recurseLevels % 2) === 0 ) {
- return "[" . join(', ', $argArr) . "]";
- } else {
- return "[ " . join(', ', $argArr) . " ]";
- }
- } else {
- return "[...]";
- }
- } else if ( get_class($arg) === 'Closure' ) {
- return '$Closure()';
- } else {
- $argKlass = get_class( $arg );
-
- if ( preg_match(ErrorHandler::REGEX_PHP_CONST_IDENTIFIER, $argKlass) ) {
- return '$' . $argKlass . '';
- } else {
- return '$' . $argKlass . '';
- }
- }
- }
-
- private $cachedFiles;
-
- private $isShutdownRegistered;
- private $isOn;
-
- private $ignoreFolders = array();
- private $ignoreFoldersLongest = 0;
-
- private $applicationFolders = array();
- private $applicationFoldersLongest = 0;
-
- private $defaultErrorReportingOn;
- private $defaultErrorReportingOff;
- private $applicationRoot;
- private $serverName;
-
- private $catchClassNotFound;
- private $catchSurpressedErrors;
- private $catchAjaxErrors;
-
- private $backgroundText;
- private $numLines;
-
- private $displayLineNumber;
- private $htmlOnly;
-
- private $isBufferSetup;
- private $bufferOutputStr;
- private $bufferOutput;
-
- private $isAjax;
-
- private $lastGlobalErrorHandler;
-
- private $classNotFoundException;
-
- /**
- * = Options =
- *
- * All options are optional, and so is passing in an options item.
- * You don't have to supply any, it's up to you.
- *
- * Note that if 'php_error.force_disable' is true, then this object
- * will try to look like it works, but won't actually do anything.
- *
- * All options can also be passed in from 'php.ini'. You do this
- * by setting it with 'php_error.' prefix. For example:
- *
- * php_error.catch_ajax_errors = On
- * php_error.error_reporting_on = E_ALL | E_STRICT
- *
- * Includes:
- * = Types of errors this will catch =
- * - catch_ajax_errors When on, this will inject JS Ajax wrapping code, to allow this to catch any future JSON errors. Defaults to true.
- * - catch_supressed_errors The @ supresses errors. If set to true, then they are still reported anyway, but respected when false. Defaults to false.
- * - catch_class_not_found When true, loading a class that does not exist will be caught. This defaults to true.
- *
- * = Error reporting level =
- * - error_reporting_on value for when errors are on, defaults to all errors
- * - error_reporting_off value for when errors are off, defaults to php.ini's error_reporting.
- *
- * = Setup Details =
- * - application_root When it's working out hte stack trace, this is the root folder of the application, to use as it's base.
- * Defaults to the servers root directory.
- *
- * A relative path can be given, but lets be honest, an explicit path is the way to guarantee that you
- * will get the path you want. My relative might not be the same as your relative.
- *
- * - snippet_num_lines The number of lines to display in the code snippet.
- * That includes the line being reported.
- *
- * - server_name The name for this server, defaults to "$_SERVER['SERVER_NAME']"
- *
- * - ignore_folders This is allows you to highlight non-framework code in a stack trace.
- * An array of folders to ignore, when working out the stack trace.
- * This is folder prefixes in relation to the application_root, whatever that might be.
- * They are only ignored if there is a file found outside of them.
- * If you still don't get what this does, don't worry, it's here cos I use it.
- *
- * - application_folders Just like ignore, but anything found in these folders takes precedence
- * over anything else.
- *
- * - background_text The text that appeares in the background. By default this is blank.
- * Why? You can replace this with the name of your framework, for extra customization spice.
- *
- * - html_only By default, PHP Error only runs on ajax and HTML pages.
- * If this is false, then it will also run when on non-HTML
- * pages too, such as replying with images of JavaScript
- * from your PHP. Defaults to true.
- *
- * @param options Optional, an array of values to customize this handler.
- * @throws Exception This is raised if given an options that does *not* exist (so you know that option is meaningless).
- */
- public function __construct( $options=null ) {
- // there can only be one to rule them all
- global $_php_error_global_handler;
- if ( $_php_error_global_handler !== null ) {
- $this->lastGlobalErrorHandler = $_php_error_global_handler;
- } else {
- $this->lastGlobalErrorHandler = null;
- }
- $_php_error_global_handler = $this;
-
- $this->cachedFiles = array();
-
- $this->isShutdownRegistered = false;
- $this->isOn = false;
-
- /*
- * Deal with the options.
- *
- * They are removed one by one, and any left, will raise an error.
- */
-
- $ignoreFolders = ErrorHandler::optionsPop( $options, 'ignore_folders' , null );
- $appFolders = ErrorHandler::optionsPop( $options, 'application_folders', null );
-
- if ( $ignoreFolders !== null ) {
- ErrorHandler::setFolders( $this->ignoreFolders, $this->ignoreFoldersLongest, $ignoreFolders );
- }
- if ( $appFolders !== null ) {
- ErrorHandler::setFolders( $this->applicationFolders, $this->applicationFoldersLongest, $appFolders );
- }
-
- $this->defaultErrorReportingOn = ErrorHandler::optionsPop( $options, 'error_reporting_on' , -1 );
- $this->defaultErrorReportingOff = ErrorHandler::optionsPop( $options, 'error_reporting_off', error_reporting() );
-
- $this->applicationRoot = ErrorHandler::optionsPop( $options, 'application_root' , $_SERVER['DOCUMENT_ROOT'] );
- $this->serverName = ErrorHandler::optionsPop( $options, 'error_reporting_off', $_SERVER['SERVER_NAME'] );
-
- /*
- * Relative paths might be given for document root,
- * so we make it explicit.
- */
- $dir = @realpath( $this->applicationRoot );
- if ( ! is_string($dir) ) {
- throw new Exception("Document root not found: " . $this->applicationRoot);
- } else {
- $this->applicationRoot = str_replace( '\\', '/', $dir );
- }
-
- $this->catchClassNotFound = !! ErrorHandler::optionsPop( $options, 'catch_class_not_found' , true );
- $this->catchSurpressedErrors = !! ErrorHandler::optionsPop( $options, 'catch_supressed_errors', false );
- $this->catchAjaxErrors = !! ErrorHandler::optionsPop( $options, 'catch_ajax_errors' , true );
-
- $this->backgroundText = ErrorHandler::optionsPop( $options, 'background_text' , '' );
- $this->numLines = ErrorHandler::optionsPop( $options, 'snippet_num_lines' , ErrorHandler::NUM_FILE_LINES );
- $this->displayLineNumber = ErrorHandler::optionsPop( $options, 'display_line_numbers' , false );
-
- $this->htmlOnly = !! ErrorHandler::optionsPop( $options, 'html_only', true );
-
- $this->classNotFoundException = null;
-
- $wordpress = ErrorHandler::optionsPop( $options, 'wordpress', false );
- if ( $wordpress ) {
- // php doesn't like | in constants and privates, so just set it directly : (
- $this->defaultErrorReportingOn = E_ERROR | E_WARNING | E_PARSE | E_USER_DEPRECATED & ~E_DEPRECATED & ~E_STRICT;
- }
-
- if ( $options ) {
- foreach ( $options as $key => $val ) {
- throw new InvalidArgumentException( "Unknown option given $key" );
- }
- }
-
- $this->isAjax = (
- isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) &&
- ( $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest' )
- ) || (
- isset( $_REQUEST['php_error_is_ajax'] )
- );
-
- $this->isBufferSetup = false;
- $this->bufferOutputStr = '';
- $this->bufferOutput = false;
-
- $this->startBuffer();
- }
-
- /*
- * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
- * Public Functions
- * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
- */
-
- /**
- * @return true if this is currently on, false if not.
- */
- public function isOn() {
- return $this->isOn;
- }
-
- /**
- * @return If this is off, this returns true, otherwise false.
- */
- public function isOff() {
- return !$this->isOn;
- }
-
- /**
- * Turns error reporting on.
- *
- * This will use the strictest error reporting available, or the
- * level you pass in when creating this using the 'error_reporting_on'
- * option.
- *
- * @return This error reporting handler, for method chaining.
- */
- public function turnOn() {
- $this->propagateTurnOff();
- $this->setEnabled( true );
-
- return $this;
- }
-
- /**
- * Turns error reporting off.
- *
- * This will use the 'php.ini' setting for the error_reporting level,
- * or one you have passed in if you used the 'error_reporting_off'
- * option when creating this.
- *
- * @return This error reporting handler, for method chaining.
- */
- public function turnOff() {
- $this->setEnabled( false );
-
- return $this;
- }
-
- /**
- * Allows you to run a callback with strict errors turned off.
- * Standard errors still apply, but this will use the default
- * error and exception handlers.
- *
- * This is useful for when loading libraries which do not
- * adhere to strict errors, such as Wordpress.
- *
- * To use:
- *
- * withoutErrors( function() {
- * // unsafe code here
- * });
- *
- * This will use the error_reporting value for when this is
- * turned off.
- *
- * @param callback A PHP function to call.
- * @return The result of calling the callback.
- */
- public function withoutErrors( $callback ) {
- if ( ! is_callable($callback) ) {
- throw new Exception( "non callable callback given" );
- }
-
- if ( $this->isOn() ) {
- $this->turnOff();
- $result = $callback();
- $this->turnOn();
-
- return $result;
- } else {
- return $callback();
- }
- }
-
- /**
- * This is the shutdown function, which should *only* be called
- * via 'register_shutdown_function'.
- *
- * It's exposed because it has to be exposed.
- */
- public function __onShutdown() {
- global $_php_error_is_ini_enabled;
-
- if ( $_php_error_is_ini_enabled ) {
- if ( $this->isOn() ) {
- $error = error_get_last();
-
- // fatal and syntax errors
- if (
- $error && (
- $error['type'] === 1 ||
- $error['type'] === 4 ||
- $error['type'] === 64
- )
- ) {
- $this->reportError( $error['type'], $error['message'], $error['line'], $error['file'] );
- } else {
- $this->endBuffer();
- }
- } else {
- $this->endBuffer();
- }
- }
- }
-
- /*
- * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
- * Private Functions
- * --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
- */
-
- private function propagateTurnOff() {
- if ( $this->lastGlobalErrorHandler !== null ) {
- $this->lastGlobalErrorHandler->turnOff();
- $this->lastGlobalErrorHandler->propagateTurnOff();
- $this->lastGlobalErrorHandler = null;
- }
- }
-
- /**
- * This is intended to be used closely with 'onShutdown'.
- * It ensures that output buffering is turned on.
- *
- * Why? The user may output content, and *then* hit an error.
- * We cannot replace the page if this happens,
- * because they have already outputted information.
- *
- * So we buffer the page, and then output at the end of the page,
- * or when an error strikes.
- */
- private function startBuffer() {
- global $_php_error_is_ini_enabled;
-
- if ( $_php_error_is_ini_enabled && !$this->isBufferSetup ) {
- $this->isBufferSetup = true;
-
- ini_set( 'implicit_flush', false );
- ob_implicit_flush( false );
-
- if ( ! @ini_get('output_buffering') ) {
- @ini_set( 'output_buffering', 'on' );
- }
-
- $output = '';
- $bufferOutput = true;
-
- $this->bufferOutputStr = &$output;
- $this->bufferOutput = &$bufferOutput;
-
- ob_start( function($string) use (&$output, &$bufferOutput) {
- if ( $bufferOutput ) {
- $output .= $string;
- return '';
- } else {
- $temp = $output . $string;
- $output = '';
- return $temp;
- }
- });
-
- $self = $this;
- register_shutdown_function( function() use ( $self ) {
- $self->__onShutdown();
- });
- }
- }
-
- /**
- * Turns off buffering, and discards anything buffered
- * so far.
- *
- * This will return what has been buffered incase you
- * do want it. However otherwise, it will be lost.
- */
- private function discardBuffer() {
- $str = $this->bufferOutputStr;
-
- $this->bufferOutputStr = '';
- $this->bufferOutput = false;
-
- return $str;
- }
-
- /**
- * Flushes the internal buffer,
- * outputting what is left.
- *
- * @param append Optional, extra content to append onto the output buffer.
- */
- private function flushBuffer() {
- $temp = $this->bufferOutputStr;
- $this->bufferOutputStr = '';
-
- return $temp;
- }
-
- /**
- * This will finish buffering, and output the page.
- * It also appends the magic JS onto the beginning of the page,
- * if enabled, to allow working with Ajax.
- *
- * Note that if PHP Error has been disabled in the php.ini file,
- * or through some other option, such as running from the command line,
- * then this will do nothing (as no buffering will take place).
- */
- public function endBuffer() {
- if ( $this->isBufferSetup ) {
- $content = ob_get_contents();
- $handlers = ob_list_handlers();
-
- $wasGZHandler = false;
-
- $this->bufferOutput = true;
- for ( $i = count($handlers)-1; $i >= 0; $i-- ) {
- $handler = $handlers[$i];
-
- if ( $handler === 'ob_gzhandler' ) {
- $wasGZHandler = true;
- ob_end_clean();
- } else if ( $handler === 'default output handler' ) {
- ob_end_clean();
- } else {
- ob_end_flush();
- }
- }
-
- $content = $this->discardBuffer();
-
- if ( $wasGZHandler ) {
- ob_start('ob_gzhandler');
- } else {
- ob_start();
- }
-
- if (
- !$this->isAjax &&
- $this->catchAjaxErrors &&
- (!$this->htmlOnly || !ErrorHandler::isNonPHPRequest())
- ) {
- $js = $this->getContent( 'displayJSInjection' );
- $js = JSMin::minify( $js );
-
- // attemp to inject the script into the HTML, after the doctype
- $matches = array();
- preg_match( ErrorHandler::REGEX_DOCTYPE, $content, $matches );
-
- if ( $matches ) {
- $doctype = $matches[0];
- $content = preg_replace( ErrorHandler::REGEX_DOCTYPE, "$doctype $js", $content );
- } else {
- echo $js;
- }
- }
-
- echo $content;
- }
- }
-
- /**
- * Calls the given method on this object,
- * captures it's output, and then returns it.
- *
- * @param method The name of the method to call.
- * @return All of the text outputted during the method call.
- */
- private function getContent( $method ) {
- ob_start();
- $this->$method();
- $content = ob_get_contents();
- ob_end_clean();
-
- return $content;
- }
-
- private function isApplicationFolder( $file ) {
- return ErrorHandler::isFolderType(
- $this->applicationFolders,
- $this->applicationFoldersLongest,
- $file
- );
- }
-
- private function isIgnoreFolder( $file ) {
- return ErrorHandler::isFolderType(
- $this->ignoreFolders,
- $this->ignoreFoldersLongest,
- $file
- );
- }
-
- private function getFolderType( $root, $file ) {
- $testFile = $this->removeRootPath( $root, $file );
-
- // it's this file : (
- if ( $file === __FILE__ ) {
- $type = ErrorHandler::FILE_TYPE_IGNORE;
- } else if ( strpos($testFile, '/') === false ) {
- $type = ErrorHandler::FILE_TYPE_ROOT;
- } else if ( $this->isApplicationFolder($testFile) ) {
- $type = ErrorHandler::FILE_TYPE_APPLICATION;
- } else if ( $this->isIgnoreFolder($testFile) ) {
- $type = ErrorHandler::FILE_TYPE_IGNORE;
- } else {
- $type = false;
- }
-
- return array( $type, $testFile );
- }
-
- /**
- * Finds the file named, and returns it's contents in an array.
- *
- * It's essentially the same as 'file_get_contents'. However
- * this will add caching at this PHP layer, avoiding lots of
- * duplicate calls.
- *
- * It also splits the file into an array of lines, and makes
- * it html safe.
- *
- * @param path The file to get the contents of.
- * @return The file we are after, as an array of lines.
- */
- private function getFileContents( $path ) {
- if ( isset($this->cachedFiles[$path]) ) {
- return $this->cachedFiles[$path];
- } else {
- $contents = @file_get_contents( $path );
-
- if ( $contents ) {
- $contents = explode(
- "\n",
- preg_replace(
- '/(\r\n)|(\n\r)|\r/',
- "\n",
- str_replace( "\t", ' ', $contents )
- )
- );
-
- $this->cachedFiles[ $path ] = $contents;
-
- return $contents;
- }
- }
-
- return array();
- }
-
- /**
- * Reads out the code from the section of the line,
- * which is at fault.
- *
- * The array is in a mapping of: array( line-number => line )
- *
- * If something goes wrong, then null is returned.
- */
- private function readCodeFile( $errFile, $errLine ) {
- try {
- $lines = $this->getFileContents( $errFile );
-
- if ( $lines ) {
- $numLines = $this->numLines;
-
- $searchUp = ceil( $numLines*0.75 );
- $searchDown = $numLines - $searchUp;
-
- $countLines = count( $lines );
-
- /*
- * Search around the errLine.
- * We should aim get half of the lines above, and half from below.
- * If that fails we get as many as we can.
- */
-
- /*
- * If we are near the bottom edge,
- * we go down as far as we can,
- * then work up the search area.
- */
- if ( $errLine+$searchDown > $countLines ) {
- $minLine = max( 0, $countLines-$numLines );
- $maxLine = $countLines;
- /*
- * Go up as far as we can, up to half the search area.
- * Then stretch down the whole search area.
- */
- } else {
- $minLine = max( 0, $errLine-$searchUp );
- $maxLine = min( $minLine+$numLines, count($lines) );
- }
-
- $fileLines = array_splice( $lines, $minLine, $maxLine-$minLine );
-
- $stripSize = -1;
- foreach ( $fileLines as $i => $line ) {
- $newLine = ltrim( $line, ' ' );
-
- if ( strlen($newLine) > 0 ) {
- $numSpaces = strlen($line) - strlen($newLine);
-
- if ( $stripSize === -1 ) {
- $stripSize = $numSpaces;
- } else {
- $stripSize = min( $stripSize, $numSpaces );
- }
- } else {
- $fileLines[$i] = $newLine;
- }
- }
- if ( $stripSize > 0 ) {
- /*
- * It's pretty common that PHP code is not flush with the left hand edge,
- * so subtract 4 spaces, if we can,
- * to account for this.
- */
- if ( $stripSize > 4 ) {
- $stripSize -= 4;
- }
-
- foreach ( $fileLines as $i => $line ) {
- if ( strlen($line) > $stripSize ) {
- $fileLines[$i] = substr( $line, $stripSize );
- }
- }
- }
-
- $fileLines = join( "\n", $fileLines );
- $fileLines = ErrorHandler::syntaxHighlight( $fileLines );
- $fileLines = explode( "\n", $fileLines );
-
- $lines = array();
- for ( $i = 0; $i < count($fileLines); $i++ ) {
- // +1 is because line numbers start at 1, whilst arrays start at 0
- $lines[ $i+$minLine+1 ] = $fileLines[$i];
- }
- }
-
- return $lines;
- } catch ( Exception $ex ) {
- return null;
- }
-
- return null;
- }
-
- /**
- * Attempts to remove the root path from the path given.
- * If the path can't be removed, then the original path is returned.
- *
- * For example if root is 'C:/users/projects/my_site',
- * and the file is 'C:/users/projects/my_site/index.php',
- * then the root is removed, and we are left with just 'index.php'.
- *
- * This is to remove line noise; you don't need to be told the
- * 'C:/whatever' bit 20 times.
- *
- * @param root The root path to remove.
- * @param path The file we are removing the root section from.
- */
- private function removeRootPath( $root, $path ) {
- $filePath = str_replace( '\\', '/', $path );
-
- if (
- strpos($filePath, $root) === 0 &&
- strlen($root) < strlen($filePath)
- ) {
- return substr($filePath, strlen($root)+1 );
- } else {
- return $filePath;
- }
- }
-
- /**
- * Parses, and alters, the errLine, errFile and message given.
- *
- * This includes adding syntax highlighting, removing duplicate
- * information we already have, and making the error easier to
- * read.
- */
- private function improveErrorMessage( $ex, $code, $message, $errLine, $errFile, $root, &$stackTrace ) {
- // change these to change where the source file is come from
- $srcErrFile = $errFile;
- $srcErrLine = $errLine;
- $altInfo = null;
- $stackSearchI = 0;
-
- $skipStackFirst = function( &$stackTrace ) {
- $skipFirst = true;
-
- foreach ( $stackTrace as $i => $trace ) {
- if ( $skipFirst ) {
- $skipFirst = false;
- } else {
- if ( $trace && isset($trace['file']) && isset($trace['line']) ) {
- return array( $trace['file'], $trace['line'], $i );
- }
- }
- }
-
- return array( null, null, null );
- };
-
- /*
- * This is for calling a function that doesn't exist.
- *
- * The message contains a long description of where this takes
- * place, even though we are already told this through line and
- * file info. So we cut it out.
- */
- if ( $code === 1 ) {
- if (
- ( strpos($message, " undefined method ") !== false ) ||
- ( strpos($message, " undefined function ") !== false )
- ) {
- $matches = array();
- preg_match( '/\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*((->|::)[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)?\\(\\)$/', $message, $matches );
-
- /*
- * undefined function or method call
- */
- if ( $matches ) {
- list( $className, $type, $functionName ) = ErrorHandler::splitFunction( $matches[0] );
-
- if ( $stackTrace && isset($stackTrace[1]) && $stackTrace[1]['args'] ) {
- $numArgs = count( $stackTrace[1]['args'] );
-
- for ( $i = 0; $i < $numArgs; $i++ ) {
- $args[]= ErrorHandler::newArgument( "_" );
- }
- }
-
- $message = preg_replace(
- '/\b[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*((->|::)[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)?\\(\\)$/',
- ErrorHandler::syntaxHighlightFunction( $className, $type, $functionName, $args ),
- $message
- );
- }
- } else if ( $message === 'Using $this when not in object context' ) {
- $message = 'Using $this outside object context';
- /*
- * Class not found error.
- */
- } else if (
- strpos($message, "Class ") !== false &&
- strpos($message, "not found") !== false
- ) {
- $matches = array();
- preg_match( '/\'(\\\\)?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*((\\\\)?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+\'/', $message, $matches );
-
- if ( count($matches) > 0 ) {
- // lose the 'quotes'
- $className = $matches[0];
- $className = substr( $className, 1, strlen($className)-2 );
-
- $message = preg_replace(
- '/\'(\\\\)?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*((\\\\)?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+\'/',
- "$className",
- $message
- );
- }
- }
- } else if ( $code === 2 ) {
- if ( strpos($message, "Missing argument ") === 0 ) {
- $message = preg_replace( '/, called in .*$/', '', $message );
-
- $matches = array();
- preg_match( ErrorHandler::REGEX_METHOD_OR_FUNCTION_END, $message, $matches );
-
- if ( $matches ) {
- $argumentMathces = array();
- preg_match( '/^Missing argument ([0-9]+)/', $message, $argumentMathces );
- $highlightArg = count($argumentMathces) === 2 ?
- (((int) $argumentMathces[1])-1) :
- null ;
-
- $numHighlighted = 0;
- $altInfo = ErrorHandler::syntaxHighlightFunctionMatch( $matches[0], $stackTrace, $highlightArg, $numHighlighted );
-
- if ( $numHighlighted > 0 ) {
- $message = preg_replace( '/^Missing argument ([0-9]+)/', 'Missing arguments ', $message );
- }
-
- if ( $altInfo ) {
- $message = preg_replace( ErrorHandler::REGEX_METHOD_OR_FUNCTION_END, $altInfo, $message );
-
- list( $srcErrFile, $srcErrLine, $stackSearchI ) = $skipStackFirst( $stackTrace );
- }
- }
- } else if (
- strpos($message, 'require(') === 0 ||
- strpos($message, 'include(') === 0
- ) {
- $endI = strpos( $message, '):' );
-
- if ( $endI ) {
- // include( is the same length
- $requireLen = strlen('require(');
-
- /*
- * +2 to include the ): at the end of the string
- */
- $postMessage = substr( $message, $endI+2 );
- $postMessage = str_replace( 'failed to open stream: No ', 'no ', $postMessage );
- $message = substr_replace( $message, $postMessage, $endI+2 );
-
- /*
- * If this string is in there, and where we think it should be,
- * swap it with a shorter message.
- */
- $replaceBit = 'failed to open stream: No ';
- if ( strpos($message, $replaceBit) === $endI+2 ) {
- $message = substr_replace( $message, 'no ', $endI+2, strlen($replaceBit) );
- }
-
- /*
- * Now put the string highlighting in there.
- */
- $match = substr( $message, $requireLen, $endI-$requireLen );
- $newString = "'$match'),";
- $message = substr_replace( $message, $newString, $requireLen, ($endI-$requireLen)+2 );
- }
- }
- /*
- * Unexpected symbol errors.
- * For example 'unexpected T_OBJECT_OPERATOR'.
- *
- * This swaps the 'T_WHATEVER' for the symbolic representation.
- */
- } else if ( $code === 4 ) {
- if ( $message === "syntax error, unexpected T_ENCAPSED_AND_WHITESPACE" ) {
- $message = "syntax error, string is not closed";
- } else {
- $semiColonError = false;
- if ( strpos($message, 'syntax error,') === 0 && $errLine > 2 ) {
- $lines = ErrorHandler::getFileContents( $errFile );
-
- $line = $lines[$errLine-1];
- if ( preg_match( ErrorHandler::REGEX_MISSING_SEMI_COLON_FOLLOWING_LINE, $line ) !== 0 ) {
- $content = rtrim( join( "\n", array_slice($lines, 0, $errLine-1) ) );
-
- if ( strrpos($content, ';') !== strlen($content)-1 ) {
- $message = "Missing semi-colon";
- $errLine--;
- $srcErrLine = $errLine;
- $semiColonError = true;
- }
- }
- }
-
- if ( $semiColonError ) {
- $matches = array();
- $num = preg_match( '/\bunexpected ([A-Z_]+|\\$end)\b/', $message, $matches );
-
- if ( $num > 0 ) {
- $match = $matches[0];
- $newSymbol = ErrorHandler::phpSymbolToDescription( str_replace('unexpected ', '', $match) );
-
- $message = str_replace( $match, "unexpected $newSymbol", $message );
- }
-
- $matches = array();
- $num = preg_match( '/, expecting ([A-Z_]+|\\$end)( or ([A-Z_]+|\\$end))*/', $message, $matches );
-
- if ( $num > 0 ) {
- $match = $matches[0];
- $newMatch = str_replace( ", expecting ", '', $match );
- $symbols = explode( ' or ', $newMatch );
- foreach ( $symbols as $i => $sym ) {
- $symbols[$i] = ErrorHandler::phpSymbolToDescription( $sym );
- }
- $newMatch = join( ', or ', $symbols );
-
- $message = str_replace( $match, ", expecting $newMatch", $message );
- }
- }
- }
- /**
- * Undefined Variable, add syntax highlighting and make variable from 'foo' too '$foo'.
- */
- } else if ( $code === 8 ) {
- if (
- strpos($message, "Undefined variable:") !== false
- ) {
- $matches = array();
- preg_match( ErrorHandler::REGEX_VARIABLE, $message, $matches );
-
- if ( count($matches) > 0 ) {
- $message = 'Undefined variable $' . $matches[0] . '' ;
- }
- }
- /**
- * Invalid type given.
- */
- } else if ( $code === 4096 ) {
- if ( strpos($message, 'must be an ') ) {
- $message = preg_replace( '/, called in .*$/', '', $message );
-
- $matches = array();
- preg_match( ErrorHandler::REGEX_METHOD_OR_FUNCTION, $message, $matches );
-
- if ( $matches ) {
- $argumentMathces = array();
- preg_match( '/^Argument ([0-9]+)/', $message, $argumentMathces );
- $highlightArg = count($argumentMathces) === 2 ?
- (((int) $argumentMathces[1])-1) :
- null ;
-
- $fun = ErrorHandler::syntaxHighlightFunctionMatch( $matches[0], $stackTrace, $highlightArg );
-
- if ( $fun ) {
- $message = str_replace( 'passed to ', 'calling ', $message );
- $message = preg_replace( ErrorHandler::REGEX_METHOD_OR_FUNCTION, $fun, $message );
- $prioritizeCaller = true;
-
- /*
- * scalars not supported.
- */
- $scalarType = null;
- if ( ! ErrorHandler::$IS_SCALAR_TYPE_HINTING_SUPPORTED ) {
- foreach ( ErrorHandler::$SCALAR_TYPES as $scalar ) {
- if ( stripos($message, "must be an instance of $scalar,") !== false ) {
- $scalarType = $scalar;
- break;
- }
- }
- }
-
- if ( $scalarType !== null ) {
- $message = preg_replace( '/^Argument [0-9]+ calling /', 'Incorrect type hinting for ', $message );
- $message = preg_replace(
- '/ must be an instance of ' . ErrorHandler::REGEX_PHP_IDENTIFIER . '\b.*$/',
- ", ${scalarType} is not supported",
- $message
- );
-
- $prioritizeCaller = false;
- } else {
- $message = preg_replace( '/ must be an (instance of )?' . ErrorHandler::REGEX_PHP_IDENTIFIER . '\b/', '', $message );
-
- if ( preg_match('/, none given$/', $message) ) {
- $message = preg_replace( '/^Argument /', 'Missing argument ', $message );
- $message = preg_replace( '/, none given$/', '', $message );
- } else {
- $message = preg_replace( '/^Argument /', 'Incorrect argument ', $message );
- }
- }
-
- if ( $prioritizeCaller ) {
- list( $srcErrFile, $srcErrLine, $stackSearchI ) = $skipStackFirst( $stackTrace );
- }
- }
- }
- }
- }
-
- if ( $stackTrace !== null ) {
- $isEmpty = count( $stackTrace ) === 0 ;
-
- if ( $isEmpty ) {
- array_unshift( $stackTrace, array(
- 'line' => $errLine,
- 'file' => $errFile
- ) );
- } else if (
- count($stackTrace) > 0 && (
- (! isset($stackTrace[0]['line'])) ||
- ($stackTrace[0]['line'] !== $errLine)
- )
- ) {
- array_unshift( $stackTrace, array(
- 'line' => $errLine,
- 'file' => $errFile
- ) );
- }
-
- if ( $stackTrace && !$isEmpty ) {
- $ignoreCommons = false;
- $len = count($stackTrace);
-
- /*
- * The code above can prioritize a location in the stack trace,
- * this is 'stackSearchI'. So we should start our search from there,
- * and work down the stack.
- *
- * This is built in a way so that when it reaches the end, it'll loop
- * back round to the beginning, and check the traces we didn't check
- * last time.
- *
- * If stackSearchI was not altered, then it just searches from top
- * through to the bottom.
- */
- for ( $i = $stackSearchI; $i < $stackSearchI+$len; $i++ ) {
- $trace = &$stackTrace[ $i % $len ];
-
- if ( isset($trace['file']) && isset($trace['line']) ) {
- list( $type, $_ ) = $this->getFolderType( $root, $trace['file'] );
-
- if ( $type !== ErrorHandler::FILE_TYPE_IGNORE ) {
- if ( $type === ErrorHandler::FILE_TYPE_APPLICATION ) {
- $srcErrLine = $trace['line'];
- $srcErrFile = $trace['file'];
-
- break;
- } else if ( ! $ignoreCommons ) {
- $srcErrLine = $trace['line'];
- $srcErrFile = $trace['file'];
-
- $ignoreCommons = true;
- }
- }
- }
- }
- }
- }
-
- return array( $message, $srcErrFile, $srcErrLine, $altInfo );
- }
-
- /**
- * Parses the stack trace, and makes it look pretty.
- *
- * This includes adding in the syntax highlighting,
- * highlighting the colours for the files,
- * and padding with whitespace.
- *
- * If stackTrace is null, then null is returned.
- */
- private function parseStackTrace( $code, $message, $errLine, $errFile, &$stackTrace, $root, $altInfo=null ) {
- if ( $stackTrace !== null ) {
- /*
- * For whitespace padding.
- */
- $lineLen = 0;
- $fileLen = 0;
-
- // parse the stack trace, and remove the long urls
- foreach ( $stackTrace as $i => $trace ) {
- if ( $trace ) {
- if ( isset($trace['line'] ) ) {
- $lineLen = max( $lineLen, strlen($trace['line']) );
- } else {
- $trace['line'] = '';
- }
-
- $info = '';
-
- if ( $i === 0 && $altInfo !== null ) {
- $info = $altInfo;
- /*
- * Skip for the first iteration,
- * as it's usually magical PHP calls.
- */
- } else if (
- $i > 0 && (
- isset($trace['class']) ||
- isset($trace['type']) ||
- isset($trace['function'])
- )
- ) {
- $args = array();
- if ( isset($trace['args']) ) {
- foreach ( $trace['args'] as $arg ) {
- $args[]= ErrorHandler::identifyTypeHTML( $arg, 1 );
- }
- }
-
- $info = ErrorHandler::syntaxHighlightFunction(
- isset($trace['class']) ? $trace['class'] : null,
- isset($trace['type']) ? $trace['type'] : null,
- isset($trace['function']) ? $trace['function'] : null,
- $args
- );
- } else if ( isset($trace['info']) && $trace['info'] !== '' ) {
- $info = ErrorHandler::syntaxHighlight( $trace['info'] );
- } else if ( isset($trace['file']) && !isset($trace['info']) ) {
- $contents = $this->getFileContents( $trace['file'] );
-
- if ( $contents ) {
- $info = ErrorHandler::syntaxHighlight(
- trim( $contents[$trace['line']-1] )
- );
- }
- }
-
- $trace['info'] = $info;
-
- if ( isset($trace['file']) ) {
- list( $type, $file ) = $this->getFolderType( $root, $trace['file'] );
-
- $trace['file_type'] = $type;
- $trace['is_native'] = false;
- } else {
- $file = '[Internal PHP]';
-
- $trace['file_type'] = '';
- $trace['is_native'] = true;
- }
-
- $trace['file'] = $file;
-
- $fileLen = max( $fileLen, strlen($file) );
-
- $stackTrace[$i] = $trace;
- }
- }
-
- /*
- * We are allowed to highlight just once, that's it.
- */
- $highlightI = -1;
- foreach ( $stackTrace as $i => $trace ) {
- if (
- $trace['line'] === $errLine &&
- $trace['file'] === $errFile
- ) {
- $highlightI = $i;
- break;
- }
- }
-
- foreach ( $stackTrace as $i => $trace ) {
- if ( $trace ) {
- // line
- $line = str_pad( $trace['line'] , $lineLen, ' ', STR_PAD_LEFT );
-
- // file
- $file = $trace['file'];
- $fileKlass = '';
- if ( $trace['is_native'] ) {
- $fileKlass = 'file-internal-php';
- } else {
- $fileKlass = 'filename ' . ErrorHandler::folderTypeToCSS( $trace['file_type'] );
- }
- $file = $file . str_pad( '', $fileLen-strlen($file), ' ', STR_PAD_LEFT );
-
- // info
- $info = $trace['info'];
- if ( $info ) {
- $info = str_replace( "\n", '\n', $info );
- $info = str_replace( "\r", '\r', $info );
- } else {
- $info = ' ';
- }
-
- // line + file + info
- $stackStr =
- "$line | " .
- "$file | " .
- "$info | " ;
-
- if ( $trace['is_native'] ) {
- $cssClass = 'is-native ';
- } else {
- $cssClass = '';
- }
-
- if ( $highlightI === $i ) {
- $cssClass .= ' highlight';
- } else if ( $highlightI > $i ) {
- $cssClass .= ' pre-highlight';
- }
-
- if (
- $i !== 0 &&
- isset($trace['exception']) &&
- $trace['exception']
- ) {
- $ex = $trace['exception'];
-
- $exHtml = '' .
- 'exception "' .
- htmlspecialchars( $ex->getMessage() ) .
- '"' .
- ' |
';
- } else {
- $exHtml = '';
- }
-
- $data = '';
- if ( isset($trace['file-lines-id']) ) {
- $data = 'data-file-lines-id="' . $trace['file-lines-id'] . '"';
- }
-
- $stackTrace[$i] = "$exHtml$stackStr
";
- }
- }
-
- return '' . join( "", $stackTrace ) . '
';
- } else {
- return null;
- }
- }
-
- private function logError( $message, $file, $line, $ex=null ) {
- if ( $ex ) {
- $trace = $ex->getTraceAsString();
- $parts = explode( "\n", $trace );
- $trace = " " . join( "\n ", $parts );
-
- if ( ! ErrorHandler::isIIS() ) {
- error_log( "$message \n $file, $line \n$trace" );
- }
- } else {
- if ( ! ErrorHandler::isIIS() ) {
- error_log( "$message \n $file, $line" );
- }
- }
- }
-
- /**
- * Given a class name, which can include a namespace,
- * this will report that it is not found.
- *
- * This will also report it as an exception,
- * so you will get a full stack trace.
- */
- public function reportClassNotFound( $className ) {
- throw new ErrorException( "Class '$className' not found", E_ERROR, E_ERROR, __FILE__, __LINE__ );
- }
-
- /**
- * Given an exception, this will report it.
- */
- public function reportException( $ex ) {
- $this->reportError(
- $ex->getCode(),
- $ex->getMessage(),
- $ex->getLine(),
- $ex->getFile(),
- $ex
- );
- }
-
- /**
- * The entry point for handling an error.
- *
- * This is the lowest entry point for error reporting,
- * and for that reason it can either take just error info,
- * or a combination of error and exception information.
- *
- * Note that this will still log errors in the error log
- * even when it's disabled with ini. It just does nothing
- * more than that.
- */
- public function reportError( $code, $message, $errLine, $errFile, $ex=null ) {
- $this->discardBuffer();
-
- if (
- $ex === null &&
- $code === 1 &&
- strpos($message, "Class ") === 0 &&
- strpos($message, "not found") !== false &&
- $this->classNotFoundException !== null
- ) {
- $ex = $this->classNotFoundException;
-
- $code = $ex->getCode();
- $message = $ex->getMessage();
- $errLine = $ex->getLine();
- $errFile = $ex->getFile();
- $stackTrace = $ex->getTrace();
- }
-
- $this->logError( $message, $errFile, $errLine, $ex );
-
- /**
- * It runs if:
- * - it is globally enabled
- * - this error handler is enabled
- * - we believe it is a regular html request, or ajax
- */
- global $_php_error_is_ini_enabled;
- if (
- $_php_error_is_ini_enabled &&
- $this->isOn() && (
- $this->isAjax ||
- !$this->htmlOnly ||
- !ErrorHandler::isNonPHPRequest()
- )
- ) {
- $root = $this->applicationRoot;
-
- list( $ex, $stackTrace, $code, $errFile, $errLine ) =
- $this->getStackTrace( $ex, $code, $errFile, $errLine );
-
- list( $message, $srcErrFile, $srcErrLine, $altInfo ) =
- $this->improveErrorMessage(
- $ex,
- $code,
- $message,
- $errLine,
- $errFile,
- $root,
- $stackTrace
- );
-
- $errFile = $srcErrFile;
- $errLine = $srcErrLine;
-
- list( $fileLinesSets, $numFileLines ) = $this->generateFileLineSets( $srcErrFile, $srcErrLine, $stackTrace );
-
- list( $type, $errFile ) = $this->getFolderType( $root, $errFile );
- $errFileType = ErrorHandler::folderTypeToCSS( $type );
-
- $stackTrace = $this->parseStackTrace( $code, $message, $errLine, $errFile, $stackTrace, $root, $altInfo );
- $fileLines = $this->readCodeFile( $srcErrFile, $srcErrLine );
-
- // load the session, if it's there
-
- if ( isset($_COOKIE[session_name()]) && session_id() !== '' && !isset($_SESSION)) {
- session_start();
- }
-
- $request = ErrorHandler::getRequestHeaders();
- $response = ErrorHandler::getResponseHeaders();
-
- $dump = $this->generateDumpHTML(
- array(
- 'post' => ( isset($_POST) ? $_POST : array() ),
- 'get' => ( isset($_GET) ? $_GET : array() ),
- 'session' => ( isset($_SESSION) ? $_SESSION : array() ),
- 'cookies' => ( isset($_COOKIE) ? $_COOKIE : array() )
- ),
-
- $request,
- $response,
-
- $_SERVER
- );
- $this->displayError( $message, $srcErrLine, $errFile, $errFileType, $stackTrace, $fileLinesSets, $numFileLines, $dump );
-
- // exit in order to end processing
- $this->turnOff();
- exit(0);
- }
- }
-
- private function getStackTrace( $ex, $code, $errFile, $errLine ) {
- $stackTrace = null;
-
- if ( $ex !== null ) {
- $next = $ex;
- $stackTrace = array();
- $skipStacks = 0;
-
- for (
- $next = $ex;
- $next !== null;
- $next = $next->getPrevious()
- ) {
- $ex = $next;
-
- $stack = $ex->getTrace();
- $file = $ex->getFile();
- $line = $ex->getLine();
-
- if ( $stackTrace !== null && count($stackTrace) > 0 ) {
- $stack = array_slice( $stack, 0, count($stack)-count($stackTrace) + 1 );
- }
-
- if ( count($stack) > 0 && (
- !isset($stack[0]['file']) ||
- !isset($stack[0]['line']) ||
- $stack[0]['file'] !== $file ||
- $stack[0]['line'] !== $line
- ) ) {
- array_unshift( $stack, array(
- 'file' => $file,
- 'line' => $line
- ) );
- }
-
- $stackTrace = ( $stackTrace !== null ) ?
- array_merge( $stack, $stackTrace ) :
- $stack ;
-
- if ( count($stackTrace) > 0 ) {
- $stackTrace[0]['exception'] = $ex;
- }
- }
-
- $message = $ex->getMessage();
- $errFile = $ex->getFile();
- $errLine = $ex->getLine();
-
- $code = method_exists($ex, 'getSeverity') ?
- $ex->getSeverity() :
- $ex->getCode() ;
- }
-
- return array( $ex, $stackTrace, $code, $errFile, $errLine );
- }
-
- private function generateDumpHTML( $arrays, $request, $response, $server ) {
- $arrToHtml = function( $name, $array, $css='' ) {
- $max = 0;
-
- foreach ( $array as $e => $v ) {
- $max = max( $max, strlen( $e ) );
- }
-
- $snippet = "";
-
- foreach ( $array as $e => $v ) {
- $e = str_pad( $e, $max, ' ', STR_PAD_RIGHT );
-
- $e = htmlentities( $e );
- $v = ErrorHandler::identifyTypeHTML( $v, 3 );
-
- $snippet .= "$e
=>
$v
";
- }
-
- return "$snippet
";
- };
-
- $html = '';
- foreach ( $arrays as $key => $value ) {
- if ( isset($value) && $value ) {
- $html .= $arrToHtml( $key, $value );
- } else {
- unset($arrays[$key]);
- }
- }
-
- return "" .
- $html .
- $arrToHtml( 'request', $request, 'dump_request' ) .
- $arrToHtml( 'response', $response, 'dump_response' ) .
- $arrToHtml( 'server', $server, 'dump_server' ) .
- "
";
- }
-
- private function generateFileLineSets( $srcErrFile, $srcErrLine, &$stackTrace ) {
- $fileLineID = 1;
- $srcErrID = "file-line-$fileLineID";
- $fileLineID++;
-
- $lines = $this->readCodeFile( $srcErrFile, $srcErrLine );
- $minSize = count( $lines );
- $fileLinesSets = array( new FileLinesSet( $srcErrLine, $srcErrID, $lines, true ) );
-
- if ( $stackTrace ) {
- foreach ( $stackTrace as $i => &$trace ) {
- if ( $trace && isset($trace['file']) && isset($trace['line']) ) {
- $file = $trace['file'];
- $line = $trace['line'];
-
- if ( $file === $srcErrFile && $line === $srcErrLine ) {
- $trace['file-lines-id'] = $srcErrID;
- } else {
- $traceFileID = "file-line-$fileLineID";
- $trace['file-lines-id'] = $traceFileID;
-
- $lines = $this->readCodeFile( $file, $line );
- $minSize = max( $minSize, count($lines) );
- $fileLinesSets[]= new FileLinesSet( $line, $traceFileID, $lines, false );
-
- $fileLineID++;
- }
- }
- }
- }
-
- return array( $fileLinesSets, $minSize );
- }
-
- /*
- * Even if disabled, we still act like reporting is on,
- * if it's turned on.
- *
- * We just don't do anything.
- */
- private function setEnabled( $isOn ) {
- $wasOn = $this->isOn;
- $this->isOn = $isOn;
-
- global $_php_error_is_ini_enabled;
- if ( $_php_error_is_ini_enabled ) {
- /*
- * Only turn off, if we're moving from on to off.
- *
- * This is so if it's turned off without turning on,
- * we don't change anything.
- */
- if ( !$isOn ) {
- if ( $wasOn ) {
- $this->runDisableErrors();
- }
- /*
- * Always turn it on, even if already on.
- *
- * This is incase it was messed up in some way
- * by the user.
- */
- } else if ( $isOn ) {
- $this->runEnableErrors();
- }
- }
- }
-
- private function runDisableErrors() {
- global $_php_error_is_ini_enabled;
-
- if ( $_php_error_is_ini_enabled ) {
- error_reporting( $this->defaultErrorReportingOff );
-
- @ini_restore( 'html_errors' );
-
- if ( ErrorHandler::isIIS() ) {
- @ini_restore( 'log_errors' );
- }
- }
- }
-
- /*
- * Now the actual hooking into PHP's error reporting.
- *
- * We enable _ALL_ errors, and make them all exceptions.
- * We also need to hook into the shutdown function so
- * we can catch fatal and compile time errors.
- */
- private function runEnableErrors() {
- global $_php_error_is_ini_enabled;
-
- if ( $_php_error_is_ini_enabled ) {
- $catchSurpressedErrors = &$this->catchSurpressedErrors;
- $self = $this;
-
- // all errors \o/ !
- error_reporting( $this->defaultErrorReportingOn );
- @ini_set( 'html_errors', false );
-
- if ( ErrorHandler::isIIS() ) {
- @ini_set( 'log_errors', false );
- }
-
- set_error_handler(
- function( $code, $message, $file, $line, $context ) use ( $self, &$catchSurpressedErrors ) {
- /*
- * DO NOT! log the error.
- *
- * Either it's thrown as an exception, and so logged by the exception handler,
- * or we return false, and it's logged by PHP.
- *
- * Also DO NOT! throw an exception, instead report it.
- * This is because if an operation raises both a user AND
- * fatal error (such as require), then the exception is
- * silently ignored.
- */
- if ( $self->isOn() ) {
- /*
- * When using an @, the error reporting drops to 0.
- */
- if ( error_reporting() !== 0 || $catchSurpressedErrors ) {
- $ex = new ErrorException( $message, $code, $code, $file, $line );
-
- $self->reportException( $ex );
- }
- } else {
- return false;
- }
- },
- $this->defaultErrorReportingOn
- );
-
- set_exception_handler( function($ex) use ( $self ) {
- if ( $self->isOn() ) {
- $self->reportException( $ex );
- } else {
- return false;
- }
- });
-
- if ( ! $self->isShutdownRegistered ) {
- if ( $self->catchClassNotFound ) {
- $classException = &$self->classNotFoundException;
- $autoloaderFuns = ErrorHandler::$SAFE_AUTOLOADER_FUNCTIONS;
-
- /*
- * When this is called, the key point is that we don't error!
- *
- * Instead we record that an error has occurred,
- * if we believe one has, and then let PHP error as normal.
- * The stack trace we record is then used later.
- *
- * This is done for two reasons:
- * - functions like 'class_exists' will run the autoloader, and we shouldn't error on them
- * - on PHP 5.3.0, the class loader registered functions does *not* return closure objects, so we can't do anything clever.
- *
- * So we watch, but don't touch.
- */
- spl_autoload_register( function($className) use ( $self, &$classException, &$autoloaderFuns ) {
- if ( $self->isOn() ) {
- $classException = null;
-
- // search the stack first, to check if we are running from 'class_exists' before we error
- if ( defined('DEBUG_BACKTRACE_IGNORE_ARGS') ) {
- $trace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS );
- } else {
- $trace = debug_backtrace();
- }
- $error = true;
-
- foreach ( $trace as $row ) {
- if ( isset($row['function']) ) {
- $function = $row['function'];
-
- // they are just checking, so don't error
- if ( in_array($function, $autoloaderFuns, true) ) {
- $error = false;
- break;
- // not us, and not the autoloader, so error!
- } else if (
- $function !== '__autoload' &&
- $function !== 'spl_autoload_call' &&
- strpos($function, 'php_error\\') === false
- ) {
- break;
- }
- }
- }
-
- if ( $error ) {
- $classException = new ErrorException( "Class '$className' not found", E_ERROR, E_ERROR, __FILE__, __LINE__ );
- }
- }
- } );
- }
-
- $self->isShutdownRegistered = true;
- }
- }
- }
-
- private function displayJSInjection() {
- ?>applicationRoot;
- $serverName = $this->serverName;
- $backgroundText = $this->backgroundText;
- $displayLineNumber = $this->displayLineNumber;
-
- /*
- * When a query string is not provided,
- * in some versions it's a blank string,
- * whilst in others it's not set at all.
- */
- if ( isset($_SERVER['QUERY_STRING']) ) {
- $requestUrl = str_replace( $_SERVER['QUERY_STRING'], '', $_SERVER['REQUEST_URI'] );
- $requestUrlLen = strlen( $requestUrl );
-
- // remove the '?' if it's there (I suspect it isn't always, but don't take my word for it!)
- if ( $requestUrlLen > 0 && substr($requestUrl, $requestUrlLen-1) === '?' ) {
- $requestUrl = substr( $requestUrl, 0, $requestUrlLen-1 );
- }
- } else {
- $requestUrl = $_SERVER['REQUEST_URI'];
- }
-
- $this->displayHTML(
- // pre, in the head
- function() use( $message, $errFile, $errLine ) {
- echo "";
- },
-
- // the content
- function() use (
- $requestUrl,
- $backgroundText, $serverName, $applicationRoot,
- $message, $errLine, $errFile, $errFileType, $stackTrace,
- &$fileLinesSets, $numFileLines,
- $displayLineNumber,
- $dumpInfo
- ) {
- if ( $backgroundText ) { ?>
-
-
-
- |
-
- AJAX PAUSED
-
-
-
- X
- RETRY
-
-
-
-
-
-
- getHTMLID();
- $fileLines = $fileLinesSet->getLines();
- $show = $fileLinesSet->isShown();
- $highlightLine = $fileLinesSet->getLine();
-
- // calculate last line number length
- end($fileLines);
- $maxLineNumber = key($fileLines);
- $lineDecimals = strlen($maxLineNumber);
- ?>
-
- $origLine ) {
- $line = ltrim($origLine, ' ');
- $numSpaces = strlen($origLine) - strlen($line);
-
- $size = 8*$numSpaces + 64;
- $style = "style='padding-left: " . $size . "px; text-indent: -" . $size . "px;'";
-
- for ( $i = 0; $i < $numSpaces; $i++ ) {
- $line = " $line";
- }
-
- if ($displayLineNumber) {
- $lineNumLabel = str_replace(' ', ' ', sprintf("%{$lineDecimals}d", $lineNum));
- } else {
- $lineNumLabel = '';
- }
-
- ?>
class="error-file-line ">
-
-
-
-
-
-
-
- htmlOnly && ErrorHandler::isNonPHPRequest()) {
- @header( "Content-Type: text/html" );
- }
- @header( ErrorHandler::PHP_ERROR_MAGIC_HEADER_KEY . ': ' . ErrorHandler::PHP_ERROR_MAGIC_HEADER_VALUE );
-
- echo '';
-
- if ( $head !== null ) {
- $head();
- }
-
- echo "";
-
- ?>file = $file;
- $this->line = $line;
- }
- }
-
- /**
- * Code is outputted multiple times, for each file involved.
- * This allows us to wrap up a single set of code.
- */
- class FileLinesSet
- {
- private $id;
- private $lines;
- private $isShown;
- private $line;
-
- public function __construct( $line, $id, array $lines, $isShown ) {
- $this->id = $id;
- $this->lines = $lines;
- $this->isShown = $isShown;
- $this->line = $line;
- }
-
- public function getHTMLID() {
- return $this->id;
- }
-
- public function getLines() {
- return $this->lines;
- }
-
- public function isShown() {
- return $this->isShown;
- }
-
- public function getLine() {
- return $this->line;
- }
- }
-
- /**
- * jsmin.php - PHP implementation of Douglas Crockford's JSMin.
- *
- * This is pretty much a direct port of jsmin.c to PHP with just a few
- * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
- * outputs to stdout, this library accepts a string as input and returns another
- * string as output.
- *
- * PHP 5 or higher is required.
- *
- * Permission is hereby granted to use this version of the library under the
- * same terms as jsmin.c, which has the following license:
- *
- * --
- * Copyright (c) 2002 Douglas Crockford (www.crockford.com)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * The Software shall be used for Good, not Evil.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- * --
- *
- * @package JSMin
- * @author Ryan Grove
- * @copyright 2002 Douglas Crockford (jsmin.c)
- * @copyright 2008 Ryan Grove (PHP port)
- * @copyright 2012 Adam Goforth (Updates)
- * @license http://opensource.org/licenses/mit-license.php MIT License
- * @version 1.1.2 (2012-05-01)
- * @link https://github.com/rgrove/jsmin-php
- */
- class JSMin
- {
- const ORD_LF = 10;
- const ORD_SPACE = 32;
- const ACTION_KEEP_A = 1;
- const ACTION_DELETE_A = 2;
- const ACTION_DELETE_A_B = 3;
-
- protected $a = '';
- protected $b = '';
- protected $input = '';
- protected $inputIndex = 0;
- protected $inputLength = 0;
- protected $lookAhead = null;
- protected $output = '';
-
- // -- Public Static Methods --------------------------------------------------
-
- /**
- * Minify Javascript
- *
- * @uses __construct()
- * @uses min()
- * @param string $js Javascript to be minified
- * @return string
- */
- public static function minify($js) {
- $jsmin = new JSMin($js);
- return $jsmin->min();
- }
-
- // -- Public Instance Methods ------------------------------------------------
-
- /**
- * Constructor
- *
- * @param string $input Javascript to be minified
- */
- public function __construct($input) {
- $this->input = str_replace("\r\n", "\n", $input);
- $this->inputLength = strlen($this->input);
- }
-
- // -- Protected Instance Methods ---------------------------------------------
-
- /**
- * Action -- do something! What to do is determined by the $command argument.
- *
- * action treats a string as a single character. Wow!
- * action recognizes a regular expression if it is preceded by ( or , or =.
- *
- * @uses next()
- * @uses get()
- * @throws JSMinException If parser errors are found:
- * - Unterminated string literal
- * - Unterminated regular expression set in regex literal
- * - Unterminated regular expression literal
- * @param int $command One of class constants:
- * ACTION_KEEP_A Output A. Copy B to A. Get the next B.
- * ACTION_DELETE_A Copy B to A. Get the next B. (Delete A).
- * ACTION_DELETE_A_B Get the next B. (Delete B).
- */
- protected function action($command) {
- switch($command) {
- case self::ACTION_KEEP_A:
- $this->output .= $this->a;
-
- case self::ACTION_DELETE_A:
- $this->a = $this->b;
-
- if ($this->a === "'" || $this->a === '"') {
- for (;;) {
- $this->output .= $this->a;
- $this->a = $this->get();
-
- if ($this->a === $this->b) {
- break;
- }
-
- if (ord($this->a) <= self::ORD_LF) {
- throw new JSMinException('Unterminated string literal.');
- }
-
- if ($this->a === '\\') {
- $this->output .= $this->a;
- $this->a = $this->get();
- }
- }
- }
-
- case self::ACTION_DELETE_A_B:
- $this->b = $this->next();
-
- if ($this->b === '/' && (
- $this->a === '(' || $this->a === ',' || $this->a === '=' ||
- $this->a === ':' || $this->a === '[' || $this->a === '!' ||
- $this->a === '&' || $this->a === '|' || $this->a === '?' ||
- $this->a === '{' || $this->a === '}' || $this->a === ';' ||
- $this->a === "\n" )) {
-
- $this->output .= $this->a . $this->b;
-
- for (;;) {
- $this->a = $this->get();
-
- if ($this->a === '[') {
- /*
- inside a regex [...] set, which MAY contain a '/' itself. Example: mootools Form.Validator near line 460:
- return Form.Validator.getValidator('IsEmpty').test(element) || (/^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]\.?){0,63}[a-z0-9!#$%&'*+/=?^_`{|}~-]@(?:(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])$/i).test(element.get('value'));
- */
- for (;;) {
- $this->output .= $this->a;
- $this->a = $this->get();
-
- if ($this->a === ']') {
- break;
- } elseif ($this->a === '\\') {
- $this->output .= $this->a;
- $this->a = $this->get();
- } elseif (ord($this->a) <= self::ORD_LF) {
- throw new JSMinException('Unterminated regular expression set in regex literal.');
- }
- }
- } elseif ($this->a === '/') {
- break;
- } elseif ($this->a === '\\') {
- $this->output .= $this->a;
- $this->a = $this->get();
- } elseif (ord($this->a) <= self::ORD_LF) {
- throw new JSMinException('Unterminated regular expression literal.');
- }
-
- $this->output .= $this->a;
- }
-
- $this->b = $this->next();
- }
- }
- }
-
- /**
- * Get next char. Convert ctrl char to space.
- *
- * @return string|null
- */
- protected function get() {
- $c = $this->lookAhead;
- $this->lookAhead = null;
-
- if ($c === null) {
- if ($this->inputIndex < $this->inputLength) {
- $c = substr($this->input, $this->inputIndex, 1);
- $this->inputIndex += 1;
- } else {
- $c = null;
- }
- }
-
- if ($c === "\r") {
- return "\n";
- }
-
- if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
- return $c;
- }
-
- return ' ';
- }
-
- /**
- * Is $c a letter, digit, underscore, dollar sign, or non-ASCII character.
- *
- * @return bool
- */
- protected function isAlphaNum($c) {
- return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
- }
-
- /**
- * Perform minification, return result
- *
- * @uses action()
- * @uses isAlphaNum()
- * @uses get()
- * @uses peek()
- * @return string
- */
- protected function min() {
- if (0 == strncmp($this->peek(), "\xef", 1)) {
- $this->get();
- $this->get();
- $this->get();
- }
-
- $this->a = "\n";
- $this->action(self::ACTION_DELETE_A_B);
-
- while ($this->a !== null) {
- switch ($this->a) {
- case ' ':
- if ($this->isAlphaNum($this->b)) {
- $this->action(self::ACTION_KEEP_A);
- } else {
- $this->action(self::ACTION_DELETE_A);
- }
- break;
-
- case "\n":
- switch ($this->b) {
- case '{':
- case '[':
- case '(':
- case '+':
- case '-':
- case '!':
- case '~':
- $this->action(self::ACTION_KEEP_A);
- break;
-
- case ' ':
- $this->action(self::ACTION_DELETE_A_B);
- break;
-
- default:
- if ($this->isAlphaNum($this->b)) {
- $this->action(self::ACTION_KEEP_A);
- }
- else {
- $this->action(self::ACTION_DELETE_A);
- }
- }
- break;
-
- default:
- switch ($this->b) {
- case ' ':
- if ($this->isAlphaNum($this->a)) {
- $this->action(self::ACTION_KEEP_A);
- break;
- }
-
- $this->action(self::ACTION_DELETE_A_B);
- break;
-
- case "\n":
- switch ($this->a) {
- case '}':
- case ']':
- case ')':
- case '+':
- case '-':
- case '"':
- case "'":
- $this->action(self::ACTION_KEEP_A);
- break;
-
- default:
- if ($this->isAlphaNum($this->a)) {
- $this->action(self::ACTION_KEEP_A);
- }
- else {
- $this->action(self::ACTION_DELETE_A_B);
- }
- }
- break;
-
- default:
- $this->action(self::ACTION_KEEP_A);
- break;
- }
- }
- }
-
- return $this->output;
- }
-
- /**
- * Get the next character, skipping over comments. peek() is used to see
- * if a '/' is followed by a '/' or '*'.
- *
- * @uses get()
- * @uses peek()
- * @throws JSMinException On unterminated comment.
- * @return string
- */
- protected function next() {
- $c = $this->get();
-
- if ($c === '/') {
- switch($this->peek()) {
- case '/':
- for (;;) {
- $c = $this->get();
-
- if (ord($c) <= self::ORD_LF) {
- return $c;
- }
- }
-
- case '*':
- $this->get();
-
- for (;;) {
- switch($this->get()) {
- case '*':
- if ($this->peek() === '/') {
- $this->get();
- return ' ';
- }
- break;
-
- case null:
- throw new JSMinException('Unterminated comment.');
- }
- }
-
- default:
- return $c;
- }
- }
-
- return $c;
- }
-
- /**
- * Get next char. If is ctrl character, translate to a space or newline.
- *
- * @uses get()
- * @return string|null
- */
- protected function peek() {
- $this->lookAhead = $this->get();
- return $this->lookAhead;
- }
- }
-
- // -- Exceptions ---------------------------------------------------------------
- class JSMinException extends Exception {}
-
- if (
- $_php_error_is_ini_enabled &&
- $_php_error_global_handler === null &&
- @get_cfg_var('php_error.autorun')
- ) {
- reportErrors();
- }
- }
diff --git a/application/views/adif/data/exportall.php b/application/views/adif/data/exportall.php
index 8607c254..11538d72 100644
--- a/application/views/adif/data/exportall.php
+++ b/application/views/adif/data/exportall.php
@@ -1,7 +1,7 @@
session->userdata('user_callsign').'-'.date('dmY-Hi').'.adi"')
?>
2.2
config->item('app_name')); ?>>config->item('app_name')."\n"; ?>
diff --git a/application/views/layout/footer.php b/application/views/layout/footer.php
index 4972f3ed..37526163 100644
--- a/application/views/layout/footer.php
+++ b/application/views/layout/footer.php
@@ -1,6 +1,9 @@
+
-
+
@@ -127,4 +127,3 @@
-
diff --git a/application/views/user/profile.php b/application/views/user/profile.php
index 770f6aa3..d7017251 100644
--- a/application/views/user/profile.php
+++ b/application/views/user/profile.php
@@ -68,3 +68,4 @@
+
diff --git a/css/main.css b/css/main.css
index 97e03115..3904ed6d 100644
--- a/css/main.css
+++ b/css/main.css
@@ -1,14 +1,18 @@
-html, body {height: 100%;}
-
-#wrap {min-height: 100%;}
-
-#main {overflow:hidden; padding-bottom: 3em; /* must be same height as the footer */ }
+body,html{
+ height:100%;
+}
+#wrap {
+ min-height:100%;
+}
+#footer{
+ margin-top:-40px;
+ text-align: right;
+ padding-bottom: 10px;
+}
+
#container { padding-top: 50px; width: 940px; margin: 0 auto; }
-#footer { width: 940px; margin: -3em auto; text-align: right; position: relative; clear:both; height: 3em;
-/* margin-top must be the negative value of footer height */ }
-
table .titles { font-weight: bold; color: #439BF6; }
table .title { font-weight: bold; color: #439BF6; }