PHP如何同时管理请求

PHP如何同时管理请求,php,multithreading,security,Php,Multithreading,Security,今天我想知道PHP是如何同时处理请求的。由于PHP可以同时处理多个请求,我考虑了PHP脚本中可能存在的安全漏洞或bug,我只是想知道我是否有点太害怕 因此,在同时有100个请求的情况下,apache被配置为将它们转发到PHP。PHP将如何处理以下示例(我在一些实际应用程序中看到的所有示例都是这样的) 所有的例子都是相似的。(我不寻求更好的方法来解决这些案例) 示例1:创建缓存 <?php if (!file_exists('my_cache.txt')) { // do some

今天我想知道PHP是如何同时处理请求的。由于PHP可以同时处理多个请求,我考虑了PHP脚本中可能存在的安全漏洞或bug,我只是想知道我是否有点太害怕

因此,在同时有100个请求的情况下,apache被配置为将它们转发到PHP。PHP将如何处理以下示例(我在一些实际应用程序中看到的所有示例都是这样的)

所有的例子都是相似的。(我寻求更好的方法来解决这些案例)


示例1:创建缓存

<?php
if (!file_exists('my_cache.txt')) {
    // do something slow (taking a second or so)
    file_put_contents('my_cache.txt', $cache);
}
<?php
writeItemToDatabase($myItem);

if (countAllItemsInDatabase() > 100) {
    $items = readAllItemsFromDatabase();
    deleteAllItemsFromDatabase();
    // Process items
}

<代码> 你考虑的东西,代码样本是“强”>不是线程安全< /强>。这不是PHP的问题,而是并发性的一般问题

解决办法是:

  • 对于像示例1和示例2这样的文件操作,请使用文件锁

  • 对于像货币交易这样的操作,请使用数据库交易或最终使用表锁

据我所知,PHP不提供信号量机制。请记住,服务器的内部实现或配置(如apache prefork/worker)甚至可以在另一个进程中生成每个请求,因此您不必担心共享内存。担心资源——文件、数据库等


您提到的这种信号量不是一个好的解决方案。例如,在数据库级别,db引擎可以锁定/解锁单个表甚至行,这与“在那段代码上锁定整个服务器”相比是非常有效的

Memcache
cas()
add()
函数对于文件锁定的实现非常方便

Add()
仅当服务器上还不存在某个键时,才使用该键存储变量<代码>Cas()还执行“检查并设置”操作。 基于这些操作之一设计信号量是非常容易的

对不起我的英语

首先,我将描述一些一般特性:

  • 这是真的=)

    
    $semaphore->lock()

    //做些危险的事

    $semaphore->unlock();

  • 我试图描述基本概念。代码不适合发布

  • 信号量应该有一些类型:文件、数据库和 其他必要的
  • 每种类型的实现都不同
  • 首先让我们实现文件。我们将使用嵌入式功能(感谢)

    让我们添加列,它将模拟“锁定”记录:

    现在我们可以将锁定记录的_lockfild设置为1

    重要提示:必须通过以下单个查询获取锁:
    updatethreadingset\u lock=1,其中id=1和\u lock 1
    注意:
    和_lock1
    防止记录在已锁定时锁定,因此您可以确定记录是否被受影响的机制锁定

    <?php
    
    // connect
    mysql_connect('localhost','root','root');
    mysql_selectdb('testing');
    
    // get info
    $res = mysql_query('select * from threading where id = 1;');
    $row = mysql_fetch_assoc($res);
    
    print_r($row); // debug
    
    if($row['val']>=70){
      sleep(5); // emulate long-long operation =)
    
      // try to lock
      mysql_query('update threading set _lock = 1 where id = 1 AND _lock <> 1 ;'); // _lock <> 1 - very IMPORTANT!
      sleep(5); // emulate long-long operation =)
      $affected_rows = mysql_affected_rows();
      if($affected_rows!=1){  
        // lock failed -  locked by another instance
        echo '<br> LOCKED!';
      }else{
        // lock succeed
        mysql_query('update threading set val = val-70 where id = 1;');//something dangerous
    
        mysql_query('update threading set _lock = 0 where id = 1;'); // UNLOCK!
      }
    
    }
    
    // view result
    $res = mysql_query('select * from threading where id = 1;');
    $row2 = mysql_fetch_assoc($res);
    
    echo '<br>';
    print_r($row2);
    
    // disconnect
    mysql_close();
    
    
    
    需要“SafeCache.class.php”;
    //获取非阻塞独占锁
    $safe=新的SafeCache(“独占锁定id”);
    如果($safe->getExclusive()){
    打印“我们现在拥有独占锁
    ”; // ... 打印“释放锁
    ”; $safe->doneeExclusive(); }
    另外,请看其他安全缓存生成的示例。

    这是一个真正的问题。(i) PHP有一个内置的
    flock
    函数,用于(ii)PHP序列化会话(iii)数据库有自己的并发管理机制。
    <?php
    $semaphore->lock();
    // Do something dangerous
    $semaphore->unlock();
    
    <?php
    $fname = 'test.txt';
    
    $file = fopen($fname, 'a+');
    sleep(5); // long operation
    if(flock($file,LOCK_EX|LOCK_NB )){// we get file lock - $semaphore->lock();
    
      sleep(5); // long operation
      fputs($file, "\n".date('d-m-Y H:i:s')); //something dangerous
      echo 'writed';
      flock($file,LOCK_UN ); // release lock - $semaphore->unlock();
    }else{
      // file already locked
      echo 'LOCKED';
    }
    fclose($file);
    
     CREATE TABLE `threading` (
            `id` INT(10) NOT NULL AUTO_INCREMENT,
            `val` INT(10) NOT NULL,
            PRIMARY KEY (`id`)
        )COLLATE='utf8_general_ci'
        ENGINE=InnoDB
    
    ALTER TABLE `threading`
        ADD COLUMN `_lock` BIT NOT NULL AFTER `val`;
    
    <?php
    
    // connect
    mysql_connect('localhost','root','root');
    mysql_selectdb('testing');
    
    // get info
    $res = mysql_query('select * from threading where id = 1;');
    $row = mysql_fetch_assoc($res);
    
    print_r($row); // debug
    
    if($row['val']>=70){
      sleep(5); // emulate long-long operation =)
    
      // try to lock
      mysql_query('update threading set _lock = 1 where id = 1 AND _lock <> 1 ;'); // _lock <> 1 - very IMPORTANT!
      sleep(5); // emulate long-long operation =)
      $affected_rows = mysql_affected_rows();
      if($affected_rows!=1){  
        // lock failed -  locked by another instance
        echo '<br> LOCKED!';
      }else{
        // lock succeed
        mysql_query('update threading set val = val-70 where id = 1;');//something dangerous
    
        mysql_query('update threading set _lock = 0 where id = 1;'); // UNLOCK!
      }
    
    }
    
    // view result
    $res = mysql_query('select * from threading where id = 1;');
    $row2 = mysql_fetch_assoc($res);
    
    echo '<br>';
    print_r($row2);
    
    // disconnect
    mysql_close();
    
    require "SafeCache.class.php";
    
    
    // get non blocking exclusive lock
    $safe = new SafeCache("exclusive_lock_id");
    
    if ( $safe->getExclusive() ) {
      print "we have exclusive lock now<br>";
    
      // ...
    
      print "releasing the lock<br>";
      $safe->doneExclusive();
    }