482 lines
13 KiB
PHP
482 lines
13 KiB
PHP
<?php
|
|
/**
|
|
* @brief Template Class
|
|
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
|
* @copyright (c) Invision Power Services, Inc.
|
|
* @license https://www.invisioncommunity.com/legal/standards/
|
|
* @package Invision Community
|
|
* @since 9 Sept 2013
|
|
*/
|
|
|
|
namespace IPSUtf8\Output\Browser;
|
|
|
|
/**
|
|
* Template Class
|
|
*/
|
|
class Template
|
|
{
|
|
public static function wrapper( $title="IPS Converter", $content="", $isError=false )
|
|
{
|
|
$iniTime = @ini_get('max_execution_time');
|
|
$execTime = ( \is_numeric( $iniTime ) ) ? $iniTime : 30;
|
|
$url = \IPSUtf8\Output\Browser::$url;
|
|
$title = ( empty( $title ) ) ? 'IPS Converter' : $title;
|
|
$active = array( 'convert' => '', 'tools' => '', 'archive' => '' );
|
|
$hasArchive = \IPSUtf8\Session::i()->has_archive;
|
|
$controller = preg_replace( "/[^a-zA-Z0-9]/", '', empty( \IPSUtf8\Request::i()->controller ) ? 'browser' : \IPSUtf8\Request::i()->controller );
|
|
$version = \IPSUtf8\Convert::VERSION_ID;
|
|
$copyrightDate = date('Y');
|
|
|
|
if ( $controller == 'browser' )
|
|
{
|
|
$active['convert'] = 'active';
|
|
}
|
|
else if ( $controller === 'archive' )
|
|
{
|
|
$active['archive'] = 'active';
|
|
}
|
|
else
|
|
{
|
|
$active['tools'] = 'active';
|
|
}
|
|
|
|
$html = <<<EOFHTML
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>{$title}</title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
|
|
<link href="css/jumbotron.css" rel="stylesheet" media="screen">
|
|
</head>
|
|
<body data-url="{$url}">
|
|
<div class="container">
|
|
<div class="header">
|
|
EOFHTML;
|
|
|
|
if ( ! $isError )
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<ul class="nav nav-pills pull-right">
|
|
<li class="{$active['convert']}"><a href="{url="?controller=browser"}">Convert</a></li>
|
|
EOFHTML;
|
|
if ( $hasArchive )
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<li class="{$active['archive']}"><a href="{url="?controller=archive"}">Archive</a></li>
|
|
EOFHTML;
|
|
}
|
|
|
|
$html .= <<<EOFHTML
|
|
<li class="{$active['tools']}"><a href="{url="?controller=tools"}">Tools</a></li>
|
|
</ul>
|
|
EOFHTML;
|
|
}
|
|
$html .= <<<EOFHTML
|
|
<h3 class="text-muted">IPS UTF8 Converter</h3>
|
|
</div>
|
|
{$content}
|
|
<div class="footer">
|
|
<p>UTF8 Converter v{$version} © {$copyrightDate} Invision Power Services, Inc.</p>
|
|
</div>
|
|
</div>
|
|
<script type="text/javascript">
|
|
var ipsSettings = { maxExecTime: {$execTime}, 'controller': '{$controller}' };
|
|
</script>
|
|
<script src="js/jquery.min.js"></script>
|
|
<script src="js/app.js?v=1"></script>
|
|
<script src="js/bootstrap.min.js"></script>
|
|
</body>
|
|
</html>
|
|
<div class="modal fade" id="confirmModal" data-url="" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
<h4 class="modal-title">Confirm</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p id="confirmModalText">Please confirm this action</p>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-primary" data-modal="submit">Confirm</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
EOFHTML;
|
|
|
|
return static::parse( $html );
|
|
}
|
|
|
|
/**
|
|
* Tools page
|
|
*/
|
|
public static function tools( $isUtf8, $msg )
|
|
{
|
|
$html = <<<EOFHTML
|
|
<div class="jumbotron">
|
|
<h1>Tools</h1>
|
|
EOFHTML;
|
|
|
|
if ( $msg !== null )
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<p>
|
|
<div class='alert alert-info'>{$msg}</div>
|
|
</p>
|
|
<p> </p>
|
|
EOFHTML;
|
|
}
|
|
|
|
if ( ! isset( \IPSUtf8\Request::i()->do ) )
|
|
{
|
|
if ( $isUtf8 === true )
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<p class="text-info">The database is set to UTF-8.</p>
|
|
<p><a class="btn btn-lg btn-info" href="{url="?controller=tools&do=collation"}">Check and fix UTF-8 collation</a></p>
|
|
EOFHTML;
|
|
}
|
|
else
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<p class="text-info">Please <a href="{url="?controller=browser"}">convert to UTF-8</a> first.</p>
|
|
EOFHTML;
|
|
}
|
|
}
|
|
|
|
$html .= <<<EOFHTML
|
|
</div>
|
|
EOFHTML;
|
|
|
|
$code = implode( "<br />", \IPSUtf8\Convert::i()->getDebugString() );
|
|
|
|
$html .= <<<EOFHTML
|
|
<div class="jumbotron">
|
|
<h1>Info</h1>
|
|
<code>
|
|
{$code}
|
|
</code>
|
|
</div>
|
|
EOFHTML;
|
|
|
|
return static::parse( $html );
|
|
}
|
|
|
|
/**
|
|
* Error page
|
|
*/
|
|
public static function error( $msg )
|
|
{
|
|
$html = <<<EOFHTML
|
|
<div class="jumbotron">
|
|
<h1>Error</h1>
|
|
<p class="lead">{$msg}</p>
|
|
</div>
|
|
EOFHTML;
|
|
|
|
return static::parse( $html );
|
|
}
|
|
|
|
/**
|
|
* Error page explaining about database being Invision Community already
|
|
*/
|
|
public static function errorAlreadyIPS4()
|
|
{
|
|
$html = <<<EOFHTML
|
|
<p style="text-align:left">
|
|
The target database is already running Invision Community. There is no conversion required and the UTF8 converter is locked.
|
|
<br>To override this and unlock the UTF8 converter, please create a file called "constants.php" and upload it to your /admin/convertutf8/ directory with the following contents:
|
|
</p>
|
|
<p><textarea class="form-control" style="height:90px;"><?php
|
|
\\define( 'BYPASS_SAFETY_LOCK', true );
|
|
|
|
</textarea>
|
|
</p>
|
|
<p class="text-danger">Please remember to remove the constants.php file when you are finished!</p>
|
|
|
|
EOFHTML;
|
|
|
|
return static::parse( $html );
|
|
}
|
|
|
|
/**
|
|
* Welcome page
|
|
*/
|
|
public static function welcome( $isUtf8, $status, $percent=false, $controller='browser' )
|
|
{
|
|
$convertClass = ( $controller === 'browser' ) ? '\IPSUtf8\Convert' : '\IPSUtf8\Convert\Archive';
|
|
$origUtf8Charset = \IPSUtf8\Db::i('utf8')->getCharset();
|
|
$canUseMb4 = ( version_compare( \IPSUtf8\Db::i()->server_info, '5.5.3', '>=' ) AND \IPSUtf8\Db::i('utf8')->set_charset('utf8mb4') !== FALSE );
|
|
\IPSUtf8\Db::i('utf8')->set_charset( $origUtf8Charset );
|
|
$badCollations = $convertClass::i()->getNonUtf8CollationTables();
|
|
$badTablesCnt = \count( $convertClass::i()->getNonUtf8Tables() );
|
|
$path = ROOT_PATH;
|
|
$dbCharSetIsCorrect = TRUE;
|
|
$isUtf8mb4 = ( $isUtf8 === TRUE AND \IPSUtf8\Convert::i()->database_charset == 'utf8mb4' );
|
|
|
|
if ( file_exists( ROOT_PATH . '/conf_global.php' ) )
|
|
{
|
|
require_once( ROOT_PATH . '/conf_global.php' );
|
|
if ( !isset( $INFO['sql_charset'] ) OR ! \in_array( $INFO['sql_charset'], array( 'utf8', 'utf8mb4' ) ) )
|
|
{
|
|
$dbCharSetIsCorrect = FALSE;
|
|
}
|
|
}
|
|
|
|
if ( isset( \IPSUtf8\Request::i()->convert_anyway ) AND \IPSUtf8\Request::i()->convert_anyway == 1 )
|
|
{
|
|
$badTablesCnt = \IPSUtf8\Session::i()->json['tableCount'];
|
|
}
|
|
|
|
$html = <<<EOFHTML
|
|
<div class="jumbotron">
|
|
<h1>Welcome</h1>
|
|
EOFHTML;
|
|
|
|
if ( $controller === 'archive' )
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<p class="text-info">The converter has detected that you have an archive table in a different database.</p>
|
|
EOFHTML;
|
|
}
|
|
|
|
if ( $status === 'processing' )
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<p class="text-warning">Conversion in progress ({$percent}% complete).</p>
|
|
EOFHTML;
|
|
}
|
|
else if ( $isUtf8 !== true )
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<p class="lead">You have {$badTablesCnt} table(s) in this database that are not UTF-8.\nYou must convert these tables to UTF-8 before you can proceed with the upgrade.</p>
|
|
EOFHTML;
|
|
}
|
|
else if ( $isUtf8 === true )
|
|
{
|
|
if ( \count( $badCollations ) )
|
|
{
|
|
$cnt = \count( $badCollations );
|
|
$html .= <<<EOFHTML
|
|
<p class="text-info">
|
|
The database is set to UTF-8, however {$cnt} table(s) have incorrect collations and need fixing.
|
|
<p><a class="btn btn-lg btn-info" href="{url="?controller=tools&do=collation"}">Fix UTF-8 collations</a></p>
|
|
</p>
|
|
EOFHTML;
|
|
}
|
|
else
|
|
{
|
|
/* If the charset stored for the gb_char_set setting is not utf-8, then we'll hit an endless loop unless we fix it here */
|
|
\IPSUtf8\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => 'utf-8' ), array( 'conf_key=?', 'gb_char_set' ) );
|
|
|
|
$html .= <<<EOFHTML
|
|
|
|
<p class="text-info">
|
|
The database tables are UTF-8, collations are correct and there is nothing to convert. You can <strong><a href="../upgrade">proceed with the upgrade</strong>.
|
|
</p>
|
|
EOFHTML;
|
|
}
|
|
}
|
|
|
|
if ( ! $isUtf8 and $canUseMb4 )
|
|
{
|
|
$text = ( $status === 'processing' ) ? "Continue Conversion" : "Begin Conversion";
|
|
|
|
$html .= <<<EOFHTML
|
|
<p>
|
|
<a data-status="{$status}" class="btn btn-lg btn-info" href="{url="?controller={$controller}&do=process&use_utf8mb4=1"}">{$text}</a>
|
|
</p>
|
|
EOFHTML;
|
|
}
|
|
|
|
if ( ! $isUtf8 and !$canUseMb4 )
|
|
{
|
|
$label = 'Start using UTF-8 (utf8)';
|
|
$selector = 'btn-success';
|
|
$more = <<<EOFHTML
|
|
<br>
|
|
<div class='small'>
|
|
<small>
|
|
Please note that you should turn your community offline before starting any conversion on a live site.
|
|
</small>
|
|
</div>
|
|
<br>
|
|
<div class='small'>
|
|
<small>
|
|
If you have a large community, or are experiencing browser timeouts during conversion, you may wish to consider running the conversion via the Command Line.<br>
|
|
<code>
|
|
cd {$path}/admin/convertutf8
|
|
php cli.php
|
|
</code>
|
|
</small>
|
|
</div>
|
|
EOFHTML;
|
|
}
|
|
|
|
if ( $status === 'processing' )
|
|
{
|
|
$label = 'Continue Conversion';
|
|
$selector = 'btn-warning';
|
|
$more = '';
|
|
}
|
|
else if ( ! $isUtf8 )
|
|
{
|
|
$label = "Begin Conversion";
|
|
$selector = 'btn-info';
|
|
}
|
|
|
|
if ( $label and $selector AND ! $isUtf8 and ! $canUseMb4 )
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<p>
|
|
<a data-status="{$status}" class="btn btn-lg {$selector}" href="{url="?controller={$controller}&do=process"}">{$label}</a>
|
|
{$more}
|
|
</p>
|
|
EOFHTML;
|
|
}
|
|
|
|
if ( $status === 'processing' )
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<p><small><a data-status="reset" data-confirm="true" class='text-danger' href="{url="?controller={$controller}&do=reset"}">Reset conversion and restart</a></small></p>
|
|
EOFHTML;
|
|
}
|
|
$html .= <<<EOFHTML
|
|
</div>
|
|
EOFHTML;
|
|
|
|
return static::parse( $html );
|
|
}
|
|
|
|
/**
|
|
* Process page
|
|
*/
|
|
public static function process( $status, $percent, $msg )
|
|
{
|
|
$utfPrefix = \IPSUtf8\Db::i('utf8')->prefix . \IPSUtf8\Db::i()->prefix;
|
|
|
|
$html = <<<EOFHTML
|
|
<div class="jumbotron" data-init="processInit">
|
|
<h1>Converting</h1>
|
|
<p> </p>
|
|
<p>
|
|
<div class="progress progress-striped active">
|
|
<div id="progressBar" data-start="{$percent}" class="progress-bar" role="progressbar" aria-valuenow="{$percent}" aria-valuemin="0" aria-valuemax="100" style="width: {$percent}%">
|
|
<span class='sr-only'>{$msg}</span>
|
|
</div>
|
|
</div>
|
|
</p>
|
|
<p id="message">{$msg}</p>
|
|
</div>
|
|
EOFHTML;
|
|
|
|
return static::parse( $html );
|
|
}
|
|
|
|
/**
|
|
* Completed page
|
|
*/
|
|
public static function completed( $timeTaken )
|
|
{
|
|
$html = <<<EOFHTML
|
|
<div class="jumbotron">
|
|
<h1>Almost there!</h1>
|
|
<p class="lead">The database has now been converted!</p>
|
|
<p><small>Conversion took {$timeTaken}</small></p>
|
|
<p> </p>
|
|
<p><a class="btn btn-lg btn-info" href="{url="?controller=browser&do=finish"}">Click here to finish</a></p>
|
|
</div>
|
|
EOFHTML;
|
|
|
|
return static::parse( $html );
|
|
}
|
|
|
|
/**
|
|
* Finish page
|
|
*/
|
|
public static function finished( $updated )
|
|
{
|
|
$utfPrefix = \IPSUtf8\Db::i('utf8')->prefix;
|
|
$normalPrefix = \IPSUtf8\Db::i()->prefix;
|
|
$sessionData = \IPSUtf8\Session::i()->json;
|
|
$sql_charset = ( array_key_exists( 'utf8mb4', $sessionData['charSets'] ) ) ? 'utf8mb4' : 'utf8';
|
|
|
|
/* Phil made me give him credit for some changes in this code */
|
|
$html = <<<EOFHTML
|
|
<div class="jumbotron">
|
|
<h1>Finished!</h1>
|
|
<p class="lead">The database has now been converted and the tables correctly renamed!</p>
|
|
EOFHTML;
|
|
|
|
if ( \IPSUtf8\Request::i()->controller === 'browser' )
|
|
{
|
|
if( !$updated )
|
|
{
|
|
$utf8mb4 = ( $sql_charset == 'utf8mb4' ) ? "<br>\$INFO['sql_utf8mb4'] = true;" : '';
|
|
$html .= <<<EOFHTML
|
|
<p>You can now <strong>complete the conversion</strong> by editing conf_global.php to add <br><code>\$INFO['sql_charset'] = '{$sql_charset}';{$utf8mb4}</code>.<br>Afterwards, you can <strong><a href="../upgrade">proceed with the upgrade</strong>.</p>
|
|
</div>
|
|
EOFHTML;
|
|
}
|
|
else
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<p>You can now <strong><a href="../upgrade">proceed with the upgrade</strong>.</p>
|
|
</div>
|
|
EOFHTML;
|
|
}
|
|
}
|
|
else if ( \IPSUtf8\Request::i()->controller === 'archive' )
|
|
{
|
|
$html .= <<<EOFHTML
|
|
<p>You can now <strong>complete the conversion</strong> by converting the <a href="{url="?controller=browser"}">main database</a> if you've not already done so.</p>
|
|
</div>
|
|
EOFHTML;
|
|
}
|
|
return static::parse( $html );
|
|
}
|
|
|
|
/**
|
|
* Basic HTML parsing
|
|
*
|
|
* @param string $html Raw HTML
|
|
* @return string
|
|
*/
|
|
protected static function parse( $html )
|
|
{
|
|
/* Parse {plugin="foo"} tags */
|
|
$html = preg_replace_callback
|
|
(
|
|
'/\{([a-z]+?=([\'"]).+?\\2 ?+)}/',
|
|
function( $matches )
|
|
{
|
|
/* Work out the plugin and the values to pass */
|
|
preg_match_all( '/(.+?)='.$matches[2].'(.+?)'.$matches[2].'\s?/', $matches[1], $submatches );
|
|
|
|
$plugin = array_shift( $submatches[1] );
|
|
$value = array_shift( $submatches[2] );
|
|
$options = array();
|
|
|
|
foreach ( $submatches[1] as $k => $v )
|
|
{
|
|
$options[ $v ] = $submatches[2][ $k ];
|
|
}
|
|
|
|
switch( $plugin )
|
|
{
|
|
case 'url':
|
|
return \IPSUtf8\Output\Browser::$url . $value;
|
|
break;
|
|
}
|
|
},
|
|
$html
|
|
);
|
|
|
|
return $html;
|
|
|
|
}
|
|
|
|
} |