PHP에서 mysql_* 함수를 사용하면 안 되는 이유는 무엇입니까?

사용해서는 안 되는 기술적 이유는 무엇입니까?mysql_*기능하고 있습니까?(예:mysql_query(),mysql_connect()또는mysql_real_escape_string())?

내 사이트에서 작동하는데 다른 것을 사용해야 하는 이유는 무엇입니까?

내 사이트에서 작동하지 않는 경우 다음과 같은 오류가 발생하는 이유는 무엇입니까?

경고: mysql_connect(): 해당 파일 또는 디렉토리가 없습니다.



질문에 대한 답변



MySQL 확장자:

  • 현재 개발 중이 아님
  • PHP 5.5(2013년 6월 출시)를 기점으로 공식적으로 폐지되었습니다.
  • PHP 7.0(2015년 12월 출시)에서 완전히 삭제되었습니다.
    • 즉, 2018년 12월 31일 현재 지원되는 버전의 PHP에는 존재하지 않습니다.이를 지원하는 PHP 버전을 사용하는 경우 보안 문제가 해결되지 않은 버전을 사용하는 것입니다.
  • OO 인터페이스가 없음
  • 지원하지 않음:
    • 비블로킹, 비동기 쿼리
    • 준비된 문 또는 매개 변수화된 쿼리
    • 저장 프로시저
    • 복수 스테이트먼트
    • 트랜잭션
    • “새로운” 비밀번호 인증 방식(MySQL 5.6에서는 기본 설정, 5.7에서는 필수)
    • MySQL 5.1 이후 신기능 중 하나

더 이상 사용되지 않기 때문에 이 기능을 사용하면 향후 코드 증명에 도움이 되지 않습니다.

준비된 스테이트먼트를 지원하지 않는 것이 특히 중요합니다.이것은, 다른 함수 호출에 의해서 수동으로 데이터를 이스케이프 하는 것보다, 외부 데이터를 이스케이프 해 견적하는, 보다 명확하고 에러가 발생하기 쉬운 방법을 제공하기 때문입니다.

SQL 확장비교를 참조하십시오.




PHP는 MySQL에 접속하기 위한 3가지 API를 제공합니다.(PHP 7에서 삭제됨), 및 확장입니다.

mysql_*예전에는 매우 인기가 많았지만, 이제는 그 사용이 권장되지 않습니다.문서 팀은 데이터베이스 보안 상황에 대해 논의하고 있으며, 일반적으로 사용되는 ext/mysql 확장자에서 벗어나도록 사용자를 교육하는 것도 그 일부입니다(ph.internals: decreating ext/mysql).

그리고 나중에 나온 PHP 개발자 팀은 사용자가 MySQL에 접속할 때 오류를 발생시키기로 결정했습니다.mysql_connect(),mysql_pconnect()또는 암묵적인 접속기능이 내장되어 있습니다.ext/mysql.

ext/mysql PHP 5.5에서 공식적으로 폐지되었으며 PHP 7에서 제거되었습니다.

빨간 상자 보여?

어떤 일을 할 때mysql_*기능 매뉴얼 페이지에 빨간색 상자가 표시되어 더 이상 사용하지 않아야 함을 설명합니다.

왜죠


에서 벗어나다ext/mysql보안뿐만 아니라 MySQL 데이터베이스의 모든 기능에 액세스할 수 있어야 합니다.

ext/mysqlMySQL 3.23용으로 구축되어 그 이후 거의 추가되지 않았지만 대부분 이전 버전과의 호환성을 유지하고 있어 코드를 유지하기가 다소 어렵습니다.에서 지원되지 않는 기능 누락ext/mysqlinclude: (PHP 매뉴얼 참조)

기능을 사용하지 않는 이유:

  • 현재 개발 중이 아님
  • PHP 7에서 삭제됨
  • OO 인터페이스가 없음
  • 비차단 비동기 쿼리를 지원하지 않습니다.
  • 준비된 문 또는 매개 변수화된 쿼리를 지원하지 않습니다.
  • 저장 프로시저를 지원하지 않습니다.
  • 여러 문을 지원하지 않습니다.
  • 트랜잭션을 지원하지 않습니다.
  • MySQL 5.1의 일부 기능을 지원하지 않음

