Linux

utf8을utf8mb4로변환 업그레이드 php프로그램

아이티제어 2022. 5. 11. 11:10

euckr 에서 utf8넘어온후에 DB문자셋 변경할일 없을줄알았는데..

아래 그림은 이모지의 코드번호 캡춰화면이다  .

이모티콘 그림을  문자로 만들어 놓은것으로 생각된다.

그것도 모르고 여적 문자가 아닌 그림인 줄알았다. ^^ -_-;

한글URL주소 처럼 이모티콘URL주소도 가능하고 , text 이모티콘 검색어로도 가능하다.

카톡에 이모티콘(이모지) 문자포함된글을  게시판에 붙어넣었더니글이 짤리는 버그가 발견되었다.

왜그런가 한참을 원인 분석하다가 결국 이모티콘 특수문자에서 잘린것을 알았다.

그리고 어떤떄엔  이모지, 이모티콘이 모두 물음표(????) 로만 나왔다.

이젠 그누보드도 게시판 글쓰기 오류를 패치해야할 때가 온것같다.~

 

-------------이모지(이모티콘) utf8mb4코드 ( 4바이트)===

--------------------------------------------------------------------그림1-------

 

 

1) utf8 문자셋(3바이트)을 utf8mb4 로  4바이트 문자셋으로 바꿔야한다.

2)정렬은 utf8_general_ci 가 아닌 utf8mb4_general_ci 혹은 utf8_unicode_ci 로 collation 해줘야.

3) MySQL 5.7이상 업그레이드 필요.

4)​ 카톡,네이버 구글 ,주소창 모두 이모지 문자가 먹힌다. gnu에서는 현재 물음표(?) 로 표시된다.

어떤것은 이모지문자후에 글자가 잘린다.

---------- 변환 시작 -----

1. DB 기본세팅 변경

ALTER TABLE `yourDBName`.`yourTableName` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

2. Table 변경 프로그램 가동한다. 

 

<?php
/**
 * Requires php >= 5.5
 *  
 * This is a PHP port from: https://gist.github.com/njvack/6113127
 *
 *이것을 하기전에 백업하세요. mysqldump -h localhost -u root -pYourPW  yourDBName >  yourDbName_bakup.sql
 *
 * DB는  utf8 시작 입니다.
 *
 * $dsn = 'mysql:host=localhost;port=3306;charset=utf8';
 * 
 *  한번만 실행하면 끝나는데.  에러나만 계속 새로고침 합니다.  
 *
 * @author hollodotme *
 * @author derclops since 2019-07-01
 *         - convert the database to utf8mb4
 *         - convert all tables to utf8mb4
 *         - actually then also convert the data to utf8mb4

아래는 위에 저작자분이 만든것을 일부수정 ydb=YurDBName  넣어서 쓸수있게 하였고 lantin1 을  utf8로 하였음. 

이소스를 my_cvt_utf8to_utf8mb4.php로저장했다면 

  http://localhost/my_cvt_utf8to_utf8mb4.php?ydb=YurDbName   이런식으로  실행합니다.

 */
 
error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING );

$ydb=$_GET['ydb'];
if(!$ydb) {echo "<h1>ydb=</h1>"; exit ; }

$dsn      = 'mysql:host=localhost;port=3306;charset=utf8';
$user     = 'root';
$password = 'YOUR_PW';
$options  = [
    \PDO::ATTR_CURSOR                   => \PDO::CURSOR_FWDONLY,
    \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
    \PDO::MYSQL_ATTR_INIT_COMMAND       => "SET CHARACTER SET utf8",
];


header('Content-Type: text/plain; charset=utf-8');

$oDb = new \PDO( $dsn, $user, $password, $options );

$databasesToConvert = [ $ydb/** database3, ... */ ];
$typesToConvert     = [ 'char', 'varchar', 'tinytext', 'mediumtext', 'text', 'longtext' ];

