Pen*_*der 8 php sql-server pdo
我一直在使用PDO和PHP一段时间使用MySQL和Apache服务器.我最近的任务是将业务的遗留Web应用程序转换为新的设置.旧的设置是标准的Linux Web堆栈(Apache/PHP/MySQL/Filezilla),新的设置将是带有IIS/PHP(快速cgi安装)/ SQL Server 2003 /无FTP的Windows服务器2003.
除了转换MySQL语句以更新具有文件访问信息的表之外,我几乎所有工作都在工作.将PDO与SQLSRV驱动程序一起使用并在"文件下载"PHP脚本中执行insert语句,将多个记录插入SQL表中.
download.php DOES向SQL服务器发出多个查询.一次检查一个表中的文件是否存在和变量,然后THEN用访问信息更新另一个表.
请参阅下面的download.php代码
调试显示$ count的打印/回显为1.但是,检查SQL服务器记录时,始终显示多个已插入.有时它只是一个额外的行,总共两个,但有时它插入的高达四个EXTRA语句.在每种情况下,$ count仍显示为1.
此特定PHP脚本在调用此insert语句之前验证SQL数据库的信息.首先,验证文件访问的验证(成功),验证文件是否存在(成功),然后用下载信息(ERROR)更新访问表,最后将PDF提供给用户(成功).
当我手动向查询分析器发出INSERT语句时,它成功并按预期工作; 它每次都插入一行.该错误似乎与执行()的SQLSRV或PDO实现有关.
我已经在stackoverflow,serverfault和全能的Google上搜索了有关此内容的信息.返回的唯一类型的结果是用户需要在一个语句/执行中执行多个查询/插入.我的问题恰恰相反; 我希望只执行一个插入语句,但总是会执行多个插入语句.
问题是:为什么会发生这种情况,如何防止多次插入?
每次请求更新
访问此文件的代码是来自另一个网页的一个单一链接.该页面列出了允许用户访问的当前文件,并提供了download.php脚本的链接,用于验证,更新和实际提供PDF.
查看页面有一个链接列表(打印在for循环中),排列如下:
<a href='download.php?f={$item['name']}&t={$type}' target='_blank'>{$item['name']}</a>
Run Code Online (Sandbox Code Playgroud)
当用户点击该链接时,除了上面的download.php的其他代码之外,下面的脚本也会运行.它成功地提供PDF文件.内容由download.php作为PHP标题/内联PDF发送:
见下面的代码
查看服务器日志显示对download.php文件的两个 GET请求:
2012-02-14 17:44:37 W3SVC1785071458 172.17.31.254 GET /download.php f=06304844-1A.pdf&t=av 4090 - 172.17.31.112 Mozilla/5.0+(Windows+NT+6.1)+AppleWebKit/535.7+(KHTML,+like+Gecko)+Chrome/16.0.912.77+Safari/535.7 200 0 0
2012-02-14 17:44:37 W3SVC1785071458 172.17.31.254 GET /download.php f=06304844-1A.pdf&t=av 4090 - 172.17.31.112 Mozilla/5.0+(Windows+NT+6.1)+AppleWebKit/535.7+(KHTML,+like+Gecko)+Chrome/16.0.912.77+Safari/535.7 200 0 0
Run Code Online (Sandbox Code Playgroud)
我已经在Firefox,Opera和IE(6-9b)中测试过,结果是一样的.
更新两个
将整个download.php文件放在这里:
<?php
session_start();
require("cgi-bin/auth.php");
// Don't timeout when downloading large files
@ignore_user_abort();
@set_time_limit(0);
//error_reporting(E_ALL);
//ini_set('display_errors',1);
function getfile() {
require('cgi-bin/connect_db_pdf.php');
//Verify information
if (!isset($_GET) || !isset($_GET['f']) || !isset($_GET['t'])) {
echo "Nothing to do!";
exit(0);
}
//Update variables
$vuname = strtolower(trim($_SESSION['uname']));
$file = trim($_GET['f']); //Filename we're looking for
$type = trim($_GET['t']);//Filetype
if (!preg_match('/^[a-zA-Z0-9_\-\.]{1,60}$/', $file) || !preg_match('/^av|ds|cr|dp$/', $type)) {
echo "Non conforming values";
exit(0);
}
try {
$sQuery = "SELECT * FROM pdf_info WHERE PDF_name=:file AND PDF_type=:type";
$statm = $conn->prepare($sQuery);
$statm->execute(array(':file'=>$file,':type'=>$type));
$result = $statm->fetch();
$count = $statm->rowCount();
$sQuery = null;
$statm = null;
if ($count == 1 ){ //File was found in the database so let them download it. Update the time as well
$sQuery = "INSERT INTO access (PDF_name,PDF_type, PDF_time, PDF_access) VALUES (:file, :type, GetDate(), :vuname)";
$statm = $conn->prepare($sQuery);
$statm->execute(array( ':vuname'=>$vuname, ':file'=>$file, ':type'=>$type));
$count = $statm->rowCount();
$sQuery = null;
$statm = null;
$sQuery = "UPDATE pdf_info SET last_view=GetDate(),viewed_uname=:vuname WHERE PDF_name=:file AND PDF_type=:type";
$statm = $conn->prepare($sQuery);
$statm->execute(array( ':vuname'=>$vuname, ':file'=>$file, ':type'=>$type));
$sQuery = null;
$statm = null;
//$result is from FIRST SELECT query outside this 'if' scope.
$file_loc = $result['floc'];
$file_name = $result['filename'];
$fileh = fopen($file_loc,'rb');//Send content to browser as inline PDF
header("Content-Type: application/pdf");
header("Pragma: no-cache");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Length: " . filesize($file_loc));
header("Accept-Ranges: bytes");
header("Content-Disposition: inline; filename={$file_name}");
while (!feof($fileh)) {
echo(@fgets($fileh, 8192));
}
fclose ($fileh);
exit(0);
} else { //We did not find a file in the database. Redirect the user to the view page.
header("Location: view.php");
}
} catch(PDOException $err) {//PDO SQL error.
//echo $err;
header('Location: error.php');
exit(0);
}
}
getfile();
?>
Run Code Online (Sandbox Code Playgroud)
您评论说下载脚本被调用两次,如果找不到正确的值,则应退出。情况可能并非如此,因为您滥用 PDOStatementrowCount()来测试找到的文件。此方法旨在返回 DELETE、UPDATE 或 INSERT 语句(但不是 SELECT)受影响的行数。
如果关联的 PDOStatement 执行的最后一个 SQL 语句是 SELECT 语句,则某些数据库可能会返回该语句返回的行数。但是,并不能保证所有数据库都具有这种行为,并且不应依赖于可移植应用程序。 http://php.net/manual/en/pdostatement.rowcount.php
他们继续:
对于大多数数据库,PDOStatement::rowCount() 不返回受 SELECT 语句影响的行数。相反,使用 PDO::query() 发出 SELECT COUNT(*) 语句,其谓词与预期的 SELECT 语句相同,然后使用 PDOStatement::fetchColumn() 检索将返回的行数。
如果您调用 download.php 脚本两次——第一次使用不正确的文件值(碰巧通过了正则表达式测试),另一次使用正确的值,则很可能您插入了两次,即使您只下载一次。
| 归档时间: |
|
| 查看次数: |
3682 次 |
| 最近记录: |