쿠엔틴의 답변에서 인용한 상기 사항

준비된 스테이트먼트를 지원하지 않는 것이 특히 중요합니다.이는 다른 함수 호출을 사용하여 수동으로 데이터를 이스케이프하는 것보다 더 명확하고 오류가 발생하기 쉬운 외부 데이터 이스케이프 방법을 제공하기 때문입니다.

SQL 확장의 비교를 참조하십시오.


폐지 경고 억제

코드 변환 중MySQLi/PDO,E_DEPRECATED에러는, 설정함으로써 억제할 수 있습니다.error_reporting제외할 php.iniE_DEPRECATED:

error_reporting = E_ALL ^ E_DEPRECATED 

이것은 다른 권장 해제 경고도 숨겨지지만 MySQL 이외의 경고일 수 있습니다.(PHP 매뉴얼 참조)

PDO와 Dejan Marjanovic의 MySQLi: Which Should You Use?가 선택에 도움이 됩니다.

그리고 더 좋은 방법은PDO, 그리고 나는 지금 간단한 글을 쓰고 있다.PDO튜토리얼을 참조해 주세요.


간단하고 짧은 PDO 튜토리얼


Q. 첫 번째 의문점은 PDO가 무엇인가였다.

A. “PDO PHP Data Objects – 여러 데이터베이스에 대한 통일된 액세스 방법을 제공하는 데이터베이스 액세스 계층입니다.”

alt text


MySQL에 연결

와 함께mysql_*또는 이전 방식으로 말할 수 있습니다(PHP 5.5 이상에서는 권장되지 않음).

$link = mysql_connect('localhost', 'user', 'pass'); mysql_select_db('testdb', $link); mysql_set_charset('UTF-8', $link); 

와 함께PDO: 새로 작성하기만 하면 됩니다.PDO물건.생성자가 데이터베이스 소스를 지정하기 위한 매개 변수를 수락합니다.PDO의 컨스트럭터는 주로 다음 4개의 파라미터를 취합니다.DSN(데이터 소스 이름) 및 옵션username,password.

여기서 당신은 모든 것에 익숙하다고 생각합니다만,DSN의 새로운 기능PDO.aDSN기본적으로는 일련의 옵션입니다.PDO사용할 드라이버 및 연결 세부 정보.자세한 내용은 PDO MySQL DSN을 참조하십시오.

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password'); 

주의: 다음을 사용할 수도 있습니다.charset=UTF-8단, 에러가 발생할 수 있으므로 를 사용하는 것이 좋습니다.utf8.

접속 에러가 발생했을 경우, 이 에러는PDOException잡을 수 있는 물건Exception더.

올바른 읽기: 연결연결 관리

여러 드라이버 옵션을 배열로 네 번째 매개 변수에 전달할 수도 있습니다.이 매개 변수를 전달할 것을 권장합니다.PDO예외 모드로 합니다.왜냐하면…PDO드라이버는 네이티브 준비 스테이트먼트를 지원하지 않기 때문에PDO는 준비 에뮬레이션을 수행합니다.이 에뮬레이션을 수동으로 실행할 수도 있습니다.네이티브 서버 측에서 준비된 문을 사용하려면 명시적으로 설정해야 합니다.false.

다른 하나는 에서 활성화되어 있는 준비 에뮬레이션을 끄는 것입니다.MySQL디폴트 드라이버입니다만, 에뮬레이션을 사용하려면 , 준비 에뮬레이션을 오프할 필요가 있습니다.PDO안전하게.

준비 에뮬레이션을 꺼야 하는 이유는 나중에 설명하겠습니다.이유를 찾으려면 이 게시물을 확인하십시오.

이전 버전의 를 사용하고 있는 경우에만 사용할 수 있습니다.MySQL추천하지 않습니다.

다음은 그 방법의 예입니다.

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',                'username',                'password',               array(PDO::ATTR_EMULATE_PREPARES => false,               PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); 

PDO 시공 후 속성을 설정할 수 있습니까?

, PDO 구축 후 몇 가지 속성을 설정할 수도 있습니다.setAttribute방법:

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',                'username',                'password'); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); 

에러 처리


에러 처리의 용이성은PDO보다mysql_*.

사용하는 경우의 일반적인 방법mysql_*다음과 같습니다.

