왜 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 인터페이스가 부족합니다 지원되지 않습니다. 비 차단, 비동기 쿼리 준비한 진술 또는 매개 변수화 된 쿼리 저장 프로 시저 여러 문장 업무 "New"암호 인증 방법 (기본적으로 MySQL 5.6; 5.7에서 필수) MySQL 5.1 이상의 새로운 기능 중 하나
사용되지 않으므로 사용하여 코드가 덜 미래 증명됩니다.
준비된 진술에 대한 지원 부족은 특히 분리 된 기능 호출로 수동으로 이스케이프링하는 것보다 외부 데이터를 탈출하고 견적하는 더 명확하고 덜 오류가 발생하기 쉬운 방법을 제공합니다.
SQL 확장자의 비교를 참조하십시오.
답변
PHP는 MySQL에 연결하기 위해 세 가지 다른 API를 제공합니다.이것들은 mysql (PHP 7에서 제거), mysqli 및 pdo 확장자입니다.
mysql_ * 함수는 매우 인기가 있지만 더 이상 사용하는 것이 권장되지 않습니다.문서 팀은 데이터베이스 보안 상황에 대해 논의하고 일반적으로 사용되는 ext / mysql 확장자에서 사용자가 멀리 이동하도록 교육하는 것입니다 (PHP.Internals : Ext / MySQL이 아프다.
그리고 이후 PHP 개발자 팀은 사용자가 mysql_connect (), mysql_pconnect () 또는 ext / mysql에 내장 된 암시 적 연결 기능을 통한 MySQL에 연결할 때 e_depected 오류를 생성하도록 결정했습니다.
EXT / MySQL은 PHP 5.5로 공식적으로 더 이상 사용되지 않으며 PHP 7의대로 제거되었습니다.
빨간색 상자를 참조하십시오.
mysql_ * 함수 매뉴얼 페이지를 사용하면 더 이상 사용해서는 안됩니다.
왜
Ext / MySQL에서 멀리 이동하는 것은 보안에 대해서만뿐만 아니라 MySQL 데이터베이스의 모든 기능에 액세스 할 수 있습니다.
Ext / MySQL은 MySQL 3.23 용으로 빌드되었으며 그 이후로 더 많은 기능을 얻었으므로 코드를 조금 더 열심히 유지하는이 이전 버전과의 호환성을 유지합니다.Ext / MySQL에서 지원하지 않는 누락 된 기능은 다음과 같습니다. (PHP 매뉴얼에서).
저장 프로 시저 (여러 결과 세트를 처리 할 수 없음) 준비한 진술 암호화 (SSL) 압축 전체 샤릭 지원
mysql_ * 함수를 사용하지 않는 이유 :
적극적인 개발 중이 아닙니다 PHP 7의 마찬가지로 제거되었습니다 OO 인터페이스가 부족합니다 비 차단, 비동기 쿼리를 지원하지 않습니다 준비된 문이나 매개 변수화 된 쿼리를 지원하지 않습니다 저장 프로 시저를 지원하지 않습니다 여러 문을 지원하지 않습니다 거래를 지원하지 않습니다 MySQL 5.1의 모든 기능을 지원하지 않습니다
위의 포인트는 Quentin의 답변에서 인용되었습니다
준비된 진술에 대한 지원 부족은 특히 분명한 기능 호출로 수동으로 이스케이프링하는 것보다 외부 데이터를 탈출하고 따옴표로 탈출하고 인용하는 오류가 적기 때문에 특히 중요합니다.
SQL 확장자의 비교를 참조하십시오.
감가 상한 경고를 억제합니다
코드가 MySQLI / PDO로 변환되는 동안 php.ini에서 error_reporting을 설정하여 e_deprecated를 제외시켜 억제 할 수 있습니다.
error_reporting = E_ALL ^ E_DEPRECATED
그러나 이것은 MySQL 이외의 것들을위한 것들을위한 다른 특성 경고를 숨길 수 있습니다.(PHP 매뉴얼에서)
이 기사 PDO 대 MySQLI : 당신이 사용해야합니까?Dejan Marjanovic의 선택을 도와줍니다.
그리고 더 좋은 방법은 PDO이며, 이제 간단한 PDO 자습서를 작성하고 있습니다.
간단하고 짧은 PDO 자습서
Q. 내 마음 속의 첫 번째 질문은`pdo` 란 무엇입니까?
A. "PDO - PHP 데이터 객체 - 여러 데이터베이스에 대한 균일 한 액세스 방법을 제공하는 데이터베이스 액세스 계층입니다."

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의 생성자를 지정하기위한 매개 변수를 허용하여 DSN (데이터 소스 이름) 및 선택적으로 사용자 이름, 암호 인 4 개의 매개 변수를 주로 수행합니다.
여기에서는 DSN을 제외한 모든 것에 익숙하다고 생각합니다.이것은 PDO의 새로운 기능입니다.DSN은 기본적으로 PDO를 사용할 드라이버 및 연결 세부 사항을 알려주는 옵션의 문자열입니다.추가 참조를 위해 PDO MySQL DSN을 확인하십시오.
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
참고 : charset = utf-8을 사용할 수도 있지만 때로는 오류가 발생하므로 UTF8을 사용하는 것이 좋습니다.
연결 오류가 있으면 예외를 더 처리하도록 지정할 수있는 PDOException 객체를 던지게됩니다.
좋은 읽기 : 연결 및 연결 관리 ¶
또한 여러 드라이버 옵션을 네 번째 매개 변수의 배열로 전달할 수도 있습니다.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);
오류 처리
오류 처리는 mysql_ *보다 PDO에서 훨씬 쉽습니다.
mysql_ *를 사용할 때 일반적인 연습은 다음과 같습니다.
//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));
또는 죽을 때 우리는 죽을 수 없기 때문에 오류를 처리하는 좋은 방법이 아닙니다.스크립트가 갑자기 종료 한 다음 일반적으로 최종 사용자에게 표시하지 않으려 고하는 화면에 오류를 반향하고 피 묻은 해커가 스키마를 발견하게합니다.또는 mysql_ * 함수의 반환 값은 mysql_error ()와 함께 오류를 처리 할 수 있습니다.
PDO는 더 나은 솔루션을 제공합니다 : 예외.우리가 PDO로하는 일은 TRY-CATCH 블록에 싸여 있어야합니다.우리는 오류 모드 속성을 설정하여 PDO를 세 가지 오류 모드 중 하나로 강제로 할 수 있습니다.세 가지 오류 처리 모드가 아래에 있습니다.
PDO :: errmode_silent.오류 코드를 설정하고 각 결과를 확인한 다음 $ DB-> ERRORINFO ()를 확인해야합니다.오류 세부 정보를 얻으려면. PDO :: errMode_Warning eReage e_warning.(런타임 경고 (치명적이지 않은 오류). 스크립트의 실행은 중단되지 않습니다.) PDO :: errMode_Exception : 예외를 던지십시오.그것은 PDO가 제기 한 오류를 나타냅니다.자신의 코드에서 PDOException을 던져서는 안됩니다.PHP의 예외에 대한 자세한 정보는 예외를 참조하십시오.그것은 매우 많이 또는 죽거나 죽을 수 있습니다 (mysql_error ());그러나 ()와 달리 (), 당신이 그렇게하기로 결정한 경우 pdoexception을 우아하게 잡히고 처리 할 수 있습니다.
좋은 읽기 :
오류 및 오류 처리 ¶ 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 );
그리고 아래와 같이 Try-catch로 랩핑 할 수 있습니다.
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());
}
당신은 지금 try-catch와 함께 취급 할 필요가 없습니다.언제든지 적절하게 잡을 수는 있지만 TRY-CATCH를 사용하는 것이 좋습니다.또한 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.
}
또한, 당신은 () 또는 죽거나, 우리가 mysql_ *처럼 말할 수는 있지만, 정말로 다양 할 것입니다.display_errors를 끄고 오류 로그를 읽으면 위험한 오류 메시지를 프로덕션에서 숨길 수 있습니다.
이제 위의 모든 일을 읽은 후에는 사고가 될 것입니다 : 방해가 간단한 선택, 삽입, 업데이트 또는 삭제 명령문을 기울이고 싶을 때 어떤 이런 일이 틀림 없습니다.걱정하지 마세요, 여기에 우리가 간 :
데이터 선택

