src/Upload/AbstractUploadProvider.php
<?php
namespace Nodes\Assets\Upload;
use finfo;
use Illuminate\Support\Str;
use Nodes\Assets\Support\DataUri;
use Nodes\Assets\Upload\Exceptions\AssetsBadRequestException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* Class AbstractUploadProvider.
*/
abstract class AbstractUploadProvider implements ProviderInterface
{
/**
* Process file.
*
* @author Casper Rasmussen <cr@nodes.dk>
* @abstract
*
* @param \Symfony\Component\HttpFoundation\File\UploadedFile $uploadedFile
* @param \Nodes\Assets\Upload\Settings $settings
*
* @return string $path
* @throws \Nodes\Assets\Upload\Exceptions\AssetsUploadFailedException
*/
abstract protected function store(UploadedFile $uploadedFile, Settings $settings);
/**
* Save/Upload an uploaded file.
*
* @author Casper Rasmussen <cr@nodes.dk>
*
* @param \Symfony\Component\HttpFoundation\File\UploadedFile $uploadedFile
* @param string $folder
* @param \Nodes\Assets\Upload\Settings $settings
*
* @return string $path
* @throws \Nodes\Assets\Upload\Exceptions\AssetsBadRequestException
* @throws \Nodes\Assets\Upload\Exceptions\AssetsUploadFailedException
*/
public function addFromUpload(UploadedFile $uploadedFile, $folder, Settings $settings)
{
// Set folder
if (! $settings->hasFolder()) {
$settings->setFolder($folder);
}
// Generate filename
if (! $settings->hasFilename()) {
$settings->setFileName($this->generateFilename($uploadedFile));
}
// Generate file extension
if (! $settings->hasFileExtension()) {
$settings->setFileExtension($this->generateFileExtension($uploadedFile));
}
// Throw exception if required data is missing
$settings->checkRequiredData();
// Process uploaded file
return $this->store($uploadedFile, $settings);
}
/**
* addFromUrl.
*
* @author Casper Rasmussen <cr@nodes.dk>
*
* @param string $url
* @param string $folder
* @param \Nodes\Assets\Upload\Settings $settings
*
* @return string
* @throws \Nodes\Assets\Upload\Exceptions\AssetsBadRequestException
*/
public function addFromUrl($url, $folder, Settings $settings)
{
// Stream file from URL
$streamContextOptions = [
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
],
];
$content = @file_get_contents($url, false, stream_context_create($streamContextOptions));
if (empty($content)) {
throw ( new AssetsBadRequestException('Could not stream content from given URL') )->setStatusCode(400);
}
// Write streamed content to temp. file
$file = tempnam('/tmp', '');
file_put_contents($file, $content);
// File's mime-type
$mimeType = ( new finfo(FILEINFO_MIME) )->file($file);
// Parse URL
$pathInfo = pathinfo($url);
// Generate an UploadedFile object
$uploadedFile = new UploadedFile($file, $pathInfo['basename'], $mimeType, filesize($file));
// Set folder
if (! $settings->hasFolder()) {
$settings->setFolder($folder);
}
// Generate filename
if (! $settings->hasFilename()) {
$settings->setFileName($this->generateFilename($uploadedFile));
}
// Generate file extension
if (! $settings->hasFileExtension()) {
$settings->setFileExtension($this->generateFileExtension($uploadedFile));
}
// Throw exception if required data is missing
$settings->checkRequiredData();
// Process file
$storedFile = $this->store($uploadedFile, $settings);
// delete tmp file
unlink($file);
return $storedFile;
}
/**
* addFromDataUri.
*
* @author Casper Rasmussen <cr@nodes.dk>
*
* @param string $dataUri
* @param string $folder
* @param \Nodes\Assets\Upload\Settings $settings
*
* @return string
* @throws \Nodes\Assets\Upload\Exceptions\AssetsBadRequestException
*/
public function addFromDataUri($dataUri, $folder, Settings $settings)
{
// Data URI container
$dataUriObject = null;
// Try and parse data URI to our container
if (! DataUri::tryParse($dataUri, $dataUriObject)) {
throw ( new AssetsBadRequestException('Could not stream the content') )->setStatusCode(400);
}
// Retrieve the data
$content = $dataUriObject->getEncodedData();
// Write parsed content to temp. file
$file = tempnam('/tmp', '');
file_put_contents($file, base64_decode($content));
// File's mime-type
$mimeType = ( new finfo(FILEINFO_MIME) )->file($file);
// Generate an UploadedFile object
$uploadedFile = new UploadedFile($file, Str::random(10).'.'.$dataUriObject->getFileExtension(), $mimeType,
filesize($file));
// Set folder
if (! $settings->hasFolder()) {
$settings->setFolder($folder);
}
// Generate filename
if (! $settings->hasFilename()) {
$settings->setFileName($this->generateFilename($uploadedFile));
}
// Generate file extension
if (! $settings->hasFileExtension()) {
$settings->setFileExtension($this->generateFileExtension($uploadedFile));
}
// Throw exception if required data is missing
$settings->checkRequiredData();
// Process file
return $this->store($uploadedFile, $settings);
}
/**
* generateFilename.
*
* @author Casper Rasmussen <cr@nodes.dk>
*
* @param \Symfony\Component\HttpFoundation\File\UploadedFile $uploadedFile
*
* @return string
*/
protected function generateFilename(UploadedFile $uploadedFile)
{
// Retrieve original file name
$filePath = $uploadedFile->getClientOriginalName();
// Parse URL
$filePath = pathinfo($filePath);
// Sanitize filename
$filename = preg_replace('/[^a-z0-9_-]/ui', '', $filePath['filename']);
// Append random sting and extension to filename
$filename .= '_'.Str::random(10);
return $filename;
}
/**
* Generate file extension.
*
* @author Casper Rasmussen <cr@nodes.dk>
*
* @param \Symfony\Component\HttpFoundation\File\UploadedFile $uploadedFile
*
* @return string
* @throws \Nodes\Assets\Upload\Exceptions\AssetsBadRequestException
*/
public function generateFileExtension(UploadedFile $uploadedFile)
{
// Retrieve original file name
$filePath = $uploadedFile->getClientOriginalName();
// Parse URL
$fileInfo = pathinfo($filePath);
// Return extension is available
if (! empty($fileInfo['extension'])) {
return strtolower($fileInfo['extension']);
}
throw ( new AssetsBadRequestException('Cannot detect file extension, provide it before uploading.') )->setStatusCode(400);
}
}