//Connected to MySQL $result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link)); 

OR die()에러를 처리하는 방법은 적절하지 않습니다.그것은, 에러에 대처할 수 없기 때문입니다.die스크립트가 갑자기 종료되고 보통 최종 사용자에게 보여주고 싶지 않은 오류가 화면에 반영되어 빌어먹을 해커들이 스키마를 발견하게 됩니다.또는 의 반환값mysql_*함수를 mysql_error()와 함께 사용하여 오류를 처리할 수 있습니다.

PDO는 예외라는 더 나은 해결책을 제공합니다.우리가 하는 모든 일PDO에 싸야 한다trycatch차단해, 강제로PDO에러 모드 Atribute를 설정함으로써, 3개의 에러 모드 중 하나로 이행합니다.3가지 에러 처리 모드를 다음에 나타냅니다.

  • PDO::ERRMODE_SILENT에러 코드를 설정했을 뿐이며, 동작은 다음과 같습니다.mysql_*각 결과를 확인하고 나서$db->errorInfo();에러의 상세를 취득합니다.
  • PDO::ERRMODE_WARNING올리다E_WARNING. (실행시 경고(치명적이지 않은 오류)스크립트의 실행은 정지되지 않습니다).
  • PDO::ERRMODE_EXCEPTION: 예외를 설정합니다.PDO에 의해 발생한 오류를 나타냅니다.던지면 안 돼요PDOException당신의 코드로요.PHP의 예외에 대한 자세한 내용은 예외를 참조하십시오.이 동작은 마치or die(mysql_error());잡히지 않을 때.하지만 그와는 달리or die(),그PDOException를 검출하여 적절하게 처리할 수 있습니다.

좋은 읽기:

예를 들어 다음과 같습니다.

$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT ); $stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING ); $stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); 

그리고 당신은 그것을 포장할 수 있다.trycatch다음과 같습니다.

