PHP、PDO 和 SQLSRV 对一个 INSERT 语句执行多次

2024-06-02

我已经在 MySQL 和 Apache 服务器上使用 PDO 和 PHP 一段时间了。我最近的任务是将企业的旧 Web 应用程序转换为新设置。旧设置是标准 Linux Web 堆栈 (Apache/PHP/MySQL/Filezilla),新设置将是带有 IIS/PHP(快速 cgi 安装)/ SQL Server 2003/无 FTP 的 Windows Server 2003。

除了转换 MySQL 语句以更新包含文件访问信息的表之外,我几乎一切都在工作。使用带有 SQLSRV 驱动程序的 PDO 并在“文件下载”PHP 脚本内执行插入语句,将多条记录插入到 SQL 表中。

download.php 确实向 SQL 服务器发出多个查询。一次检查一个表中的文件是否存在和变量,然后使用访问信息更新另一个表。

请参阅下面的 download.php 代码

调试显示 $count 的 print/echo 为 1。然而,检查 SQL Server 记录,总是显示插入的不止一个。有时它只是额外的一行,总共两行,但其他时候则多达四个额外的语句被插入。在每种情况下,$count 都保持显示为 1。

这个特定的 PHP 脚本在调用此插入语句之前根据 SQL 数据库验证信息。首先,验证文件访问的身份验证(成功),验证文件存在(成功),然后使用下载信息更新访问表(错误),最后将 PDF 提供给用户(成功)。

当我向查询分析器手动发出 INSERT 语句时,它成功并按预期工作;它每次插入一行。该错误似乎与execute() 的SQLSRV 或PDO 实现有关。

我在 stackoverflow、serverfault 和万能的 Google 上搜索了有关此的信息。用户需要在一个语句/执行中执行多个查询/插入时返回的唯一结果类型。我的问题在哪里是相反的;我希望只执行一条插入语句,但是总是会执行多个插入语句。

问题是:为什么会发生这种情况以及如何防止发生多次插入?

根据请求更新

访问此文件的代码是来自另一个网页的单个链接。该页面列出了允许用户访问的当前文件,并提供了 download.php 脚本的链接,用于验证、更新和实际提供 PDF。

查看页面有一个链接列表(以 for 循环打印),排列如下:

<a href='download.php?f={$item['name']}&t={$type}' target='_blank'>{$item['name']}</a>

当用户单击该链接时,除了上面 download.php 的其他代码之外,还会运行下面的脚本。它成功地提供了 PDF 文件。内容由 download.php 作为 PHP 标头/内联 PDF 发送:

请参阅下面的代码

查看服务器日志显示two对 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

我在 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();

?>

您评论说下载脚本被调用两次,如果找不到正确的值,则应退出。情况可能并非如此,因为您滥用了 PDOStatement 的rowCount()测试找到的文件。此方法旨在返回 DELETE、UPDATE 或 INSERT 语句受影响的行数,但是不选择.

如果关联的 PDOStatement 执行的最后一个 SQL 语句是 SELECT 语句,则某些数据库可能会返回该语句返回的行数。但是,并不能保证所有数据库都会出现这种行为并且不应依赖于便携式应用程序。http://php.net/manual/en/pdostatement.rowcount.php http://php.net/manual/en/pdostatement.rowcount.php

他们继续:

对于大多数数据库,PDOStatement::rowCount() 不返回受 SELECT 语句影响的行数。相反,使用 PDO::query() 发出 SELECT COUNT(*) 语句,其谓词与预期的 SELECT 语句相同,然后使用 PDOStatement::fetchColumn() 检索将返回的行数。

