PHP에서 mysql_ * 함수를 사용하지 않아야하는 이유는 무엇입니까?


2502

mysql_*함수를 사용하지 않아야하는 기술적 이유는 무엇입니까 ? (예를 들어 mysql_query(), mysql_connect()또는 mysql_real_escape_string())?

사이트에서 작업하는 경우에도 다른 것을 사용해야하는 이유는 무엇입니까?

그들이 내 사이트에서 작동하지 않으면 왜 같은 오류가 발생합니까

경고 : mysql_connect () : 그런 파일이나 디렉토리가 없습니다


다음과 같은 오류 : 치명적인 오류 : 잡히지 않은 오류 : 정의되지 않은 함수 호출 mysql_connect () ...
Bimal Poudel

21
더 이상 사용되지 않기 때문에이를 피할 수 있습니다.
Sasa1234

답변:


2088

MySQL 확장 :

  • 활발한 개발 중이 아님
  • 되어 공식적으로 사용되지 않는 PHP 5.5로 (6 월 2013 년 발표).
  • PHP 7.0 부터 완전히 제거 되었습니다 (2015 년 12 월 출시)
    • 이는 2018 년 12 월 31 일 현재 지원되는 PHP 버전에 존재하지 않음을 의미합니다. 지원하는 PHP 버전을 사용하는 경우 보안 문제가 해결되지 않은 버전을 사용하고 있습니다.
  • OO 인터페이스 부족
  • 지원하지 않습니다 :
    • 비 차단 비동기식 쿼리
    • 준비된 명령문 또는 매개 변수화 된 쿼리
    • 저장 프로 시저
    • 여러 문장
    • 업무
    • "새로운"패스워드 인증 방법 (MySQL 5.6에서는 기본적으로; 5.7에서는 필수)
    • MySQL 5.1 이상의 새로운 기능

더 이상 사용되지 않으므로 사용하면 코드의 미래 증거가 줄어 듭니다.

준비된 명령문에 대한 지원 부족은 별도의 함수 호출로 외부 데이터를 수동으로 이스케이프 처리하는 것보다 명확하고 오류가 발생하기 쉬운 외부 ​​데이터 이스케이프 및 인용 방법을 제공하므로 특히 중요합니다.

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


286
더 이상 사용되지 않기 때문에 피할 수 있습니다. 그들은 언젠가 거기에 없을 것이며, 당신이 그들에게 의존한다면 행복하지 않을 것입니다. 나머지는 오래된 확장 기능을 사용하여 사람들이 배우지 못하게 한 것들의 목록입니다.
Tim Post

111
지원 중단은 모든 사람이 생각하는 마법의 총알이 아닙니다. PHP 자체는 언젠가는 존재하지 않지만 오늘날 우리가 사용할 수있는 도구에 의존합니다. 도구를 변경해야 할 때 우리는 할 것입니다.
궤도에서 가벼움 레이스

133
@LightnessRacesinOrbit — Deprecation은 마법의 총알이 아닙니다. "이것이 짜증나서 더 이상 지원하지 않을 것"이라는 플래그입니다. 향후 코드 교정을 개선하는 것이 더 이상 사용되지 않는 기능에서 벗어나는 좋은 이유이지만, 유일한 기능 (또는 주요 기능)도 아닙니다. 강요된 도구가 아니라 더 좋은 도구가 있기 때문에 도구를 변경하십시오. (그리고 강요되기 전에 도구를 변경한다는 것은 코드가 작동을 멈추고 어제 수정이 필요하기 때문에 새로운 도구를 배우지 않는다는 것을 의미합니다 ... 이는 새로운 도구를 배우는 최악의 시간입니다).
Quentin

18
준비된 진술의 부족에 대해 언급하지 않은 한 가지는 성능 문제입니다. 명령문을 발행 할 때마다 , MySQL 데몬이 이해할 수 있도록 무언가 를 컴파일해야합니다. 이 API를 사용하면 루프에서 동일한 쿼리 200,000 개를 발행하면 MySQL에서 쿼리를 이해하기 위해 쿼리를 200,000 배 컴파일해야합니다. 준비된 명령문을 사용하면 한 번 컴파일 된 후 값이 컴파일 된 SQL에 매개 변수화됩니다.
Goldentoa11

20
@symcbean, 반드시 준비된 문장을 지원 하지 않습니다 . 이것이 실제로 더 이상 사용되지 않는 주된 이유입니다. 준비된 문장이 없으면 mysql 확장은 종종 SQL 주입 공격의 대상이됩니다.
rustyx

1287

PHP는 MySQL에 연결하기 위해 세 가지 다른 API를 제공합니다. 이것들은 mysql(PHP 7에서 제거) mysqli, 그리고 PDO확장입니다.

mysql_*기능은 매우 인기가 있었지만 더 이상 사용하지 않는 것이 좋습니다. 문서화 팀은 데이터베이스 보안 상황을 논의하고 있으며 사용자에게 일반적으로 사용되는 ext / mysql 확장에서 벗어나도록 교육하는 것이 이것의 일부입니다 ( php.internals : deprecating ext / mysql 확인 ).

그리고 나중에 PHP 개발자 팀 생성하기로 결정 취한 E_DEPRECATED통해 여부를 사용자가 MySQL을 연결할 때 오류 mysql_connect(), mysql_pconnect()또는에 내장 된 암시 적 연결 기능을 ext/mysql.

ext/mysql공식적으로 PHP 5.5으로 사용되지 하고있다 PHP 7로 제거 .

레드 박스를 보시겠습니까?

mysql_*기능 매뉴얼 페이지 로 이동하면 더 이상 사용해서는 안되는 빨간색 상자가 표시됩니다.


멀어지면 ext/mysql보안뿐만 아니라 MySQL 데이터베이스의 모든 기능에 액세스해야합니다.

ext/mysqlMySQL 3.23을 위해 만들어졌으며 그 이후로 거의 추가되지 않았지만 대부분이 이전 버전과의 호환성을 유지하여 코드를 유지하기가 조금 더 어려워졌습니다. 지원되지 않는 기능 ext/mysql은 다음 을 포함합니다 : ( PHP manual에서 ).

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

  • 적극적 개발 중이 아님
  • PHP 7에서 제거
  • OO 인터페이스 부족
  • 비 차단 비동기 쿼리를 지원하지 않습니다
  • 준비된 명령문 또는 매개 변수화 된 쿼리를 지원하지 않습니다
  • 저장 프로 시저를 지원하지 않습니다
  • 여러 문장을 지원하지 않습니다
  • 거래를 지원하지 않습니다
  • MySQL 5.1의 모든 기능을 지원하지는 않습니다

Quentin의 답변에서 인용 한 위의 내용

준비된 명령문에 대한 지원 부족은 별도의 함수 호출로 외부 데이터를 수동으로 이스케이프 처리하는 것보다 명확하고 오류가 발생하기 쉬운 외부 ​​데이터 이스케이프 및 인용 방법을 제공하므로 특히 중요합니다.

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


지원 중단 경고 억제

코드로 변환되는 동안 MySQLi/ PDO, E_DEPRECATED설정하여 오류를 억제 할 수 error_reporting에서 php.ini 파일 제외E_DEPRECATED:

error_reporting = E_ALL ^ E_DEPRECATED