try {     //Connect as appropriate as above     $db->query('hi'); //Invalid query! }  catch (PDOException $ex) {     echo "An Error occured!"; //User friendly message/message you want to show to user     some_logging_function($ex->getMessage()); } 

를 사용하여 처리할 필요가 없습니다.trycatch지금 당장.언제든지 적절한 시간에 잡을 수 있지만, 나는 당신이 그것을 사용하는 것을 강력히 추천한다.trycatch또, 콜 하는 함수의 외부로부터 캐치 하는 것이, 보다 타당할 가능성이 있습니다.PDO내용:

function data_fun($db) {     $stmt = $db->query("SELECT * FROM table");     return $stmt->fetchAll(PDO::FETCH_ASSOC); }  //Then later try {     data_fun($db); } catch(PDOException $ex) {     //Here you can handle error and show message/perform action you want. } 

또한 다음 방법으로 처리할 수 있습니다.or die()혹은 이렇게 말할 수 있다.mysql_*하지만 정말 다양할 거예요.다음을 수행하여 프로덕션에서 위험한 오류 메시지를 숨길 수 있습니다.display_errors off에러 로그를 읽고 있습니다.

이제, 위의 모든 것을 읽고 나면, 당신은 아마 생각할 것이다: 내가 단지 단순하게 기대고 싶을 때, 대체 저게 뭐지?SELECT,INSERT,UPDATE, 또는DELETE스테이트먼트걱정 마세요. 여기 있습니다.


데이터 선택

PDO select image

그래서 지금 하고 있는 일은mysql_*다음과 같습니다.

<?php $result = mysql_query('SELECT * from table') or die(mysql_error());  $num_rows = mysql_num_rows($result);  while($row = mysql_fetch_assoc($result)) {     echo $row['field1']; } 

자, 들어가겠습니다.PDO다음과 같이 할 수 있습니다.

<?php $stmt = $db->query('SELECT * FROM table');  while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {     echo $row['field1']; } 

또는

<?php $stmt = $db->query('SELECT * FROM table'); $results = $stmt->fetchAll(PDO::FETCH_ASSOC);  //Use $results 

주의: 다음과 같은 방법을 사용하는 경우(query()), 이 메서드는PDOStatement물건.따라서 결과를 가져오려면 위와 같이 사용하십시오.

<?php foreach($db->query('SELECT * FROM table') as $row) {     echo $row['field1']; } 

PDO 데이터에서 이 정보는->fetch()스테이트먼트 핸들링의 메서드.fetch를 호출하기 전에 가장 좋은 방법은 PDO에 데이터 가져오기 방법을 알려주는 것입니다.아래 섹션에서는 이에 대해 설명합니다.

가져오기 모드

의 사용에 주의해 주세요.PDO::FETCH_ASSOC에서fetch()그리고.fetchAll()위의 코드이것이 말해준다PDO필드 이름을 키로 하여 행을 연관 배열로 반환합니다.그 밖에도 여러 가지 페치모드가 있어 하나하나 설명하겠습니다.

먼저 fetch 모드를 선택하는 방법을 설명합니다.

 $stmt->fetch(PDO::FETCH_ASSOC) 

위에서는, 지금까지,fetch(). 다음 항목도 사용할 수 있습니다.

이제 가져오기 모드로 들어갑니다.

  • PDO::FETCH_ASSOC: 결과 세트에 반환된 대로 열 이름으로 인덱스된 어레이를 반환합니다.
  • PDO::FETCH_BOTH(기본값): 결과 집합에 반환된 대로 열 이름과 0-숫자 열 번호로 인덱싱된 배열이 반환됩니다.

더 많은 선택지가 있다!Fetch 설명서에서 이러한 모든 내용을 읽어보십시오.

개수 가져오기:

사용하는 대신mysql_num_rows반환된 행의 수를 얻으려면,PDOStatement하고 있다rowCount()예를 들어 다음과 같습니다.

<?php $stmt = $db->query('SELECT * FROM table'); $row_count = $stmt->rowCount(); echo $row_count.' rows selected'; 

마지막으로 삽입된 ID 가져오기

<?php $result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')"); $insertId = $db->lastInsertId(); 

문 삽입 및 업데이트 또는 삭제

Insert and update PDO image

델이 하고 있는 일mysql_*기능은 다음과 같습니다.

<?php $results = mysql_query("UPDATE table SET field='value'") or die(mysql_error()); echo mysql_affected_rows($result); 

pdo에서는 다음과 같은 작업을 수행할 수 있습니다.

<?php $affected_rows = $db->exec("UPDATE table SET field='value'"); echo $affected_rows; 

위의 쿼리에서 SQL 문을 실행하고 영향을 받는 행 수를 반환합니다.

삽입 및 삭제에 대해서는 나중에 설명하겠습니다.

위의 방법은 쿼리에서 변수를 사용하지 않는 경우에만 유용합니다.단, 쿼리에서 변수를 사용해야 할 경우 위와 같이 prepared 스테이트먼트 또는 파라미터화된 스테이트먼트를 시도하지 마십시오.


준비된 스테이트먼트

Q. 준비된 진술서는 무엇이며 왜 필요한가?
A. 준비된 문은 미리 컴파일된 SQL 문을 말하며, 서버에 데이터만 전송하여 여러 번 실행할 수 있습니다.

준비된 스테이트먼트를 사용하는 일반적인 워크플로는 다음과 같습니다(Wikipedia 3에서 인용).

  1. 준비:스테이트먼트 템플릿은 어플리케이션에 의해 작성되어 Database Management System(DBMS; 데이터베이스 관리 시스템)으로 전송됩니다.파라미터, 플레이스 홀더 또는 바인드 변수(라벨 부착)라고 불리는 특정 값은 지정되지 않은 상태로 남습니다.?이하에 나타냅니다.

    INSERT INTO PRODUCT (name, price) VALUES (?, ?)

  2. DBMS는 문 템플릿을 구문 분석, 컴파일 및 쿼리 최적화를 수행하고 결과를 실행하지 않고 저장합니다.

  3. 실행:나중에 응용 프로그램은 파라미터의 값을 제공하고(또는 바인드), DBMS는 문을 실행합니다(결과를 반환할 수 있습니다).응용 프로그램은 다른 값을 사용하여 원하는 횟수만큼 문을 실행할 수 있습니다.이 예에서는 첫 번째 파라미터에 ‘Bread’를 제공할 수 있습니다.1.00두 번째 파라미터로 설정합니다.

SQL에 자리 표시자를 포함하여 준비된 문을 사용할 수 있습니다.기본적으로 플레이스 홀더가 없는 것은 세 가지(위의 변수와 함께 시도하지 않음), 이름 없는 플레이스 홀더가 있는 플레이스 홀더와 이름 있는 플레이스 홀더가 있는 플레이스 홀더가 있는 플레이스 홀더가 있습니다.

Q. 그럼 플레이스 홀더란 무엇이며 어떻게 사용해야 합니까?
A. 이름 있는 플레이스 홀더.물음표 대신 콜론 앞에 설명적인 이름을 사용합니다.이름 자리 보유자의 위치/값 순서는 상관없습니다.

 $stmt->bindParam(':bla', $bla); 

bindParam(parameter,variable,data_type,length,driver_options)

실행 어레이를 사용하여 바인드할 수도 있습니다.

<?php $stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name"); $stmt->execute(array(':name' => $name, ':id' => $id)); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); 

또 하나의 뛰어난 기능OOPfriends는 지정된 플레이스홀더가 지정된 필드와 속성이 일치한다고 가정할 때 데이터베이스에 오브젝트를 직접 삽입할 수 있는 기능입니다.예를 들어 다음과 같습니다.

class person {     public $name;     public $add;     function __construct($a,$b) {         $this->name = $a;         $this->add = $b;     }  } $demo = new person('john','29 bla district'); $stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)"); $stmt->execute((array)$demo); 

