<?php

/**
  * Ahead WebSoft Technologies Pvt Ltd.
  * @copyright  Copyright 2006-2026 Ahead WebSoft Technologies Pvt Ltd.
  * @license    https://www.socialengine.com/policies
*/
class Core_Api_MediaUpload extends Core_Api_Abstract
{
  const MAX_IMAGE_SIZE = 47185920;

  public function getPhotoFromRequest($fieldName, $baseName = 'photo', $request = null)
  {
    if (null === $request) {
      $request = Zend_Controller_Front::getInstance()->getRequest();
    }

    $photo = $this->getPhotoFromData($request->getParam($fieldName . '_camera'), $baseName);
    if ($photo) {
      return $photo;
    }

    return $this->getPhotoFromUrl($request->getParam($fieldName . '_url'), $baseName);
  }

  public function getPhotoFromUrl($url, $baseName = 'photo')
  {
    $url = trim((string) $url);
    if (!empty($url) && !preg_match('/^[a-z][a-z0-9+.-]*:\/\//i', $url)) {
      $url = 'https://' . $url;
    }
    if (empty($url) || !filter_var($url, FILTER_VALIDATE_URL)) {
      return null;
    }

    $scheme = strtolower(parse_url($url, PHP_URL_SCHEME));
    if (!in_array($scheme, array('http', 'https'))) {
      return null;
    }

    $host = parse_url($url, PHP_URL_HOST);
    if (!$host || in_array(strtolower($host), array('localhost'))) {
      return null;
    }
    if (filter_var($host, FILTER_VALIDATE_IP) && !filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
      return null;
    }
    $hostIp = gethostbyname($host);
    if ($hostIp && $hostIp !== $host && !filter_var($hostIp, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
      return null;
    }

    $temporaryPath = APPLICATION_PATH . DIRECTORY_SEPARATOR . 'temporary';
    $temporaryFile = tempnam($temporaryPath, 'media_remote_');
    if (!$temporaryFile) {
      return null;
    }

    $data = null;
    if (function_exists('curl_init')) {
      $ch = curl_init($url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
      curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
      curl_setopt($ch, CURLOPT_TIMEOUT, 20);
      curl_setopt($ch, CURLOPT_USERAGENT, 'SocialEngine Media Upload');
      $data = curl_exec($ch);
      $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);
      if ($status < 200 || $status >= 300) {
        @unlink($temporaryFile);
        return null;
      }
    } else {
      $data = @file_get_contents($url);
    }

    if (empty($data) || strlen($data) > self::MAX_IMAGE_SIZE) {
      @unlink($temporaryFile);
      return null;
    }

    if (!@file_put_contents($temporaryFile, $data)) {
      @unlink($temporaryFile);
      return null;
    }

    $imageInfo = @getimagesize($temporaryFile);
    $extensions = array(
      'image/jpeg' => 'jpg',
      'image/png' => 'png',
      'image/gif' => 'gif',
      'image/webp' => 'webp',
    );

    if (empty($imageInfo['mime']) || empty($extensions[$imageInfo['mime']])) {
      @unlink($temporaryFile);
      return null;
    }

    $extension = $extensions[$imageInfo['mime']];
    $photoFile = $temporaryFile . '.' . $extension;
    @rename($temporaryFile, $photoFile);

    return array(
      'tmp_name' => $photoFile,
      'name' => $baseName . '.' . $extension,
    );
  }

  public function getPhotoFromData($data, $baseName = 'photo')
  {
    $data = trim((string) $data);
    if (empty($data) || !preg_match('/^data:image\/(jpeg|jpg|png|gif|webp);base64,(.+)$/i', $data, $matches)) {
      return null;
    }

    $extension = strtolower($matches[1]);
    if ($extension == 'jpeg') {
      $extension = 'jpg';
    }

    $binary = base64_decode($matches[2], true);
    if (empty($binary) || strlen($binary) > self::MAX_IMAGE_SIZE) {
      return null;
    }

    $temporaryPath = APPLICATION_PATH . DIRECTORY_SEPARATOR . 'temporary';
    $temporaryFile = tempnam($temporaryPath, 'media_camera_');
    if (!$temporaryFile) {
      return null;
    }

    $photoFile = $temporaryFile . '.' . $extension;
    if (!@file_put_contents($photoFile, $binary)) {
      @unlink($temporaryFile);
      return null;
    }
    @unlink($temporaryFile);

    $imageInfo = @getimagesize($photoFile);
    if (empty($imageInfo['mime']) || strpos($imageInfo['mime'], 'image/') !== 0) {
      @unlink($photoFile);
      return null;
    }

    return array(
      'tmp_name' => $photoFile,
      'name' => $baseName . '.' . $extension,
    );
  }

  public function cleanupTemporaryPhoto($photo)
  {
    if (is_array($photo) && !empty($photo['tmp_name']) && file_exists($photo['tmp_name'])) {
      @unlink($photo['tmp_name']);
    }
  }

  public function saveToItem($form, $item, array $values, array $options)
  {
    if (empty($options['field'])) {
      return false;
    }

    $fieldName = $options['field'];
    if (!$form || !method_exists($form, 'getElement') || !$form->getElement($fieldName)) {
      return false;
    }

    $setter = !empty($options['setter']) ? $options['setter'] : 'setPhoto';
    if (!is_callable(array($item, $setter))) {
      return false;
    }

    $baseName = !empty($options['baseName']) ? $options['baseName'] : $fieldName;
    $removeField = !empty($options['remove']) ? $options['remove'] : null;
    $property = !empty($options['property']) ? $options['property'] : null;
    $deletePrevious = !empty($options['deletePrevious']);
    $setterArgs = !empty($options['setterArgs']) ? (array) $options['setterArgs'] : array();
    $photo = null;

    if (!empty($values[$fieldName])) {
      $photo = $form->getElement($fieldName);
    } else {
      $photo = $this->getPhotoFromRequest($fieldName, $baseName);
    }

    if ($photo) {
      if ($deletePrevious && $property) {
        $this->deleteStorageProperty($item, $property);
      }

      try {
        call_user_func_array(array($item, $setter), array_merge(array($photo), $setterArgs));
      } catch (Exception $e) {
        $this->cleanupTemporaryPhoto($photo);
        throw $e;
      }
      $this->cleanupTemporaryPhoto($photo);
      return true;
    }

    if ($removeField && !empty($values[$removeField]) && $property) {
      $this->deleteStorageProperty($item, $property);
      return true;
    }

    return false;
  }

  protected function deleteStorageProperty($item, $property)
  {
    if (empty($item->{$property})) {
      return;
    }

    $storage = Engine_Api::_()->getItem('storage_file', $item->{$property});
    $item->{$property} = 0;
    $item->save();
    if ($storage) {
      $storage->delete();
    }
  }
}
