处理来自多个XHR实例的多个PHP脚本调用

处理来自多个XHR实例的多个PHP脚本调用,php,jquery,apache,validation,jquery-file-upload,Php,Jquery,Apache,Validation,Jquery File Upload,以前的问题: 我决定重新表述关于这个问题的整个问题,并尽可能彻底地讨论。您可以阅读上面粘贴的问题 首先,感谢所有人的回应,但不幸的是,他们没有给我任何帮助。我的问题仍然需要帮助 因此,我正在使用一个名为blueimp jQuery File Upload的jQuery插件,它很好地处理了异步文件上传,并且包含了很多选项。这个插件对我来说已经足够好了,但是我需要执行服务器端检查,以避免被滥用的用户攻击我说的是限制一次上传的次数 默认情况下,插件的工作方式如下:用户选择多个文件(或将它们放到放置区域

以前的问题:

我决定重新表述关于这个问题的整个问题,并尽可能彻底地讨论。您可以阅读上面粘贴的问题

首先,感谢所有人的回应,但不幸的是,他们没有给我任何帮助。我的问题仍然需要帮助

因此,我正在使用一个名为blueimp jQuery File Upload的jQuery插件,它很好地处理了异步文件上传,并且包含了很多选项。这个插件对我来说已经足够好了,但是我需要执行服务器端检查,以避免被滥用的用户攻击我说的是限制一次上传的次数

默认情况下,插件的工作方式如下:用户选择多个文件(或将它们放到放置区域),每个文件创建一个单独的XHR实例,然后调用my
upload.php
脚本,该脚本负责存储文件。PHP upload脚本处理XHR请求时就好像它只是一个图像一样,因此基本上,每个需要上传的图像都分别调用
upload.PHP
脚本

我允许上传的是图片。但是,我想对免费用户的上传数量限制为10,对高级用户的上传数量限制为20。这是可以通过Javascript实现的,是的,但我并不真正信任Javascript进行这种验证,因此我正在寻求服务器端验证。但是,如何?这是不可能(至少对我来说)安全地完成的。我需要在我的上传脚本上确保用户没有超过10(或20)图像上传限制

我发现这个jQuery插件有一个名为
singleFileUploads
的选项:

默认情况下,选择的每个文件都使用单独的 请求XHR类型的上载。将此选项设置为false以上载文件 每个请求中有一个选择

注意:通过一个请求上载多个文件需要多部分 选项设置为true(默认值)

  • 类型:布尔型
  • 默认值:
    true
这正是我需要它做的——发送一个完全填充的
$\u文件
数组,其中包含所有提交的图像上传。但我仍然看到了这个问题。这仍由Javascript本身决定。用户能否修改脚本的这一部分并再次将
singleFileUploads
设置为
false
?我想他们可以!如果他们不能,那么这个问题现在就有答案了——但我不知道

下面有一个答案建议使用Apache的
mod_qos
来限制图像上传量,但我不知道如何区分两种不同的用户类型(免费和高级)

请注意,客人也可以上传图片,免费用户限制应适用于他们


那么关于这一切我都做了些什么?

我曾尝试创建一个包含会话的解决方案,该解决方案将跟踪用户正在上载的内容,并且对于每次新上载,会话的值将增加一个会话的值—正如下面所建议的那样,该解决方案不够安全,因为cookie可以被清除。除此之外,我无法应用下面答案中的任何内容


问题

好吧,问题从一开始就很清楚:如何将来宾/免费用户的并发图像上传数量限制为10,而将高级用户的并发图像上传数量限制为20

编辑:我想值得一提的是,每个上传的图像在数据库中都有自己的行,以及上传时间和名称。也许这会有帮助


谢谢。

也许我不理解您的目标,但您不能将会话变量分配给另一个变量,在每次循环之前重置会话变量,并使用$\u会话计数和“上一次”计数之和进行比较吗?您是在试图阻止每个用户进行10次以上的聚合上载,还是只是一次阻止10次连续上载

// Before starting your loop, assign your session variable to another.
$previously_uploaded = $_SESSION['images_session_uploaded'];

// Reset $_SESSION['images_session_uploaded'] at onset
$_SESSION['images_session_uploaded'] = 0;

// ... Do yo' thang.

// Make a comparison at the end of each loop for whatever you're checking against.
if (($_SESSION['images_session_uploaded'] + $previously_uploaded) >= MAX_FREEUSER_UPLOADS_SESSION)
{
  // User has uploaded more than ten images total, but not necessarily more than ten in this round of uploads. 
}

首先,使用会话将再次保护您—普通用户,但如果有人知道他们在做什么,他们可以简单地擦除他们的cookie,并且只要您的服务器知道他们是新用户

也许您可以通过让每个用户登录或跟踪其IP地址或浏览器签名来唯一地标识每个用户?这取决于你的申请

这里的关键问题似乎是您对未定义短语上载会话的使用什么是上传会话?这里我假设是30分钟。所以我们限制他们每半小时上传10次

使用会话的解决方案:

// Start sessions before you can use them
session_start();

// "Config"
$_MAX_UPLOAD_COUNT = MAX_FREEUSER_UPLOADS_SESSION; // limit to this every session timeout
$_SESSION_TIMEOUT = 60 * 30; // 30 mins

// Current upload count (default to zero)
$total_uploads_so_far = isset($_SESSION['total_uploads']) ? $_SESSION['total_uploads'] : 0;

// --- Count their uploads this session ---
// #1 Either by looping through the uploads
$uploaded_image += 1;

// #2 Or before handling the upload by counting the amount of uploaded files
$uploaded_images = count($_FILES['images']);

// They've exhausted their uploads immediately
if($uploaded_images > $_MAX_UPLOAD_COUNT) {
  // Throw an error saying you can't select more than 10 images at once
  // Don't upload any images or modify the sessions.
}

// --- Before finishing the upload check that they haven't uploaded more than 10 items ---

// Have they uploaded before, was it in the past 30 mins?
$uploaded_recently = isset($_SESSION['last_upload']) && ($_SESSION['last_upload'] + $_SESSION_TIMEOUT) > time();

if($uploaded_recently && ($total_uploads_so_far + $uploaded_images) > $_MAX_UPLOAD_COUNT) {
  // Fail to upload, throw an error etc

} else {
  // Process your upload

  // Update the info in the users session
  $_SESSION['last_upload') = time();
  $_SESSION['total_uploads') = $uploaded_images + $total_uploads_so_far;

}
使用IP/签名的解决方案:

但是,请执行与上述相同的操作,而不是将上次上载时间和上载总数存储在用户会话中,将其存储在数据库或文本文件中

设置为它们的ip地址(从
$\u服务器['REMOTE\u ADDR']
),或其他东西来唯一标识它们。这将允许您按用户(或使用IP地址的伪用户)查找它

例如(使用文件):


您可以在生成主机页面(发出xhr调用的页面)时创建一个激活码(即随机数),并将其作为页面内的变量传递给脚本。然后,您可以修改js脚本,将激活码作为get参数传递给处理文件上载的脚本。通过这种方式,您可以使用激活代码作为db表的键来存储和跟踪使用该代码执行的上载次数

请注意,几乎所有内容都可以通过HTTP/TCP(不仅仅是会话)进行操作,因此
$uploads = unserialize(file_get_contents('uploads.txt');
if(!$uploads) $uploads = array();

// To update the user (using variables from the above example)
$uploads[$_SERVER['REMOTE_ADDR']] = array('total_uploads' => $uploaded_images + $total_uploads_so_far, 'last_upload' => time());

file_put_contents('uploads.txt', serialize($uploads));
--------------------------------------------------------------------------------------
|  id (unsigned int, auto increment) |  ip (varchar) |  timestamp (current timestamp)|
--------------------------------------------------------------------------------------
SELECT * FROM `uploads` WHERE `ip` = '{$userIP}' AND `timestamp` > DATE_SUB(NOW(), INTERVAL 30 MINUTE)
INSERT INTO `uploads` (`ip`) VALUES ('{$userIP}')
$('#fileupload').change(function(){
    var files = $(this)[0].files;
    if(files.length > 10){
       //do what you want , like alert warning
       // and disable submit button
    }else{
      //do what you want , like enable submit button
    }
});
"pic1.png", "pic2.jpg", "pic3.jpg"