mirror of
https://github.com/bdnugget/magento2.git
synced 2026-11-07 09:17:35 +00:00
308 lines
9.0 KiB
PHP
308 lines
9.0 KiB
PHP
<?php
|
|
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
|
|
namespace Magento\Downloadable\Helper;
|
|
|
|
use Magento\Framework\App\Filesystem\DirectoryList;
|
|
use Magento\Framework\App\ObjectManager;
|
|
use Magento\Framework\File\Mime;
|
|
use Magento\Framework\Filesystem;
|
|
use Magento\Framework\Exception\LocalizedException as CoreException;
|
|
|
|
/**
|
|
* Downloadable Products Download Helper
|
|
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
|
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
|
|
*/
|
|
class Download extends \Magento\Framework\App\Helper\AbstractHelper
|
|
{
|
|
/**
|
|
* Link type for url
|
|
*/
|
|
public const LINK_TYPE_URL = 'url';
|
|
|
|
/**
|
|
* Link type for file
|
|
*/
|
|
public const LINK_TYPE_FILE = 'file';
|
|
|
|
/**
|
|
* Config path to content disposition
|
|
*/
|
|
public const XML_PATH_CONTENT_DISPOSITION = 'catalog/downloadable/content_disposition';
|
|
|
|
/**
|
|
* Type of link
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_linkType = self::LINK_TYPE_FILE;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected $_resourceFile = null;
|
|
|
|
/**
|
|
* Resource open handle
|
|
*
|
|
* @var \Magento\Framework\Filesystem\File\ReadInterface
|
|
*/
|
|
protected $_handle = null;
|
|
|
|
/**
|
|
* Remote server headers
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_urlHeaders = [];
|
|
|
|
/**
|
|
* MIME Content-type for a file
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_contentType = 'application/octet-stream';
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected $_fileName = 'download';
|
|
|
|
/**
|
|
* Core file storage database
|
|
*
|
|
* @var \Magento\MediaStorage\Helper\File\Storage\Database
|
|
*/
|
|
protected $_coreFileStorageDb;
|
|
|
|
/**
|
|
* @var \Magento\Downloadable\Helper\File
|
|
*/
|
|
protected $_downloadableFile;
|
|
|
|
/**
|
|
* @var \Magento\Framework\Filesystem
|
|
*/
|
|
protected $_filesystem;
|
|
|
|
/**
|
|
* @var \Magento\Framework\Filesystem\File\ReadFactory
|
|
*/
|
|
protected $fileReadFactory;
|
|
|
|
/**
|
|
* Working Directory (valid for LINK_TYPE_FILE only).
|
|
* @var \Magento\Framework\Filesystem\Directory\Read
|
|
*/
|
|
protected $_workingDirectory;
|
|
|
|
/**
|
|
* @var \Magento\Framework\Session\SessionManagerInterface
|
|
*/
|
|
protected $_session;
|
|
|
|
/**
|
|
* @var Mime
|
|
*/
|
|
private $mime;
|
|
|
|
/**
|
|
* @param \Magento\Framework\App\Helper\Context $context
|
|
* @param File $downloadableFile
|
|
* @param \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDb
|
|
* @param Filesystem $filesystem
|
|
* @param \Magento\Framework\Session\SessionManagerInterface $session
|
|
* @param Filesystem\File\ReadFactory $fileReadFactory
|
|
* @param Mime|null $mime
|
|
*/
|
|
public function __construct(
|
|
\Magento\Framework\App\Helper\Context $context,
|
|
\Magento\Downloadable\Helper\File $downloadableFile,
|
|
\Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDb,
|
|
\Magento\Framework\Filesystem $filesystem,
|
|
\Magento\Framework\Session\SessionManagerInterface $session,
|
|
\Magento\Framework\Filesystem\File\ReadFactory $fileReadFactory,
|
|
Mime $mime = null
|
|
) {
|
|
parent::__construct($context);
|
|
$this->_downloadableFile = $downloadableFile;
|
|
$this->_coreFileStorageDb = $coreFileStorageDb;
|
|
$this->_filesystem = $filesystem;
|
|
$this->_session = $session;
|
|
$this->fileReadFactory = $fileReadFactory;
|
|
$this->mime = $mime ?? ObjectManager::getInstance()->get(Mime::class);
|
|
}
|
|
|
|
/**
|
|
* Retrieve Resource file handle (socket, file pointer etc)
|
|
*
|
|
* @return \Magento\Framework\Filesystem\File\ReadInterface
|
|
* @throws CoreException|\Exception
|
|
*/
|
|
protected function _getHandle()
|
|
{
|
|
if (!$this->_resourceFile) {
|
|
throw new CoreException(__('Please set resource file and link type.'));
|
|
}
|
|
|
|
if ($this->_handle === null) {
|
|
if ($this->_linkType == self::LINK_TYPE_URL) {
|
|
$path = $this->_resourceFile;
|
|
// phpcs:ignore Magento2.Functions.DiscouragedFunction
|
|
$protocol = strtolower(parse_url($path, PHP_URL_SCHEME));
|
|
if ($protocol) {
|
|
// Strip down protocol from path
|
|
$path = preg_replace('#.+://#', '', $path);
|
|
}
|
|
$this->_handle = $this->fileReadFactory->create($path, $protocol);
|
|
} elseif ($this->_linkType == self::LINK_TYPE_FILE) {
|
|
$this->_workingDirectory = $this->_filesystem->getDirectoryRead(DirectoryList::MEDIA);
|
|
$fileExists = $this->_downloadableFile->ensureFileInFilesystem($this->_resourceFile);
|
|
if ($fileExists) {
|
|
$this->_handle = $this->_workingDirectory->openFile($this->_resourceFile);
|
|
} else {
|
|
throw new CoreException(__('Invalid download link type.'));
|
|
}
|
|
} else {
|
|
throw new CoreException(__('Invalid download link type.'));
|
|
}
|
|
}
|
|
return $this->_handle;
|
|
}
|
|
|
|
/**
|
|
* Retrieve file size in bytes
|
|
*
|
|
* @return int
|
|
*/
|
|
public function getFileSize()
|
|
{
|
|
return $this->_getHandle()->stat($this->_resourceFile)['size'];
|
|
}
|
|
|
|
/**
|
|
* Return MIME type of a file.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getContentType()
|
|
{
|
|
$this->_getHandle();
|
|
if ($this->_linkType === self::LINK_TYPE_FILE) {
|
|
$absolutePath = $this->_workingDirectory->getAbsolutePath($this->_resourceFile);
|
|
return $this->mime->getMimeType($absolutePath);
|
|
}
|
|
if ($this->_linkType === self::LINK_TYPE_URL) {
|
|
return (is_array($this->_handle->stat($this->_resourceFile)['type'])
|
|
? end($this->_handle->stat($this->_resourceFile)['type'])
|
|
: $this->_handle->stat($this->_resourceFile)['type']);
|
|
}
|
|
return $this->_contentType;
|
|
}
|
|
|
|
/**
|
|
* Return name of the file
|
|
*
|
|
* @return string
|
|
* phpcs:disable Magento2.Functions.DiscouragedFunction
|
|
* phpcs:disable Generic.PHP.NoSilencedErrors
|
|
*/
|
|
public function getFilename()
|
|
{
|
|
$this->_getHandle();
|
|
if ($this->_linkType == self::LINK_TYPE_FILE) {
|
|
return pathinfo($this->_resourceFile, PATHINFO_BASENAME);
|
|
} elseif ($this->_linkType == self::LINK_TYPE_URL) {
|
|
$stat = $this->_handle->stat($this->_resourceFile);
|
|
if (isset($stat['disposition'])) {
|
|
$contentDisposition = explode('; ', $stat['disposition']);
|
|
if (!empty($contentDisposition[1]) && preg_match(
|
|
'/filename=([^ ]+)/',
|
|
$contentDisposition[1],
|
|
$matches
|
|
)
|
|
) {
|
|
return $matches[1];
|
|
}
|
|
}
|
|
$fileName = @pathinfo($this->_resourceFile, PATHINFO_BASENAME);
|
|
if ($fileName) {
|
|
return $fileName;
|
|
}
|
|
}
|
|
return $this->_fileName;
|
|
}
|
|
|
|
/**
|
|
* Set resource file for download
|
|
*
|
|
* @param string $resourceFile
|
|
* @param string $linkType
|
|
* @return $this
|
|
* @throws \InvalidArgumentException
|
|
*/
|
|
public function setResource($resourceFile, $linkType = self::LINK_TYPE_FILE)
|
|
{
|
|
if (self::LINK_TYPE_FILE == $linkType) {
|
|
//check LFI protection
|
|
if ($resourceFile && preg_match('#\.\.[\\\/]#', $resourceFile)) {
|
|
throw new \InvalidArgumentException(
|
|
'Requested file may not include parent directory traversal ("../", "..\\" notation)'
|
|
);
|
|
}
|
|
}
|
|
|
|
$this->_resourceFile = $resourceFile;
|
|
|
|
/**
|
|
* check header for urls
|
|
*/
|
|
if ($linkType === self::LINK_TYPE_URL) {
|
|
// phpcs:ignore Magento2.Functions.DiscouragedFunction
|
|
$headers = array_change_key_case(get_headers($this->_resourceFile, 1), CASE_LOWER);
|
|
if (isset($headers['location'])) {
|
|
$this->_resourceFile = is_array($headers['location']) ? current($headers['location'])
|
|
: $headers['location'];
|
|
}
|
|
}
|
|
|
|
$this->_linkType = $linkType;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Output file contents
|
|
*
|
|
* @return void
|
|
*/
|
|
public function output()
|
|
{
|
|
$handle = $this->_getHandle();
|
|
$this->_session->writeClose();
|
|
while (true == ($buffer = $handle->read(1024))) {
|
|
// phpcs:ignore Magento2.Security.LanguageConstruct
|
|
echo $buffer; //@codingStandardsIgnoreLine
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Use Content-Disposition: attachment
|
|
*
|
|
* @param mixed $store
|
|
* @return bool
|
|
* @SuppressWarnings(PHPMD.BooleanGetMethodName)
|
|
*/
|
|
public function getContentDisposition($store = null)
|
|
{
|
|
return $this->scopeConfig->getValue(
|
|
self::XML_PATH_CONTENT_DISPOSITION,
|
|
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
|
|
$store
|
|
);
|
|
}
|
|
}
|