그래서 당신이 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를 가져올 데이터를 어떻게 가져올 수 있는지 알려줍니다.아래 섹션에서는 이것을 설명하고 있습니다.
가져 오기 모드
위의 fetch () 및 fetchall () 코드에서 pdo :: fetch_assoc의 사용을 유의하십시오.이렇게하면 PDO가 필드 이름이 키로가있는 연관 배열로 행을 반환하도록 PDO를 알려줍니다.여러 가지 다른 페치 모드도 하나씩 설명 할 것입니다.
우선, 가져 오기 모드를 선택하는 방법을 설명합니다.
$stmt->fetch(PDO::FETCH_ASSOC)
위의 경우, 나는 fetch ()를 사용하고 있습니다.다음을 사용할 수도 있습니다.
pdostatement :: fetretmall () - 모든 결과 집합 행이 포함 된 배열을 반환합니다. pdostatement :: fetchColumn () - 결과 세트의 다음 행에서 단일 열을 반환합니다. pdostatement :: fetchObject () - 다음 행을 가져 와서 객체로 반환합니다. pdostatement :: setFetchMode () -이 명령문의 기본 페치 모드 설정
이제 나는 가져 오기 모드로옵니다.
PDO :: Fetch_Ascoc : 결과 집합에서 반환 된 열 이름으로 인덱싱 된 배열을 반환합니다. PDO :: Fetch_Both (기본값) : 결과 집합에서 반환 된 열 이름과 0 인덱싱 된 열 번호가 모두 인덱싱 된 배열을 반환합니다.
더 많은 선택이 있습니다!그들 모두를 pdostatement 가져 오기 문서에서 읽어보십시오.
행 수를 얻는 방법 :
반환 된 행의 수를 가져 오려면 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();
삽입 및 업데이트 또는 문을 삭제하십시오

