<?php
/**
 * Copyright (C) 2020  Eddy (eddy.subratha@gmail.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY and FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

use SLiMS\Json;
use SLiMS\Http\Client;

/* Image Processing */

// key to authenticate
define('INDEX_AUTH', '1');

// main system configuration
require '../../../sysconfig.inc.php';
require SB.'admin/default/session.inc.php';
require SB.'admin/default/session_check.inc.php';
require LIB.'http_request.inc.php';

// privileges checking
$can_read = utility::havePrivilege('bibliography', 'r');
$can_write = utility::havePrivilege('bibliography', 'w');

// sent HTTP header
if (!($can_read && $can_write)) {
    $response = Json::stringify(['status' => 'UNAUTHORIZED', 'message' => 'Unauthorized Access!'])->withHeader();
    exit($response);
}

try {
    // field check
    if (!isset($_POST['imageURL']) && empty($_POST['imageURL'])) throw new Exception(__('URL can\'t empty!'));
    // make sure it is http request only
    $parsed_url = parse_url($_POST['imageURL']);
    if (!isset($parsed_url['scheme']) || !in_array(strtolower($parsed_url['scheme']), ['http','https'], true)) {
        throw new Exception(__('Must be http/https URL!'));
    }

    // imageURL must be a valid URL format
    $url = $_POST['imageURL'];
    if (!filter_var($url, FILTER_VALIDATE_URL)) throw new Exception(__('URL not valid!'));

    // no private ip addresses
    $ip = gethostbyname($parsed_url['host']);
    if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
        throw new Exception('Access to addresses is not allowed');
    }

    // Get image from another service
    try {
        $stream = Client::get($url, [
            'headers' => [
                'User-Agent' => $_SERVER['HTTP_USER_AGENT']],
                'timeout' => 10,
                'max_redirects' => 0,
        ]);
    } catch (\Exception $e) {
        $message = $e->getMessage();
        if (strpos($message, 'cURL error') !== false || strpos($message, 'timed out') !== false) {
             throw new Exception(__('Failed to connect to image source or connection timed out. Check the URL and server connectivity.'));
        }
        throw new Exception($message);
    }

    // Get image info from string
    $imageInfo = getimagesizefromstring($image = $stream->getContent());

    if (!$imageInfo) throw new Exception(__('Image is not valid!'));

    $mime = $imageInfo['mime'] ?? '';
    $ext = $mime ? ltrim(strtolower(image_type_to_extension($imageInfo[2], false)), '.') : '';
    if (!$mime || !in_array($mime, $sysconf['allowed_images_mimetype'], true) || ($ext && !in_array($ext, $sysconf['allowed_images'], true))) {
        throw new Exception(__('Image type not allowed!'));
    }
    
    if (strlen($image) > 1 * 512 * 512) { // 512kb limit
        throw new Exception('Image larger than expected');
    }

    if (!$imageInfo || strpos($imageInfo['mime'], 'image/') !== 0) {
        throw new Exception('Invalid image');
    }

    if (extension_loaded('gd') && $img = @imagecreatefromstring($image)) {
        $mime = $imageInfo['mime'];
        $gd_failed = false;

        ob_start();
        switch ($mime) {
            case 'image/jpeg':
            case 'image/jpg':
                imagejpeg($img, null, 100);
                break;
            case 'image/png':
                imagealphablending($img, false);
                imagesavealpha($img, true);
                imagepng($img, null, 9);
                break;
            case 'image/gif':
                imagegif($img, null);
                break;
            default:
                ob_end_clean();
                $gd_failed = true;
                break;
        }

        if (!$gd_failed) {
            $cleaned_image = ob_get_clean();
            if (!empty($cleaned_image)) {
                $image = $cleaned_image;
            }
        }

        imagedestroy($img);
    }

    $src = 'data:' . $imageInfo['mime'] . ';base64,'. ($encodedImage = base64_encode($image));
    $type = str_replace('image/', '',$imageInfo['mime']);
    $result = $encodedImage. '#image/type#' . $type;
    exit(Json::stringify(['status' => 'VALID', 'message' => $src, 'image' => $result])->withHeader());

} catch (Exception $e) {
    $response = Json::stringify(['status' => 'INVALID', 'message' => $e->getMessage()])->withHeader();
    exit($response);
}
