共享主机具有固定的最大执行时间; 我的管理员PHP脚本超过了

问题描述:

My client is an entrepeneur and has no html knowledge. He has a website that was created with PHP on a linux shared hosting environment (basic package). On his site he wants to show his previous jobs with photos. But he complains he finds it to hard to login as admin and uploads those photos himself.

-now he asks me to write something easy for him so that the photos in his Dropbox account are uploaded on his site. I said OK :)

I created an admin page ( Here my client can choose which dropbox album he wants to download to his site. ) -I have used the dropbox api for php to locate his photo-albums. -I made a form where I list those albums with submit buttons that will do a POST-request(parameter = path to file on dropbox account).

Here is the code for that request:

if (isset($_POST['AlbumAdd'])) { 
    $name = $_POST['AlbumAdd'];
    //echo "submitted: $name <br>";
    $entry = getClient()->getMetadataWithChildren($name); //dropbox-sdk 
    if ($entry['is_dir']) {

        //for now create file on localhost -> replace with ftp to upload on shared hosting site
        if (!file_exists(__DIR__ . "/../examples/folder" . $name)) { //if !excists create folder on localhost
            mkdir(__DIR__ . "/../examples/folder" . $name, 0777, true);
            //echo "created " . $name  . "on localhost";
        } 
        foreach ($entry['contents'] as $child) {
            $cp = $child['path'];
            $size = $child['size'];
            $cn = basename($cp);
            echo "basename (cn)= " . $cn . " [$size] <br>";
            if (!$child['is_dir']) //files only
            {
                //download from dropbox to localhost 
                getClient()->getFile($cp, fopen(__DIR__ . '/../examples/folder' . $cp, 'w+b'));
            }
        }
    }
}

This works fine for small files, but throws this exception when the album is too large:

Fatal error: Maximum execution time of 30 seconds exceeded in C:\wamp\www\dropbox-sdk-php-1.1.4\dropbox-sdk\Dropbox\CurlStreamRelay.php on line 26
TEST OUTPUT:
basename (cn)= 01.mp3 [8.1 MB]
basename (cn)= 02.mp3 [7.3 MB]
basename (cn)= 03.mp3 [6 MB] 

What is the best thing to do now?? -Helpdesk of the hosting site says they can't change the setting of the maximum execution time. So there is no point in changing my php.ini file.

-upload each photo individually?

-switching to dedicated server means I have full control? I don't know if my client likes to pay 125€ extra/month

I think you should refactor your logic, using also some client-side logic...
You should first download the structure of remote folder (with getMetadataWithChildren()), and store it on disk with some kind of indexing (i.e.: assigning each file/dir to be downloaded a unique id). This task should hopefully terminate within the maximum execution time limit set by your provider...
Then you should build a second script to download the real data, reading the previously downloaded index, one file/dir at a time.
The script should catch the "MAXIMUM EXECUTION TIME" error to signal it has not yet finished it's job... Something like this:

File: "download_data_from_dropbox.php"

<?php
  register_shutdown_function('shutdown');

  global $id;
  DOWNLOAD_DATA($id);
  echo json_encode(array("done" => 1);
  exit 0;

  function shutdown() {
    $e = error_get_last();
    if ($e == "max_execution_time") {
      echo json_encode(array("lastId" => $id);
      exit 0;
    }
  }
?>

Then, you should call the php script to download data from dropbox repeatedly, until it finishes:

File "index.html":

<html>
  <head>
  </head>
  <body>
  ...
  <div id="status"></div>
  ...
  <script>
  $(document).ready(function() {
      var done = false, id = '',
      while (!done) {
          var url = "download_data_from_dropbox.php?id=" + id;
          $.ajax({
              url: url,
              dataType: 'json',
          }).done(function(response) {
              if (response.done === 1) {
                  // php script is done
                  done = true;
              }
              $("#status").html("Downloading data, last file ID is " + response.lastId   + " ...");
          }).fail(function(jqXHR, textStatus) {
              $("#mybox").html("Error while downloading data: " textStatus);
              done = true;
          });
      }
  });
  </script>
  </body>
</html>

Note: this code is a simple attempt to show a possible solution, it contains some pseudocode, it's not at all finished, and, of course, untested... :-) You should also probably use setInterval(), instead of the while (!done) loop, in javascript code...

A route you can explore is using a commandline script. PHP scripts on the commandline are usually not limited on execution time. So you would use your adminpage to let your client select the Dropbox album. You store those choices somewhere (in the database for example). Your cronjob can do the actual downloading. When its ready, it should remove the entry from the database again or mark it as downloaded. You can then also use this database to show the download status in the admin page.

EDIT: Now that I think about it a bit more, ask him why he finds the upload difficult? Perhaps there is a much more simple sollution to his problem.