251 lines
6.6 KiB
PHP
251 lines
6.6 KiB
PHP
<?php
|
|
/**
|
|
* @brief Init for UTF8 Conversion
|
|
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
|
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
|
* @license http://www.invisionpower.com/legal/standards/
|
|
* @package IPS Community Suite
|
|
* @since 4 Sept 2013
|
|
* @version SVN_VERSION_NUMBER
|
|
*/
|
|
|
|
namespace IPSUtf8;
|
|
|
|
/**
|
|
* Class to contain IPS Community Suite autoloader and exception handler
|
|
*/
|
|
class IPSUtf8
|
|
{
|
|
/**
|
|
* Initiate IPS Community Suite UTF8 Converter, autoloader and exception handler
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function init()
|
|
{
|
|
/* Set timezone */
|
|
date_default_timezone_set( 'UTC' );
|
|
|
|
/* Set default MB internal encoding */
|
|
mb_internal_encoding('UTF-8');
|
|
|
|
/* Constants */
|
|
define( 'THIS_PATH', __DIR__ );
|
|
|
|
$bits = explode( DIRECTORY_SEPARATOR, THIS_PATH );
|
|
$bit = array_pop( $bits );
|
|
$bit2 = array_pop( $bits );
|
|
|
|
define( 'ROOT_PATH', preg_replace( '#' . preg_quote( DIRECTORY_SEPARATOR, '#' ) . $bit2 . preg_quote( DIRECTORY_SEPARATOR, '#' ) . $bit . '$#', '', THIS_PATH ) );
|
|
|
|
define( 'IS_CLI', ( PHP_SAPI == 'cli' || empty( $_SERVER['REMOTE_ADDR'] ) ) ? true : false );
|
|
|
|
/* Set Options - deliberately do not use root constants */
|
|
if ( file_exists( './constants.php' ) )
|
|
{
|
|
@include_once( './constants.php' );
|
|
}
|
|
|
|
foreach( static::defaultConstants() AS $k => $v )
|
|
{
|
|
if ( !defined( $k ) )
|
|
{
|
|
define( $k, $v );
|
|
}
|
|
}
|
|
|
|
@set_time_limit(0);
|
|
|
|
/* Set autoloader */
|
|
spl_autoload_register( '\IPSUtf8\IPSUtf8::autoloader', true, true );
|
|
|
|
set_error_handler( '\IPSUtf8\IPSUtf8::errorHandler' );
|
|
set_exception_handler( '\IPSUtf8\IPSUtf8::exceptionHandler' );
|
|
}
|
|
|
|
/**
|
|
* Default Constants
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function defaultConstants()
|
|
{
|
|
return array(
|
|
'IPB_FIREWALL' => 1, /* This is a workaround for an old exploit to prevent upgrade issues */
|
|
'IPB_LOCK' => TRUE, /* Lock conversion to only IP.Board Databases */
|
|
'BYPASS_SAFETY_LOCK' => FALSE,
|
|
'FORCE_CONVERT' => FALSE, /* Enforce conversion */
|
|
'FORCE_CONVERT_CHARSET' => NULL,
|
|
'FORCE_CONVERT_METHOD' => NULL,
|
|
'SOURCE_DB_CHARSET' => NULL, /* If set, will force the source database connection to use this charset */
|
|
'UTF8_INSERT_ONLY' => FALSE, /* If true, and sql_charset is present and set to utf8 in conf_global.php, then the "fast" method will simply insert without converting. Useful for mixed collation databases where the utf8 tables are real utf8 */
|
|
'FORCE_MULTI_CONVERT' => FALSE, /* Forces the converter to use CONVERT(CONVERT(CONVERT(x AS <SOURCE_DB_CHARSET>) AS BINARY) AS UTF8) which is needed in some random old data sets */
|
|
'LOG' => FALSE, /* Log Conversion Data */
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Error Handler
|
|
*
|
|
* @param int $errno Error number
|
|
* @param errstr $errstr Error message
|
|
* @param string $errfile File
|
|
* @param int $errline Line
|
|
* @param array $trace Backtract
|
|
* @return void
|
|
*/
|
|
public static function errorHandler( $errno, $errstr, $errfile, $errline, $trace=NULL )
|
|
{
|
|
if ( in_array( $errno, array( E_NOTICE ) ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
throw new \ErrorException( $errstr, $errno, 0, $errfile, $errline );
|
|
}
|
|
|
|
/**
|
|
* Exception Handler
|
|
*
|
|
* @param \Exception $exception Exception class
|
|
* @return void
|
|
*/
|
|
public static function exceptionHandler( $exception )
|
|
{
|
|
/* Send a diagnostics report if we can */
|
|
$trace = $exception->getTrace();
|
|
if ( isset( $trace[0]['class'] ) )
|
|
{
|
|
self::diagnostics( $exception, $trace[0]['class'] );
|
|
}
|
|
|
|
/* And display an error screen */
|
|
try
|
|
{
|
|
if ( IS_CLI )
|
|
{
|
|
print "\nError: " . $exception->getMessage() . "\nFile: " . str_replace( THIS_PATH, '', $exception->getFile() ) . "\nLine: " . $exception->getLine() . "\n";
|
|
}
|
|
else
|
|
{
|
|
/* @todo Elaborate on this for browser */
|
|
print "\nError: " . $exception->getMessage() . "\nFile: " . str_replace( THIS_PATH, '', $exception->getFile() ) . "\nLine: " . $exception->getLine() . "\n";
|
|
}
|
|
}
|
|
catch ( \Exception $e )
|
|
{
|
|
if( isset( $_SERVER['SERVER_PROTOCOL'] ) and \strstr( $_SERVER['SERVER_PROTOCOL'], '/1.0' ) !== false )
|
|
{
|
|
header( "HTTP/1.0 500 Internal Server Error" );
|
|
}
|
|
else
|
|
{
|
|
header( "HTTP/1.1 500 Internal Server Error" );
|
|
}
|
|
|
|
if ( IS_CLI )
|
|
{
|
|
print "\nError: " . $e->getMessage() . "\nString: " . $e->getString() . "\nFile: " . str_replace( THIS_PATH, '', $e->getFile() ) . "\nLine: " . $e->getLine() . "\n";
|
|
}
|
|
else
|
|
{
|
|
/* @todo Elaborate on this for browser */
|
|
print "\nError: " . $e->getMessage() . "\nString: " . $e->getString() . "\nFile: " . str_replace( THIS_PATH, '', $e->getFile() ) . "\nLine: " . $e->getLine() . "\n";
|
|
}
|
|
}
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Diagnostics Reporting
|
|
*
|
|
* @param \Exception $exception Exception
|
|
* @param string $class Class that caused the exception
|
|
* @return void
|
|
*/
|
|
public static function diagnostics( $exception, $class )
|
|
{
|
|
try
|
|
{
|
|
@file_put_contents( THIS_PATH . '/tmp/error_' . date('Y-m-d') . '.cgi', "\n" . str_repeat( '-', 48 ) . "\n" . date('r') . "\n" . var_export( $exception, true ), FILE_APPEND );
|
|
}
|
|
catch ( \Exception $e ) {}
|
|
}
|
|
|
|
/**
|
|
* Autoloader
|
|
*
|
|
* @param string $classname Class to load
|
|
* @return void
|
|
*/
|
|
public static function autoloader( $classname )
|
|
{
|
|
/* Separate by namespace */
|
|
$bits = explode( '\\', $classname );
|
|
$vendorName = array_shift( $bits );
|
|
|
|
/* Work out what namespace we're in */
|
|
$class = array_pop( $bits );
|
|
$namespace = empty( $bits ) ? 'IPSUtf8' : ( 'IPSUtf8\\' . implode( '\\', $bits ) );
|
|
|
|
if( !class_exists( "{$namespace}\\{$class}", FALSE ) )
|
|
{
|
|
/* Locate file */
|
|
$path = THIS_PATH . '/';
|
|
$sourcesDirSet = FALSE;
|
|
|
|
foreach ( array_merge( $bits, array( $class ) ) as $i => $bit )
|
|
{
|
|
if( preg_match( "/^[a-z0-9]/", $bit ) )
|
|
{
|
|
if( $i === 0 )
|
|
{
|
|
$sourcesDirSet = TRUE;
|
|
}
|
|
}
|
|
else if( $sourcesDirSet === FALSE )
|
|
{
|
|
$path .= 'system/';
|
|
|
|
$sourcesDirSet = TRUE;
|
|
}
|
|
|
|
$path .= "{$bit}/";
|
|
}
|
|
|
|
/* Load it */
|
|
$path = \substr( $path, 0, -1 ) . '.php';
|
|
|
|
if( !file_exists( $path ) )
|
|
{
|
|
$path = \substr( $path, 0, -4 ) . \substr( $path, \strrpos( $path, '/' ) );
|
|
|
|
if ( !file_exists( $path ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
require_once( $path );
|
|
|
|
/* Is it an interface? */
|
|
if ( interface_exists( "{$namespace}\\{$class}", FALSE ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Doesn't exist? */
|
|
if( !class_exists( "{$namespace}\\{$class}", FALSE ) )
|
|
{
|
|
trigger_error( "Class {$classname} could not be loaded. Ensure it is in the correct namespace.", E_USER_ERROR );
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* Init */
|
|
IPSUtf8::init();
|
|
|
|
|