복붙노트

"SET NAMES"사용 여부

PHP

"SET NAMES"사용 여부

오라일리 (O'Reilly)의 "고성능 MySQL"을 읽으면서 다음과 같은 것을 발견했습니다.

나는 "SET NAMES utf8"을 모든 스크립트의 맨 위에 놓았 기 때문에 db가 내 쿼리가 utf8로 인코딩되었음을 알았 기 때문에 약간 혼란 스럽습니다.

누구든지 위의 인용문을 언급하거나 더 공식적으로 말하면 내 데이터베이스 워크 플로우가 유니 코드를 인식하도록하기위한 제안 / 우수 사례는 무엇입니까?

내 대상 언어는 관련성이있는 경우 php 및 python입니다.

해결법

  1. ==============================

    1.mysql_set_charset ()은 옵션이 될 것이지만 옵션은 ext / mysql로 ​​제한된다. ext / mysqli의 경우 mysqli_set_charset이고 PDO :: mysql의 경우 연결 매개 변수를 지정해야합니다.

    mysql_set_charset ()은 옵션이 될 것이지만 옵션은 ext / mysql로 ​​제한된다. ext / mysqli의 경우 mysqli_set_charset이고 PDO :: mysql의 경우 연결 매개 변수를 지정해야합니다.

    이 함수를 사용하면 MySQL API 호출이되므로 쿼리를 실행하는 것보다 훨씬 빨리 고려해야합니다.

    성능 측면에서 스크립트와 MySQL 서버 간의 UTF-8 기반 통신을 보장하는 가장 빠른 방법은 MySQL 서버를 올바르게 설정하는 것입니다. SET NAMES x는 다음과 같습니다.

    SET character_set_client = x;
    SET character_set_results = x;
    SET character_set_connection = x;
    

    SET character_set_connection = x는 내부적으로 SET collation_connection = << default_collation_of_character_set_x >>도 실행합니다. my.ini / cnf에서이 서버 변수를 정적으로 설정할 수도 있습니다.

    동일한 MySQL 서버 인스턴스에서 실행 중이고 다른 문자 집합이 필요한 다른 응용 프로그램에 발생할 수있는 문제점을 알고 있어야합니다.

  2. ==============================

    2.

    // The key is the "charset=utf8" part.
    $dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8';
    $dbh = new PDO($dsn, 'user', 'pass');
    

    이 답변은 PHP의 pdo 라이브러리에 중점을두고 있기 때문에 매우 유비 쿼터스합니다.

    간단한주의 사항 - mysql은 클라이언트 - 서버 아키텍처이다. 이것은 실제 데이터베이스가있는 mysql 서버뿐만 아니라 별도의 엔티티 인 mysql 서버와 통신하는 별도의 mysql 클라이언트 드라이버가 있기 때문에 중요합니다. mysql 클라이언트와 pdo가 함께 섞여 있다고 할 수 있습니다.

    set names utf8을 사용할 때, mysql에 표준 sql 쿼리를 보낸다. sql 쿼리는 pdo를 통과 한 다음 mysql 클라이언트 라이브러리를 통과하고 마지막으로 mysql 서버에 도달하지만 mysql 서버는 해당 sql 쿼리를 구문 분석하고 해석합니다. 이는 mysql 서버가 pdo 또는 mysql 클라이언트에게 문자 세트를 알려주고 인코딩이 변경되었음을 알리는 메시지를 보내지 않기 때문에 중요합니다. 따라서 mysql 클라이언트와 pdo는 실제로 일어난 사실을 전혀 모릅니다.

    클라이언트 라이브러리가 현재 문자 집합을 인식하지 못하는 경우 문자열을 제대로 처리 할 수 ​​없으므로이 작업을 수행하지 않는 것이 중요합니다. 대부분의 일반 작업은 클라이언트가 올바른 문자 집합을 알지 못해도 올바르게 작동하지만 PDO :: quote와 같이 문자열 이스케이프 처리가되지 않습니다. Prepared Statement를 사용하기 때문에 수동 원시 문자열 이스케이프에 대해 걱정할 필요가 없다고 생각할 수도 있습니다. 그러나 사실 pdo : mysql 사용자는 pdo : mysql의 기본 설정이기 때문에 모르는 사이에 prepared prepared statement를 사용합니다. 운전사는 아주 오랫동안 지금. 에뮬레이션 된 prepared statement는 mysql API에 의해 제공되는 실제 native mysql prepared statement를 사용하지 않는다; 대신 PHP는 모든 값에 대해 PDO :: quote ()를 호출하고 인용 된 값으로 모든 자리 표시자를 str_replacing하는 것과 동일합니다.

    사용중인 문자 집합을 알지 못하면 문자열을 올바르게 이스케이프 할 수 없으므로 집합 이름을 통해 특정 문자 집합으로 변경 한 경우 이러한 에뮬레이트 된 준비 문은 SQL 삽입에 취약합니다. SQL 삽입의 가능성에 관계없이 다른 문자 집합을위한 이스케이프 스키마를 사용하면 문자열을 손상시킬 수 있습니다.

    pdo mysql 드라이버의 경우 DSN에 지정하여 연결할 때 문자 집합을 지정할 수 있습니다. 이렇게하면 클라이언트 라이브러리와 서버가 문자 세트를 인식하게되므로 필요한대로 작동합니다.

    // The key is the "charset=utf8" part.
    $dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8';
    $dbh = new PDO($dsn, 'user', 'pass');
    

    그러나 부적절한 문자열 이스케이프는 유일한 문제는 아닙니다. 예를 들어, 열 이름이 문자열로 지정 되었기 때문에 PDO :: bindColumn을 사용하는 데 문제가있을 수 있으므로 다시 인코딩해야합니다. 예를 들어 ütube라는 열 이름 (움라우트 참고)이있을 수 있으며 라틴에서 utf8로 설정 이름을 사용하여 전환 한 다음 $ stmt-> bindColumn ( 'ütube', $ var); php 파일은 utf8로 인코딩되기 때문에 ütube는 utf8로 인코딩 된 문자열입니다. 작동하지 않을 것입니다. 문자열을 latin1 변형으로 인코딩해야합니다. 이제 모든 종류의 미쳐 버릴 수 있습니다.

  3. ==============================

    3.py에 대해서는 잘 모르겠지만 php는 mysql_set_charset을 가지고 있습니다. 이것은 "SET NAMES를 실행하기 위해 mysql_query ()를 사용하여 charset [및]을 변경하는 것이 더 바람직하지 않습니다." 이 함수는 MySQL 5.0.7에서 처음 소개되었으므로 이전 버전에서는 작동하지 않습니다.

    py에 대해서는 잘 모르겠지만 php는 mysql_set_charset을 가지고 있습니다. 이것은 "SET NAMES를 실행하기 위해 mysql_query ()를 사용하여 charset [및]을 변경하는 것이 더 바람직하지 않습니다." 이 함수는 MySQL 5.0.7에서 처음 소개되었으므로 이전 버전에서는 작동하지 않습니다.

    mysql_set_charset('utf8', $link);
    

    $ link는 mysql_connect로 생성 된 연결이다.

  4. from https://stackoverflow.com/questions/1650591/whether-to-use-set-names by cc-by-sa and MIT license