Disallow rebuilding data before encoding conversion
authorAlexander Ebert <ebert@woltlab.com>
Sat, 19 Nov 2016 20:07:36 +0000 (21:07 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Sat, 19 Nov 2016 20:07:36 +0000 (21:07 +0100)
wcfsetup/install/files/acp/templates/rebuildData.tpl
wcfsetup/install/files/lib/acp/page/RebuildDataPage.class.php

index 9988c47e0d831af89d91b9732c03d243bb78b34b..fc50f88e75eab9e1ba83995fdb996e42c58f03fb 100644 (file)
        </header>
        
        {foreach from=$objectTypes item=objectType}
+               {assign var=_allowRebuild value=true}
+               {if !$convertEncoding && $objectType->objectType != 'com.woltlab.wcf.databaseConvertEncoding'}
+                       {assign var=_allowRebuild value=false}
+               {/if}
+               
                <dl class="wide">
                        <dd>
-                               <a class="button small" id="rebuildData{@$objectType->objectTypeID}">{lang}wcf.acp.rebuildData.{@$objectType->objectType}{/lang}</a>
+                               <a class="button small{if !$_allowRebuild} disabled{/if}" id="rebuildData{@$objectType->objectTypeID}">{lang}wcf.acp.rebuildData.{@$objectType->objectType}{/lang}</a>
                                <small>{lang}wcf.acp.rebuildData.{@$objectType->objectType}.description{/lang}</small>
                                
-                               <script data-relocate="true">
-                                       $(function() {
-                                               $('#rebuildData{@$objectType->objectTypeID}').click(function () {
-                                                       new WCF.ACP.Worker('cache', '{@$objectType->className|encodeJS}', '{lang}wcf.acp.rebuildData.{@$objectType->objectType}{/lang}');
+                               {if $_allowRebuild}
+                                       <script data-relocate="true">
+                                               $(function() {
+                                                       $('#rebuildData{@$objectType->objectTypeID}').click(function () {
+                                                               new WCF.ACP.Worker('cache', '{@$objectType->className|encodeJS}', '{lang}wcf.acp.rebuildData.{@$objectType->objectType}{/lang}');
+                                                       });
                                                });
-                                       });
-                               </script>
+                                       </script>
+                               {/if}
                        </dd>
                </dl>
        {/foreach}
index c15fc4311d43ff5efd9bdcb1b38841647db8957a..7bcbb888fef5a427eb90fb8d5098e635e2dd6239 100644 (file)
@@ -18,6 +18,12 @@ class RebuildDataPage extends AbstractPage {
         */
        public $activeMenuItem = 'wcf.acp.menu.link.maintenance.rebuildData';
        
+       /**
+        * disallow any rebuild actions unless `wcfN_user_storage` uses `utf8mb4`
+        * @var boolean
+        */
+       public $convertEncoding = false;
+       
        /**
         * @inheritDoc
         */
@@ -66,6 +72,25 @@ class RebuildDataPage extends AbstractPage {
                if ($row && $row['Value'] == 1) {
                        $this->showInnoDBWarning = true;
                }
+               
+               // We're disallowing rebuilding any other data unless the
+               // database encoding has been converted to utf8mb4. The
+               // user_storage table is used as a reference, as it is the
+               // last WCF table that holds a varchar column.
+               // 
+               // Querying the columns for each table to reliably detect
+               // the need of an encoding conversion isn't an option, as
+               // it turns out to be super slow to retrieve this data.
+               $sql = "SHOW FULL COLUMNS FROM wcf".WCF_N."_user_storage";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute();
+               while ($row = $statement->fetchArray()) {
+                       if ($row['Field'] === 'field') {
+                               if (preg_match('~^utf8mb4~', $row['Collation'])) {
+                                       $this->convertEncoding = true;
+                               }
+                       }
+               }
        }
        
        /**
@@ -75,6 +100,7 @@ class RebuildDataPage extends AbstractPage {
                parent::assignVariables();
                
                WCF::getTPL()->assign([
+                       'convertEncoding' => $this->convertEncoding,
                        'objectTypes' => $this->objectTypes,
                        'showInnoDBWarning' => $this->showInnoDBWarning
                ]);