Q. 그럼 이름 없는 플레이스 홀더는 무엇이며 어떻게 사용해야 합니까?
A. 예를 들어 보겠습니다.

<?php $stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)"); $stmt->bindValue(1, $name, PDO::PARAM_STR); $stmt->bindValue(2, $add, PDO::PARAM_STR); $stmt->execute(); 

그리고.

$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)"); $stmt->execute(array('john', '29 bla district')); 

위에서 볼 수 있습니다.?네임플레이스 홀더에 있는 이름 대신.첫 번째 예에서는 다양한 플레이스 홀더에 변수를 할당합니다($stmt->bindValue(1, $name, PDO::PARAM_STR);그런 다음 플레이스 홀더에 값을 할당하고 문을 실행합니다.두 번째 예에서는 첫 번째 배열 요소가 첫 번째 배열 요소로 이동합니다.?그리고 두 번째에서 두 번째까지?.

메모: 이름 없는 플레이스 홀더에서는 어레이 내에서 전달되는 요소의 올바른 순서를 관리할 필요가 있습니다.PDOStatement::execute()방법.


SELECT,INSERT,UPDATE,DELETE준비된 쿼리

  1. 다음과 같습니다SELECT.

    $stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name"); $stmt->execute(array(':name' => $name, ':id' => $id)); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); 
  2. 다음과 같습니다INSERT.

    $stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)"); $stmt->execute(array(':field1' => $field1, ':field2' => $field2)); $affected_rows = $stmt->rowCount(); 
  3. 다음과 같습니다DELETE.

    $stmt = $db->prepare("DELETE FROM table WHERE id=:id"); $stmt->bindValue(':id', $id, PDO::PARAM_STR); $stmt->execute(); $affected_rows = $stmt->rowCount(); 
  4. 다음과 같습니다UPDATE.

    $stmt = $db->prepare("UPDATE table SET name=? WHERE id=?"); $stmt->execute(array($name, $id)); $affected_rows = $stmt->rowCount(); 

주의:

하지만PDO및/또는MySQLi완전히 안전하지 않습니다.PDO 준비 문장은 SQL 주입을 방지하기에 충분한가?”라는 답변을 확인합니다.ircmaxell에 의해.또, 나는 그의 대답의 일부를 인용하고 있다.

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $pdo->query('SET NAMES GBK'); $stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1"); $stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*")); 



먼저, 모든 고객에게 제공하는 표준적인 코멘트부터 시작하겠습니다.

새로운 코드의 함수는 사용하지 말아 주세요.그것들은 더 이상 유지되지 않고 공식적으로 폐지된다.빨간 상자 보이지?대신 준비된 문장에 대해 알아보고 PDO 또는 MySQLi사용하십시오. 이 문서는 어떤 문장이 어떤 것인지 결정하는 데 도움이 됩니다.PDO를 선택한 경우 다음 튜토리얼을 참고하십시오.