foreach ( $databasesToConvert as $database )
{
    echo $database, ":\n";
    echo str_repeat( '=', strlen( $database ) + 1 ), "\n";

    $oDb->exec( "USE `{$database}`" );

    echo "converting database to correct locale too ... \n";

    $oDb->exec("ALTER DATABASE `{$database}` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci");


    $tablesStatement = $oDb->query( "SHOW TABLES" );
    while ( ($table = $tablesStatement->fetchColumn()) )
    {
        echo "Table: {$table}:\n";
        echo str_repeat( '-', strlen( $table ) + 8 ), "\n";

        $columnsToConvert = [ ];

        $columsStatement = $oDb->query( "DESCRIBE `{$table}`" );

        while ( ($tableInfo = $columsStatement->fetch( \PDO::FETCH_ASSOC )) )
        {
            $column = $tableInfo['Field'];
            echo ' * ' . $column . ': ' . $tableInfo['Type'];

            $type = preg_replace( "#\(\d+\)#", '', $tableInfo['Type'] );

            if ( in_array( $type, $typesToConvert ) )
            {
                echo " => must be converted\n";

                $columnsToConvert[] = $column;
            }
            else
            {
                echo " => not relevant\n";
            }
        }


        //convert table also!!!
        $convert = "ALTER TABLE `{$table}` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci";

        echo "\n", $convert, "\n";
        $oDb->exec( $convert );
        $databaseErrors = $oDb->errorInfo();
        if( !empty($databaseErrors[1]) ){
            echo "\n !!!!!!!!!!!!!!!!! ERROR OCCURED ".print_r($databaseErrors, true)." \n";
            exit;
        }


        if ( !empty($columnsToConvert) )
        {
            $converts = array_map(
                function ( $column )
                {
                    //return "`{$column}` = IFNULL(CONVERT(CAST(CONVERT(`{$column}` USING utf8) AS binary) USING utf8mb4),`{$column}`)";
                    return "`{$column}` = CONVERT(BINARY(CONVERT(`{$column}` USING utf8)) USING utf8mb4)";
                },
                $columnsToConvert
            );

            $query = "UPDATE IGNORE `{$table}` SET " . join( ', ', $converts );

            //alternative
            // UPDATE feedback SET reply = CONVERT(BINARY(CONVERT(reply USING utf8)) USING utf8mb4) WHERE feedback_id = 15015;


            echo "\n", $query, "\n";


            $oDb->exec( $query );

            $databaseErrors = $oDb->errorInfo();
            if( !empty($databaseErrors[1]) ){
                echo "\n !!!!!!!!!!!!!!!!! ERROR OCCURED ".print_r($databaseErrors, true)." \n";
                exit;
            }
        }

        echo "\n--\n";
    }

    echo "\n";
}
?>

 

 

이것을 실행하게되면 아래 에러가 발생하는경우 있다.

==아래 에러코드 == <code>

 

!!!!!!!!!!!!!!!!! ERROR OCCURED Array ( [0] => 42000 [1] => 1071 [2] => Specified key was too long; max key length is 1000 bytes )

 

에러마다 alter table 해서 필드 크기를 줄여줘야한다.  끝날때까지 새로고침. 계속 해준다.

<code>#예제

 

alter table `g5_apms_cache` change `c_name` `c_name` varchar(200) NOT NULL DEFAULT '' ;

끝까지 필드 에 맞게 계속 반복..


/common.php 파일수정 

#이부분 을 찾아

    $connect_db = sql_connect(G5_MYSQL_HOST, G5_MYSQL_USER, G5_MYSQL_PASSWORD) or die('MySQL Connect Error!!!'); 
    $select_db  = sql_select_db(G5_MYSQL_DB, $connect_db) or die('MySQL DB Error!!!');       
    // mysql connect resource $g5 배열에 저장 - 명랑폐인님 제안
    $g5['connect_db'] = $connect_db; 

    #이건 빼고 --    sql_set_charset('utf8', $connect_db); 

    #++ 아래 추가. 

        define('G5_NAMES','utf8mb4');

        sql_set_charset(G5_NAMES , $connect_db); 
        if( G5_NAMES =="utf8mb4" )$utf8_general_ci="utf8mb4_unicode_ci";

        sql_query("set session character_set_connection=".G5_NAMES);
        sql_query("set session character_set_results=".G5_NAMES);
        sql_query("set session character_set_client=".G5_NAMES);
        if($utf8_general_ci) sql_query("SET collation_connection = $utf8_general_ci ");  

 

#/adm/dbupdate.php 파일수정

  # $COLL 을 원하는곳 common.php나 config.php에  선언해두고 alter table 혹은 create table 등 코드중간에 $COLL을 넣어준다. 
  $COLL ="COLLATE utf8mb4_unicode_ci ";  

  dbupdate.php 파일의  sql문장 varchar 중간에 $COLL 을 넣어준다,  varchar(200) $COLL 식으로.

 

    #++  끝

 

my.cnf 파일 수정해도 되고 안해도되고

[mysqld]

character-set-server=utf8mb4

collation-server=utf8mb4_unicode_ci

 

이상으로 이모지, 이모티콘 변환방법을 마칩니다.

 

다음엔 시간나면 새로추가된 이모지, 이모티콘 특수문자에 대해서 ~ 쓰고싶어짐니다.^^

도움이 되셨다면 좋아요  꾹~ (그러면  글쓰는 이에게  힘이 되곘죠!)

 2020.9.26

수다원 올림.

참고: https://github.com/emoji/emoji.github.com

 

GitHub - emoji/emoji.github.com

Contribute to emoji/emoji.github.com development by creating an account on GitHub.

github.com

아이티제어 ( = 수다원 )  2022.05.11  gnuboard DB utf8에서  utf8mb4로 upgrade방법