将PHP脚本上载到实时环境

时间:2011-02-02 10:24:38

标签: php file-upload

我有一个PHP应用程序需要半频繁的代码更新。我现在所做的是,每当我必须上传新脚本时,我都会关闭应用程序以进行维护,从而有效地关闭除我之外的所有用户的应用程序。

如果我不这样做,我总会在日志中看到很多“意外的$ end”错误消息,因为PHP试图解释半上传的脚本。我当然希望避免这种情况。

我的问题是:是否有一种安全的方法可以在不将应用程序停止维护的情况下执行此操作?在具有大量并发用户的环境中,上传到临时目录然后在服务器上本地移动文件的速度是否足以避免这些错误?是否可以通过某种方式实现方便的工作流程?

谢谢!

5 个答案:

答案 0 :(得分:6)

我认为一个好的做法是为新版本创建一个checkout(你应该使用一个版本控制系统),然后在其中的所有内容之后,只需符号链接到新目录,如下所示:

更新前:

/live => Symlink to /release-2011-02-01

更新后:

/live => Symlink to /release-2011-02-02

然后,您可以在一段时间后清理旧版本。

答案 1 :(得分:2)

与FTP一起使用的一种非常简单的方法是有两个目录:

/site_live
/site_shadow

当新版本出现时,请将其上传到site_shadow。完成后,将site_live重命名为site_shadow,反之亦然。

这很好,没有中断;如果您在应用程序中存储任何用户数据,则还必须移动这些目录。

扩展版本适用于版本控制软件的版本号,将每个版本存储在特定目录中。

/site_live 
/site_101
/site_102
/site_106

如果在您的环境中可用,@ schneck显示的符号链接方法是最好的,而不是重命名目录!

答案 2 :(得分:0)

如果您经常需要更新脚本,那么您的应用中存在设计缺陷。如果脚本中存在错误,您只能更改脚本。如果您想要对您的应用进行竞争性改造,则需要进行重大更新。

如果更改是每天更改(比如EShop的商品价格),那么您应该维护某种类型的数据库表,并在那里更新这些值,从而无需更新脚本。

截至目前,您可以考虑重新设计您的应用程序,并牢记这一点。

答案 3 :(得分:0)

我认为最安全的方法是创建网站的卷影副本以进行环境测试。

您将拥有一个单独的子域,如下所示:

  

http://dev.mysite.com

需要http身份验证和ip验证以防止任何人访问此项,您将构建迁移脚本来处理将文件从dev移动到主实时目录的过程。

我这样做的方式是这样的:

  • 在现场启动维护模式
  • 触发迁移脚本
  • 查看新代码生效的网站
  • 删除维护模式

迁移脚本并不难,它基本上是一个执行以下操作的脚本:

  • 将您的实时网站上传到秘密位置
  • 递归地多次为实时网站投放目录结构
    • 第一次迭代:如果某个文件存在于开发但不存在,则将文件复制到那里
    • 第二次迭代:如果文件存在于dev和live上,则检查md5哈希值和上次修改的时间戳以查看该文件是否应该被覆盖。
    • 第三次迭代:创建一个将用于下次更新的md5 sum文件。
  • 然后你会相应地修改你的修订版。

构建这样的流程很简单但需要一些工作,创建一个管理面板来帮助实现这一点将真正让您的生活更轻松。


在发布我的回答后,我会建议您使用@schneck's回答,因为它更容易管理。

答案 4 :(得分:0)

有很多方法可以减少这个问题 - 大多数其他答案归结为制作网站的本地镜像,在那里应用更改然后切换镜像代替实时代码。实际上,这些只是减少了新文件的写入时间 - 它们实际上并没有消除这个问题。例如假设您有20个要更新的文件,列表顶部的文件需要列表底部的文件?

我猜这是一个托管服务 - 一个VPS,或一个专用/共享主机 - 这消除了在文件更新操作发生时将可访问IP地址传输到另一个群集节点的可能性。假设您没有对公共存储基板的依赖性(例如粘性会话处理,数据库结构),这种方法可以完全消除停机时间。

可以使用自动前置脚本在一定程度上暂停活动,同时操作完成,例如......

<?php

if (file_exists('/somewhere/uploading_new_content')) {
     // following should be implemented as a seperate file
     // which is only included when necessary....
     $targettime=30; // assuming the update takes 30 seconds....
     $sleeptime=$targettime - time() + filemtime('/somewhere/uploading_new_content');
     sleep($sleeptime);
     print "Sorry - Your request was paused due to essential maintenance<br />\n";
     $dest=$_SERVER['REQUEST_URI'];
     if (count($_POST)) {
         print "<form method='POST' action='$dest'>";
         foreach ($_POST as $key=>$val) {
             $val=htmlentities($val);
             $key=htmlentities($key);
             print "<input type='hidden' name='$key' value='$val'>\n";
         }
         print "<input type='submit' name='uploading_pause' value='continue'>\n";
         print "</form>\n";
     } else {
         print "<a href='$dest'>continue</a>";
     }
     exit;
}