scratch – Rev 136

Subversion Repositories:
Rev:
<?php

###########################################################################
##  Copyright (C) Wizardry and Steamworks 2017 - License: GNU GPLv3      ##
###########################################################################

require_once('php/pseudocrypt.php');
require_once('php/functions.php');
require_once('vendor/autoload.php');

### FFMpeg
require_once('vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFMpeg.php');

### Aura URI
require_once('vendor/aura/uri/src/Aura/Uri/PublicSuffixList.php');
require_once('vendor/aura/uri/src/Aura/Uri/Url/Factory.php');
require_once('vendor/aura/uri/src/Aura/Uri/Query.php');
require_once('vendor/aura/uri/src/Aura/Uri/Host.php');
require_once('vendor/aura/uri/src/Aura/Uri/Url.php');
require_once('vendor/aura/uri/src/Aura/Uri/Path.php');
use Aura\Uri\Url\Factory as UrlFactory;
use Aura\Uri\PublicSuffixList;

### Load configuration.
$config = spyc_load_file('config.yaml');

### If no file has been specified for download then return.
if (!isset($_GET['hash']) or empty($_GET['hash'])) {
    http_response_code(404);
    die('File not found.');
}

### Find the requested file.
$file = array_shift(
    preg_grep(
        "/".$_GET['hash']."/",
        scandir($config['STORE_FOLDER'])
    )
);

if (!isset($file) or empty($file)) {
    http_response_code(404);
    die('File not found.');
}

### Check the path for path traversals.
$fileExtension = pathinfo($file, PATHINFO_EXTENSION);

#### If the extension is not allowed then return.
if (!isset($fileExtension) ||
    !in_array(strtoupper($fileExtension),
        array_map('strtoupper', $config['ALLOWED_FILE_EXTENSIONS']))) {
    http_response_code(403);
    die('File extension not allowed.');
}

#### Build the user path.
$userPath = join(
    DIRECTORY_SEPARATOR,
    array(
        $config['STORE_FOLDER'],
        $file
    )
);

#### Check for path traversals
$pathPart = pathinfo($userPath);
if (strcasecmp(
    realpath($pathPart['dirname']), realpath($config['STORE_FOLDER'])) != 0) {
    http_response_code(500);
    die('Internal server error.');
}

#### Check if the file exists.
if (!file_exists($userPath)) {
    http_response_code(404);
    die('File not found.');
}

### Extract the server path.
$URLFactory = new UrlFactory(
    $_SERVER,
    new PublicSuffixList(require 'vendor/aura/uri/data/public-suffix-list.php')
);
$URL = $URLFactory->newCurrent();

### HTTPs has to be enforced for opengraph sharing.
if(strtoupper($URL->scheme) != 'HTTPS')
    $URL->setScheme('https');

$URL_PATH = array_shift(
    explode(
        'og/'.$_GET['hash'],
        $URL->getFull()
    )
);

$GRAPH_URL = $URL_PATH.'og/'.$_GET['hash'];
$CANON_URL = $URL_PATH.'file.php?hash='.$_GET['hash'];
$BASIC_URL = $URL_PATH.$_GET['hash'];

switch(strtoupper($fileExtension)) {
    case 'GIF':
        list($width, $height) = getimagesize($userPath);
        echo <<<END
<html>
  <head>
    <meta property="fb:app_id" content="144991146129146">
    <meta property="og:site_name" content="Scratch Copy">
    <meta property="og:description" content="Scratch Copy">
    <meta property="og:url" content="$BASIC_URL">
    <meta property="og:title" content="Scratch Copy">
    <meta property="og:type" content="video.other">
    <meta property="og:image" content="$BASIC_URL">
    <meta property="og:image:width" content="$width">
    <meta property="og:image:height" content="$height">
  </head>

  <body>
    <p>
      <img src="$BASIC_URL">
    </p>
  </body>

</html>
END;
    break;
    case 'MP4':
    ### Create a thumbnail for the video.
    $file = strtolower(
        PseudoCrypt::hash(
            preg_replace(
                '/\D/',
                '',
                hash(
                    'sha512',
                    $_GET['hash']
                )
            ),
            $config['ASSET_HASH_SIZE']
        )
    );
    
    #### Build the user path.
    $userPath = join(
        DIRECTORY_SEPARATOR,
        array(
            $config['STORE_FOLDER'],
            $file
        )
    );
    
    ### Do not re-create the thumbnail if it already exists. 
    if(!file_exists($userPath.'.'.'jpg')) {
        ### Extract thumbnail.
        $ffmpeg = FFMpeg\FFMpeg::create();
        $video = $ffmpeg->open($CANON_URL);
        $frame = $video->frame(
            FFMpeg\Coordinate\TimeCode::fromSeconds(
                $config['VIDEO_PREVIEW_IMAGE_FRAME_SECOND']
            )
        );
        $frame->save($userPath.'.'.'jpg');
    }
    
    ### Get preview image size.
    list($imageWidth, $imageHeight) = getimagesize($userPath.'.'.'jpg');
    
    ### Probe video for width and height.
    $ffprobe = FFMpeg\FFProbe::create();
    $dimension = $ffprobe
        ->streams($CANON_URL)
        ->videos()
        ->first()
        ->getDimensions();
    $videoDuration = round(
        $ffprobe
            ->streams($CANON_URL)
            ->videos()
            ->first()
            ->get('duration'),
        0,
        PHP_ROUND_HALF_UP
    );
    
    $videoWidth = $dimension->getWidth();
    $videoHeight = $dimension->getHeight();
    
    ### Build paths.
    $PREVIEW_IMAGE_URL = $URL_PATH.$file;
    $FLOW_PLAYER_VIDEO_URL = $URL_PATH.'flowplayer/flowplayer.swf?config={"clip":"'.$BASIC_URL.'"}';
    $FLOW_PLAYER = $URL_PATH.'flowplayer/flowplayer.swf';
    
    echo <<<END
<html>
  <head>
      <meta property="fb:app_id" content="144991146129146">
      <meta property="og:type" content="video.other">
      <meta property="og:title" content="Scratch Copy">
      <meta property="og:site_name" content="Scratch Copy">
      <meta property="og:description" content="Scratch Copy">
      <meta property="og:url" content="$GRAPH_URL">
      <meta property="og:image" content="$PREVIEW_IMAGE_URL">
      <meta property="og:video" content='$FLOW_PLAYER_VIDEO_URL'>
      <meta property="og:video:secure_url" content='$FLOW_PLAYER_VIDEO_URL'>
      <meta property="og:video:type" content="application/x-shockwave-flash">
      <meta property="video:duration" content="$videoDuration">
      <meta property="og:video:width" content="$videoWidth">
      <meta property="og:video:height" content="$videoHeight">
      <meta property="og:image:width" content="$imageWidth">
      <meta property="og:image:height" content="$imageHeight">
  </head>

  <body>
    <p>
      <object width="$videoWidth" height="$videoHeight" id="Scratch Copy" name="Scratch Copy" data="$FLOW_PLAYER" type="application/x-shockwave-flash"><param name="movie" value="$FLOW_PLAYER" /><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="flashvars" value='config={"clip":"$BASIC_URL"}' /></object>
    </p>
  </body>

</html>
END;
    break;
}