그럼 한 문장 한 문장씩 살펴보고 설명하겠습니다.

  • 그것들은 더 이상 유지되지 않고 공식적으로 폐지된다.

    이는 PHP 커뮤니티가 이러한 매우 오래된 기능에 대한 지원을 점차 중단하고 있음을 의미합니다.PHP의 미래(최근) 버전에는 존재하지 않을 수 있습니다!이러한 기능을 계속 사용하면 앞으로 코드가 깨질 수 있습니다(그렇지 않을 수도 있습니다.

    신규! – PHP 5.5에서 ext/mysql은 공식적으로 폐지되었습니다!

    최신! ext/mysql이 PHP 7에서 제거되었습니다.

  • 대신, 당신은 준비된 문장을 배워야 합니다.

    mysql_*extension은 SQL Injection에 대한 매우 효과적인 대책인 준비된 문을 지원하지 않습니다.이를 통해 MySQL 종속 응용 프로그램의 매우 심각한 취약성을 수정하여 공격자가 스크립트에 액세스하고 데이터베이스에서 가능한 쿼리를 수행할 수 있습니다.

    자세한 내용은 PHP에서 SQL 주입을 방지하는 방법을 참조하십시오.

  • 빨간 상자 보여?

    아무데나 가면mysql기능 매뉴얼 페이지에 빨간색 상자가 표시되어 더 이상 사용하지 않아야 함을 설명합니다.

  • PDO 또는 MySQLi 사용

    데이터베이스 상호 작용에 대한 완전한 OOP 접근 방식을 제공하는 PDOPHP Database Object와 MySQL 고유의 개선점인 MySQLi 등 보다 우수하고 견고하며 잘 구축된 대안이 있습니다.




사용의 용이성

분석적 이유와 종합적 이유는 이미 언급되었다.새로 온 사람에게는 날짜 mysql_ 함수의 사용을 중지하는 것이 더 큰 인센티브입니다.

최신 데이터베이스 API는 사용하기가 더 쉬울 뿐입니다.

코드를 단순화할 수 있는 것은 대부분 바운드 파라미터입니다.또, 뛰어난 튜토리얼(상기 참조)을 사용하고 있기 때문에, PDO로의 이행은 그다지 어렵지 않습니다.

단, 한 번에 더 큰 코드 베이스를 다시 쓰려면 시간이 걸립니다.이 중간 대안을 위한 Raison d’étre:

mysql_* 대신 동등한 pdo_* 함수

<pdo_mysql.php>를 사용하면 최소한의 노력으로 오래된 mysql_ 함수에서 전환할 수 있습니다.가세하다pdo_기능 래퍼를 대체하다mysql_상대편

  1. 간단하게include_once("pdo_mysql.php");데이터베이스와 상호 작용해야 하는 각 호출 스크립트에서 사용됩니다.

  2. 함수 프리픽스를 삭제하고 로 교체합니다.

    • mysql_connect()가 되다connect()
    • mysql_query()가 되다query()
    • mysql_num_rows()가 되다num_rows()
    • mysql_insert_id()가 되다insert_id()
    • mysql_fetch_array()가 되다fetch_array()
    • mysql_fetch_assoc()가 되다fetch_assoc()
    • mysql_real_escape_string()가 되다real_escape_string()
    • 기타 등등…

  3. 코드는 동일하게 동작하지만 대부분 동일하게 표시됩니다.

    include_once("pdo_mysql.php");   pdo_connect("localhost", "usrABC", "pw1234567"); pdo_select_db("test");  $result = pdo_query("SELECT title, html FROM pages");    while ($row = pdo_fetch_assoc($result)) {     print "$row[title] - $row[html]"; } 

엣보일라
코드가 PDO를 사용하고 있습니다.
이제 실제로 활용할 때입니다.

바운드 파라미터의 사용이 용이함

덜 다루기 쉬운 API만 있으면 됩니다.

pdo_query()는 바인딩된 파라미터에 대한 매우 쉬운 지원을 추가합니다.이전 코드 변환은 간단합니다.

SQL 문자열에서 변수를 이동합니다.

  • 이들을 콤마로 구분된 함수 파라미터로 추가합니다.pdo_query().
  • 물음표 배치?자리 표시자로 사용할 수 있습니다.
  • 제거하다'이전에 문자열 값 또는 문자열을 묶은 작은 따옴표.

코드의 길이가 길수록 이점이 더욱 뚜렷해집니다.

대부분의 문자열 변수는 SQL에 보간될 뿐만 아니라 중간에 이스케이프 콜과 연결됩니다.

pdo_query("SELECT id, links, html, title, user, date FROM articles    WHERE title='" . pdo_real_escape_string($title) . "' OR id='".    pdo_real_escape_string($title) . "' AND user <> '" .    pdo_real_escape_string($root) . "' ORDER BY date") 

와 함께?플레이스 홀더 신청은 번거롭지 않습니다.

pdo_query("SELECT id, links, html, title, user, date FROM articles    WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root) 

pdo_*는 여전히 또는 둘 중 하나를 허용합니다.
변수를 이스케이프하지 말고 동일한 쿼리에 바인딩하십시오.

  • 플레이스 홀더 기능은 플레이스 홀더 뒤에 있는 실제 PDO에 의해 제공됩니다.
  • 그러므로 또한 허용된다.:named나중에 플레이스 홀더 리스트를 참조해 주세요.

더 중요한 것은 $_REQUEST[] 변수를 쿼리 뒤에 안전하게 전달할 수 있다는 것입니다.제출 시<form>필드는 데이터베이스 구조와 정확히 일치합니다.

pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST); 

너무 단순해요.하지만 왜 제거하거나 탈출하고 싶은지에 대한 몇 가지 조언과 기술적인 이유로 돌아가 봅시다.

구식 기능 수정 또는 제거

모든 콜을 로 변환하면pdo_query바인드된 매개 변수를 사용하여 모든 중복 제거pdo_real_escape_string콜을 클릭합니다.

특히 수정해야 합니다.sanitize또는clean또는filterThis또는clean_data는 다음 중 하나의 형식으로 날짜가 지난 튜토리얼에 의해 애드버타이즈된 기능을 합니다.

function sanitize($str) {    return trim(strip_tags(htmlentities(pdo_real_escape_string($str)))); } 

여기서 가장 눈에 띄는 문제는 문서화의 부족이다.더 중요한 것은 필터링 순서가 정확히 잘못되었다는 것입니다.

  • 올바른 순서는 다음과 같습니다: 권장되지 않음stripslashes그럼 제일 안쪽의 전화로서trim, 그 후strip_tags,htmlentities출력 콘텍스트의 경우,_escape_string응용 프로그램이 SQL 인터스패싱에 직접 선행해야 하기 때문입니다.

  • 하지만 첫 번째 단계로 을 제거합니다.

  • 나머지 부분은 보관해야 할 수도 있습니다.sanitize()데이터베이스와 어플리케이션플로우가 HTML 컨텍스트 세이프 스트링을 요구하고 있는 경우는, 현시점에서는 기능합니다.이후 HTML 이스케이프만 적용된다는 주석을 추가합니다.

  • 문자열/값 처리는 PDO 및 해당 매개 변수화된 문에 위임됩니다.

  • 에 대한 언급이 있었다면stripslashes()sanitize 기능에서는 더 높은 수준의 감시를 나타낼 수 있습니다.

    • 그것은 일반적으로 폐지된 로부터의 파손(이중 탈출)을 복구하기 위해 있었다.단, 스트링별로가 아니라 중앙에서 수정하는 것이 가장 좋습니다.

    • 사용자 랜드 반전 접근법 중 하나를 사용합니다.그런 다음 를 삭제합니다.stripslashes()에서sanitize기능.

    magic_quotes의 이력 노트.그 기능은 당연히 권장되지 않는다.그러나 보안 기능 장애로 잘못 묘사되는 경우가 많습니다.그러나 magic_quotes는 테니스공이 영양 공급원만큼 실패한 보안 기능입니다.그것은 단순히 그들의 목적이 아니었다.

    PHP2/FI의 원래 구현에서는 “인용어가 자동으로 이스케이프되므로 데이터를 msql 쿼리에 직접 전달하기가 쉬워집니다.”라고 명시되어 있습니다.특히 ASCII만 지원하므로 mSQL에서 사용하는 것은 우발적으로 안전합니다.
    그 후 PHP3/Zend는 MySQL용 magic_quotes를 재도입하여 잘못 문서화하였습니다.그러나 원래 이것은 보안을 목적으로 한 것이 아니라 편의 기능일 뿐입니다.

준비된 진술이 어떻게 다른가

문자열 변수를 SQL 쿼리에 스크램블하면 더 복잡해질 뿐만 아니라MySQL은 코드와 데이터를 다시 분리하는 작업도 불필요합니다.

SQL 주입은 단순히 데이터가 코드 컨텍스트에 블리딩되는 경우입니다.데이터베이스 서버는 나중에 쿼리 구 사이에 원래 PHP가 붙어 있던 변수를 찾을 수 없습니다.

경계 매개 변수를 사용하여 PHP 코드에서 SQL 코드와 SQL 컨텍스트 값을 구분합니다.그러나 이 문제는 뒷전에서는 다시 일어나지 않습니다(PDO 제외:에뮬레이트_PREPARES).데이터베이스는 변경되지 않은 SQL 명령과 1:1 변수 값을 수신합니다.

이 답변에서는 drop의 가독성 이점에 유의해야 한다고 강조합니다.이러한 가시적이고 기술적인 데이터/코드 분리에 의해 퍼포먼스가 향상되는 경우가 있습니다(INSERT의 값이 다른 반복).

파라미터 바인딩은 여전히 모든 SQL 주입에 대한 마법의 원스톱 솔루션이 아닙니다.데이터/값의 가장 일반적인 용도를 처리합니다.그러나 열 이름/테이블 식별자, 동적 절 구성 또는 일반 배열 값 목록만 화이트리스트로 만들 수는 없습니다.

하이브리드 PDO 사용

이것들pdo_*wrapper 함수는 코딩 친화적인 임시 API를 만듭니다.MYSQLI특이한 기능 시그니처 시프트가 없었다면 가능했을 것입니다).또한 대부분의 경우 실제 PDO를 노출합니다.
새 pdo_ 함수 이름을 사용하여 다시 쓸 필요가 없습니다.각 pdo_query()를 플레인 $pdo->prepare()->execute()콜로 하나씩 이행할 수 있습니다.

