복붙노트

PDO MySQL : PDO :: ATTR_EMULATE_PREPARES를 사용하거나 사용하지 않습니까?

PHP

PDO MySQL : PDO :: ATTR_EMULATE_PREPARES를 사용하거나 사용하지 않습니까?

이것은 PDO에 관한 지금까지 읽은 것입니다 :: ATTR_EMULATE_PREPARES :

나는이 진술 중 어떤 것이 더 이상 진실인지 모른다. MySQL 인터페이스를 선택할 때 가장 큰 관심사는 SQL 삽입을 방지하는 것입니다. 두 번째 관심사는 실적입니다.

내 응용 프로그램은 현재 준비된 문없이 절차 적 MySQLi를 사용하며 쿼리 캐시를 상당히 활용합니다. 단일 요청으로 준비된 문을 거의 다시 사용하지 않습니다. 필자는 명명 된 매개 변수와 준비된 문에 대한 보안을 위해 PDO 로의 이동을 시작했습니다.

MySQL 5.1.61과 PHP 5.3.2를 사용하고 있습니다.

PDO :: ATTR_EMULATE_PREPARES를 활성화 상태로 두어야합니까? 쿼리 캐시의 성능과 준비된 명령문의 보안을 둘 다 가질 수있는 방법이 있습니까?

