<?php
namespace Core\Installation;
use Admincp_Service_Module_Process;
use Admincp_Service_Product_Process;
use Core\App;
use Core\Cache;
use Core\Db;
use Core\Lib;
use Core\Theme;
use Core\Theme\Object;
use Language_Service_Process;
use Phpfox;
use Phpfox_Error;
/**
* Class Manager
*
* @package Core\Installation
*/
class Manager
{
/**
*
*/
CONST PHPFOX_STORE_ENDPOINT_URL = '';
/**
* @var array
*/
private $packages = [];
/**
* @var array
*/
private $messages = [];
/**
* @var Vfs method
*/
private $vfs;
private $host;
private $port;
private $userName;
private $passWord;
private $managerControl;
private $_is_upgrade = false;
public function __construct($hostInfo = [])
{
if (isset($hostInfo['method'])) {
$this->vfs = $hostInfo['method'];
} else {
$this->vfs = Phpfox::getParam('core.upload_method');
}
if (isset($hostInfo['host_name'])) {
$this->host = $hostInfo['host_name'];
} else {
$this->host = Phpfox::getParam('core.ftp_host_name');
}
if (isset($hostInfo['port'])) {
$this->port = $hostInfo['port'];
} else {
$this->port = Phpfox::getParam('core.ftp_port');
}
if (isset($hostInfo['user_name'])) {
$this->userName = $hostInfo['user_name'];
} else {
$this->userName = Phpfox::getParam('core.ftp_user_name');
}
if (isset($hostInfo['password'])) {
$this->passWord = $hostInfo['password'];
} else {
$this->passWord = Phpfox::getParam('core.ftp_password');
}
$param = [
'port' => $this->port,
'host' => $this->host,
'user' => $this->userName,
'pass' => $this->passWord,
];
switch ($this->vfs) {
case 'sftp_ssh':
$this->managerControl = new Ssh2($param);
break;
case 'ftp':
$this->managerControl = new Ftp($param);
break;
case 'file_system':
default:
$this->managerControl = new FileSystem($param);
}
}
/**
* @return Vfs
*/
public function getVfs()
{
if (null == $this->vfs) {
$this->vfs = new FileSystem([]);
}
return $this->vfs;
}
/**
* @param Vfs $vfs
*/
public function setVfs($vfs)
{
$this->vfs = $vfs;
}
/**
* @return array
*/
public function getPackages()
{
return $this->packages;
}
/**
* @param array $packages
*/
public function setPackages($packages)
{
$this->packages = $packages;
}
/**
* @return array
*/
public function getMessages()
{
return $this->messages;
}
/**
* @param array $messages
*/
public function setMessages($messages)
{
$this->messages = $messages;
}
/**
*
*/
public function process()
{
foreach ($this->packages as $package) {
}
}
/**
* Follow step by step
* + Rollback database [if step]
* + Rollback filesystem
*/
public function rollback()
{
}
/**
* @param array $param
*
* @return string
*/
public function install($param)
{
$this->onBeforeInstall($param);
$returnUrl = $this->onInstall($param);
$this->onAfterInstall($param);
return $returnUrl;
}
public function upgrade($param)
{
}
public function uninstall()
{
}
/**
* @param array $param
*
* @return string
*/
public function onInstall($param)
{
$this->copyFile($param);
$returnUrl = $this->runInstall($param);
$this->cleanInstall();
return $returnUrl;
}
/**
* @param $param
*
* @return bool
*/
public function copyFile($param)
{
if (empty($param['type'])) {
throw new \InvalidArgumentException("Missing [type]");
}
$bReturn = true;
$copyResult = null;
$result = ['files' => [], 'tempPath' => '', 'newPath' => '',];
switch ($param['type']) {
case 'app':
case 'application':
$copyResult = $this->copyFileForApp($param);
break;
case 'theme':
case 'flavor':
$copyResult = $this->copyFileForTheme($param);
break;
case 'module':
case 'product':
$copyResult = $this->copyFileForModule($param);
break;
case 'language':
$copyResult = $this->copyFileForLanguage($param);
break;
default:
throw new \InvalidArgumentException(sprintf('unexpected copy file for type [%s]',
$param['type']));
break;
}
$result = array_merge($result, $copyResult);
if (!empty($result['files'])) {
$this->managerControl->setFile($result['files'])
->setFromPath($result['tempPath'])
->setToPath($result['newPath'])
->run();
}
return $bReturn;
}
/**
* @param $param
*
* @return string
*/
public function getTemporaryExtractThemeDirectory($param)
{
return PHPFOX_DIR_FILE . 'static' . PHPFOX_DS . 'phpfox-theme-'
. $param['productId'] . '/';
}
/**
* @param $param
*
* @return string
*/
public function getTemporaryExtractProductDirectory($param)
{
return PHPFOX_DIR_FILE . 'static' . PHPFOX_DS . 'phpfox-product-'
. $param['productId'] . PHPFOX_DS;
}
/**
* @param $param
*
* @return string
*/
public function getTemporaryExtractAppDirectory($param)
{
return PHPFOX_DIR_FILE . 'static' . PHPFOX_DS . 'phpfox-app-'
. $param['productId'] . PHPFOX_DS;
}
/**
* @param array $param
*
* @return array
*/
public function copyFileForTheme($param)
{
// forward this method to runInstall theme.
return [];
}
public function copyFileForLanguage($param)
{
$temporaryDir = $param['targetDirectory']
. 'upload/include/xml/language/';
foreach (scandir($temporaryDir) as $folder) {
if (file_exists($temporaryDir . $folder
. '/phpfox-language-import.xml')) {
Language_Service_Process::instance()
->installPackFromFolder($folder,
$temporaryDir . $folder . '/');
$dir = base64_encode($temporaryDir . $folder . '/');
url()->send('/admincp/language/import', ['dir' => $dir]);
}
}
}
/**
* @param array $param
*
* @return array
*/
public function copyFileForModule($param)
{
$temporaryDir = $this->getTemporaryExtractProductDirectory($param);
$fileList = json_decode(file_get_contents($temporaryDir
. 'checksum.json'), true);
return [
'tempPath' => $temporaryDir,
'newPath' => realpath(dirname(rtrim(PHPFOX_DIR, '/'))),
'files' => array_values($fileList),
];
}
/**
* Do not use this method directly.
*
* @param $param [type: string, name: string]
*
* @return array [files: [], newPath: string, tempPath: string]
* @ignore
*/
public function copyFileForApp($param)
{
if (empty($param['productName'])) {
throw new \InvalidArgumentException("Missing params [name]");
}
if (isset($param['apps_dir']) && !empty($param['apps_dir'])) {
$name = base64_decode($param['apps_dir']);
} else {
$name = $param['productName'];
}
$tempPath = $this->getTemporaryExtractAppDirectory($param);
$newPath = realpath(PHPFOX_DIR_SITE) . PHPFOX_DS . 'Apps' . PHPFOX_DS
. $name;
if (is_dir($newPath)) {
$this->_is_upgrade = true;
}
if (file_exists($tempPath . 'checksum.json')) {
$fileList = json_decode(file_get_contents($tempPath
. 'checksum.json'), true);
if (isset($param['apps_dir']) && !empty($param['apps_dir'])) {
foreach ($fileList as $iKey => $sFile) {
$fileList[$iKey] = str_replace($param['productName'],
base64_decode($param['apps_dir']), $sFile);
}
}
$newPath = realpath(dirname(rtrim(PHPFOX_DIR, '/')));
}
if (empty($fileList)) {
$result = $this->compareFiles($tempPath, $newPath);;
$fileList = [];
if (count($result['new'])) {
foreach ($result['new'] as $file) {
$file = trim(str_replace($name, '', $file), PHPFOX_DS);
$fileList[] = $file;
}
}
//case delete file we upgrade later
if (count($result['update'])) {
foreach ($result['update'] as $file) {
$file = trim(str_replace($name, '', $file), PHPFOX_DS);
$fileList[] = $file;
}
}
}
return [
'files' => array_values($fileList),
'tempPath' => rtrim($tempPath, '/'),
'newPath' => rtrim($newPath),
];
}
/**
* @param array $param
*
* @throws
* @return string
*/
public function runInstallForApp($param)
{
if (empty($param['productName'])) {
throw new \InvalidArgumentException('Missing params [productName]');
}
$productName = $param['productName'];
$is_upgrade = false;
$autoloader = include PHPFOX_DIR . 'vendor' . PHPFOX_DS
. 'autoload.php';
if (isset($param['apps_dir']) && !empty($param['apps_dir'])) {
$sAppDirName = base64_decode($param['apps_dir']);
} else {
$sAppDirName = $param['productName'];
}
$autoloader->setPsr4('Apps\\' . $productName . '\\',
PHPFOX_PARENT_DIR . 'PF.Site' . PHPFOX_DS . 'Apps' . PHPFOX_DS
. $sAppDirName);
if ($this->_is_upgrade) {
$is_upgrade = true;
}
$rename_on_upgrade = false;
// check app rename on update
$current = Phpfox::getLib('database')
->select('apps_dir')
->from(':apps')
->where("apps_id='$productName'")
->execute('getRow');
if(null != $current){
if($current['apps_dir'] == null){
$current['apps_dir'] = $productName;
}
if($current['apps_dir'] != $sAppDirName){
Phpfox::getLib('database')
->update(':apps', ['apps_dir' => $sAppDirName],
['apps_id' => $productName]);
$rename_on_upgrade = true;
}
}
if ($rename_on_upgrade) {
$url = Phpfox::getLib('url')->makeUrl('admincp.apps', [
'rename_on_upgrade' => 1,
'apps_dir' => $sAppDirName,
'apps_id' => $productName,
'is_upgrade' => $is_upgrade,
]);
Phpfox::getLib('cache')->remove();
header('location: '. $url); exit;
}
return $this->callRunInstallForApp($productName, $sAppDirName,
$is_upgrade);
}
/**
* @param array $param
*
* @return string
*/
public function runInstallForTheme($param)
{
$temporaryDirectory = $this->getTemporaryExtractThemeDirectory($param);
$extra = isset($param['extra']) ? $param['extra'] : [];
$productId = $param['productId'];
$exists = false;
$themeService = new Theme();
$fileList = null;
$flavors = null;
$name = null;
if ($productId) {
foreach ($themeService->all() as $theme) {
if ($theme->internal_id == $productId) {
$exists = $theme;
break;
}
}
}
if (file_exists($temporaryDirectory . 'checksum.json')) {
$data = json_decode(file_get_contents($temporaryDirectory
. 'package.json'), true);
$flavors = $data['flavors'];
$fileList = json_decode(file_get_contents($temporaryDirectory
. 'checksum.json'), true);
$name = $data['name'];
} else {
$scanFiles = $this->scanFiles($temporaryDirectory, false);
$jsonFile = null;
foreach ($scanFiles as $fileName) {
if (substr($fileName, -9) == '.zip.json') {
$jsonFile = $temporaryDirectory . $fileName;
break;
}
}
$data = json_decode(file_get_contents($jsonFile), true);
foreach ($data['files'] as $path => $content) {
$filename = 'PF.Site/themes/0/' . $path;
$fullname = $temporaryDirectory . $filename;
if (!is_dir($dirname = dirname($fullname))) {
mkdir($dirname, 0777, true);
chmod($dirname, 0777);
}
file_put_contents($fullname, $content);
@chmod($fullname, 0777);
$fileList[] = $filename;
}
if (!isset($data['flavors'])) {
$data['flavors'] = [$data['flavor_folder'] => $data['name']];
}
$flavors = $data['flavors'];
$name = $data['name'];
}
$db = new Db();
$cache = new Cache();
$isUpdate = false;
// copy file from theme to theme.
if ($exists instanceof Object) {
$isUpdate = $exists->theme_id;
$db->update(':theme', ['website' => json_encode($extra)],
['theme_id' => $exists->theme_id]);
$db->update(':setting', [
'value_actual' => ((int)\Phpfox::getParam('core.css_edit_id')
+ 1),
], 'var_name = \'css_edit_id\'');
$cache->del('setting');
}
$existsTheme = null;
if (!empty($extra)) {
$websiteId = $extra['id'];
$themes = $db->select('*')
->from(':theme', 't')
->all();
foreach ($themes as $theme) {
if (!empty($theme['website'])) {
$k = json_decode($theme['website'], true);
if ($websiteId == $k['id']) {
$existsTheme = $theme;
break;
}
}
}
}
if (!empty($existsTheme)) {
$themeId = $existsTheme['theme_id'];
} else {
$themeId = $db->insert(':theme', [
'name' => $data['name'],
'folder' => '__',
'website' => (isset($extra) ? json_encode($extra) : null),
'created' => PHPFOX_TIME,
'is_active' => 1,
]);
$db->update(':theme', ['folder' => $themeId,],
['theme_id' => $themeId]);
}
$validateFileList = [];
$folder = '0';
if (!empty($fileList)) {
$array = explode('/', $fileList[0]);
$folder = $array[2];
}
foreach ($fileList as $filename) {
$to_filename = str_replace('PF.Site/themes/' . $folder . '/',
'PF.Site/themes/' . $themeId . '/', $filename);
$validateFileList[$filename] = $to_filename;
}
// do not run vfs here, it's require only themes
$rootPath = realpath(dirname(trim(PHPFOX_DIR, '/')));
foreach ($validateFileList as $fromPath => $toPath) {
$to_filename = $rootPath . $toPath;
if (!is_dir($dir = dirname($to_filename))) {
mkdir($dir, 0777, 1);
chmod($dir, 0777);
}
if (!@copy($temporaryDirectory . $fromPath, $to_filename)) {
$db->delete(':theme', ['theme_id' => $themeId]);
throw new \RuntimeException(sprintf('Can not copy from "%s" to "%s"',
$temporaryDirectory . $fromPath, $to_filename));
}
}
if (false == $isUpdate) {
$iteration = 0;
foreach ($flavors as $flavorId => $flavorName) {
$iteration++;
$db->insert(':theme_style', [
'theme_id' => $themeId,
'name' => $flavorName,
'folder' => $flavorId,
'is_default' => ($iteration === 1 ? '1' : '0'),
'is_active' => 1,
'created' => PHPFOX_TIME,
]);
}
}
$url = \Phpfox::getLib('url')
->makeUrl('admincp.theme.manage', ['id' => $themeId]);
return $url;
}
/**
* @param array $param
*
* @return string
*/
public function runInstallForModule($param)
{
$bOverwrite = true;
$bIsUpdate = false;
$sProductFile = $param['productId'];
$aCache = [];
$aModuleInstall = [];
$xmlFileName = PHPFOX_DIR_XML . $sProductFile . '.xml';
if (!file_exists($xmlFileName)) {
throw new \RuntimeException(_p('unable_to_find_xml_file_to_import_for_this_product'
. $xmlFileName));
}
$aParams = Phpfox::getLib('xml.parser')
->parse(file_get_contents($xmlFileName));
if (isset($aParams['modules'])) {
$aModules = (is_array($aParams['modules']['module_id'])
? $aParams['modules']['module_id']
: [$aParams['modules']['module_id']]);
foreach ($aModules as $sModule) {
$aModuleInstall[$sModule] = [
'table' => 'true',
'installed' => 'false',
];
}
}
foreach ($aCache as $sModuleCheck => $mTrue) {
if (!Phpfox::isModule($sModuleCheck)) {
throw new \RuntimeException(_p('the_module_name_is_required',
['name' => $sModuleCheck]));
}
}
if (!isset($aParams['data']['product_id'])) {
throw new \RuntimeException(_p('not_a_valid_xml_file'));
}
Phpfox::getLib('cache')->lock();
$productService = Admincp_Service_Product_Process::instance();
$bIsProduct = $productService->isProduct($aParams['data']['product_id']);
// Upgrade or Install ?
if ($bIsProduct) {
$productService->upgrade($param['productId']);
} else {
if (isset($aParams['dependencies'])) {
$aDependencies
= (isset($aParams['dependencies']['dependency'][1])
? $aParams['dependencies']['dependency']
: [$aParams['dependencies']['dependency']]);
foreach ($aDependencies as $aDependancy) {
if (!isset($aDependancy['type_id'])
|| !isset($aDependancy['dependency_start'])
) {
continue;
}
switch ($aDependancy['type_id']) {
case 'php':
if (version_compare(PHP_VERSION,
$aDependancy['dependency_start'], '<')) {
throw new \RuntimeException(_p('product_requires_php_version',
['dependency_start' => $aDependancy['dependency_start']]));
}
if (isset($aDependancy['dependency_end'])
&& $aDependancy['dependency_end'] != ''
) {
if (version_compare(PHP_VERSION,
$aDependancy['dependency_end'], '>')) {
throw new \RuntimeException(_p('product_requires_php_version_up_until',
[
'dependency_start' => $aDependancy['dependency_start'],
'dependency_end' => $aDependancy['dependency_end'],
]));
}
}
break;
case 'phpfox':
if (version_compare(Phpfox::getVersion(),
$aDependancy['dependency_start'], '<')) {
throw new \RuntimeException(_p('product_requires_phpfox_version',
[
'dependency_start',
$aDependancy['dependency_start'],
]));
}
if (isset($aDependancy['dependency_end'])
&& $aDependancy['dependency_end'] != ''
) {
if (version_compare(Phpfox::getVersion(),
$aDependancy['dependency_end'], '>')) {
throw new \RuntimeException(_p('product_requires_phpfox_version_up_until',
[
'dependency_start' => $aDependancy['dependency_start'],
'dependency_end' => $aDependancy['dependency_end'],
]));
}
}
break;
case 'product':
if (!isset($aDependancy['check_id'])) {
continue;
}
$aProductVersion
= $productService->getProductDependency($aDependancy['check_id']);
if (isset($aProductVersion['product_id'])) {
if (version_compare($aProductVersion['version'],
$aDependancy['dependency_start'], '<')) {
throw new \RuntimeException(_p('product_requires_check_id_version_dependency_start',
[
'check_id' => $aProductVersion['title'],
'dependency_start' => $aDependancy['dependency_start'],
]));
}
if (!empty($aDependancy['dependency_end'])) {
if (version_compare($aProductVersion['version'],
$aDependancy['dependency_end'], '>')) {
throw new \RuntimeException(_p('product_requires_check_id_version_dependency_start_up_until_dependency_end',
[
'check_id' => $aProductVersion['title'],
'dependency_start' => $aDependancy['dependency_start'],
'dependency_end' => $aDependancy['dependency_end'],
]));
}
}
} else {
throw new \RuntimeException(_p('product_requires_check_id_version_dependency_start',
[
'check_id' => $aDependancy['check_id'],
'dependency_start' => $aDependancy['dependency_start'],
]));
}
break;
default:
break;
}
}
}
$addResult = $productService->add([
'product_id' => $aParams['data']['product_id'],
'title' => $aParams['data']['title'],
'description' => (empty($aParams['data']['description'])
? null : $aParams['data']['description']),
'version' => (empty($aParams['data']['version'])
? null : $aParams['data']['version']),
'is_active' => 1,
'url' => (empty($aParams['data']['url']) ? null
: $aParams['data']['url']),
'url_version_check' => (empty($aParams['data']['url_version_check'])
? null : $aParams['data']['url_version_check']),
'icon' => (empty($aParams['data']['icon']) ? null
: $aParams['data']['icon']),
'vendor' => (empty($aParams['data']['vendor']) ? null
: $aParams['data']['vendor']),
], $bIsUpdate);
if (!$addResult) {
throw new \RuntimeException('Can not insert product'
. Phpfox_Error::get());
}
if (!empty($aParams['dependencies'])) {
$aDependencies
= (isset($aParams['dependencies']['dependency'][1])
? $aParams['dependencies']['dependency']
: [$aParams['dependencies']['dependency']]);
foreach ($aDependencies as $aDependancy) {
$aDependancy['product_id'] = $aParams['data']['product_id'];
$productService->addDependency($aDependancy);
}
}
if (!empty($aParams['installs'])) {
$aInstalls = (isset($aParams['installs']['install'][1])
? $aParams['installs']['install']
: [$aParams['installs']['install']]);
$aInstallOrder = [];
foreach ($aInstalls as $aInstall) {
$aInstallOrder[$aInstall['version']] = $aInstall;
$aInstall['product_id'] = $aParams['data']['product_id'];
$productService->addInstall($aInstall);
}
sort($aInstallOrder);
try {
$productService->invokeInstallCode($aInstallOrder);
} catch (\Exception $ex) {
throw new \RuntimeException($ex->getMessage());
}
}
$moduleService = Admincp_Service_Module_Process::instance();
$moduleService->processInstall($sProductFile, $aModuleInstall,
null);
Phpfox::getLib('cache')->unlock();
Phpfox::getLib('cache')->remove();
}
flavor()->rebuild_bootstrap();
return \Phpfox::getLib('url')->makeUrl('admincp.apps', []);
}
/**
* @param array $param
*
* @return string
*
* @throws \InvalidArgumentException
*/
private function runInstall($param)
{
if (empty($param['type'])) {
throw new \InvalidArgumentException('Missing params [name, type]');
}
$returnUrl = null;
switch ($param['type']) {
case 'app':
case 'application':
$returnUrl = $this->runInstallForApp($param);
break;
case 'theme':
case 'flavor':
$returnUrl = $this->runInstallForTheme($param);
break;
case 'module':
case 'product':
$returnUrl = $this->runInstallForModule($param);
break;
case 'language':
break;
default:
throw new \InvalidArgumentException(sprintf('Unexpected copy file for type [%s]',
$param['type']));
break;
}
return $returnUrl;
}
/**
* Clean temporary directory after install
* TODO: correct path?
*/
private function cleanInstall()
{
$path = PHPFOX_DIR_FILE . 'temp';
$this->removeDir($path);
}
/**
* @param $path
*/
private function removeDir($path, $removeRoot = false)
{
if (!is_dir($path)) {
return;
}
$items = scandir($path);
foreach ($items as $item) {
if (in_array($item, ['.', '..'])) {
continue;
}
$filePath = $path . PHPFOX_DS . $item;
/**
* Check writeable
*/
if (!is_writable($filePath)) {
continue;
}
is_dir($filePath) ? $this->removeDir($filePath, true)
: @unlink($filePath);
}
if ($removeRoot && is_dir($path)) {
rmdir($path);
}
}
/**
* Do something before install
*
* @param $param
*/
private function onBeforeInstall($param)
{
}
private function onAfterInstall($param)
{
//remove temp dir after copy
switch ($param['type']) {
case 'app':
case 'application':
$tempDir = $this->getTemporaryExtractAppDirectory($param);
break;
case 'theme':
case 'flavor':
$tempDir = $this->getTemporaryExtractThemeDirectory($param);
break;
case 'module':
case 'product':
$tempDir = $this->getTemporaryExtractProductDirectory($param);
break;
case 'language':
//TODO find the temp folder when install language
// $tempDir = $this->verifyFilesystemForLanguage($param);
$tempDir = false;
break;
default:
throw new \InvalidArgumentException(sprintf('Unexpected params type: %s', $param['type']));
}
if (!empty($tempDir) && is_dir($tempDir)) {
$this->managerControl->deleteDir($tempDir);
}
}
/**
* Image is app, theme, module, language ?
*
* @param array $param
*
* @return array
*/
public function verifyFilesystem($param)
{
if (empty($param['type']) or empty($param['filename'])) {
throw new \InvalidArgumentException('Missing params [type, filename]');
}
$result = null;
switch ($param['type']) {
case 'app':
case 'application':
$result = $this->verifyFilesystemForApp($param);
break;
case 'theme':
case 'flavor':
$result = $this->verifyFilesystemForTheme($param);
break;
case 'module':
case 'product':
$result = $this->verifyFilesystemForModule($param);
break;
case 'language':
$result = $this->verifyFilesystemForLanguage($param);
break;
default:
throw new \InvalidArgumentException(sprintf('Unexpected params type: %s',
$param['type']));
}
return $result;
}
/**
* @param array $param
*
* @return array
*/
public function verifyFilesystemForTheme($param)
{
if (empty($param['filename'])) {
throw new \InvalidArgumentException('Missing params [filename]');
}
$productId = empty($param['productId']) ? 0 : $param['productId'];
$zip = $param['filename'];
$temporaryDirectory = $this->getTemporaryExtractThemeDirectory($param);
$Zip = new \ZipArchive();
$Zip->open($zip);
$Zip->extractTo($temporaryDirectory);
$Zip->close();
$themeName = null;
$File = \Phpfox_File::instance();
$result = [];
foreach (scandir($temporaryDirectory) as $f) {
if ($File->extension($f) == 'json') {
$data = json_decode(file_get_contents($temporaryDirectory . $f),
true);
$themeName = $data['name'];
foreach ($data['files'] as $fileName => $fileData) {
$temporaryFilename = $temporaryDirectory . '/' . $fileName;
$dirname = dirname($temporaryFilename);
if (!is_dir($dirname)) {
if (!mkdir($dirname, 0777, true)) {
throw new \RuntimeException(sprintf('Could not open "%s" to write new file',
$temporaryFilename));
}
chmod($dirname, 0777);
}
file_put_contents($temporaryFilename, $fileData);
chmod($temporaryFilename, 0777);
}
}
}
$result['new'] = $this->scanFiles($temporaryDirectory, false);
$result['upgrade'] = [];
$result['remove'] = [];
$result['productName'] = $themeName;
$result['productId'] = $productId;
$result['type'] = 'theme';
return $result;
}
public function verifyFilesystemForLanguage($param)
{
$sourceFilename = $param['filename'];
$targetDirectory = str_replace('import.zip', 'extract/',
$sourceFilename);
try {
$zipArchive = new \ZipArchive();
$zipArchive->open($sourceFilename);
$zipArchive->extractTo($targetDirectory);
$zipArchive->close();
} catch (\Exception $ex) {
throw new \RuntimeException('Missing or invalid zip filename');
}
// compare hashed files.
$result = $this->compareFiles($targetDirectory, []);
$result['targetDirectory'] = $targetDirectory;
return $result;
}
/**
* @param array $param
*
* @return array
*/
public function verifyFilesystemForModule($param)
{
if (empty($param['filename'])) {
throw new \InvalidArgumentException('Missing params [filename]');
}
$sourceFilename = $param['filename'];
$targetDirectory = $this->getTemporaryExtractProductDirectory($param);
try {
$zipArchive = new \ZipArchive();
$zipArchive->open($sourceFilename);
$zipArchive->extractTo($targetDirectory);
$zipArchive->close();
} catch (\Exception $ex) {
throw new \RuntimeException('Missing or invalid zip filename');
}
// compare hashed files.
$result = $this->compareFiles($targetDirectory, []);
register_shutdown_function(function () use ($sourceFilename) {
// unlink($filename);
});
return $result;
}
/**
* @param array $param
*
* @return array
* @throws \RuntimeException|\InvalidArgumentException
*/
public function verifyFilesystemForApp($param)
{
if (empty($param['filename']) or empty($param['productId'])) {
throw new \InvalidArgumentException('Missing params [filename, productId]');
}
$filename = $param['filename'];
$appId = $param['productId'];
$archive = new \ZipArchive();
$openResult = $archive->open($filename);
if ($openResult !== true) {
throw new \RuntimeException(sprintf('Can not open "%s"',
$filename));
}
$base = $this->getTemporaryExtractAppDirectory($param);
if (!is_dir($base)) {
if (!@mkdir($base, 0777, true)) {
throw new \RuntimeException("Could not make dir $base");
}
}
$archive->close();
$newZip = new \ZipArchive();
$newZip->open($filename);
$newZip->extractTo($base);
$newZip->close();
//Rename dir
if (isset($param['apps_dir']) && !empty($param['apps_dir'])) {
$sAppDir = $base . 'PF.Site' . PHPFOX_DS . 'Apps' . PHPFOX_DS
. $appId;
$sNewAppDir = $base . 'PF.Site' . PHPFOX_DS . 'Apps' . PHPFOX_DS
. base64_decode($param['apps_dir']);
if (is_dir($sAppDir)) {
@rename($sAppDir, $sNewAppDir);
}
}
//Delete zip file after extract
@unlink($filename);
@rmdir(dirname($filename));
$result = $this->compareFiles($base,
$old = PHPFOX_DIR_SITE . '/PF.Site/Apps/' . $appId);
register_shutdown_function(function () use ($filename) {
// unlink($filename);
});
$result['productName'] = $appId;
return $result;
}
/**
* @param array $newFileList List of new files
* @param array $oldFileList list of old files
*
* @return array [upgrade, new, remove]
*/
public function compareFileList($newFileList, $oldFileList)
{
$newFile = array_diff($newFileList, $oldFileList);
$removeFile = array_diff($oldFileList, $newFileList);
$override = array_intersect($oldFileList, $newFileList);
return [
'new' => $newFile,
'remove' => $removeFile,
'update' => $override,
];
}
/**
* @param array $newDirList
* @param array $oldDirList
*
* @return array [new: array, remove: array, update: array]
*/
public function compareFiles($newDirList, $oldDirList)
{
$oldFileList = $this->scanFiles($oldDirList, false);
$newFileList = $this->scanFiles($newDirList, false);
$newFile = array_diff($newFileList, $oldFileList);
$removeFile = array_diff($oldFileList, $newFileList);
$override = array_intersect($oldFileList, $newFileList);
return [
'new' => $newFile,
'remove' => $removeFile,
'update' => $override,
];
}
/**
* Get list all files recursive
*
* @param string $directories
* @param bool $includeParentDirectory Add parent directory to result.
*
* @return array
*/
public function scanFiles($directories, $includeParentDirectory = true)
{
if (is_string($directories)) {
$directories = [$directories];
}
$result = [];
foreach ($directories as $directory) {
$rootPath = $includeParentDirectory ? realpath(dirname($directory))
: realpath($directory);
if (!is_dir($directory)) {
continue;
}
$iterator
= new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($directory),
null);
foreach ($iterator as $fileInfo) {
if (false == $fileInfo->isFile()) {
continue;
}
$path = str_replace($rootPath, '', $fileInfo->getPathName());
$path = trim($path, DIRECTORY_SEPARATOR);
$result[] = $path;
}
}
return $result;
}
public function verifyFtpAccount()
{
if ($this->vfs == 'file_system') {
//file system don't need to check here
return true;
}
return $this->managerControl->connect();
}
public function setToPath($path)
{
$this->managerControl->setToPath($path);
}
public function deleteDir($path)
{
$this->managerControl->connect();
$this->managerControl->deleteDir($path);
}
public function deleteFile($path, $check_dir = false)
{
$this->managerControl->deleteFile($path, $check_dir);
}
/**
* @param $productName
* @param $sAppDirName
* @param $is_upgrade
*
* @return string
* @throws \Exception
*/
public function callRunInstallForApp(
$productName,
$sAppDirName,
$is_upgrade
) {
$base = realpath(PHPFOX_DIR_SITE) . PHPFOX_DS . 'Apps' . PHPFOX_DS
. $sAppDirName . PHPFOX_DS;;
$baseTemp = PHPFOX_DIR_FILE . 'static' . PHPFOX_DS . 'phpfox-app-'
. $productName . PHPFOX_DS;
//Save file app.lock in temp folder
$lockPath = $baseTemp . 'app.lock';
if (file_exists($lockPath)) {
unlink($lockPath);
}
$oApp = new App();
if (!$json = \Core\Lib::appInit($productName, $sAppDirName)) {
$json = file_get_contents($base . 'app.json');
$json = json_decode($json);
if ($is_upgrade) {
$oApp->processUpgrade($json, $base);
} else {
$oApp->processJson($json, $base);
}
} else {
if (!$json->isValid()) {
throw new \Exception(implode("\n", $json->getErrorMessages()));
}
$json->processInstall();
}
$CoreApp = new App(true);
$CoreApp->add($json->id);
$Object = $CoreApp->get($json->id);
if (!$is_upgrade) {
$internalId = 0;
$requestProduct = Phpfox::getCookie('product');
$requestAuthId = Phpfox::getCookie('auth_id');
$requestAuthKey = Phpfox::getCookie('auth_key');
if ($requestProduct) {
$product = json_decode($requestProduct);
$internalId = $product->id;
}
$oApp->makeKey($Object, $requestAuthId, $requestAuthKey,
$internalId);
}
return Phpfox::getLib('url')->makeUrl('admincp.app',
['id' => $Object->id, 'verify' => $is_upgrade]);
}
}