<?php

namespace ArpPageTimer;

chdir('.');
require_once 'TimerManager.php';
$timer = new TimerManager();
$timer->start('test1');
sleep(4);
$timer->start('test2');
sleep(5);
$timer->start('test3');
sleep(1);
// Fluid interface when calling stop
$timer->stop('test3')->stop('test2')->stop('test1');
$format = '<p>Script execution for timer \'%s\' took \'%f\' seconds.</p>';
$tests = ['test1', 'test2', 'test3'];
foreach ($tests as $test) {
    printf($format, $test, $timer->getExecutionTime($test));
}
printf('<p>The total execution time for all \'%d\' tests was \'%f\' seconds.</p>', count($tests), $timer->getExecutionTime());
Example #2
0
function start($PARAMS)
{
    if (isset($PARAMS["secure"]) and !isset($_SERVER["HTTPS"])) {
        //logg("server name: ".$_SERVER["SERVER_NAME"]."\nrequest uri: ".$_SERVER["REQUEST_URI"]);
        //header("Location: https://".$_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"]);               // redirect to https
        header("Location: https://t.oslo.opera.com" . $_SERVER["REQUEST_URI"]);
        // redirect to https [T version]
        exit(0);
    }
    // defined constants
    define("DEFAULT_CHUNK_SIZE", 1024 * 1024);
    // DEFAULT_CHUNK_SIZE is 1 MB
    // define startup defaults
    $SUPPORT_RANGE_HEADER = true;
    // whether or not we (the server) support the range header  [default: true                      ]
    $FORCE_BROWSER_NOCACHE = false;
    // whether or not to send no-cache (and friends) headers    [default: false                     ]
    $FORCE_CHUNKED = false;
    // whether or not to send chunked data                      [default: false                     ]
    $filename = "11s.webm";
    // media file to serve                                      [default: 11s.webm                  ]
    //$filename               = "../../../../../../resources/media/webm/11s.webm";                    // media file to serve                                      [default: 11s.webm                  ]
    $rate = 0.0;
    // data burst rate                                          [default: no limit                  ]
    $chunksize = 1.0 * DEFAULT_CHUNK_SIZE;
    // max chunk size                                           [default: 1 MB                      ]
    $sleep = 0.0;
    // delay between chunks                                     [default: 0s                        ]
    $timeout = 3;
    // timeout for the connection                               [default: 3s                        ]
    $limitsize = false;
    // limit the number of bytes to send                        [default: disabled                  ]
    $ifrange = false;
    // control if-range behavior                                [default: disabled                  ]
    // the below parameter has meaning only if USE_CONTENTRANGE is true and SUPPORT_HEADER_RANGE is true
    $offset = 0;
    // bytes added to range end to invoke invalid response      [default: 0                         ]
    // list of headers to send
    $HEADERS = array();
    $USE_ETAG = false;
    // whether or not to send the etag header                   [default: false                     ]
    $HTTP_STATUS = false;
    // http status header to send (use 206 or 200 if not set)   [default: false                     ]
    $date = false;
    // date header to send                                      [default: don't send any            ]
    $contenttype = "application/octet-stream";
    // content type header to send (autodetected if not set)    [default: application/octet-stream  ]
    // the below headers have meaning only if SUPPORT_RANGE_HEADER is true (norange parameter is not set)
    $USE_CONTENTRANGE = true;
    // whether or not to send the content range header          [default: true                      ]
    $acceptranges = "bytes";
    // accept ranges header to send                             [default: bytes                     ]
    // the below headers have meaning only if FORCE_BROWSER_CACHE is false (nocache parameter is not set)
    $expires = false;
    // expires header to send                                   [default: don't send any            ]
    $lastmodified = false;
    // last modified header to send                             [default: don't send any            ]
    $cachecontrol = false;
    // cache control header to send                             [default: don't send any            ]
    $id = $_SERVER["REMOTE_ADDR"];
    // set the script execution ID (for use with force timeout) [default: client IP                 ]
    // override default values with provided parameters (+sanity checks)
    if (isset($PARAMS["norange"])) {
        $SUPPORT_RANGE_HEADER = false;
    }
    // disable server support for the range header
    if (isset($PARAMS["nocache"])) {
        $FORCE_BROWSER_NOCACHE = true;
    }
    // enable sending of no-cache (and friends) headers
    if (isset($PARAMS["chunked"])) {
        $FORCE_CHUNKED = true;
    }
    // enable Transfer-Encoding: chunked (disable Content-Length)
    if (isset($PARAMS["contentrange"])) {
        $USE_CONTENTRANGE = false;
    }
    // disable sending the Content-Range header
    if (isset($PARAMS["acceptranges"])) {
        $acceptranges = $PARAMS["acceptranges"];
    }
    // change the default Accept-Ranges header
    if (isset($PARAMS["etag"])) {
        $USE_ETAG = true;
    }
    // enable sending the ETag header
    if (isset($PARAMS["status"])) {
        $HTTP_STATUS = $PARAMS["status"];
    }
    // change the default HTTP/1.1 status header
    if (isset($PARAMS["date"])) {
        $date = $PARAMS["date"];
    }
    // enable sending the Date header and set it's value or 'yes' for current date -1s
    if (isset($PARAMS["expires"])) {
        $expires = $PARAMS["expires"];
    }
    // enable sending the Expires header and set to how many seconds from current date it should be set
    if (isset($PARAMS["lastmodified"])) {
        $lastmodified = $PARAMS["lastmodified"];
    }
    // enable sending the Last-Modified header and set it's value or 'yes' for the actual file modification date
    if (isset($PARAMS["cachecontrol"])) {
        $cachecontrol = $PARAMS["cachecontrol"];
    }
    // enable sending the Cache-Control header and set it's value
    if (isset($PARAMS["file"])) {
        $filename = $PARAMS["file"];
    }
    // set custom file name
    if (isset($PARAMS["size"])) {
        $limitsize = $PARAMS["size"];
    }
    // limit the number of bytes to send
    if (isset($PARAMS["if-range"])) {
        $ifrange = $PARAMS["if-range"];
    }
    // control the if-range behavior
    if (isset($PARAMS["timeout"]) and is_numeric($PARAMS["timeout"])) {
        $timeout = floatval($PARAMS["timeout"]);
    }
    // set custom timeout
    if (isset($PARAMS["rate"]) and is_numeric($PARAMS["rate"])) {
        $rate = floatval($PARAMS["rate"]) * DEFAULT_CHUNK_SIZE;
    }
    // set custom size
    if (isset($PARAMS["contenttype"])) {
        $contenttype = $PARAMS["contenttype"];
    } else {
        $contenttype = getcontenttype($filename, $contenttype);
    }
    // or try to determine what it is based on filename
    if (isset($PARAMS["contentrangeoffset"])) {
        $offset = intval($PARAMS["offset"]);
    }
    // add some bytes to the range end to invoke an invalid range response
    if (isset($PARAMS["forcetimeout"])) {
        die(setForceTimeoutLock($PARAMS["forcetimeout"]));
    }
    // enable instant "timeout" simulation
    if (isset($PARAMS["id"])) {
        $id = $PARAMS["id"];
    }
    // set script execution ID (for use with force timeout)
    if (!($video = fopen($filename, "r"))) {
        exit(0);
    }
    // check if file exists and can be opened for reading
    $filesize = $limitsize ? intval($limitsize) : filesize($filename);
    // get filesize (used frequently later on)
    if ($ifrange and $_SERVER["HTTP_IF_RANGE"]) {
        switch ($ifrange) {
            case "200":
                // case 200
                $SUPPORT_RANGE_HEADER = false;
                // disable range support (same as norange=1)
                break;
            case "400":
                // case 400
                header("HTTP/1.1 400 Bad Request");
                // send bad request status
                die("Sorry, requested range (" . $_SERVER["HTTP_RANGE"] . ") is not satisfiable!");
                // and exit the script
                break;
        }
    }
    if (isset($_SERVER["HTTP_RANGE"]) and $SUPPORT_RANGE_HEADER) {
        $RANGE = explode("=", $_SERVER["HTTP_RANGE"]);
        // split the header into type and range
        // sanity check
        if (count($RANGE, 2)) {
            $RANGE = explode("-", $RANGE[1]);
            // split the range into start and end
            // sanity checks
            if (count($RANGE) == 1) {
                array_push($RANGE, $filesize - 1);
            }
            // make sure the range end value is set
            if (is_numeric($RANGE[0])) {
                $RANGE[0] = intval($RANGE[0]);
            } else {
                $RANGE[0] = 0;
            }
            // if not then set to default: 0
            if (is_numeric($RANGE[1])) {
                $RANGE[1] = intval($RANGE[1]);
            } else {
                $RANGE[1] = $filesize - 1;
            }
            // if not then set to default: max (filesize - 1 as per RFC)
        } else {
            $RANGE = array(0, $filesize - 1);
        }
        // set default start and end values
        array_unshift($RANGE, $_SERVER["HTTP_RANGE"]);
        // just because :)
        // set the required response headers for a range request
        array_push($HEADERS, "HTTP/1.1 " . ($HTTP_STATUS ? $HTTP_STATU : "206 Partial Content"));
        array_push($HEADERS, "Accept-Ranges: " . $acceptranges);
        if ($USE_CONTENTRANGE) {
            array_push($HEADERS, "Content-Range: bytes " . $RANGE[1] . "-" . ($RANGE[2] + $offset) . "/" . $filesize);
        }
    } else {
        // set headers for a standard http server response
        array_push($HEADERS, "HTTP/1.1 " . ($HTTP_STATUS ? $HTTP_STATUS : "200 OK"));
        $RANGE = array("not set", 0, $filesize - 1);
    }
    // set additional required and optional headers
    if ($FORCE_CHUNKED) {
        array_push($HEADERS, "Transfer-Encoding: chunked");
    } else {
        array_push($HEADERS, "Content-Length: " . ($RANGE[2] - $RANGE[1] + 1));
    }
    // ELSE set the Content-Length header
    if ($USE_ETAG) {
        array_push($HEADERS, "ETag: " . md5(floor(mktime() / 30) * 30));
    }
    // IF etag was requested set the ETag header
    if ($date) {
        $date = $date == "yes" ? httpdate(time() - 1) : $date;
        // use the date provided or create a data 1s in the past
        array_push($HEADERS, "Date: " . $date . " GMT");
        // and set the Date header
    }
    if ($FORCE_BROWSER_NOCACHE) {
        array_push($HEADERS, "Last-Modified: " . httpdate(filemtime($filename)) . " GMT");
        array_push($HEADERS, "Cache-Control: max-age=0, no-cache, no-store, must-revalidate");
        array_push($HEADERS, "Pragma: no-cache");
        array_push($HEADERS, "Expires: Wed, 11 Jan 1984 05:00:00 GMT");
    } else {
        if ($cachecontrol) {
            array_push($HEADERS, "Cache-Control: " . $cachecontrol);
        }
        // IF cache control was requested set Cache-Control header
        if ($lastmodified) {
            $lastmodified = $lastmodified == "yes" ? httpdate(filemtime($filename)) : $lastmodified;
            // use the lastmodified provided or get the actual file modification date
            array_push($HEADERS, "Last-Modified: " . $lastmodified);
            // set Last-Modified header
        }
        if ($expires) {
            array_push($HEADERS, "Expires: " . gmdate("D, j M Y H:i:s T", time() + $expires));
            // set the Expires header
            array_push($HEADERS, "Cache-Control: max-age=" . $expires . ", must-revalidate");
            // and the Cache-Control header with max-age and must-revalidate
        }
    }
    array_push($HEADERS, "Content-Type: " . $contenttype);
    // add the content type header
    foreach ($HEADERS as $header) {
        header($header);
    }
    // send the headers
    // move the file pointer to the range start (with sanity check)
    if (fseek($video, $RANGE[1]) == -1) {
        $position = 0;
    } else {
        $position = $RANGE[1];
    }
    // set the position to where we seeked in the file
    // initialize timers and counters
    $chunks = 0;
    // initialize the chunk counter
    $bytes = 0;
    if ($rate != 0) {
        $usleep = 10;
        // initialize time interval for sending data chunks to 10 microseconds when data rate is limited
        $chunksize = round($rate * ($usleep / 1000000));
        // initialize chunk size based on data rate limit
    }
    logg("\n");
    logg("-------------------");
    logg("Range:             " . $RANGE[0]);
    logg("script id:         " . $id);
    logg("rate:              " . ($rate != 0 ? $rate . " B/s" : "no limit") . ", sleep: " . $sleep / 1000000 . ", usleep: " . $usleep . ", chunksize: " . $chunksize);
    logg("timeout:           " . $timeout . "s");
    logg("clear locks:       " . clearForceTimeoutLocks());
    $timers = new TimerManager();
    $timers->start("total");
    // initialize data burst timer
    $timers->start("timeout");
    // initialize the connection timer
    // start the data sending loop
    while (connection_status() == CONNECTION_NORMAL) {
        ignore_user_abort(true);
        // allow the client to abort the connection
        set_time_limit($timeout);
        // this doesn't seem to work at all
        if (checkForceTimeoutLock($id)) {
            logg("exit reason:       forced timeout");
            break;
        }
        // if forced timeout is enabled
        if ($timers->elapsed("timeout") > $timeout) {
            logg("exit reason:       timeout");
            break;
        }
        // if timeout, then break
        if ($RANGE[2] + 1 <= $position) {
            logg("exit reason:       done");
            break;
        }
        // break if we've sent all the requested data (range end limit)
        if ($rate != 0) {
            $chunksize = max($chunksize + (round($timers->elapsed("total") * $rate) - ($position + $chunksize)), 0);
        }
        if ($RANGE[2] + 1 < $position + $chunksize) {
            // otherwise the file pointer will be set to far for the next read, also we
            $chunksize = $RANGE[2] + 1 - $position;
            // might read past file end
        }
        $timers->start("timeout");
        // reset the connection timer (we want to timeout only on idle connections,
        // eg. video paused, not on active ones, eg. video playing)
        if ($chunksize > 0) {
            $timers->start("fread");
            $data = fread($video, $chunksize);
            // read the data
            $timers->stop("fread");
            $position += $chunksize;
            // update the current position
            $bytes += $chunksize;
            $chunks += 1;
            // increment the chunk counter
            //logg("chunk ".($chunks).": ".($position - $chunksize)."-".($position - 1)." [".(strlen($data))." bytes] (size: ".($chunksize).")");
            // send the data to the client
            print $data;
            $timers->start("flush");
            flush();
            $timers->stop("flush");
            $timers->start("obflush");
            ob_flush();
            $timers->stop("obflush");
        }
        $timers->start("sleep");
        usleep($usleep);
        // wait before sending the next chunk of data
        $timers->stop("sleep");
    }
    $timers->stop("total");
    logg("connection status: " . connection_status());
    logg("sent:              " . $bytes . " bytes in " . $chunks . " chunks [avg chunksize: " . $bytes / $chunks . " bytes, rate: " . $bytes / $timers->total("sleep") . " B/s, real rate: " . $bytes / $timers->total("total") . " B/s]");
    logg("bench:             " . $timers->show("fread") . ", " . $timers->show("flush") . ", " . $timers->show("obflush") . ", " . $timers->show("sleep") . ", " . $timers->show("total"));
    logg("-------------------");
    fclose($video);
    // close the file
    exit(0);
    // exit the script
}