이것은 또한 다른 지원 중단 경고를 숨길 것 입니다. 그러나 이것은 MySQL 이외의 것들에 대한 것일 수도 있습니다. ( PHP 매뉴얼에서 )

PDO vs. MySQLi 기사 : 어느 것을 사용해야합니까? 에 의해 Dejan Marjanovic 당신이 선택하는 데 도움이 될 것입니다.

더 좋은 방법은 입니다. PDO이제 간단한 PDO자습서를 작성하고 있습니다.


간단하고 짧은 PDO 튜토리얼


Q. 내 마음의 첫 번째 질문은 'PDO'란 무엇입니까?

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

대체 텍스트


MySQL에 연결

mysql_*우리가 그것을 옛날 방식을 말할 수있는 함수 또는 (위의 PHP에서 5.5을 사용되지 않음)

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

With PDO: 새 PDO객체를 생성하기 만하면됩니다. 생성자는 데이터베이스 소스 생성자를 지정하기위한 매개 변수를 승인합니다. (데이터 소스 이름) 및 선택적으로 , PDO네 개의 매개 변수를 사용 합니다.DSNusernamepassword

여기서 나는 당신이 제외한 모든 것을 잘 알고 있다고 생각합니다 DSN. 이것은의 새로운 기능입니다 PDO. A DSN는 기본적으로 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더 나은 솔루션을 제공합니다 : 예외. 우리가 함께 할 아무것도 PDOA의 포장되어야한다 try- catch블록. PDOerror mode 속성을 설정하여 세 가지 오류 모드 중 하나로 강제 설정할 수 있습니다 . 다음은 세 가지 오류 처리 모드입니다.

  • 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 );

그리고 아래와 같이 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.
}

또한 처리 할 수 or die()있거나처럼 말할 수 mysql_*있지만 실제로는 다양합니다. display_errors off오류 로그를 돌려서 읽으면 프로덕션에서 위험한 오류 메시지를 숨길 수 있습니다 .

자, 위의 모든 것들을 읽고 나면, 당신은 아마 생각 : 도대체 무엇인지 그 난 그냥 간단하게 기대어 시작하려고 할 때 SELECT, INSERT, UPDATE, 또는 DELETE문을? 걱정하지 마십시오.


데이터 선택

PDO 이미지 선택

그래서 당신이하고있는 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 Data에서는 ->fetch()명령문 핸들의 메소드 인를 통해 얻습니다 . 가져 오기를 호출하기 전에 가장 좋은 방법은 PDO에게 데이터를 가져 오는 방법을 알려주는 것입니다. 아래 섹션에서 이것을 설명합니다.

페치 모드

PDO::FETCH_ASSOCfetch()fetchAll()코드 에서 의 사용에 유의하십시오 . 이것은 PDO필드 이름을 키로 사용하여 행을 연관 배열로 리턴하도록 지시 합니다. 다른 페치 모드도 많이 있는데, 하나 하나 설명하겠습니다.

우선, 가져 오기 모드를 선택하는 방법에 대해 설명합니다.

 $stmt->fetch(PDO::FETCH_ASSOC)

위에서는을 사용하고 fetch()있습니다. 다음을 사용할 수도 있습니다.

이제 가져 오기 모드가되었습니다.

  • PDO::FETCH_ASSOC: 결과 세트에 리턴 된대로 열 이름으로 색인화 된 배열을 리턴합니다.
  • PDO::FETCH_BOTH (기본값) : 결과 집합에 반환 된 열 이름과 0 색인 열 번호로 색인 된 배열을 반환합니다.

더 많은 선택이 있습니다! PDOStatementFetch 문서 에서 이에 대해 모두 읽으십시오 . .

행 개수 얻기 :

mysql_num_rows반환 된 행 수를 얻는 데 사용 하는 대신 a PDOStatement와 do를 얻을 수 있습니다 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();

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

PDO 이미지 삽입 및 업데이트

우리가 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 point에서 인용 ).

  1. 준비 : 명령문 템플리트는 애플리케이션에 의해 작성되고 데이터베이스 관리 시스템 (DBMS)으로 전송됩니다. 매개 변수, 자리 표시 자 또는 바인드 변수라고하는 특정 값은 지정되지 않은 상태로 유지 ?됩니다 ( 아래에 표시 ).

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

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

  3. Execute : 나중에 어플리케이션은 매개 변수에 값을 제공 (또는 바인드)하고 DBMS는 명령문을 실행합니다 (결과를 리턴 할 수 있음). 응용 프로그램은 다른 값으로 원하는만큼 명령문을 실행할 수 있습니다. 이 예에서는 첫 번째 매개 변수와 1.00두 번째 매개 변수에 'Bread'를 제공 할 수 있습니다 .

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);

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);)에 변수를 할당합니다 . 그런 다음 해당 자리 표시 자에 값을 할당하고 문을 실행합니다. 두 번째 예에서, 첫 번째 배열 요소는 첫 번째로 가고 ?두 번째는 두 번째로 ?갑니다.

