참고 : MySQL 확장을 사용하는 완벽한 코드 샘플은 무엇입니까? [닫은]
PHP참고 : MySQL 확장을 사용하는 완벽한 코드 샘플은 무엇입니까? [닫은]
매일 Stack Overflow에서 mysql_ * 패밀리를 사용하여 코드 스 니펫이 정말 큰 문제가 있습니다. 보통 PDO로 향하는 것이 가장 좋지만 때로는 가능하지도 않으며 (예를 들어, 계승 된 레거시 소프트웨어) 현실적인 기대 (사용자는 이미 자신의 프로젝트에서이 소프트웨어를 사용하고 있습니다).
mysql_ * 라이브러리를 사용하는 코드의 일반적인 문제점은 다음과 같습니다.
함수의 mySQL_ * 패밀리를 사용하여 다음을 수행하는 PHP 코드 샘플을 작성해 보겠습니다.
그리고 위에 열거 된 약점은 보여주지 않습니다.
가능한 한 간단해야합니다. 이상적으로는 함수 나 클래스를 포함하지 않습니다. 목표는 복사 / 붙여 넣기가 가능한 라이브러리를 만드는 것이 아니라 데이터베이스 질의를 안전하게하기 위해해야 할 일을 최소한으로 보여주는 것입니다.
좋은 코멘트를위한 보너스 포인트.
목표는이 질문을 사용자가 잘못된 코드가있는 질문 작성자와 만날 때 (물론 질문의 초점이 아니더라도) 링크 할 수있는 리소스로 만들거나 실패한 쿼리와 마주하고 있지 않은 리소스를 만드는 것입니다. 그것을 고치는 법을 알아라.
PDO 토론을 선점하려면 다음을 수행하십시오.
그렇습니다. 개인을 PDO에 보내는 것이 바람직합니다. 선택 사항 일 때 그렇게해야합니다. 그러나 언제나 가능하지는 않습니다 - 때로는 묻는 질문자가 기존 코드를 작업 중이거나 이미이 라이브러리로 먼 길을왔다 갔다하고 지금은 변경하지 않을 수도 있습니다. 또한, mysql_ * 함수 군은 적절히 사용된다면 완벽하게 안전하다. 따라서 "PDO 사용"답변은 여기에 없습니다.
해결법
-
==============================
1.
내 찌르기. 현실적인 편의를 유지하면서 가능한 한 간단하게 유지하려고했습니다.
유니 코드를 처리하고 가독성을 위해 느슨한 비교를 사용합니다. 착하게 굴 어라 ;-)
<?php header('Content-type: text/html; charset=utf-8'); error_reporting(E_ALL | E_STRICT); ini_set('display_errors', 1); // display_errors can be changed to 0 in production mode to // suppress PHP's error messages /* Can be used for testing $_POST['id'] = 1; $_POST['name'] = 'Markus'; */ $config = array( 'host' => '127.0.0.1', 'user' => 'my_user', 'pass' => 'my_pass', 'db' => 'my_database' ); # Connect and disable mysql error output $connection = @mysql_connect($config['host'], $config['user'], $config['pass']); if (!$connection) { trigger_error('Unable to connect to database: ' . mysql_error(), E_USER_ERROR); } if (!mysql_select_db($config['db'])) { trigger_error('Unable to select db: ' . mysql_error(), E_USER_ERROR); } if (!mysql_set_charset('utf8')) { trigger_error('Unable to set charset for db connection: ' . mysql_error(), E_USER_ERROR); } $result = mysql_query( 'UPDATE tablename SET name = "' . mysql_real_escape_string($_POST['name']) . '" WHERE id = "' . mysql_real_escape_string($_POST['id']) . '"' ); if ($result) { echo htmlentities($_POST['name'], ENT_COMPAT, 'utf-8') . ' updated.'; } else { trigger_error('Unable to update db: ' . mysql_error(), E_USER_ERROR); }
-
==============================
2.
나는 총을 뛰어 다니기로 결심했다. 그것은 무엇부터 시작해야합니다. 오류가 발생하면 예외가 발생합니다.
function executeQuery($query, $args) { $cleaned = array_map('mysql_real_escape_string', $args); if($result = mysql_query(vsprintf($query, $cleaned))) { return $result; } else { throw new Exception('MySQL Query Error: ' . mysql_error()); } } function updateTablenameName($id, $name) { $query = "UPDATE tablename SET name = '%s' WHERE id = %d"; return executeQuery($query, array($name, $id)); } try { updateTablenameName($_POST['id'], $_POST['name']); } catch(Exception $e) { echo $e->getMessage(); exit(); }
-
==============================
3.
/** * Rule #0: never trust users input! */ //sanitize integer value $id = intval($_GET['id']); //sanitize string value; $name = mysql_real_escape_string($_POST['name']); //1. using `dbname`. is better than using mysql_select_db() //2. names of tables and columns should be quoted by "`" symbol //3. each variable should be sanitized (even in LIMIT clause) $q = mysql_query("UPDATE `dbname`.`tablename` SET `name`='".$name."' WHERE `id`='".$id."' LIMIT 0,1 "); if ($q===false) { trigger_error('Error in query: '.mysql_error(), E_USER_WARNING); } else { //be careful! $name contains user's data, remember Rule #0 //always use htmlspecialchars() to sanitize user's data in output print htmlspecialchars($name).' updated'; } ######################################################################## //Example, how easily is to use set_error_handler() and trigger_error() //to control error reporting in production and dev-code //Do NOT use error_reporting(0) or error_reporting(~E_ALL) - each error //should be fixed, not muted function err_handler($errno, $errstr, $errfile, $errline) { $hanle_errors_print = E_ALL & ~E_NOTICE; //if we want to print this type of errors (other types we can just write in log-file) if ($errno & $hanle_errors_print) { //$errstr can contain user's data, so... Rule #0 print PHP_EOL.'Error ['.$errno.'] in file '.$errfile.' in line '.$errline .': '.htmlspecialchars($errstr).PHP_EOL; } //here you can write error into log-file } set_error_handler('err_handler', E_ALL & ~E_NOTICE & E_USER_NOTICE & ~E_STRICT & ~E_DEPRECATED);
그리고 코멘트에 대한 설명 :
-
==============================
4.
<? mysql_connect(); mysql_select_db("new"); $table = "test"; if($_SERVER['REQUEST_METHOD']=='POST') { $name = mysql_real_escape_string($_POST['name']); if ($id = intval($_POST['id'])) { $query="UPDATE $table SET name='$name' WHERE id=$id"; } else { $query="INSERT INTO $table SET name='$name'"; } mysql_query($query) or trigger_error(mysql_error()." in ".$query); header("Location: http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']); exit; } if (!isset($_GET['id'])) { $LIST=array(); $query="SELECT * FROM $table"; $res=mysql_query($query); while($row=mysql_fetch_assoc($res)) $LIST[]=$row; include 'list.php'; } else { if ($id=intval($_GET['id'])) { $query="SELECT * FROM $table WHERE id=$id"; $res=mysql_query($query); $row=mysql_fetch_assoc($res); foreach ($row as $k => $v) $row[$k]=htmlspecialchars($v); } else { $row['name']=''; $row['id']=0; } include 'form.php'; } ?>
form.php
<? include 'tpl_top.php' ?> <form method="POST"> <input type="text" name="name" value="<?=$row['name']?>"><br> <input type="hidden" name="id" value="<?=$row['id']?>"> <input type="submit"><br> <a href="?">Return to the list</a> </form> <? include 'tpl_bottom.php' ?>
list.php
<? include 'tpl_top.php' ?> <a href="?id=0">Add item</a> <? foreach ($LIST as $row): ?> <li><a href="?id=<?=$row['id']?>"><?=$row['name']?></a> <? endforeach ?> <? include 'tpl_bottom.php' ?>
-
==============================
5.
내 다른 대답이 질문의 목적을 놓친 것처럼 보입니다. (이 중 하나는 일부 요구 사항을 충족시키지 못하지만 볼 수 있듯이 안전한 쿼리의 초석이되는 자리 표시자를 처리하는 기능을 구현하지 않으면 안전 솔루션을 얻을 수 없습니다.
그래서, mysql 질의를 안전하면서도 편리하게 만드는 간결한 해결책을 게시하려는 또 다른 시도가 있습니다.
오랜 시간 전에 작성한 함수로 기업 표준 OOP 기반 솔루션으로 옮길 때까지 잘 서비스했습니다. 보안 및 사용 편의성이라는 두 가지 목표를 추구했습니다.
첫 번째는 자리 표시자를 구현하여 얻을 수 있습니다. 두 번째는 자리 표시 자 및 다른 결과 유형을 구현하여 얻을 수 있습니다.
기능은 반드시 이상적인 것이 아닙니다. 몇 가지 단점은 다음과 같습니다.
그러나 그것은 안전하고 간결하며, 전체 라이브러리를 설치할 필요가 없습니다.
function dbget() { /* usage: dbget($mode, $query, $param1, $param2,...); $mode - "dimension" of result: 0 - resource 1 - scalar 2 - row 3 - array of rows */ $args = func_get_args(); if (count($args) < 2) { trigger_error("dbget: too few arguments"); return false; } $mode = array_shift($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); if (!$query) return false; $res = mysql_query($query); if (!$res) { trigger_error("dbget: ".mysql_error()." in ".$query); return false; } if ($mode === 0) return $res; if ($mode === 1) { if ($row = mysql_fetch_row($res)) return $row[0]; else return NULL; } $a = array(); if ($mode === 2) { if ($row = mysql_fetch_assoc($res)) return $row; } if ($mode === 3) { while($row = mysql_fetch_assoc($res)) $a[]=$row; } return $a; } ?>
사용 예제
$name = dbget(1,"SELECT name FROM users WHERE id=%d",$_GET['id']); $news = dbget(3,"SELECT * FROM news WHERE title LIKE %s LIMIT %d,%d", "%$_GET[search]%",$start,$per_page);
Stackoverflow에 게시 된 모든 코드와 주요 차이점 인 위의 예제에서 볼 수 있듯이 안전 및 데이터 검색 루틴은 모두 기능 코드에 캡슐화되어 있습니다. 따라서 수동 바인딩, 이스케이프 / 인용 또는 캐스팅은 물론 수동 데이터 검색도 없습니다.
다른 도우미 기능과 결합
function dbSet($fields,$source=array()) { $set = ''; if (!$source) $source = &$_POST; foreach ($fields as $field) { if (isset($source[$field])) { $set.="`$field`='".mysql_real_escape_string($source[$field])."', "; } } return substr($set, 0, -2); }
이런 식으로 사용했습니다.
$fields = explode(" ","name surname lastname address zip phone regdate"); $_POST['regdate'] = $_POST['y']."-".$_POST['m']."-".$_POST['d']; $sql = "UPDATE $table SET ".dbSet($fields).", stamp=NOW() WHERE id=%d"; $res = dbget(0,$sql, $_POST['id']); if (!$res) { _503;//calling generic 503 error function }
OP의 예제를 포함하여 거의 모든 필요를 충족시킬 수 있습니다.
from https://stackoverflow.com/questions/6198104/reference-what-is-a-perfect-code-sample-using-the-mysql-extension by cc-by-sa and MIT lisence
'PHP' 카테고리의 다른 글
PHP 세션 보안 (0) | 2018.09.04 |
---|---|
매개 변수화 된 쿼리 란 무엇입니까? (0) | 2018.09.04 |
jquery $ .ajax를 사용하여 PHP 함수 호출하기 (0) | 2018.09.04 |
PHP에서 JavaScript 함수를 호출하는 방법? (0) | 2018.09.04 |
PHP에서 데이터베이스 비밀번호를 보호하는 방법은 무엇입니까? (0) | 2018.09.04 |