우리가 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;
위의 쿼리에서 PDO :: Exec SQL 문을 실행하고 영향을받는 행의 수를 반환합니다.
삽입 및 삭제는 나중에 다루어집니다.
위의 방법은 쿼리에서 변수를 사용하지 않을 때만 유용합니다.그러나 쿼리에서 변수를 사용해야 할 때 위의 것처럼 보이지 않고 준비된 진술이나 매개 변수화 된 진술을 위해서는 거기에 없습니다.
준비한 진술
Q. 준비된 진술이란 무엇이며 왜 내가 그들을 필요로합니까? A. 준비된 문은 서버에 데이터 만 전송하여 여러 번 실행할 수있는 사전 컴파일 된 SQL 문입니다.
준비된 명령문을 사용하는 일반적인 워크 플로우는 다음과 같습니다 (Wikipedia 3 점에서 인용 된 3 점).
Prepare: The statement template is created by the application and sent to the database management system (DBMS). Certain values are left unspecified, called parameters, placeholders or bind variables (labelled
?
below):INSERT INTO PRODUCT (name, price) VALUES (?, ?)
The DBMS parses, compiles, and performs query optimization on the statement template, and stores the result without executing it.
- Execute: At a later time, the application supplies (or binds) values for the parameters, and the DBMS executes the statement (possibly returning a result). The application may execute the statement as many times as it wants with different values. In this example, it might supply 'Bread' for the first parameter and
1.00
for the second parameter.
SQL의 자리 표시자를 포함하여 준비된 문을 사용할 수 있습니다.기본적으로 자리 표시자가없는 세 가지가 있습니다 (위의 변수로 이것을 시도하지 마십시오.) 명명되지 않은 자리 표시자가있는 사람과 명명 된 자리 표시자가있는 것입니다.
Q. 이제는 자리 표시 자와 어떻게 사용합니까? A. 명명 된 자리 표시 자.물음표 대신 콜론 앞에있는 설명적인 이름을 사용하십시오.이름 장소 홀더의 위치 / 순서를 상관하지 않습니다.
$stmt->bindParam(':bla', $bla);
bindParam (매개 변수, 변수, data_type, 길이, 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);
OOP 친구들을위한 또 다른 좋은 기능은 명명 된 필드와 일치하는 속성이 데이터베이스에 직접 객체를 삽입 할 수있는 기능이 있습니다.예를 들어:
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)에 변수를 할당합니다.).그런 다음 해당 자리 표시 자에게 값을 지정하고 명령문을 실행합니다.두 번째 예에서 첫 번째 배열 요소는 첫 번째로 이동합니까?두 번째로 두 번째로?
참고 : 명명되지 않은 자리 표시 자에서는 PDOSTATEME :: EXECUTE () 메서드에 전달되는 배열의 요소의 적절한 순서를 처리해야합니다.
준비, 삽입, 업데이트, 준비 쿼리 삭제
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);
INSERT
:$stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)"); $stmt->execute(array(':field1' => $field1, ':field2' => $field2)); $affected_rows = $stmt->rowCount();
DELETE
:$stmt = $db->prepare("DELETE FROM table WHERE id=:id"); $stmt->bindValue(':id', $id, PDO::PARAM_STR); $stmt->execute(); $affected_rows = $stmt->rowCount();
UPDATE
:$stmt = $db->prepare("UPDATE table SET name=? WHERE id=?"); $stmt->execute(array($name, $id)); $affected_rows = $stmt->rowCount();
노트:
그러나 PDO 및 / 또는 MySQLI는 완전히 안전하지 않습니다.응답은 SQL 주입을 방지하기에 충분한 PDO 준비 진술입니까?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 /*"));
답변
첫째, 우리가 모두에게주는 표준 의견으로 시작하겠습니다.
새 코드에서 mysql_ * 함수를 사용하지 마십시오.그들은 더 이상 유지되지 않고 공식적으로 더 이상 사용되지 않습니다.빨간색 상자를 참조하십시오.대신 준비한 진술에 대해 알아보고 PDO 또는 MySQLI를 사용하십시오.이 기사는 당신이 결정하는 데 도움이됩니다.PDO를 선택하면 여기에 좋은 자습서가 있습니다.
문장에 의해 문장을 지나서 설명하고 설명하십시오.
그들은 더 이상 유지되지 않으며 공식적으로 더 이상 사용되지 않습니다. 즉, PHP 커뮤니티는 이러한 매우 오래된 기능에 대한 지원을 점차적으로 삭제하고 있음을 의미합니다. PHP의 미래 (최근) 버전에 존재하지 않을 것입니다! 이러한 기능을 지속적으로 사용하면 (그렇지 않은) 앞으로의 코드를 끊을 수 있습니다. 새로운! - Ext / MySQL은 현재 PHP 5.5로 공식적으로 더 이상 사용되지 않습니다! 새로운! EXT / MySQL이 PHP 7에서 제거되었습니다. 대신 준비한 진술을 배울 것입니다 mysql_ * 확장자는 준비된 진술을 지원하지 않습니다. 이것은 (다른 것들 중에서) SQL 주입에 대한 매우 효과적인 대책입니다. 공격자가 스크립트에 액세스하고 데이터베이스에서 가능한 모든 쿼리를 수행 할 수있게 해주는 MySQL 종속 응용 프로그램에서 매우 심각한 취약점을 수정했습니다. 자세한 내용은 PHP에서 SQL 주입을 방지 할 수 있습니까? 빨간색 상자를 참조하십시오. MySQL 함수 매뉴얼 페이지로 이동하면 빨간색 상자가 표시되어 더 이상 사용해서는 안됩니다. PDO 또는 MySQLI를 사용하십시오 데이터베이스 상호 작용에 대한 완전한 OOP 접근 방식을 제공하는 PDO-PHP 데이터베이스 오브젝트가 더 좋고 강력하고 잘 지어진 대안이 더 좋으며 MySQL 특정 개선이되는 MySQLI가 있습니다.
답변
사용의 용이성
분석 및 합성 이유는 이미 언급되었습니다.신규 이민자에게는 dated mysql_ 함수를 사용하여 멈추는 것이 더 중요한 인센티브가 있습니다.
현대 데이터베이스 API가 사용하기가 쉽습니다.
그것은 주로 코드를 단순화 할 수있는 바운드 매개 변수입니다.그리고 훌륭한 자습서로 (위와 같이) PDO 로의 전환은 지나치게 힘들지 않습니다.
그러나 더 큰 코드 기반을 한 번에 다시 쓰는 데 시간이 걸립니다.이 중급 대안을위한 Raison D 'être :
동등한 PDO_ * mysql_ * 대신 함수
Simply
include_once(
"pdo_mysql.php"
);
in each invocation script that has to interact with the database.Remove the
function prefix everywhere and replace it withmysql_
pdo_
.mysql_
connect()
becomespdo_
connect()
mysql_
query()
becomespdo_
query()
mysql_
num_rows()
becomespdo_
num_rows()
mysql_
insert_id()
becomespdo_
insert_id()
mysql_
fetch_array()
becomespdo_
fetch_array()
mysql_
fetch_assoc()
becomespdo_
fetch_assoc()
mysql_
real_escape_string()
becomespdo_
real_escape_string()
- and so on...
Your code will work alike and still mostly look the same:
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]"; }
et voilà. 코드가 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가 제공합니다. 따라서 허용 된 위치 : 명명 된 자리 표시 자 목록은 나중에 나중에 있습니다.
더 중요한 것은 $ _request [] 변수를 모든 쿼리 뒤에 안전하게 전달할 수 있습니다.제출 된 <양식> 필드가 데이터베이스 구조와 정확하게 일치하면 더 짧습니다.
pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);
너무나 간단하게.그러나 왜 mysql_ 및 이스케이프를 제거하고 싶을 수있는 이유에 대한 조언 및 기술적 이유로 다시 작성하십시오.
OldSchool Sanitize () 기능을 수정하거나 제거하십시오
모든 mysql_ 호출을 바운드 매개 변수로 pdo_query로 변환 한 후 모든 중복 pdo_real_escape_string 호출을 제거하십시오.
특히 일류 또는 다른 튜토리얼에서 광고 된대로 살균되거나 깨끗하거나 필터링하거나 Clean_Data 함수를 수정해야합니다.
function sanitize($str) {
return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}
대부분의 눈부신 버그는 문서의 부족입니다.더 중요한 것은 필터링 순서가 정확히 잘못된 순서에있었습니다.
올바른 순서가 있었을 것입니다. 사용되지 않는 명령은 가장 안심스럽게 통화로, 그 후에, 나중에, 출력 컨텍스트의 HTMLENTITITS, 그리고 마지막으로 _ESSAPE_STRING 만 SQL InterSparsing에 직접 연계되어야합니다. 그러나 첫 번째 단계는 _real_escape_string 호출을 제거합니다. 데이터베이스 및 응용 프로그램 흐름이 HTML 컨텍스트 안전 문자열을 기대하는 경우 지금은 나머지 SANITIZE () 함수를 유지해야 할 수 있습니다. HTML 이스케이프링을 적용하는 주석을 추가하십시오. string / 값 처리는 PDO와 매개 변수화 된 명령문으로 위임됩니다. 귀하의 살균 기능에 Spipslashes ()에 대한 언급이 있으면 더 높은 수준 감독을 나타낼 수 있습니다. 그것은 일반적으로 사용되지 않는 magic_quotes에서 손상 (이중 이스케이프)을 실행 취소합니다. 그렇지만 문자열 별 문자열이 아닌 중앙에서 가장 잘 고정되어 있습니다. 사용자 랜드 반전 접근법 중 하나를 사용하십시오. 그런 다음 SANITIZE 함수에서 stripslashes ()를 제거하십시오. Magic_Quotes의 역사적인 메모. 그 기능은 적절하지 않습니다. 그러나 실패한 보안 기능으로 종종 잘못 묘사됩니다. 그러나 Tennis Balls가 영양 소스로 실패했기 때문에 Magic_Quotes가 실패한 보안 기능이 많습니다. 그것은 단순히 그들의 목적이 아니 었습니다. PHP2 / FI의 원래 구현은 "따옴표만으로도 명시 적으로 소개되어 자동으로 양식 데이터를 직접 MSQL 쿼리에 전달하는 것이 더 쉽게"됩니다. 특히 ASCII에서만 지원되는 것과 같이 MSQL과 함께 사용하는 것이 탁월하게 안전했습니다. 그런 다음 PHP3 / Zend reintroduced magic_quotes mysql 및 잘못된 설명. 그러나 원래는 보안을 위해 의도하지 않는 편의성이었습니다.
준비한 진술이 어떻게 달라진지
String 변수를 SQL 쿼리에 스크램블 할 때 더 많은 복잡성을 얻을 수 없습니다.코드와 데이터를 다시 분리하기 위해 MySQL에 대한 외관적인 노력이기도합니다.

SQL 주입은 데이터가 코드 컨텍스트로 출혈하는 경우 간단합니다.데이터베이스 서버는 PHP가 원래 쿼리 클로스를 inbetween inbetween inbetween 인 위치에서 나중에 지시 할 수 없습니다.
바운드 매개 변수를 사용하면 PHP 코드에서 SQL 코드 및 SQL 컨텍스트 값을 분리합니다.그러나 그것은 장면 뒤에서 다시 섞이지 않습니다 (PDO :: Emulate_PRepares 제외).데이터베이스는 냉혹 한 SQL 명령과 1 : 1 변수 값을 수신합니다.

이 답변은 mysql_을 삭제하는 가독성 이점을 걱정해야한다는 것을 강조합니다.이러한 가시적이고 기술적 인 데이터 / 코드 분리로 인해 실적 이점이있는 (단지 다른 값으로 반복되는 삽입물이 반복되는 삽입)이 있습니다.
매개 변수 바인딩은 여전히 모든 SQL 주입에 대한 마법 원 스톱 솔루션이 아닙니다.데이터 / 값에 가장 일반적인 사용을 처리합니다.그러나 화선자 이름 / 테이블 식별자, Dynamic 절 구성 또는 일반 배열 값 목록 만 사용하는 데 도움이 될 수 없습니다.
하이브리드 PDO 사용
이러한 PDO_ * 래퍼 함수는 코딩 친화적 인 스톱 갭 API를 만듭니다.(Mysqli가 특이한 기능 서명 이동을위한 것이 아니라면 꽤 많이 꽤 많이있었습니다).그들은 또한 대부분의 시간에 실제 PDO를 노출시킵니다. 재 작성은 새로운 PDO_ 함수 이름을 사용하여 멈출 필요가 없습니다.각 PDO_QUERY () 각 PDO_QUERY ()를 일반 $ PDO-> PREPATE () -> execute () 호출로 전환 할 수 있습니다.
그러나 다시 단순화시 시작하는 것이 가장 좋습니다.예를 들어 공통 결과 가져 오기 :
$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {
foreach 반복으로 대체 될 수 있습니다.
foreach ($result as $row) {
또는 직접적이고 완전한 배열 검색 :
$result->fetchAll();
대부분의 경우 PDO 또는 MySQL_는 일반적으로 쿼리가 실패한 후에 제공됩니다.
다른 옵션
그래서 이것은 MySQL을 떨어 뜨리는 실용적인 이유와 가치있는 경로를 시각적으로 시각적으로 시각적으로 시각했습니다.
그냥 PDO로 전환하지는 않습니다.pdo_query () 또한 단지 프론트 엔드입니다.
매개 변수 바인딩을 도입하거나 Nicer API에서 다른 것을 사용할 수있는 경우가 아니라면 무의미한 스위치입니다.나는 그것이 신규 이민자들에게 낙담하지 않을 정도로 간단하게 묘사되기를 바랍니다.(교육은 대개 금지보다 우수합니다.)
그것은 가장 단순한 것 - 할 수없는 일을 할 수없는 범주를 자격이 있지만 여전히 실험적인 코드도 여전히 있습니다.나는 주말에 그것을 썼다.그러나 그러나 대안의 대안이 있습니다.PHP 데이터베이스 추상화를위한 Google은 조금 탐색합니다.그러한 업무에 대해 항상 많은 훌륭한 라이브러리가 있었을 것입니다.
데이터베이스 상호 작용을 더 단순화하려는 경우 파리 / 대기체와 같은 매퍼는 시도할만한 가치가 있습니다.아무도 JavaScript에서 Bland DOM을 사용하지 않는 것처럼 요즘 원시 데이터베이스 인터페이스를 베이비 시트 할 필요가 없습니다.
답변
mysql_ 함수 :
- are out of date - they're not maintained any more
- don't allow you to move easily to another database backend
- don't support prepared statements, hence
- encourage programmers to use concatenation to build queries, leading to SQL injection vulnerabilities
답변
기술적 인 이유로 말하면, 매우 구체적이며 거의 사용되지 않습니다.가장 큰 당신은 결코 당신의 삶에서 그들을 사용하지 않을 것입니다. 어쩌면 나는 너무 무지하고 있지만, 나는 그들을 사용할 수있는 기회가 없었습니다.
비 차단, 비동기 쿼리 저장 프로 시저가 여러 개의 resultset을 반환합니다 암호화 (SSL) 압축
당신이 그들을 필요로하는 경우, 이들은 더 세련되고 현대적인 것으로 뭔가를 향해 MySQL 연장에서 벗어나는 기술적 이유가 아닙니다.
그럼에도 불구하고, 당신의 경험을 조금 더 열심히 할 수있는 비 기술적 인 문제도 있습니다.
최신 PHP 버전으로 이러한 기능을 더 사용하면 더 이상 사용되지 않는 레벨의 통지가 발생합니다.그들은 단순히 꺼질 수 있습니다. 먼 미래에는 기본 PHP 빌드에서 제거 할 수 있습니다.MyDSQL Ext가 PECL로 이동하면 모든 Hoster가 수십 년 동안 일하고있는 클라이언트를 잃고 싶지 않으므로 PHP를 컴파일하게되어 기쁘게 생각합니다. Stackoverflow 커뮤니티에서 강한 저항.그렇습니다.이 정직한 기능을 언급하면 엄격한 금기가 있음을 알려줍니다. 평균 PHP 사용자가되며,이 기능을 사용하는 것에 대한 아이디어는 오류가 발생하기 쉽고 잘못되었습니다.이러한 모든 수많은 튜토리얼과 설명서가 잘못된 방식으로 가르치는 수동으로 인해.기능이 아닙니다. 나는 그것을 강조해야합니다. 그러나 그들이 사용되는 방식입니다.
이 후자의 문제는 문제입니다. 그러나 제 의견으로 제안 된 해결책은 더 좋지 않습니다. 그 모든 PHP 사용자가 SQL 쿼리를 즉시 처리하는 방법을 배우는 꿈이 너무 이상 주의적 인 것처럼 보입니다.MySQL_ *를 MySQLI_ * 기계적으로 변경할 가능성이 높으면 접근 방식을 똑같이합니다.특히 mysqli가 준비한 진술이 믿을 수없는 고통스럽고 번거로운 것을 사용하기 때문입니다. Native Deplined 문이 SQL 주입으로부터 보호하기에 충분하지 않다는 것을 언급하지 않고 MySQLI 또는 PDO는 해결책을 제공하지 않습니다.
그래서,이 정직한 확장을 싸우는 대신, 나는 잘못된 관행을 싸우고 사람들을 올바른 방법으로 교육시키는 것을 선호합니다.
또한 거짓 또는 중요하지 않은 이유가 있습니다.
저장 프로 시저를 지원하지 않습니다 (mysql_query ( "my_proc 호출"); 시대에 대한) 트랜잭션을 지원하지 않습니다 (위와 동일) 여러 문장을 지원하지 않습니다 (누가 필요합니까?) 적극적인 발전을받지 않고 (그래서? 실제적인 방법으로 어떤 영향을 미칩니 까?) OO 인터페이스가 부족합니다 (하나는 몇 시간 중 하나입니다) 준비한 진술이나 매개 변수화 된 쿼리를 지원하지 않습니다
마지막 것은 흥미로운 점입니다.MySQL Ext는 기본 준비 문장을 지원하지 않지만 안전을 위해 필요하지 않습니다.우리는 수동으로 취급 된 자리 표시자를 사용하여 준비된 명령문을 쉽게 가짜로 만들 수 있습니다.
function paraQuery()
{
$args = func_get_args();
$query = array_shift($args);
$query = str_replace("%s","'%s'",$query);
foreach ($args as $key => $val)
{
$args[$key] = mysql_real_escape_string($val);
}
$query = vsprintf($query, $args);
$result = mysql_query($query);
if (!$result)
{
throw new Exception(mysql_error()." [$query]");
}
return $result;
}
$query = "SELECT * FROM table where a=%s AND b LIKE %s LIMIT %d";
$result = paraQuery($query, $a, "%$b%", $limit);
voila, 모든 것이 매개 변수화되고 안전합니다.
그러나 설명서에있는 빨간색 상자가 마음에 들지 않으면 선택의 문제가 발생합니다 : MySQLi 또는 PDO?
그럼, 대답은 다음과 같습니다.
데이터베이스 추상화 계층을 사용하고 API를 찾는 필요성을 이해하고 API를 찾는 경우 MySQLI는 실제로 많은 MySQL 특정 기능을 지원하므로 MySQLI가 매우 좋은 선택입니다. 대다수의 PHP 사람들의 대다수와 마찬가지로 응용 프로그램 코드에서 RAW API 호출을 사용하는 경우 (본질적으로 잘못된 연습이기도합니다) - PDO는 유일한 선택이지만,이 확장자가 API가 아니라 오히려 반 DAL,여전히 불완전하지만 두 가지 중 두 가지가 많은 중요한 기능을 제공합니다. PDO가 MySQLI와 비판적으로 구별됩니다. MySQLI와 달리 PDO는 자리 표시자를 가치별로 바인딩 할 수 있으며 이는 매우 지저분한 코드의 여러 화면없이 동적으로 구축 된 쿼리를 가능하게합니다. mysqli와 달리 PDO는 항상 단순한 일반적인 배열로 쿼리 결과를 반환 할 수 있지만 mysqli는 mysqlnd 설치에서만 수행 할 수 있습니다.
따라서 평범한 PHP 사용자이고 기본 준비 문장을 사용할 때 두통을 톤으로 저장하고 싶다면 PDO는 유일한 선택입니다. 그러나 PDO는 실버 총알이 아니며 어려움이 없습니다. 그래서, 나는 PDO 태그 위키의 모든 일반적인 함정과 복잡한 사례에 대한 해결책을 썼습니다.
그럼에도 불구하고, 확장에 대해 이야기하는 모든 사람들은 항상 Mysqli와 PDO에 대한 2 가지 중요한 사실을 누락했습니다.
Prepared statement isn't a silver bullet. There are dynamical identifiers which cannot be bound using prepared statements. There are dynamical queries with an unknown number of parameters which makes query building a difficult task.
Neither mysqli_* nor PDO functions should have appeared in the application code.
There ought to be an abstraction layer between them and application code, which will do all the dirty job of binding, looping, error handling, etc. inside, making application code DRY and clean. Especially for the complex cases like dynamical query building.
따라서 PDO 또는 MySQLI로 전환하면 충분하지 않습니다.하나는 ORM 또는 쿼리 빌더 또는 RAW API 함수를 코드에서 호출하는 대신 데이터베이스 추상화 클래스를 사용해야합니다. 그리고 반대로 - 응용 프로그램 코드와 MySQL API간에 추상화 계층이있는 경우 실제로 엔진이 사용되는지는 중요하지 않습니다.MySQL Ext가 더 이상 사용되지 않을 때까지 사용할 때까지 모든 응용 프로그램 코드가 손상되지 않고 다른 엔진으로 추상화 클래스를 쉽게 다시 작성할 수 있습니다.
다음은 이러한 추상화 클래스가 어떻게 될지 보여주기 위해 내 SafemySQL 클래스를 기반으로하는 몇 가지 예입니다.
$city_ids = array(1,2,3);
$cities = $db->getCol("SELECT name FROM cities WHERE is IN(?a)", $city_ids);
이 한 줄을 PDO와 함께 필요로하는 코드와 함께 한 줄을 비교하십시오. 그런 다음 RAW MySQLI 준비 문장과 함께 필요한 미친 코드와 비교하십시오. 오류 처리, 프로파일 링, 이미 내장 및 실행중인 쿼리 로깅을 참고하십시오.
$insert = array('name' => 'John', 'surname' => "O'Hara");
$db->query("INSERT INTO users SET ?u", $insert);
모든 단일 필드 이름이 6 ~ 10 번 반복되는 모든 수많은 필드 이름 (모든 수많은 명명 된 자리 표시 자, 바인딩 및 쿼리 정의)에서 평소 PDO 인서트와 비교합니다.
다른 예시:
$data = $db->getAll("SELECT * FROM goods ORDER BY ?n", $_GET['order']);
이러한 실제 사례를 처리하기 위해 PDO의 예를 거의 찾을 수 없습니다. 그리고 그것은 너무 말하고 안전하지 않을 것입니다.
그래서, 한 번 더 원시 운전자만이 당신의 관심사가 아니라 추상화 수업이어야하며, 초보자 설명서의 어리석은 예뿐만 아니라 실제 문제를 해결하기 위해서는 유용합니다.
출처:https://stackoverflow.com/questions/12859942/why-shouldnt-i-use-mysql-functions-in-php
최근댓글