참고 : 명명되지 않은 자리 표시 자 에서는 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 /*"));

15
위에서 잘 읽어야 할 것 : 준비된 진술은의 의미있는 사용을 빼앗아 간다 IN (...) construct.
Eugen Rieck

24
문제는 "PHP에서 mysql_ * 함수를 사용해야하는 이유"였습니다. 이 답변은 인상적이고 유용한 정보로 가득 차 있지만 범위를 벗어난 @trejder와 같이 말합니다. 10 명 중 8 명은 4 시간이 걸리지 않기 때문에 해당 정보를 놓치게됩니다. 그것. 이것은 훨씬 더 귀중하고 여러 개의 더 정확한 질문에 대한 답변으로 사용됩니다.
Alex McMillan

Persoanlly 나는 mysqli와 PDO를 선호합니다. 그러나 다이 처리의 경우 예외 대안을 시도했습니다. 예외를 처리하는 데 function throwEx() { throw new Exception("You did selected not existng db"); } mysql_select_db("nonexistdb") or throwEx();효과적입니다.
kuldeep.kamboj

당신은 목록 Doesn't support non-blocking, asynchronous queriesmysql_로를 사용하지 않는 이유로 - 당신은 또한해야 목록이 PDO는 그 중 하나를 지원하지 않기 때문에, PDO를 사용하지 않는 이유가있다. (그러나 MySQLi는 지원)
hanshenrik

이것을 사용하는 데이터베이스가 있으므로 Charset utf8mb4_unicode_ci를 사용할 수 있습니까?
라이언 스톤

301

먼저 모든 사람에게 제공되는 표준 의견으로 시작하겠습니다.

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 데이터베이스 객체 (PDO-PHP Database Object )와 MySQL 별 개선 기능인 MySQLi가 더 강력하고 잘 구축 된 대안 이 있습니다.


6
한 가지 더 있습니다 : 나는 오래되고 오래되었지만 여전히 실행중인 CMS, 전자 상거래, 게시판 시스템 등과의 호환성-단 한 가지 이유로 PHP에 함수가 여전히 존재한다고 생각합니다. 마침내 제거되고 당신은 다시 작성해야합니다 응용 프로그램
Kamil

4
@ 카밀 : 사실이지만, 그것을 사용해서는 안되는 이유는 아닙니다. 그것을 사용하지 않는 이유는 그것이 오래되고 안전하지 않기 때문입니다. :)
Madara의 유령

4
@Mario-PHP 개발자는 프로세스를 가지고 있으며 5.5에서 ext / mysql을 공식적으로 사용하지 않기 위해 투표했습니다. 더 이상 가정적인 문제가 아닙니다.
SDC

2
PDO 또는 MySQLi와 같은 입증 된 기술을 사용하여 몇 줄을 더 추가하면 PHP가 항상 제공하는 사용 편의성을 제공합니다. 개발자를 위해 모든 자습서에서 이러한 신의 mysql_ * 함수를 보는 것이 실제로 교훈에서 멀어지고 OP 가이 종류의 코드가 10 년 전 soooo임을 알려야합니다. 튜토리얼의 관련성도!
FredTheWebGuy

1
대답은 적절하게 언급해야합니다 IN (...) construct.
Eugen Rieck

217

사용의 용이성

분석 및 합성 이유는 이미 언급되었습니다. 신규 이민자에게는 날짜가 지정된 mysql_ 함수 사용을 중단하는 것이 더 큰 동기가됩니다.

최신 데이터베이스 API는 사용 하기더 쉽습니다 .

주로 코드를 단순화 할 수 있는 바운드 매개 변수 입니다. 그리고 훌륭한 튜토리얼을 통해 (위에서 볼 수 있듯이) PDO 로의 전환 이 지나치게 힘들지는 않습니다.

그러나 더 큰 코드 기반을 한 번에 다시 작성하려면 시간이 걸립니다. 이 중간 대안을위한 Raison d' être :

mysql_ * 대신 동등한 pdo_ * 함수

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

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

  2. 어디서나mysql_ 함수 접두사를 제거 하고로 교체하십시오 .pdo_

    • mysql_connect() 된다 pdo_connect()
    • mysql_query() 된다 pdo_query()
    • mysql_num_rows() 된다 pdo_num_rows()
    • mysql_insert_id() 된다 pdo_insert_id()
    • mysql_fetch_array() 된다 pdo_fetch_array()
    • mysql_fetch_assoc() 된다 pdo_fetch_assoc()
    • mysql_real_escape_string() 된다 pdo_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]";
    }

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에 의해 제공됩니다.
  • 따라서 :named나중에 자리 표시 자 목록 도 허용 되었습니다.

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

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

매우 단순합니다. 그러나 왜 다시 제거 mysql_하고 탈출 하고 싶을 지에 대한 더 많은 재 작성 조언과 기술적 이유로 돌아가 봅시다 .

구식 sanitize()기능 수정 또는 제거

바운드 매개 변수 mysql_를 사용 pdo_query하여 모든 통화를 변환 한 후 모든 중복 pdo_real_escape_string통화를 제거하십시오 .

특히 당신은 어떤 수정해야 sanitize하거나 clean또는 filterThis또는 clean_data한 형태 또는 다른에서 날짜가 기입 된 튜토리얼에 의해 광고 등의 기능을 :

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

여기서 가장 눈에 띄는 버그는 문서가 부족하다는 것입니다. 더 중요한 것은 필터링 순서가 정확히 잘못된 순서였습니다.

  • 올바른 순서는이었을 것입니다 : deprecatedly stripslashes가장 안쪽의 호출로, 다음 trim, 나중에 strip_tags, htmlentities오직 마지막으로 출력 컨텍스트 및 위해 _escape_string자사의 응용 프로그램으로 직접 intersparsing SQL을보다 선행해야한다.

  • 그러나 첫 번째 단계로 전화를 제거_real_escape_string 하십시오.

  • sanitize()데이터베이스 및 애플리케이션 플로우에 HTML 컨텍스트 안전 문자열이 필요한 경우 나머지 기능 을 유지해야 할 수도 있습니다 . HTML 이스케이프 처리에만 적용된다는 의견을 추가하십시오.

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

  • stripslashes()살균 기능 에 대해 언급 한 내용이 있으면 더 높은 수준의 감독을 의미 할 수 있습니다.

    • 그것은 일반적으로 더 이상 사용되지 않는 피해 (두 배 탈출)를 취소하기 위해있었습니다 magic_quotes. 그러나 문자열별로가 아니라 중앙 에서 가장 잘 고정 됩니다.

    • 유저 랜드 반전 접근법 중 하나를 사용하십시오 . 그런 다음 기능 stripslashes()에서를 제거하십시오 sanitize.

    magic_quotes에 대한 역사적 메모. 이 기능은 더 이상 사용되지 않습니다. 그러나 실패한 보안 기능 으로 잘못 묘사되는 경우가 많습니다 . 그러나 magic_quotes는 테니스 공이 영양원만큼 실패한 것처럼 보안 기능이 실패한 것입니다. 그것은 단순히 그들의 목적이 아니 었습니다.

    PHP2 / FI의 원래 구현에서는 " 인용 부호가 자동으로 이스케이프되어 양식 데이터를 msql 쿼리에 직접 전달하는 것이 더 쉬워집니다 "라는 명시 적으로 도입되었습니다 . 특히 ASCII 만 지원했기 때문에 mSQL 과 함께 사용하는 것이 우연히 안전했습니다 .
    그런 다음 PHP3 / Zend는 MySQL 용 magic_quotes를 다시 도입하여 잘못 문서화했습니다. 그러나 원래는 보안을위한 것이 아니라 편의 기능 일뿐 입니다.

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

문자열 변수를 SQL 쿼리로 스크램블하면 따라 가기가 더 복잡해지지 않습니다. 또한 MySQL이 코드와 데이터를 다시 분리하기 위해 많은 노력을 기울이고 있습니다.

SQL 삽입은 단순히 데이터가 코드 컨텍스트에서 번질 때 발생 합니다 . 데이터베이스 서버는 나중에 PHP가 쿼리 절 사이에서 원래 변수를 붙인 위치를 알 수 없습니다.

바인딩 된 매개 변수를 사용하면 PHP 코드에서 SQL 코드와 SQL 컨텍스트 값을 구분합니다. 그러나 PDO :: EMULATE_PREPARES를 제외하고는 뒤에서 뒤섞이지 않습니다. 데이터베이스는 가변 SQL 명령과 1 : 1 변수 값을받습니다.

이 답변은 삭제의 가독성 이점에주의를 기울여야한다고 강조합니다 mysql_. 이 가시적이고 기술적 인 데이터 / 코드 분리로 인해 때때로 성능상의 이점 (값이 다른 INSERT 반복)이 있습니다.

매개 변수 바인딩은 여전히 모든 SQL 주입 에 대한 마법의 원 스톱 솔루션이 아닙니다 . 데이터 / 값에 가장 일반적으로 사용됩니다. 그러나 열 이름 / 테이블 식별자를 허용 목록에 추가하거나 동적 절 구성에 도움을 주거나 단순한 배열 값 목록을 만들 수 없습니다.

하이브리드 PDO 사용

이러한 pdo_*래퍼 함수는 코딩 친화적 인 스톱 갭 API를 만듭니다. ( MYSQLI특별한 기능 시그니처 시프트가 아니었다면 거의 가능했을 것입니다). 또한 대부분의 경우 실제 PDO를 노출합니다.
새로운 pdo_ 함수 이름을 사용하여 다시 쓰기를 중단 할 필요는 없습니다. 각 pdo_query ()를 일반 $ pdo-> prepare ()-> execute () 호출로 하나씩 전환 할 수 있습니다.

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

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

foreach 반복으로 대체 할 수 있습니다.

foreach ($result as $row) {

또는 직접적이고 완전한 배열 검색이 더 좋습니다.

$result->fetchAll();

대부분의 경우 PDO 또는 mysql_이 일반적으로 실패한 쿼리 후 제공하는 것보다 더 유용한 경고가 표시됩니다.

다른 옵션

이것은 희망 적인 몇 가지 실용적인 이유와 가치있는 통로를 보여 주었 으면합니다 mysql_.

그냥 전환 잘 자르지 않습니다. pdo_query()또한 그것에 대한 프론트 엔드입니다.

매개 변수 바인딩을 도입하거나 더 좋은 API의 다른 것을 활용할 수 없다면, 그것은 무의미한 스위치입니다. 나는 새로운 이민자들에게 낙담하지 않을 정도로 간단하게 묘사되기를 바랍니다. (교육은 일반적으로 금지보다 효과적입니다.)

그것은 가장 간단한 것-아마도 일할 수있는 범주에 적합하지만 여전히 매우 실험적인 코드입니다. 나는 방금 주말에 그것을 썼다. 그러나 수많은 대안이 있습니다. PHP 데이터베이스 추상화를 위해 Google을 검색하고 조금 탐색하십시오. 그러한 작업을위한 훌륭한 라이브러리는 항상 존재하고있을 것입니다.

데이터베이스 상호 작용을 더 단순화하려면 Paris / Idiorm 과 같은 매퍼를 사용해보십시오. 더 이상 JavaScript에서 블랜드 DOM을 사용하지 않는 것처럼 요즘에는 원시 데이터베이스 인터페이스를 보모 할 필요가 없습니다.


8
pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);기능에 주의하십시오 -예 :pdo_query("INSERT INTO users VALUES (?, ?, ?), $_POST); $_POST = array( 'username' => 'lawl', 'password' => '123', 'is_admin' => 'true');
rickyduck

@Tom Sure, 비록 많이 유지되지는 않았지만 (0.9.2가 마지막이었습니다) 화석 계정을 만들 거나 위키에 추가하거나 (IIRC 등록없이) 버그 보고서를 제출할 수 있습니다.
mario

pdo_real_escape_string() <-이것도 실제 함수입니까, 문서를 찾을 수 없습니까? 이에 대한 소스를 게시하십시오.
라이언 스톤

144

mysql_기능 :

  1. 오래되었습니다-더 이상 유지되지 않습니다
  2. 다른 데이터베이스 백엔드로 쉽게 이동할 수 없습니다
  3. 준비된 진술을 지원하지 않으므로
  4. 프로그래머가 연결을 사용하여 쿼리를 작성하도록 장려하여 SQL 주입 취약점으로 연결

18
# 2도 마찬가지입니다.mysqli_
eggyal

16
공평하게 말하면 SQL 언어의 변형을 고려할 때 PDO조차도 어느 정도 확실하게 # 2를 제공하지 않습니다. 적절한 ORM 래퍼가 필요합니다.
SDC

mysql_*함수는 최신 PHP 버전을위한 mysqlnd 함수의 쉘입니다. 따라서 이전 클라이언트 라이브러리가 더 이상 유지되지 않더라도 mysqlnd는 유지됩니다 :)
hakre

문제는 없습니다 많은 웹 호스팅 인해 오래된 PHP 버전으로 디자인과 같은 객체 지향 스타일을 지원할 수있는 업체입니다
라주 yourPepe을

@RajuGujarati는 가능한 웹 호스트를 찾으십시오. 웹 호스트가 그렇지 않으면 서버 공격에 취약 할 가능성이 매우 높습니다.
Alnitak

106

기술적 인 이유에 관해서는 극도로 구체적이며 거의 사용되지 않는 몇 가지가 있습니다. 아마 당신은 결코 당신의 인생에서 그들을 사용하지 않을 것입니다.
어쩌면 나는 너무 무지하지만, 나는 그들과 같은 것들을 사용할 기회가 없었습니다.

  • 비 차단 비동기 쿼리
  • 여러 결과 집합을 반환하는 저장 프로 시저
  • 암호화 (SSL)
  • 압축

필요한 경우-이것이 mysql 확장에서 더 세련되고 현대적인 것으로 이동해야 할 기술적 이유입니다.

그럼에도 불구하고 약간의 기술적이지 않은 문제도있어 경험을 조금 더 어렵게 만들 수 있습니다

  • 최신 PHP 버전에서 이러한 기능을 추가로 사용하면 더 이상 사용되지 않는 레벨의 알림이 발생합니다. 그들은 단순히 끌 수 있습니다.
  • 먼 미래에는 기본 PHP 빌드에서 제거 될 수 있습니다. mydsql ext가 PECL로 이동하고 모든 호스팅 업체는 수십 년 동안 사이트를 운영하는 클라이언트를 잃고 싶지 않기 때문에 PHP를 컴파일하는 것을 기뻐할 것이므로 큰 문제는 아닙니다.
  • Stackoverflow 커뮤니티의 강력한 저항. 당신이 정직한 기능을 언급 할 때마다, 당신은 그것들이 엄격한 금기 상태에 있다고 들었습니다.
  • 일반적인 PHP 사용자 인 경우,이 함수를 사용하려는 아이디어는 오류가 발생하기 쉽습니다. 당신에게 잘못된 길을 가르치는 수많은 튜토리얼과 매뉴얼 때문에 말입니다. 기능 자체가 아니라 강조해야합니다. 그러나 사용 방식.

후자의 문제는 문제입니다.
그러나 내 의견으로는 제안 된 솔루션도 더 나쁘지 않습니다. 모든 PHP 사용자가 SQL 쿼리를 한 번에 올바르게 처리하는 방법을 배우는
것이 너무 이상적 입니다. 대부분의 경우 접근 방식은 동일하게 남겨두고 기계적으로 mysql_ *를 mysqli_ *로 변경했을 것입니다 . 특히 mysqli는 준비된 명령문 사용법을 엄청나게 고통스럽고 번거롭기 때문에.
말할 것도없이 네이티브 준비된 명령문으로 SQL 인젝션 을 보호하기에 충분 하지 않으며 mysqli 나 PDO도 솔루션을 제공하지 않습니다.

따라서이 정직한 확장과 싸우는 대신 잘못된 관행에 맞서 싸우고 올바른 방법으로 사람들을 교육하는 것을 선호합니다.

또한 다음과 같은 허위 또는 중요하지 않은 이유가 있습니다.

  • 저장 프로 시저를 지원하지 않습니다 ( mysql_query("CALL my_proc");연령 으로 사용 중임)
  • 거래를 지원하지 않습니다 (위와 동일)
  • 여러 문장을 지원하지 않습니다 (누가 필요합니까?)
  • 적극적 개발 중이 아님 (실제로 어떤 영향 미칩니 까?)
  • OO 인터페이스가 부족합니다 (하나를 만드는 데 몇 시간이 걸립니다)
  • 준비된 문장 또는 매개 변수화 된 쿼리를 지원하지 않습니다

마지막은 흥미로운 점입니다. mysql ext는 기본 준비된 명령문을 지원하지 않지만 안전을 위해 필요하지는 않습니다. PDO처럼 수동으로 처리 된 자리 표시자를 사용하여 준비된 명령문을 쉽게 위조 할 수 있습니다.

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를 찾아야 하는 필요성을 이해한다면 , mysqli 는 실제로 많은 mysql 관련 기능을 지원하기 때문에 매우 좋은 선택입니다.
  • 대다수의 PHP 사용자와 마찬가지로 응용 프로그램 코드에서 원시 API 호출을 사용하는 경우 (실제로 잘못된 관행 임)- 이 확장은 API뿐만 아니라 semi-DAL 인 것처럼 가장하기 때문에 PDO가 유일한 선택입니다 . 여전히 불완전하지만 많은 중요한 기능을 제공합니다. 그중 두 가지는 PDO를 mysqli와 크게 구별합니다.

    • mysqli와 달리 PDO는 값으로 자리 표시자를 바인딩 할 수 있으므로 매우 복잡한 코드의 여러 화면없이 동적으로 작성된 쿼리를 실행할 수 있습니다.
    • mysqli와 달리 PDO는 항상 간단한 일반 배열로 쿼리 결과를 반환 할 수 있지만 mysqli는 mysqlnd 설치에서만 수행 할 수 있습니다.

따라서 일반적인 PHP 사용자이고 기본 준비된 명령문을 사용할 때 많은 두통을 피하고 싶다면 PDO가 유일한 선택입니다.
그러나 PDO도 은총 알이 아니며 어려움이 있습니다.
그래서 PDO 태그 위키 에서 모든 일반적인 함정과 복잡한 사례에 대한 솔루션을 작성했습니다.

그럼에도 불구하고 확장에 대해 이야기하는 모든 사람들은 항상 Mysqli와 PDO에 대한 두 가지 중요한 사실을 놓치고 있습니다 .

  1. 준비된 진술 은 은색 총알이 아닙니다 . 준비된 명령문을 사용하여 바인딩 할 수없는 동적 식별자가 있습니다. 알 수없는 매개 변수를 가진 동적 쿼리가있어 쿼리 작성을 어려운 작업으로 만듭니다.

  2. mysqli_ * 또는 PDO 함수는 애플리케이션 코드에 나타나지 않아야합니다. 응용 프로그램 코드와 응용 프로그램 코드 사이
    에는 추상화 계층 이 있어야하며 , 바인딩, 루핑, 오류 처리 등의 모든 더러운 작업을 수행하여 응용 프로그램 코드를 건조하고 깨끗하게 만듭니다. 특히 동적 쿼리 작성과 같은 복잡한 경우에 적합합니다.

따라서 PDO 또는 mysqli로 전환하는 것만으로는 충분하지 않습니다. 코드에서 원시 API 함수를 호출하는 대신 ORM 또는 쿼리 빌더 또는 모든 데이터베이스 추상화 클래스를 사용해야합니다.
반대로 응용 프로그램 코드와 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에 필요한 코드 양과 비교하십시오 .
그런 다음 원시 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의 예는 거의 없습니다.
그리고 너무 장황하고 안전하지 않을 것입니다.

따라서 한 번 더-그것은 원시 드라이버 일뿐 만 아니라 추상화 클래스입니다. 초보자 매뉴얼의 어리석은 예제뿐만 아니라 실제 문제를 해결하는 데 유용합니다.


20
mysql_*취약점을 쉽게 발견 할 수 있습니다. PHP는 많은 초보 사용자가 사용하기 때문에 mysql_*이론상 문제없이 사용할 수 있지만 실제로는 실제로 유해합니다.
Madara의 유령

4
everything is parameterized and safe-그것은 매개 변수화 될 수 있지만 함수는 실제 준비된 문장을 사용하지 않습니다 .
uınbɐɥs

6
어떻게 Not under active development에만 그 만들어 낸 '0.01 %'를? 이 정지 기능으로 무언가를 구축하고 1 년 내에 mysql-version을 업데이트하고 작동하지 않는 시스템을 사용하면 갑자기 '0.01 %'에 많은 사람들이 있습니다. 나는 그런 말 것 deprecatednot under active development밀접하게 관련되어있다. 당신은 그것에 대한 "적당한 이유"가 없다고 말할 수 있지만, 사실은 옵션들 중에서 선택을 제안 할 때, 내가 말한 no active development것만 큼 ​​나쁘다는 deprecated것입니다.
Nanne 2013

1
@MadaraUchiha : 취약점이 얼마나 쉽게 발생하는지 설명 할 수 있습니까? 특히 같은 취약점이 PDO 나 MySQLi에 영향을 미치지 않는 경우에 ... 나는 당신이 말한 하나를 알지 못하기 때문에.
ircmaxell

4
@ShaquinTrifonoff : 물론 준비된 문장을 사용하지 않습니다. 그러나 대부분의 사람들이 MySQLi보다 권장하는 PDO도 마찬가지 입니다. 따라서 이것이 여기에 큰 영향을 미치는지 확실하지 않습니다. 위의 코드 (약간 더 파싱 한)는 기본적으로 명령문을 준비 할 때 PDO가 수행하는 작업입니다.
ircmaxell

97

여러 가지 이유가 있지만 아마도 가장 중요한 이유는 이러한 함수가 준비된 명령문을 지원하지 않기 때문에 안전하지 않은 프로그래밍 방식을 장려한다는 것입니다. 준비된 명령문은 SQL 삽입 공격을 방지하는 데 도움이됩니다.

mysql_*기능을 사용할 때는 다음을 통해 사용자 제공 매개 변수를 실행해야합니다.mysql_real_escape_string() . 한곳에서 잊어 버렸거나 입력의 일부만 탈출하면 데이터베이스가 공격받을 수 있습니다.

PDO또는 준비된 문을 사용하면 mysqli이러한 종류의 프로그래밍 오류를 만들기가 더 어려워집니다.


3
불행히도 MySQLi_ *에서 가변 수의 매개 변수를 전달하는 데 대한 지원이 부족하면 (예 : IN 절에서 확인할 값 목록을 전달하려는 경우) 매개 변수를 사용하지 않도록 권장합니다. MySQL_ * 호출을 취약한 상태로 두십시오.
Kickstart

5
그러나 다시 한번, 불안감은 mysql_ * 함수의 본질적인 문제가 아니라 잘못된 사용법의 문제입니다.
Agamemnus

2
@Agamemnus 문제는 mysql_ *를 사용하면 특히 경험이 부족한 프로그래머에게 "잘못된 사용법"을 쉽게 구현할 수 있다는 것이다. 준비된 명령문을 구현하는 라이브러리는 이러한 유형의 오류를 발생시키기 어렵습니다.
Trott

75

(다른 이유들 중에서도) 입력 데이터를 위생 처리하는 것이 훨씬 어렵 기 때문입니다. 매개 변수화 된 쿼리를 사용하는 경우 PDO 또는 mysqli와 마찬가지로 위험을 완전히 피할 수 있습니다.

예를 들어, 누군가 "enhzflep); drop table users"사용자 이름으로 사용할 수 있습니다 . 이전 함수는 쿼리 당 여러 문을 실행할 수 있으므로 불쾌한 버그가 전체 테이블을 삭제할 수 있습니다.

하나가 mysqli의 PDO를 사용한다면, user-name은 종료됩니다 "enhzflep); drop table users".

bobby-tables.com을 참조하십시오 .


10
The old functions will allow executing of multiple statements per query-아뇨. ext / mysql에서는 이러한 종류의 주입이 불가능합니다. PHP 및 MySQL에서 이러한 종류의 주입이 가능한 유일한 방법은 MySQLi 및 mysqli_multi_query()함수를 사용할 때 입니다. ext / mysql 및 이스케이프되지 않은 문자열로 가능한 종류 주입은 ' OR '1' = '1액세스 할 수없는 데이터베이스에서 데이터를 추출하는 것과 같습니다 . 특정 상황에서는 하위 쿼리를 삽입 할 수 있지만 여전히 이런 방식으로 데이터베이스를 수정할 수는 없습니다.
DaveRandom

64

이 답변은 잘못 작성된 PHP 사용자 유효성 검사 코드를 우회하는 것이 얼마나 간단한 지, 이러한 공격의 작동 방식 및 사용 방법 및 이전 MySQL 기능을 안전한 준비된 문장으로 대체하는 방법 및 기본적으로 StackOverflow 사용자를 보여주기 위해 작성되었습니다. (아마도 많은 담당자와 함께) 새로운 사용자가 코드를 개선하기 위해 질문을하고 있습니다.

먼저,이 테스트 mysql 데이터베이스를 작성하십시오 (저는 광산 준비라고 불렀습니다).

mysql> create table users(
    -> id int(2) primary key auto_increment,
    -> userid tinytext,
    -> pass tinytext);
Query OK, 0 rows affected (0.05 sec)

mysql> insert into users values(null, 'Fluffeh', 'mypass');
Query OK, 1 row affected (0.04 sec)

mysql> create user 'prepared'@'localhost' identified by 'example';
Query OK, 0 rows affected (0.01 sec)

mysql> grant all privileges on prep.* to 'prepared'@'localhost' with grant option;
Query OK, 0 rows affected (0.00 sec)

이것으로 PHP 코드로 옮길 수 있습니다.

다음 스크립트는 웹 사이트의 관리자를위한 확인 프로세스라고 가정합니다 (간단하지만 테스트에 복사하여 사용하면 작동 함).

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }

    $database='prep';
    $link=mysql_connect('localhost', 'prepared', 'example');
    mysql_select_db($database) or die( "Unable to select database");

    $sql="select id, userid, pass from users where userid='$user' and pass='$pass'";
    //echo $sql."<br><br>";
    $result=mysql_query($sql);
    $isAdmin=false;
    while ($row = mysql_fetch_assoc($result)) {
        echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
        $isAdmin=true;
        // We have correctly matched the Username and Password
        // Lets give this person full access
    }
    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }
    mysql_close($link);

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

언뜻보기에 합법적 인 것 같습니다.

사용자는 로그인과 비밀번호를 입력해야합니까?

훌륭합니다. 다음을 입력하지 마십시오.

user: bob
pass: somePass

제출하십시오.

출력은 다음과 같습니다.

You could not be verified. Please try again...

감독자! 예상대로 작동하면 이제 실제 사용자 이름과 비밀번호를 사용해보십시오.

user: Fluffeh
pass: mypass

놀랄 만한! 안녕하십니까, 코드는 관리자를 올바르게 확인했습니다. 그것은 완벽!

글쎄,별로. 사용자가 영리한 작은 사람이라고 가정 해 봅시다. 그 사람이 나라고 할 수 있습니다.

다음을 입력하십시오 :

user: bob
pass: n' or 1=1 or 'm=m

그리고 출력은 다음과 같습니다

The check passed. We have a verified admin!

축하합니다. 잘못된 사용자 이름과 잘못된 비밀번호를 입력하여 완전 보호 된 관리자 전용 섹션을 입력 할 수있었습니다. 진심으로, 당신이 나를 믿지 않는다면, 내가 제공 한 코드로 데이터베이스를 생성 하고이 PHP 코드를 실행하십시오.

따라서, 당신이 왜 고문을 당하고 있는지에 대한 답입니다.

그래서 무엇이 잘못되었는지, 왜 방금 슈퍼 관리자 전용 박쥐 동굴에 들어 갔는지 살펴 보겠습니다. 나는 추측을하고 입력에주의를 기울이지 않고 단순히 데이터베이스에 직접 전달했다고 가정했습니다. 실제로 실행중인 쿼리를 변경하는 방식으로 입력을 구성했습니다. 그래서, 무엇이되어야했고, 무엇으로 끝났습니까?

select id, userid, pass from users where userid='$user' and pass='$pass'

이것이 쿼리이지만 변수를 실제 입력으로 바꾸면 다음과 같은 결과가 나타납니다.

select id, userid, pass from users where userid='bob' and pass='n' or 1=1 or 'm=m'

"암호"를 구성하여 암호 주위의 작은 따옴표를 닫은 다음 완전히 새로운 비교를 소개하는 방법을 확인하십시오. 그런 다음 안전을 위해 다른 "문자열"을 추가하여 원래 인용 한 코드에서 작은 따옴표가 예상대로 닫혔습니다.

그러나 이것은 지금 당신에게 소리 지르는 사람들이 아니라 코드를 더 안전하게 만드는 방법을 보여줍니다.

자, 무엇이 잘못되었고 어떻게 해결할 수 있습니까?

이것은 고전적인 SQL 주입 공격입니다. 그 문제에 대한 가장 간단한 것 중 하나입니다. 공격 벡터의 규모에서 이것은 탱크를 공격하고 승리하는 유아입니다.

그렇다면 신성한 관리자 섹션을 어떻게 보호하고 멋지고 안전하게 만들 수 있습니까? 가장 먼저 할 일은 실제로 오래되고 더 이상 사용되지 않는 것을 사용하지 않는 것입니다.mysql_* 기능 것입니다. 나는 당신이 온라인에서 찾은 튜토리얼을 따랐고 작동하지만 오래되었지만 구식이며 몇 분 안에 땀을 흘리지 않고 과거를 깨뜨 렸습니다.

이제 mysqli_ 또는 PDO 를 사용하는 더 나은 옵션이 있습니다 . 나는 개인적으로 PDO의 열렬한 팬 이므로이 답변의 나머지 부분에서 PDO를 사용할 것입니다. 찬반 양론이 있지만 개인적으로 나는 찬성이 찬반보다 훨씬 크다는 것을 알았습니다. 연결 문자열을 변경하여 MySQL 또는 Oracle을 사용하거나 피 묻은 것을 막론하고 여러 데이터베이스 엔진에서 이식 할 수 있으며 사용하려는 모든 멋진 기능을 갖추고 있으며 멋지고 깨끗합니다. 나는 청소를 좋아한다.

이제이 코드를 다시 살펴 보겠습니다. 이번에는 PDO 객체를 사용하여 작성했습니다.

<?php 

    if(!empty($_POST['user']))
    {
        $user=$_POST['user'];
    }   
    else
    {
        $user='bob';
    }
    if(!empty($_POST['pass']))
    {
        $pass=$_POST['pass'];
    }
    else
    {
        $pass='bob';
    }
    $isAdmin=false;

    $database='prep';
    $pdo=new PDO ('mysql:host=localhost;dbname=prep', 'prepared', 'example');
    $sql="select id, userid, pass from users where userid=:user and pass=:password";
    $myPDO = $pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
    if($myPDO->execute(array(':user' => $user, ':password' => $pass)))
    {
        while($row=$myPDO->fetch(PDO::FETCH_ASSOC))
        {
            echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
            $isAdmin=true;
            // We have correctly matched the Username and Password
            // Lets give this person full access
        }
    }

    if($isAdmin)
    {
        echo "The check passed. We have a verified admin!<br>";
    }
    else
    {
        echo "You could not be verified. Please try again...<br>";
    }

?>

<form name="exploited" method='post'>
    User: <input type='text' name='user'><br>
    Pass: <input type='text' name='pass'><br>
    <input type='submit'>
</form>

주요 차이점은 더 이상 mysql_*기능 이 없다는 것 입니다. 그것은 모두 PDO 객체를 통해 이루어지며 두 번째로 준비된 문장을 사용하고 있습니다. 자, 당신은 prepreed 진술이 무엇입니까? 쿼리를 실행하기 전에 데이터베이스에 알리는 방법입니다. 이 경우 데이터베이스에 다음과 같이 말합니다. "이제, id, userid를 원하는 select 문을 실행하고 userid가 변수이고 pass도 변수 인 테이블 사용자에게 전달하려고합니다."

그런 다음 execute 문에서 데이터베이스에 현재 예상되는 모든 변수가 포함 된 배열을 전달합니다.

결과는 환상적입니다. 이전부터 다시 사용자 이름과 비밀번호 조합을 시도 할 수 있습니다.

user: bob
pass: somePass

사용자가 확인되지 않았습니다. 대박.

어때요?

user: Fluffeh
pass: mypass

오, 방금 조금 흥분해서 작동했습니다. 수표가 통과되었습니다. 확인 된 관리자가 있습니다!

이제 영리한 챕터가 작은 검증 시스템을 통과하기 위해 입력 할 데이터를 사용해 보겠습니다.

user: bob
pass: n' or 1=1 or 'm=m

이번에 우리는 다음을 얻습니다.

You could not be verified. Please try again...

그렇기 때문에 질문을 게시 할 때 소리를 지르는 이유가 있습니다. 사람들이 코드를 우회해도 무시할 수 있기 때문입니다. 이 질문에 답하고 코드를 개선하고보다 안전하게 만들고 최신 기능을 사용하십시오.

마지막으로 이것이 완벽한 코드라고 말하는 것은 아닙니다. 예를 들어 해시 된 비밀번호를 사용하여 개선하기 위해 할 수있는 일이 더 있습니다. 데이터베이스에 민감한 정보를 저장할 때 일반 텍스트로 저장하지 않고 여러 레벨의 검증을 수행해야합니다. 당신은 당신의 오래된 주입하기 쉬운 코드를 이것으로 변경하면, 좋은 코드를 작성하는 길을 따라갈 것입니다-당신이 지금까지 얻었고 여전히 읽고 있다는 사실은 당신 이이 유형을 구현하지 않을 것이라는 희망 감을줍니다. 웹 사이트와 애플리케이션을 작성할 때 코드를 작성하지만 방금 언급 한 다른 것들을 조사해 볼 수도 있습니다. 간신히 작동하는 가장 기본적인 코드가 아니라 가능한 최고의 코드를 작성하십시오.


2
답변 주셔서 감사합니다! 내 +1을하세요! mysql_*자체적으로 안전하지는 않지만 나쁜 자습서를 통해 안전하지 않은 코드를 홍보하고 적절한 명령문 준비 API가 부족하다는 점은 주목할 가치가 있습니다.
Madara의 유령

2
해시되지 않은 암호, 공포! = oP 그렇지 않으면 +1 자세한 설명.
cryptic ツ

33

MySQL 확장은 3 개 중 가장 오래된 것으로서 개발자가 MySQL과 통신하는 데 사용한 원래 방식이었습니다. 이 확장은 현재 PHP와 MySQL의 새로운 릴리스에서 개선 된 기능 때문에 다른 두 가지 대안 을 위해 사용되지 않습니다 .

  • MySQLi 는 MySQL 데이터베이스 작업을위한 '향상된'확장입니다. 최신 버전의 MySQL 서버에서 사용할 수있는 기능을 활용하고, 기능 지향 및 객체 지향 인터페이스를 개발자에게 노출시키고 다른 멋진 기능은 거의 없습니다.

  • PDO 는 이전에 주요 데이터베이스 액세스 확장 (예 : MySQL, PostgreSQL, SQLite, MSSQL 등)에 분산 된 대부분의 기능을 통합하는 API를 제공합니다.이 인터페이스는 프로그래머가 데이터베이스 연결, 쿼리 및 결과 세트 및 저수준 드라이버는 데이터베이스 서버와의 통신 및 자원 처리를 수행합니다. 많은 토론과 작업이 PDO로 진행되고 있으며 현대적이고 전문적인 코드로 데이터베이스를 사용하는 적절한 방법으로 간주됩니다.


21

위의 답변이 실제로 너무 길어서 요약하면 다음과 같습니다.

mysqli 확장은 다음과 같은 여러 가지 이점이 있습니다.

  • 객체 지향 인터페이스
  • 준비된 진술에 대한 지원
  • 여러 문장에 대한 지원
  • 거래 지원
  • 향상된 디버깅 기능
  • 임베디드 서버 지원

출처 : MySQLi 개요


위의 답변에서 설명한 것처럼 mysql의 대안은 mysqli 및 PDO (PHP Data Objects)입니다.

  • API는 서버 측 준비 명령문을 지원합니다. MYSQLi 및 PDO에서 지원
  • API는 클라이언트 측 준비된 명령문을 지원합니다. PDO에서만 지원
  • API는 저장 프로 시저를 지원합니다 : MySQLi 및 PDO
  • API는 다중 명령문 및 모든 MySQL 4.1 이상 기능 지원-MySQLi 및 대부분 PDO에서 지원

MySQLi와 PDO는 모두 PHP 5.0에 도입되었으며 MySQL은 PHP 3.0 이전에 도입되었습니다. 주목할 점은 MySQL이 이후 버전에서 더 이상 사용되지 않지만 PHP5.x에 포함되어 있다는 것입니다.


2
답변은 너무 길지만 실제 요약은 "mysql ext is no more"입니다. 그게 다야
당신의 상식

1
@YourCommonSense 내 대답은 mysqli가 mysql을 대체 한 이유입니다. 요점은 Mysqli가 오늘날 존재한다고 말하는 것이 아니라 그것을 사용하십시오. 모두가 그것을 알고 있습니다!
애니 메논

1
글쎄, 아무도 mysqli가 mysql을 대체 한 이유를 묻지 않았다는 사실 외에도이 질문에 대답하지 않습니다. mysqli가 소개 된 이유에 대한 답변입니다. 그러나 왜 mysql과 mysqli가 병행하여 살 수 없었는지는 설명하지 않았다.
Common Sense

@YourCommonSense 또한 OP의 질문은 "내 사이트에서 작동하더라도 왜 다른 것을 사용해야합니까?"입니다. 이것이 제가 변경과 개선을 지적한 이유입니다. 그것들이 긴 다른 모든 대답을 볼 수 있으므로 요약해야한다고 생각했습니다.
애니 메논

6

mysql_*mysqli 또는 PDO를 사용하여 거의 모든 함수 를 정의 할 수 있습니다 . 기존 PHP 응용 프로그램 위에 포함 시키면 PHP7에서 작동합니다. 내 솔루션은 여기에 있습니다 .

<?php

define('MYSQL_LINK', 'dbl');
$GLOBALS[MYSQL_LINK] = null;

function mysql_link($link=null) {
    return ($link === null) ? $GLOBALS[MYSQL_LINK] : $link;
}

function mysql_connect($host, $user, $pass) {
    $GLOBALS[MYSQL_LINK] = mysqli_connect($host, $user, $pass);
    return $GLOBALS[MYSQL_LINK];
}

function mysql_pconnect($host, $user, $pass) {
    return mysql_connect($host, $user, $pass);
}

function mysql_select_db($db, $link=null) {
    $link = mysql_link($link);
    return mysqli_select_db($link, $db);
}

function mysql_close($link=null) {
    $link = mysql_link($link);
    return mysqli_close($link);
}

function mysql_error($link=null) {
    $link = mysql_link($link);
    return mysqli_error($link);
}

function mysql_errno($link=null) {
    $link = mysql_link($link);
    return mysqli_errno($link);
}

function mysql_ping($link=null) {
    $link = mysql_link($link);
    return mysqli_ping($link);
}

function mysql_stat($link=null) {
    $link = mysql_link($link);
    return mysqli_stat($link);
}

function mysql_affected_rows($link=null) {
    $link = mysql_link($link);
    return mysqli_affected_rows($link);
}

function mysql_client_encoding($link=null) {
    $link = mysql_link($link);
    return mysqli_character_set_name($link);
}

function mysql_thread_id($link=null) {
    $link = mysql_link($link);
    return mysqli_thread_id($link);
}

function mysql_escape_string($string) {
    return mysql_real_escape_string($string);
}

function mysql_real_escape_string($string, $link=null) {
    $link = mysql_link($link);
    return mysqli_real_escape_string($link, $string);
}

function mysql_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql);
}

function mysql_unbuffered_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql, MYSQLI_USE_RESULT);
}

function mysql_set_charset($charset, $link=null){
    $link = mysql_link($link);
    return mysqli_set_charset($link, $charset);
}

function mysql_get_host_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_host_info($link);
}

function mysql_get_proto_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_proto_info($link);
}
function mysql_get_server_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_server_info($link);
}

function mysql_info($link=null) {
    $link = mysql_link($link);
    return mysqli_info($link);
}

function mysql_get_client_info() {
    $link = mysql_link();
    return mysqli_get_client_info($link);
}

function mysql_create_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "CREATE DATABASE `$db`");
}

function mysql_drop_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "DROP DATABASE `$db`");
}

function mysql_list_dbs($link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, "SHOW DATABASES");
}

function mysql_list_fields($db, $table, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    $table = str_replace('`', '', mysqli_real_escape_string($link, $table));
    return mysqli_query($link, "SHOW COLUMNS FROM `$db`.`$table`");
}

function mysql_list_tables($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "SHOW TABLES FROM `$db`");
}

function mysql_db_query($db, $sql, $link=null) {
    $link = mysql_link($link);
    mysqli_select_db($link, $db);
    return mysqli_query($link, $sql);
}

function mysql_fetch_row($qlink) {
    return mysqli_fetch_row($qlink);
}

function mysql_fetch_assoc($qlink) {
    return mysqli_fetch_assoc($qlink);
}

function mysql_fetch_array($qlink, $result=MYSQLI_BOTH) {
    return mysqli_fetch_array($qlink, $result);
}

function mysql_fetch_lengths($qlink) {
    return mysqli_fetch_lengths($qlink);
}

function mysql_insert_id($qlink) {
    return mysqli_insert_id($qlink);
}

function mysql_num_rows($qlink) {
    return mysqli_num_rows($qlink);
}

function mysql_num_fields($qlink) {
    return mysqli_num_fields($qlink);
}

function mysql_data_seek($qlink, $row) {
    return mysqli_data_seek($qlink, $row);
}

function mysql_field_seek($qlink, $offset) {
    return mysqli_field_seek($qlink, $offset);
}

function mysql_fetch_object($qlink, $class="stdClass", array $params=null) {
    return ($params === null)
        ? mysqli_fetch_object($qlink, $class)
        : mysqli_fetch_object($qlink, $class, $params);
}

function mysql_db_name($qlink, $row, $field='Database') {
    mysqli_data_seek($qlink, $row);
    $db = mysqli_fetch_assoc($qlink);
    return $db[$field];
}

function mysql_fetch_field($qlink, $offset=null) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    return mysqli_fetch_field($qlink);
}

function mysql_result($qlink, $offset, $field=0) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    $row = mysqli_fetch_array($qlink);
    return (!is_array($row) || !isset($row[$field]))
        ? false
        : $row[$field];
}

function mysql_field_len($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->length : false;
}

function mysql_field_name($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgname) ? $field->name : $field->orgname;
}

function mysql_field_table($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgtable) ? $field->table : $field->orgtable;
}

function mysql_field_type($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->type : false;
}

function mysql_free_result($qlink) {
    try {
        mysqli_free_result($qlink);
    } catch (Exception $e) {
        return false;
    }
    return true;
}

솔루션에 대한 링크를 표시하는 대신 여기에 답변으로 추가하십시오.
amarnath

1

이와 유사한 같다 기능은 mysql_connect(), mysql_query()유형은 이제 사용하지 않을 PHP 즉 (PHP 4) 기능과 이전 버전입니다.

이들은으로 대체 mysqli_connect(), mysqli_query()유사 최신 PHP5에서.

이것이 오류의 원인입니다.


2
PHP 5는 2 년 넘게 최신 버전이 아닙니다.
Madara의 유령

1

MySQL은 PHP 5.5.0에서 더 이상 사용되지 않으며 PHP 7.0.0에서 제거되었습니다. 크고 오래된 응용 프로그램의 경우 각 기능을 검색하고 교체하기가 어렵습니다.

아래에서 실행중인 각 코드에 대해 래퍼 함수를 ​​만들어 MySQL 함수를 사용할 수 있습니다. 여기를 클릭하십시오


-9

더 나은 함수와 코드 구조가 개발되었다는 사실을 감안하면 mysql_ * 함수는 더 이상 사용되지 않습니다 ( PHP 5.5 기준 ). 이 기능이 더 이상 사용되지 않는다는 사실은 성능 및 보안 측면에서 더 이상 노력을 기울이지 않아도 됨을 의미하며 이는 향후 증거가 적습니다 .

더 많은 이유가 필요한 경우 :

  • mysql_ * 함수는 준비된 명령문을 지원하지 않습니다.
  • mysql_ * 함수는 매개 변수 바인딩을 지원하지 않습니다.
  • mysql_ * 함수에는 객체 지향 프로그래밍 기능이 없습니다.
  • 목록은 계속됩니다 ...

18
이 답변은 구식입니다. 게다가, 그것은 이미 존재하는 답변에 유용한 것을 추가하지 않습니다.
당신의 상식
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.