如果您调用 download.php 脚本两次——第一次使用不正确的文件值(碰巧通过了正则表达式测试),另一次使用正确的值,则很可能您插入了两次,即使您只下载一次。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PHP、PDO 和 SQLSRV 对一个 INSERT 语句执行多次 的相关文章

  • PHP - 查找和比较日期

    你好 我有 foreach 我可以在其中获取数据库中的事件数据 我使用数据库中的日期名称 例如 event date 我需要在一个 div 中比较具有相同日期和输出的操作 例如我有这个事件 活动一 9 月 13 日 活动二 9 月 1 日
  • 选择仅属于特定部门的用户

    我有下表 其中包含两个字段 即 a 和 b 如下所示 create table employe empID varchar 10 department varchar 10 插入一些记录 insert into employe values
  • 使用 PHP 运行 mysqldump 生成的空文件

    我不断收到运行时生成的空文件 command mysqldump opt h localhost u username p password dbname gt backup 2009 04 15 09 57 13 sql command
  • PHP 彗星。怎样才能做得更好呢?

    我有一个简单的彗星聊天 JavaScript 通过长轮询发送 ajax 请求 当服务器在数据库中发现新消息时 它会应答并给出 JSON 接下来 JavaScript 再次发送请求 JavaScript function cometConne
  • 存储聊天消息和文件的最佳方式

    我想知道您对将聊天消息存储在数据库中有何看法 我需要能够将其他内容绑定到它们 例如文件或联系人 并且使用数据库是我目前看到的最佳方法 文件也有同样的问题 因为它们可以绑定到聊天消息 我也必须将它们存储在数据库中 对于数千条消息和文件 我想知
  • ON DELETE CASCADE 与 Symfony 和 Doctrine 的多对多关系

    我想要与 Symfony 和 Doctrine 建立简单的多对多关系 这实际上是一个单向的一对多关联 可以通过连接表映射为文档表明 http doctrine orm readthedocs org en latest reference
  • 如何在php中显示curl的二进制数据

    我正在编写简单的 php 代理 但在显示 png 文件时遇到问题 输出是 它应该是 图像在 Notepad 中打开 我的 php 卷曲代码如下所示 ua Mozilla 5 0 Windows U Windows NT 5 1 en US
  • t-sql计算文本列中的唯一单词

    我有一列包含图像标题 我想做的是找到该栏中出现的最流行的单词 有没有办法用 t sql 来做到这一点 我认为你可以做这样的事情 我认为这不是最优化的 但您可以对其进行改进 创建一个表变量 t来存储单词 创建一个游标 循环浏览字幕表中的每一行
  • PHP SoapClient 无法处理消息,因为内容类型为“text/xml;”

    我无法连接到网络服务并发送 接收数据 Error HTTP 无法处理消息 因为内容类型为 text xml charset utf 8 不是预期的类型 application soap xml 字符集 utf 8 Code paramete
  • 从辅助类将输出写入控制台

    我有一个运行帮助程序类的控制台命令 我想用以下命令编写输出 this gt info 从助手类到控制台 我的代码如下所示 App Http Console Commands SomeCommand php function handle H
  • 功能测试 - 模拟服务不会保留在服务容器中

    我希望有人能够对我面临的这个问题有所启发 问题 我在功能单元测试中模拟了doctrine orm default entity manager 服务 我将其注入客户端服务容器中 这样我就不必在功能测试过程中访问我的数据库 对于仅涉及 GET
  • Laravel 队列不作为后台运行

    你好 我创建了一个 Laravel 队列作业来发送邮件 public function handle foreach this gt emails as value to value gt email subject this gt dat
  • 准备好的语句,转义变量

    我是否需要采取任何措施来保护这三个变量 例如使用转义字符串或绑定它们 我不确定我是否正确地执行了此操作 人们只是建议使用准备好的语句 所以我正在尝试弄清楚它们 order POST order heading POST heading co
  • Laravel mail 假装不打印任何内容

    I set pretend gt true in the mail php 创建了这个new php view div E mail user gt email br User user gt username br Pass user g
  • PHP 警告:除以零

    我正在学习 php 并构建了一个实验性的基于表单的计算器 也使用 html 和 POST 方法 该计算器将值返回到表 当我输入值并单击提交时 计算器可以正常工作 但当我第一次运行代码时 我在最后一行不断收到两个 除以零 错误 在这里或通过谷
  • Laravel - 在一个方法中返回多个值

    这是我目前陷入困境的地方 我正在执行多种方法 对同一个表进行不同的查询 public function totalOfA return a Stocks where user id this gt employee gt id gt whe
  • Symfony 3 - 你请求了一个不存在的服务,这让我发疯

    所以 这不是我第一次创建服务 但我只是无法解决错误 您请求了一个不存在的服务 global settings 我为确保服务正确设置而采取的步骤 My AppBundleExtension php namespace AppBundle De
  • 如何在 Mac v 10.7.2 上安装/使用 php

    我是对使用 PHP 感兴趣的普通大学生 谁能告诉我 101 如何使用简单明了的语言在 mac 版本 10 7 2 上安装 启用它 我将感谢任何和所有的帮助 Cheers 无需安装 PHP 或 Apache 它们已随 Mac 10 7 一起提
  • 如何在 .css 文件中使用 php 变量

    我有一个名为test css我想用它 var var is at test php test css附于test php 我的结构是这样的 test php 这是 test css test css
  • SQL Server 2008:TOP 10 和不同的一起

    正如标题所示 我正在使用 SQL Server 2008 如果这个问题非常基本 我深表歉意 我才使用 SQL 几天 现在我有以下查询 SELECT TOP 10 p id pl nm pl val pl txt val from dm la

随机推荐