그러나 다시 단순화하는 것이 가장 좋습니다.예를 들어 일반적인 결과 가져오기:

$result = pdo_query("SELECT * FROM tbl"); while ($row = pdo_fetch_assoc($result)) { 

포어치 반복만으로 대체할 수 있습니다.

foreach ($result as $row) { 

또는 직접적이고 완전한 어레이 취득:

$result->fetchAll(); 

대부분의 경우 쿼리 실패 후 PDO 또는 mysql_보다 더 유용한 경고가 표시됩니다.

기타 옵션

그래서 이것은 희망적으로 몇 가지 실제적인 이유와 떨어뜨리는 가치 있는 경로를 시각화했다.

로 바꾸는 것만으로는 충분치 않아요. pdo_query()앞부분일 뿐이죠.

파라미터 바인딩을 도입하거나 보다 좋은 API에서 다른 것을 이용할 수 없는 한 의미 없는 스위치입니다.새내기에게 더 이상 낙담하지 않을 정도로 단순하게 묘사되었으면 좋겠다. (보통 교육은 금지보다 효과가 있다.)

가장 간단한 작업 범주에 해당하지만 여전히 매우 실험적인 코드입니다.주말에 썼어.하지만 너무 많은 대안이 있다.PHP 데이터베이스 추상화를 구글에서 검색하여 조금만 참조하면 됩니다.이러한 작업을 위한 훌륭한 도서관은 항상 존재해 왔고 앞으로도 존재하게 될 것입니다.

데이터베이스 상호 작용을 더욱 단순화하고 싶다면 Paris/Idiorm과 같은 매핑을 시도해 볼 만하다.JavaScript에서 아무도 DOM을 사용하지 않는 것처럼, 오늘날에는 원시 데이터베이스 인터페이스를 돌볼 필요가 없습니다.




mysql_기능:

  1. 구식 – 더 이상 유지보수가 되지 않습니다.
  2. 다른 데이터베이스 백엔드로 쉽게 이동할 수 없음
  3. 준비된 스테이트먼트를 지원하지 않기 때문에
  4. 프로그래머가 쿼리를 작성하기 위해 연결을 사용하도록 권장하여 SQL 주입 취약성을 야기합니다.