해결법

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

    1.귀하의 우려에 대답하십시오 :

    귀하의 우려에 대답하십시오 :

    추가 고려 사항 :

    최종 권장 사항으로 MySQL + PHP의 이전 버전에서는 준비된 문장을 에뮬레이션해야한다고 생각하지만 최신 버전에서는 에뮬레이션을 해제해야합니다.

    PDO를 사용하는 몇 가지 응용 프로그램을 작성한 후 필자는 PDO 연결 기능을 만들었습니다.이 기능을 사용하면 최상의 설정이라고 생각됩니다. 아마도 다음과 같은 것을 사용하거나 원하는 설정을 조정해야합니다.

    /**
     * Return PDO handle for a MySQL connection using supplied settings
     *
     * Tries to do the right thing with different php and mysql versions.
     *
     * @param array $settings with keys: host, port, unix_socket, dbname, charset, user, pass. Some may be omitted or NULL.
     * @return PDO
     * @author Francis Avila
     */
    function connect_PDO($settings)
    {
        $emulate_prepares_below_version = '5.1.17';
    
        $dsndefaults = array_fill_keys(array('host', 'port', 'unix_socket', 'dbname', 'charset'), null);
        $dsnarr = array_intersect_key($settings, $dsndefaults);
        $dsnarr += $dsndefaults;
    
        // connection options I like
        $options = array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
        );
    
        // connection charset handling for old php versions
        if ($dsnarr['charset'] and version_compare(PHP_VERSION, '5.3.6', '<')) {
            $options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$dsnarr['charset'];
        }
        $dsnpairs = array();
        foreach ($dsnarr as $k => $v) {
            if ($v===null) continue;
            $dsnpairs[] = "{$k}={$v}";
        }
    
        $dsn = 'mysql:'.implode(';', $dsnpairs);
        $dbh = new PDO($dsn, $settings['user'], $settings['pass'], $options);
    
        // Set prepared statement emulation depending on server version
        $serverversion = $dbh->getAttribute(PDO::ATTR_SERVER_VERSION);
        $emulate_prepares = (version_compare($serverversion, $emulate_prepares_below_version, '<'));
        $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, $emulate_prepares);
    
        return $dbh;
    }
    
  2. ==============================

    2.PHP pdo_mysql이 mysqlnd에 대해 컴파일되지 않을 때 PDO :: ATTR_EMULATE_PREPARES (네이티브 준비)를 비활성화하는 것에주의하십시오.

    PHP pdo_mysql이 mysqlnd에 대해 컴파일되지 않을 때 PDO :: ATTR_EMULATE_PREPARES (네이티브 준비)를 비활성화하는 것에주의하십시오.

    오래된 libmysql은 일부 기능과 완벽하게 호환되지 않기 때문에 이상한 버그가 발생할 수 있습니다. 예를 들면 다음과 같습니다.

    이 버그는 pdo_mysql 모듈 용 libmysql을 사용하는 다른 서버로 마이그레이션 할 때 간단한 프로젝트에서 알아 냈습니다. 어쩌면 더 많은 버그가 있을지 모르겠다. 또한 새로운 64 비트 데비안 jessie에서 테스트를 거쳤습니다. 나열된 모든 버그는 필자가 apt-get php5-mysql을 설치할 때 발생하고 apt-get php5-mysqlnd를 설치할 때 사라집니다.

    PDO :: ATTR_EMULATE_PREPARES가 true (기본값)로 설정되면 PDO가이 모드에서 준비된 문을 전혀 사용하지 않기 때문에 이러한 버그는 발생하지 않습니다. 따라서 libmysql ( "mysqlnd"부분 문자열이 phpinfo의 pdo_mysql 섹션에있는 "Client API version"필드에 표시되지 않음) 기반의 pdo_mysql을 사용하는 경우 PDO :: ATTR_EMULATE_PREPARES를 해제하면 안됩니다.

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

    3.필자는 PDO가 네이티브 준비된 명령문 기능을 활용한다는 것을 의미하는 5.1을 실행하면서 에뮬레이션을 준비하지 않을 것입니다.

    필자는 PDO가 네이티브 준비된 명령문 기능을 활용한다는 것을 의미하는 5.1을 실행하면서 에뮬레이션을 준비하지 않을 것입니다.

    http://php.net/manual/en/ref.pdo-mysql.php

    나는 준비된 명명 된 구문과 더 나은 API를 위해 MySQLi를 PDO 용으로 버렸다.

    그러나 균형을 이루기 위해 PDO는 MySQLi보다 느리게 수행되지만, 염두에 두어야 할 사항입니다. 제가 선택을했을 때 이것을 알았습니다. 그리고 더 나은 API와 업계 표준을 사용하는 것이 당신을 특정 엔진에 묶는 무시할 정도로 빠른 라이브러리를 사용하는 것보다 중요하다고 결정했습니다. FWIW PHP 팀도 MySQLi를 통해 PDO를 유리하게 바라보고 있다고 생각합니다.

  4. ==============================

    4.에뮬레이션이 모든 것을 잡아 내지 못하기 때문에 실제 데이터베이스 PREPARE 호출을 활성화하는 것이 좋습니다. 예를 들어 INSERT를 준비합니다.

    에뮬레이션이 모든 것을 잡아 내지 못하기 때문에 실제 데이터베이스 PREPARE 호출을 활성화하는 것이 좋습니다. 예를 들어 INSERT를 준비합니다.

    var_dump($dbh->prepare('INSERT;'));
    $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    var_dump($dbh->prepare('INSERT;'));
    

    출력

    object(PDOStatement)#2 (1) {
      ["queryString"]=>
      string(7) "INSERT;"
    }
    bool(false)
    

    실제로 작동하는 코드에 대해 기꺼이 성능을 향상시킬 것입니다.

    FWIW

    PHP 버전 : PHP 5.4.9-4ubuntu2.4 (cli)

    MySQL 버전 : 5.5.34-0ubuntu0

  5. ==============================

    5.에뮬레이션을 '거짓'으로 전환하는 이유는 무엇입니까? 이 주된 이유는 데이터베이스 엔진이 PDO 대신 준비를 수행하면 쿼리와 실제 데이터가 별도로 전송되어 보안이 강화된다는 것입니다. 이것은 매개 변수가 쿼리에 전달 될 때 MySQL에 준비된 문이 단일 쿼리로 제한되기 때문에 SQL에 삽입하려는 시도가 차단된다는 것을 의미합니다. 즉, 매개 변수에 두 번째 쿼리를 전달하면 진정한 준비 문이 실패합니다.

    에뮬레이션을 '거짓'으로 전환하는 이유는 무엇입니까? 이 주된 이유는 데이터베이스 엔진이 PDO 대신 준비를 수행하면 쿼리와 실제 데이터가 별도로 전송되어 보안이 강화된다는 것입니다. 이것은 매개 변수가 쿼리에 전달 될 때 MySQL에 준비된 문이 단일 쿼리로 제한되기 때문에 SQL에 삽입하려는 시도가 차단된다는 것을 의미합니다. 즉, 매개 변수에 두 번째 쿼리를 전달하면 진정한 준비 문이 실패합니다.

    Prepare vs PDO를위한 데이터베이스 엔진 사용에 대한 주된 논쟁은 서버에 대한 두 번의 경로입니다. 하나는 준비를위한 것이고 다른 하나는 매개 변수가 전달되는 것입니다. 그러나 추가 된 보안은 가치가 있다고 생각합니다. 또한 적어도 MySQL의 경우 버전 5.1부터 쿼리 캐싱이 문제되지 않았습니다.

    https://michaelseiler.net/2016/07/04/dont-emulate-prepared-statements-pdo-mysql/

  6. from https://stackoverflow.com/questions/10113562/pdo-mysql-use-pdoattr-emulate-prepares-or-not by cc-by-sa and MIT license