chore: Update copyright year from 2025 to 2026 across core files

- Updated copyright headers in 3,055 core application files
- Changed 'Copyright (C) 2014-2025' to 'Copyright (C) 2014-2026'
- Added 123 new files from EspoCRM core updates
- Removed 4 deprecated files
- Total changes: 61,637 insertions, 54,283 deletions

This is a routine maintenance update for the new year 2026.
This commit is contained in:
2026-02-07 16:05:21 +01:00
parent 6a8a4a2882
commit 127fa6503b
6468 changed files with 564781 additions and 31179 deletions

View File

@@ -0,0 +1,120 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
if (substr(php_sapi_name(), 0, 3) != 'cli') {
die('The file can be run only via CLI.');
}
$options = getopt("a:d:");
if (empty($options['a'])) {
fwrite(\STDOUT, "Error: the option [-a] is required.\n");
exit;
}
$allPostData = [];
if (!empty($options['d'])) {
parse_str($options['d'], $allPostData);
if (empty($allPostData) || !is_array($allPostData)) {
fwrite(\STDOUT, "Error: Incorrect input data.\n");
exit;
}
}
$action = $options['a'];
$allPostData['action'] = $action;
chdir(dirname(__FILE__));
set_include_path(dirname(__FILE__));
require_once('../bootstrap.php');
$_SERVER['SERVER_SOFTWARE'] = 'Cli';
require_once('core/PostData.php');
$postData = new PostData();
$postData->set($allPostData);
require_once('core/InstallerConfig.php');
$installerConfig = new InstallerConfig();
if ($installerConfig->get('isInstalled')) {
fwrite(\STDOUT, "Error: EspoCRM is already installed.\n");
exit;
}
if (session_status() != \PHP_SESSION_ACTIVE) {
if (!$installerConfig->get('cliSessionId')) {
session_start();
$installerConfig->set('cliSessionId', session_id());
$installerConfig->save();
} else {
session_id($installerConfig->get('cliSessionId'));
}
}
ob_start();
try {
require('entry.php');
} catch (\Throwable $e) {
fwrite(\STDOUT, "Error: ". $e->getMessage() .".\n");
exit;
}
$result = ob_get_contents();
ob_end_clean();
if (preg_match('/"success":false/i', $result)) {
$resultData = json_decode($result, true);
if (empty($resultData)) {
fwrite(\STDOUT, "Error: Unexpected error occurred.\n");
exit;
}
fwrite(
\STDOUT,
"Error: ". (!empty($resultData['errors']) ?
print_r($resultData['errors'], true) :
$resultData['errorMsg']) ."\n"
);
exit;
}

View File

@@ -0,0 +1,757 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
use Doctrine\DBAL\Exception as DBALException;
use Espo\Core\Application;
use Espo\Core\Container;
use Espo\Core\DataManager;
use Espo\Core\Exceptions\Error;
use Espo\Core\InjectableFactory;
use Espo\Core\ORM\DatabaseParamsFactory;
use Espo\Core\Utils\Database\ConfigDataProvider;
use Espo\Core\Utils\Database\Dbal\ConnectionFactoryFactory;
use Espo\Core\Utils\Id\RecordIdGenerator;
use Espo\Core\Utils\ScheduledJob as ScheduledJobUtil;
use Espo\Core\Utils\Util;
use Espo\Core\Utils\Config\ConfigFileManager;
use Espo\Core\Utils\Config;
use Espo\Core\Utils\Config\ConfigWriter;
use Espo\Core\Utils\Config\ConfigWriterFileManager;
use Espo\Core\Utils\Database\Helper as DatabaseHelper;
use Espo\Core\Utils\PasswordHash;
use Espo\Core\Utils\SystemRequirements;
use Espo\Core\Utils\Metadata;
use Espo\Core\Utils\File\Manager as FileManager;
use Espo\Core\Utils\Language;
use Espo\Core\Binding\BindingContainerBuilder;
use Espo\Core\ORM\EntityManager;
use Espo\Entities\Job;
use Espo\Entities\ScheduledJob;
use Espo\Entities\User;
use Espo\ORM\Query\SelectBuilder;
use Espo\Tools\Installer\DatabaseConfigDataProvider;
class Installer
{
private SystemHelper $systemHelper;
private DatabaseHelper $databaseHelper;
private InstallerConfig $installerConfig;
private DatabaseParamsFactory $databaseParamsFactory;
private ?Application $app = null;
private ?Language $language = null;
private ?PasswordHash $passwordHash;
private bool $isAuth = false;
private ?array $defaultSettings = null;
private $permittedSettingList = [
'dateFormat',
'timeFormat',
'timeZone',
'weekStart',
'defaultCurrency',
'language',
'thousandSeparator',
'decimalMark',
'outboundEmailFromName',
'outboundEmailFromAddress',
'outboundEmailIsShared',
'theme',
];
public function __construct(
private Application\ApplicationParams $applicationParams = new Application\ApplicationParams(),
) {
$this->initialize();
require_once('install/core/InstallerConfig.php');
$this->installerConfig = new InstallerConfig();
require_once('install/core/SystemHelper.php');
$this->systemHelper = new SystemHelper();
$this->databaseHelper = $this->getInjectableFactory()->create(DatabaseHelper::class);
$this->databaseParamsFactory = $this->getInjectableFactory()->create(DatabaseParamsFactory::class);
}
private function initialize(): void
{
$fileManager = new ConfigFileManager();
$config = new Config($fileManager);
$configPath = $config->getConfigPath();
if (!file_exists($configPath)) {
$fileManager->putPhpContents($configPath, []);
$config->update();
}
$defaultData = include('application/Espo/Resources/defaults/config.php');
$configData = [];
foreach (array_keys($defaultData) as $key) {
if (!$config->has($key)) {
continue;
}
$configData[$key] = $config->get($key);
}
$configWriterFileManager = new ConfigWriterFileManager(
null,
$config->get('defaultPermissions') ?? null
);
$injectableFactory = (new Application($this->applicationParams))
->getContainer()
->getByClass(InjectableFactory::class);
$configWriter = $injectableFactory->createWithBinding(
ConfigWriter::class,
BindingContainerBuilder::create()
->bindInstance(Config::class, $config)
->bindInstance(ConfigWriterFileManager::class, $configWriterFileManager)
->build()
);
// Save default data if it does not exist.
if (!Util::arrayKeysExists(array_keys($defaultData), $configData)) {
$defaultData = array_replace_recursive($defaultData, $configData);
$configWriter->setMultiple($defaultData);
$configWriter->save();
}
$this->app = new Application($this->applicationParams);
}
private function getContainer(): Container
{
return $this->app->getContainer();
}
private function getEntityManager(): EntityManager
{
return $this->getContainer()->getByClass(EntityManager::class);
}
public function getMetadata(): Metadata
{
return $this->app->getContainer()->getByClass(Metadata::class);
}
public function getInjectableFactory(): InjectableFactory
{
return $this->app->getContainer()->getByClass(InjectableFactory::class);
}
public function getConfig(): Config
{
return $this->app->getContainer()->getByClass(Config::class);
}
public function createConfigWriter(): ConfigWriter
{
return $this->getInjectableFactory()->create(ConfigWriter::class);
}
private function getSystemHelper(): SystemHelper
{
return $this->systemHelper;
}
private function getInstallerConfig(): InstallerConfig
{
return $this->installerConfig;
}
private function getFileManager(): FileManager
{
return $this->app->getContainer()->getByClass(FileManager::class);
}
private function getPasswordHash(): PasswordHash
{
if (!isset($this->passwordHash)) {
$this->passwordHash = $this->getInjectableFactory()->create(PasswordHash::class);
}
return $this->passwordHash;
}
public function getVersion(): ?string
{
return $this->getConfig()->get('version');
}
private function auth(): void
{
if (!$this->isAuth) {
$this->app->setupSystemUser();
$this->isAuth = true;
}
}
public function isInstalled(): bool
{
$installerConfig = $this->getInstallerConfig();
if ($installerConfig->get('isInstalled')) {
return true;
}
return $this->app->isInstalled();
}
public function createLanguage(string $language): Language
{
return $this->getInjectableFactory()
->createWith(Language::class, ['language' => $language]);
}
public function getLanguage(): Language
{
if (!isset($this->language)) {
try {
$language = $this->app->getContainer()->get('defaultLanguage');
if (!$language instanceof Language) {
throw new RuntimeException("Can't get default language.");
}
$this->language = $language;
} catch (Throwable $e) {
echo "Error: " . $e->getMessage();
$GLOBALS['log']->error($e->getMessage());
die;
}
}
return $this->language;
}
public function getThemeList(): array
{
return [
'Espo',
'Dark',
'Light',
'Glass',
'Violet',
'Sakura',
'Hazyblue',
];
}
public function getLanguageList($isTranslated = true): array
{
$languageList = $this->getMetadata()->get(['app', 'language', 'list']);
if ($isTranslated) {
return $this->getLanguage()->translate('language', 'options', 'Global', $languageList);
}
return $languageList;
}
private function getCurrencyList(): array
{
return $this->getMetadata()->get('app.currency.list');
}
public function getInstallerConfigData()
{
return $this->getInstallerConfig()->getAllData();
}
public function getSystemRequirementList($type, $requiredOnly = false, array $additionalData = null)
{
$platform = $additionalData['databaseParams']['platform'] ?? 'Mysql';
$dbConfigDataProvider = new DatabaseConfigDataProvider($platform);
/** @var SystemRequirements $systemRequirementManager */
$systemRequirementManager = $this->app
->getContainer()
->getByClass(InjectableFactory::class)
->createWithBinding(
SystemRequirements::class,
BindingContainerBuilder::create()
->bindInstance(ConfigDataProvider::class, $dbConfigDataProvider)
->build()
);
return $systemRequirementManager->getRequiredListByType($type, $requiredOnly, $additionalData);
}
/**
* @throws DBALException
* @throws Exception
*/
public function checkDatabaseConnection(array $rawParams, bool $createDatabase = false): void
{
$params = $this->databaseParamsFactory->createWithMergedAssoc($rawParams);
$dbname = $params->getName();
try {
$this->databaseHelper->createPDO($params);
} catch (Exception $e) {
if (!$createDatabase) {
throw $e;
}
if ((int) $e->getCode() !== 1049) {
throw $e;
}
/** @noinspection RegExpRedundantEscape */
if ($dbname !== preg_replace('/[^A-Za-z0-9_\-@$#\(\)]+/', '', $dbname)) {
throw new Exception("Bad database name.");
}
$params = $params->withName(null);
$pdo = $this->databaseHelper->createPDO($params);
$connectionFactoryFactory = $this->getInjectableFactory()->create(ConnectionFactoryFactory::class);
$connection = $connectionFactoryFactory
->create($params->getPlatform(), $pdo)
->create($params);
$schemaManager = $connection->createSchemaManager();
$platform = $connection->getDatabasePlatform();
$schemaManager->createDatabase($platform->quoteIdentifier($dbname));
$this->checkDatabaseConnection($rawParams);
}
}
/**
* Save data.
*
* @param array<string, mixed> $saveData
* [
* 'driver' => 'pdo_mysql',
* 'host' => 'localhost',
* 'dbname' => 'espocrm_test',
* 'user' => 'root',
* 'password' => '',
* ]
* @return bool
*/
public function saveData(array $saveData)
{
$initData = include('install/core/afterInstall/config.php');
$databaseDefaults = $this->app
->getContainer()
->getByClass(Config::class)
->get('database');
$siteUrl = !empty($saveData['siteUrl']) ? $saveData['siteUrl'] : $this->getSystemHelper()->getBaseUrl();
$data = [
'database' => array_merge($databaseDefaults, $saveData['database']),
'language' => $saveData['language'] ?? 'en_US',
'siteUrl' => $siteUrl,
'cryptKey' => Util::generateSecretKey(),
'hashSecretKey' => Util::generateSecretKey(),
'theme' => $saveData['theme'] ?? 'Espo',
];
if (empty($saveData['defaultPermissions']['user'])) {
$saveData['defaultPermissions']['user'] = $this->getFileManager()
->getPermissionUtils()
->getDefaultOwner(true);
}
if (empty($saveData['defaultPermissions']['group'])) {
$saveData['defaultPermissions']['group'] = $this->getFileManager()
->getPermissionUtils()
->getDefaultGroup(true);
}
if (!empty($saveData['defaultPermissions']['user'])) {
$data['defaultPermissions']['user'] = $saveData['defaultPermissions']['user'];
}
if (!empty($saveData['defaultPermissions']['group'])) {
$data['defaultPermissions']['group'] = $saveData['defaultPermissions']['group'];
}
return $this->saveConfig(array_merge($data, $initData));
}
public function saveConfig($data)
{
$configWriter = $this->createConfigWriter();
$configWriter->setMultiple($data);
$configWriter->save();
return true;
}
/**
* @throws Error
*/
public function rebuild(): void
{
try {
$this->app->getContainer()->getByClass(DataManager::class)->rebuild();
} catch (Exception) {
$this->auth();
$this->app->getContainer()->getByClass(DataManager::class)->rebuild();
}
}
public function savePreferences(array $rawPreferences)
{
$preferences = $this->normalizeSettingParams($rawPreferences);
$currencyList = $this->getConfig()->get('currencyList', []);
if (
isset($preferences['defaultCurrency']) &&
!in_array($preferences['defaultCurrency'], $currencyList)
) {
$preferences['currencyList'] = [$preferences['defaultCurrency']];
$preferences['baseCurrency'] = $preferences['defaultCurrency'];
}
return $this->saveConfig($preferences);
}
private function createRecords(): void
{
$records = include('install/core/afterInstall/records.php');
foreach ($records as $entityName => $recordList) {
foreach ($recordList as $data) {
$this->createRecord($entityName, $data);
}
}
}
private function createRecord(string $entityType, array $data): void
{
$id = $data['id'] ?? null;
$entity = null;
$em = $this->getEntityManager();
if ($id) {
$entity = $em->getEntityById($entityType, $id);
if (!$entity) {
$selectQuery = $em->getQueryBuilder()
->select('id')
->from($entityType)
->withDeleted()
->where(['id' => $id])
->build();
$entity = $em->getRDBRepository($entityType)
->clone($selectQuery)
->findOne();
if ($entity) {
$updateQuery = $em->getQueryBuilder()
->update()
->in($entityType)
->set(['deleted' => false])
->where(['id' => $id])
->build();
$em->getQueryExecutor()->execute($updateQuery);
$em->refreshEntity($entity);
}
}
}
if (!$entity) {
if (isset($data['name'])) {
$entity = $this->getEntityManager()
->getRDBRepository($entityType)
->where(['name' => $data['name']])
->findOne();
}
if (!$entity) {
$entity = $this->getEntityManager()->getNewEntity($entityType);
}
}
$entity->set($data);
$this->getEntityManager()->saveEntity($entity);
}
public function createUser(string $userName, string $password): bool
{
$this->auth();
$password = $this->getPasswordHash()->hash($password);
$user = $this->getEntityManager()
->getRDBRepositoryByClass(User::class)
->clone(
SelectBuilder::create()
->from(User::ENTITY_TYPE)
->withDeleted()
->build()
)
->where(['userName' => $userName])
->findOne();
if ($user) {
$user->set([
'password' => $password,
'deleted' => false,
]);
$this->getEntityManager()->saveEntity($user);
}
if (!$user) {
$id = $this->getInjectableFactory()
->createResolved(RecordIdGenerator::class)
->generate();
$this->createRecord(User::ENTITY_TYPE, [
'id' => $id,
'userName' => $userName,
'password' => $password,
'lastName' => 'Admin',
'type' => User::TYPE_ADMIN,
]);
}
return true;
}
public function checkPermission(): bool
{
return $this->getFileManager()->getPermissionUtils()->setMapPermission();
}
public function getLastPermissionError()
{
return $this->getFileManager()->getPermissionUtils()->getLastErrorRules();
}
public function setSuccess(): void
{
$this->auth();
$this->createRecords();
$this->executeFinalScript();
$installerConfig = $this->getInstallerConfig();
$installerConfig->set('isInstalled', true);
$installerConfig->save();
$configWriter = $this->createConfigWriter();
$configWriter->set('isInstalled', true);
$configWriter->save();
}
/**
* @return array<string, mixed>
*/
public function getDefaultSettings(): array
{
if (!$this->defaultSettings) {
$settingDefs = $this->getMetadata()->get('entityDefs.Settings.fields');
$defaults = [];
foreach ($this->permittedSettingList as $fieldName) {
if (!isset($settingDefs[$fieldName])) {
continue;
}
switch ($fieldName) {
case 'defaultCurrency':
$settingDefs['defaultCurrency']['options'] = $this->getCurrencyList();
break;
case 'language':
$settingDefs['language']['options'] = $this->getLanguageList(false);
break;
case 'theme':
$settingDefs['theme']['options'] = $this->getThemeList();
break;
}
$defaults[$fieldName] = $this->translateSetting($fieldName, $settingDefs[$fieldName]);
}
$this->defaultSettings = $defaults;
}
return $this->defaultSettings;
}
private function normalizeSettingParams(array $params)
{
$defaultSettings = $this->getDefaultSettings();
$normalizedParams = [];
foreach ($params as $name => $value) {
if (!isset($defaultSettings[$name])) {
continue;
}
$paramDefs = $defaultSettings[$name];
$paramType = $paramDefs['type'] ?? 'varchar';
switch ($paramType) {
case 'enum':
if (
isset($paramDefs['options']) && array_key_exists($value, $paramDefs['options']) ||
!isset($paramDefs['options'])
) {
$normalizedParams[$name] = $value;
} else if (array_key_exists('default', $paramDefs)) {
$normalizedParams[$name] = $paramDefs['default'];
$GLOBALS['log']->warning(
'Incorrect value ['. $value .'] for Settings parameter ['. $name .']. ' .
'Use default value ['. $paramDefs['default'] .'].'
);
}
break;
case 'bool':
$normalizedParams[$name] = (bool) $value;
break;
case 'int':
case 'enumInt':
$normalizedParams[$name] = (int) $value;
break;
case 'varchar':
default:
$normalizedParams[$name] = $value;
break;
}
}
return $normalizedParams;
}
private function translateSetting($name, array $settingDefs)
{
if (!isset($settingDefs['options'])) {
return $settingDefs;
}
$translation = !empty($settingDefs['translation'])
? explode('.', $settingDefs['translation']) : null;
$label = $translation[2] ?? $name;
$category = $translation[1] ?? 'options';
$scope = $translation[0] ?? 'Settings';
$translatedOptions = $this->getLanguage()
->translate($label, $category, $scope, $settingDefs['options']);
if ($translatedOptions == $name) {
$translatedOptions = $this->getLanguage()
->translate($name, 'options', 'Global', $settingDefs['options']);
}
if ($translatedOptions == $name) {
$translatedOptions = [];
foreach ($settingDefs['options'] as $value) {
$translatedOptions[$value] = $value;
}
}
$settingDefs['options'] = $translatedOptions;
return $settingDefs;
}
public function getCronMessage(): array
{
return $this->getInjectableFactory()
->create(ScheduledJobUtil::class)
->getSetupMessage();
}
private function executeFinalScript(): void
{
$this->prepareDummyJob();
}
private function prepareDummyJob(): void
{
$scheduledJob = $this->getEntityManager()
->getRDBRepository(ScheduledJob::ENTITY_TYPE)
->where(['job' => 'Dummy'])
->findOne();
if (!$scheduledJob) {
return;
}
$this->getEntityManager()->createEntity(Job::ENTITY_TYPE, [
'name' => 'Dummy',
'scheduledJobId' => $scheduledJob->getId(),
]);
}
public function getLogoSrc(string $theme): string
{
return $this->getMetadata()->get(['themes', $theme, 'logo']) ?? 'client/img/logo.svg';
}
}

View File

@@ -0,0 +1,122 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
class InstallerConfig
{
private $data;
private $fileManager;
protected $configPath = 'install/config.php'; //full path: install/config.php
public function __construct()
{
$this->fileManager = new \Espo\Core\Utils\File\Manager();
}
protected function getFileManager()
{
return $this->fileManager;
}
protected function getContainer()
{
return $this->container;
}
protected function loadData()
{
if (file_exists($this->configPath)) {
$data = include($this->configPath);
if (is_array($data)) {
return $data;
}
}
return [];
}
public function getAllData()
{
if (!$this->data) {
$this->data = $this->loadData();
}
return $this->data;
}
public function get($name, $default = [])
{
if (!$this->data) {
$this->data = $this->loadData();
}
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
return $default;
}
public function set($name, $value = null)
{
if (!is_array($name)) {
$name = array($name => $value);
}
foreach ($name as $key => $value) {
$this->data[$key] = $value;
}
}
public function save()
{
$data = $this->loadData();
if (is_array($this->data)) {
foreach ($this->data as $key => $value) {
$data[$key] = $value;
}
}
try {
$result = $this->getFileManager()->putPhpContents($this->configPath, $data);
} catch (\Exception $e) {
$GLOBALS['log']->warning($e->getMessage());
$result = false;
}
if ($result) {
$this->data = null;
}
return $result;
}
}

View File

@@ -0,0 +1,158 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
class Language{
private $defaultLanguage = 'en_US';
private $systemHelper;
private $data = array();
protected $defaultLabels = [
'nginx' => 'linux',
'apache' => 'linux',
'microsoft-iis' => 'windows',
];
public function __construct()
{
require_once 'SystemHelper.php';
$this->systemHelper = new SystemHelper();
}
protected function getSystemHelper()
{
return $this->systemHelper;
}
public function get($language)
{
if (isset($this->data[$language])) {
return $this->data[$language];
}
if (empty($language)) {
$language = $this->defaultLanguage;
}
$langFileName = 'install/core/i18n/'.$language.'/install.json';
if (!file_exists($langFileName)) {
$langFileName = 'install/core/i18n/'.$this->defaultLanguage.'/install.json';
}
$i18n = $this->getLangData($langFileName);
if ($language != $this->defaultLanguage) {
$i18n = $this->mergeWithDefaults($i18n);
}
$this->afterRetrieve($i18n);
$this->data[$language] = $i18n;
return $this->data[$language];
}
/**
* Merge current language with default one
*
* @param array $data
* @return array
*/
protected function mergeWithDefaults($data)
{
$defaultLangFile = 'install/core/i18n/'.$this->defaultLanguage.'/install.json';
$defaultData = $this->getLangData($defaultLangFile);
foreach ($data as $categoryName => &$labels) {
foreach ($defaultData[$categoryName] as $defaultLabelName => $defaultLabel) {
if (!isset($labels[$defaultLabelName])) {
$labels[$defaultLabelName] = $defaultLabel;
}
}
}
$data = array_merge($defaultData, $data);
return $data;
}
protected function getLangData($filePath)
{
$data = file_get_contents($filePath);
$data = json_decode($data, true);
return $data;
}
/**
* After retrieve actions
*
* @param array $i18n
* @return array $i18n
*/
protected function afterRetrieve(array &$i18n)
{
/** Get rewrite rules */
$serverType = $this->getSystemHelper()->getServerType();
$serverOs = $this->getSystemHelper()->getOs();
$rewriteRules = $this->getSystemHelper()->getRewriteRules();
$label = $i18n['options']['modRewriteInstruction'][$serverType][$serverOs] ?? null;
if (!isset($label) && isset($this->defaultLabels[$serverType])) {
$defaultLabel = $this->defaultLabels[$serverType];
if (!isset($i18n['options']['modRewriteInstruction'][$serverType][$defaultLabel])) {
$defaultLangFile = 'install/core/i18n/' . $this->defaultLanguage . '/install.json';
$defaultData = $this->getLangData($defaultLangFile);
$i18n['options']['modRewriteInstruction'][$serverType][$defaultLabel] = $defaultData['options']['modRewriteInstruction'][$serverType][$defaultLabel];
}
$label = $i18n['options']['modRewriteInstruction'][$serverType][$defaultLabel];
}
if (!$label) {
return;
}
preg_match_all('/\{(.*?)\}/', $label, $match);
if (isset($match[1])) {
foreach ($match[1] as $varName) {
if (isset($rewriteRules[$varName])) {
$label = str_replace('{'.$varName.'}', $rewriteRules[$varName], $label);
}
}
}
$i18n['options']['modRewriteInstruction'][$serverType][$serverOs] = $label;
}
}

View File

@@ -0,0 +1,72 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
class PostData
{
protected $data = [];
public function __construct()
{
$this->init();
}
protected function init()
{
if (isset($_POST) && is_array($_POST)) {
$this->data = $_POST;
}
}
public function set($name, $value = null)
{
if (!is_array($name)) {
$name = [
$name => $value
];
}
foreach ($name as $key => $value) {
$this->data[$key] = $value;
}
}
public function get($name, $default = null)
{
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
return $default;
}
public function getAll()
{
return $this->data;
}
}

View File

@@ -0,0 +1,268 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
use Espo\Core\Utils\File\Manager;
use Espo\Core\Utils\File\Permission;
use Espo\Core\Utils\System;
class SystemHelper extends System
{
protected $config;
protected $mainConfig;
protected $apiPath;
protected $modRewriteUrl = '/';
protected $writableDir = 'data';
protected $combineOperator = '&&';
protected $writableMap;
public function __construct()
{
$this->config = include('config.php');
if (file_exists('data/config.php')) {
$this->mainConfig = include('data/config.php');
}
$this->apiPath = $this->config['apiPath'];
$permission = new Permission(new Manager());
$this->writableMap = $permission->getWritableMap();
}
public function initWritable()
{
if (is_writable($this->writableDir)) {
return true;
}
return false;
}
public function getWritableDir()
{
return $this->writableDir;
}
public function getBaseUrl()
{
$pageUrl = 'http://';
if (isset($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] == 'https') {
$pageUrl = 'https://';
}
if (isset($_SERVER['HTTPS']) && $_SERVER["HTTPS"] == 'on') {
$pageUrl = 'https://';
}
if ($_SERVER["SERVER_PORT"] == '443') {
$pageUrl = 'https://';
}
if (in_array($_SERVER["SERVER_PORT"], ['80', '443'])) {
$pageUrl .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
} else {
$pageUrl .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
}
return str_ireplace('/install/index.php', '', $pageUrl);
}
public function getApiPath()
{
return $this->apiPath;
}
public function getModRewriteUrl()
{
return $this->apiPath . $this->modRewriteUrl;
}
public function getChownCommand($path, $isSudo = false, $isCd = true)
{
$path = empty($path) ? '.' : $path;
if (is_array($path)) {
$path = implode(' ', $path);
}
$owner = function_exists('posix_getuid') ? posix_getuid() : null;
$group = function_exists('posix_getegid') ? posix_getegid() : null;
$sudoStr = $isSudo ? 'sudo ' : '';
if (empty($owner) || empty($group)) {
return null;
}
$cd = '';
if ($isCd) {
$cd = $this->getCd(true);
}
return $cd.$sudoStr.'chown -R '.$owner.':'.$group.' '.$path;
}
public function getChmodCommand($path, $permissions = ['755'], $isRecursive = true, $isSudo = false, $isFile = null)
{
$path = empty($path) ? '.' : $path;
if (is_array($path)) {
$path = implode(' ', $path);
}
$sudoStr = $isSudo ? 'sudo ' : '';
if (is_string($permissions)) {
$permissions = (array) $permissions;
}
if (!isset($isFile) && count($permissions) == 1) {
if ($isRecursive) {
return $sudoStr . 'find '. $path .' -type d -exec ' . $sudoStr . 'chmod '. $permissions[0] .' {} +';
}
return $sudoStr . 'chmod '. $permissions[0] .' '. $path;
}
$bufPerm = (count($permissions) == 1) ? array_fill(0, 2, $permissions[0]) : $permissions;
$commands = array();
if ($isRecursive) {
$commands[] = $sudoStr. 'find '.$path.' -type f -exec ' .$sudoStr.'chmod '.$bufPerm[0].' {} +';
$commands[] = $sudoStr . 'find '.$path.' -type d -exec ' .$sudoStr. 'chmod '.$bufPerm[1].' {} +';
} else {
if (file_exists($path) && is_file($path)) {
$commands[] = $sudoStr. 'chmod '. $bufPerm[0] .' '. $path;
} else {
$commands[] = $sudoStr. 'chmod '. $bufPerm[1] .' '. $path;
}
}
if (count($permissions) >= 2) {
return implode(' ' . $this->combineOperator . ' ', $commands);
}
return $isFile ? $commands[0] : $commands[1];
}
private function getFullPath($path)
{
if (is_array($path)) {
$pathList = [];
foreach ($path as $pathItem) {
$pathList[] = $this->getFullPath($pathItem);
}
return $pathList;
}
if (!empty($path)) {
$path = DIRECTORY_SEPARATOR . $path;
}
return $this->getRootDir() . $path;
}
/**
* Get permission commands
*
* @param string|array $path
* @param string|array $permissions
* @param boolean $isSudo
* @param bool $isFile
* @return string
*/
public function getPermissionCommands(
$path,
$permissions = ['644', '755'],
$isSudo = false,
$isFile = null,
$changeOwner = true,
$isCd = true
) {
if (is_string($path)) {
$path = array_fill(0, 2, $path);
}
[$chmodPath, $chownPath] = $path;
$commands = array();
if ($isCd) {
$commands[] = $this->getCd();
}
$chmodPath = (array) $chmodPath;
$pathList = [];
$recursivePathList = [];
foreach ($chmodPath as $pathItem) {
if (isset($this->writableMap[$pathItem]) && !$this->writableMap[$pathItem]['recursive']) {
$pathList[] = $pathItem;
continue;
}
$recursivePathList[] = $pathItem;
}
if (!empty($pathList)) {
$commands[] = $this->getChmodCommand($pathList, $permissions, false, $isSudo, $isFile);
}
if (!empty($recursivePathList)) {
$commands[] = $this->getChmodCommand($recursivePathList, $permissions, true, $isSudo, $isFile);
}
if ($changeOwner) {
$chown = $this->getChownCommand($chownPath, $isSudo, false);
if (isset($chown)) {
$commands[] = $chown;
}
}
return implode(' ' . $this->combineOperator . ' ', $commands).';';
}
protected function getCd($isCombineOperator = false)
{
$cd = 'cd '.$this->getRootDir();
if ($isCombineOperator) {
$cd .= ' '.$this->combineOperator.' ';
}
return $cd;
}
public function getRewriteRules()
{
return $this->config['rewriteRules'];
}
}

View File

@@ -0,0 +1,55 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
class Utils
{
static public $actionPath = 'install/core/actions';
static public function checkActionExists(string $actionName): bool
{
return in_array($actionName, [
'saveSettings',
'buildDatabase',
'checkPermission',
'createUser',
'errors',
'finish',
'main',
'saveEmailSettings',
'savePreferences',
'settingsTest',
'setupConfirmation',
'step1',
'step2',
'step3',
'step4',
'step5',
]);
}
}

View File

@@ -0,0 +1,36 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
ob_start();
$result = array('success' => true, 'errorMsg' => '');
$installer->rebuild();
ob_clean();
echo json_encode($result);

View File

@@ -0,0 +1,76 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
ob_start();
$result = ['success' => true, 'errorMsg' => ''];
if (!$installer->checkPermission()) {
$result['success'] = false;
$error = $installer->getLastPermissionError();
$urls = array_keys($error);
$group = [];
foreach ($error as $folder => $permission) {
$group[implode('-', $permission)][] = $folder;
}
ksort($group);
$instruction = '';
$instructionSU = '';
$changeOwner = true;
foreach($group as $permission => $folders) {
if ($permission == '0644-0755') {
$folders = '';
}
$instruction .= $systemHelper
->getPermissionCommands([$folders, ''], explode('-', $permission), false, null, $changeOwner) . "<br>";
$instructionSU .= $systemHelper
->getPermissionCommands([$folders, ''], explode('-', $permission), true, null, $changeOwner) . "<br>";
if ($changeOwner) {
$changeOwner = false;
}
}
$result['errorMsg'] = $langs['messages']['Permission denied to'] . ':<br><pre>'.implode('<br>', $urls).'</pre>';
$result['errorFixInstruction'] =
str_replace( '"{C}"' , $instruction, $langs['messages']['permissionInstruction']) .
"<br>" . str_replace( '{CSU}' , $instructionSU, $langs['messages']['operationNotPermitted']);
}
ob_clean();
echo json_encode($result);

View File

@@ -0,0 +1,49 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
ob_start();
$result = ['success' => false, 'errorMsg' => ''];
// create user
if (!empty($_SESSION['install']['user-name']) && !empty($_SESSION['install']['user-pass'])) {
$userId = $installer->createUser($_SESSION['install']['user-name'], $_SESSION['install']['user-pass']);
if (!empty($userId)) {
$result['success'] = true;
} else {
$result['success'] = false;
$result['errorMsg'] = 'Cannot create user';
}
} else {
$result['success'] = false;
$result['errorMsg'] = 'Cannot create user';
}
ob_clean();
echo json_encode($result);

View File

@@ -0,0 +1,30 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/

View File

@@ -0,0 +1,38 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
$cronMessage = $installer->getCronMessage();
$smarty->assign('cronTitle', $cronMessage['message']);
$smarty->assign('cronHelp', $cronMessage['command']);
$installer->setSuccess();
// clean session
session_unset();

View File

@@ -0,0 +1,58 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
$config = $installer->getConfig();
$fields = [
'user-lang' => [
'default' => $config->get('language', 'en_US'),
],
'theme' => [
'default' => $config->get('theme'),
],
];
foreach ($fields as $fieldName => $field) {
if (isset($_SESSION['install'][$fieldName])) {
$fields[$fieldName]['value'] = $_SESSION['install'][$fieldName];
} else {
$fields[$fieldName]['value'] = (isset($field['default']))? $field['default'] : '';
}
}
$language = $installer->createLanguage($_SESSION['install']['user-lang'] ?? 'en_US');
$themes = [];
foreach ($installer->getThemeList() as $item) {
$themes[$item] = $language->translate($item, 'themes', 'Global');
}
$smarty->assign('themeLabel', $language->translate('theme', 'fields', 'Settings'));
$smarty->assign('fields', $fields);
$smarty->assign("themes", $themes);

View File

@@ -0,0 +1,74 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
ob_start();
$result = ['success' => false, 'errorMsg' => ''];
if (!empty($_SESSION['install'])) {
$paramList = [
'outboundEmailFromName',
'outboundEmailFromAddress',
'outboundEmailIsShared',
];
$preferences = [];
foreach ($paramList as $paramName) {
switch ($paramName) {
case 'outboundEmailIsShared':
$preferences['outboundEmailIsShared'] = $_SESSION['install']['outboundEmailIsShared'] === 'true';
break;
default:
if (array_key_exists($paramName, $_SESSION['install'])) {
$preferences[$paramName] = $_SESSION['install'][$paramName];
}
break;
}
}
$res = $installer->savePreferences($preferences);
if (!empty($res)) {
$result['success'] = true;
} else {
$result['success'] = false;
$result['errorMsg'] = 'Cannot save preferences';
}
} else {
$result['success'] = false;
$result['errorMsg'] = 'Cannot save preferences';
}
ob_clean();
echo json_encode($result);

View File

@@ -0,0 +1,66 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
ob_start();
$result = array('success' => false, 'errorMsg' => '');
if (!empty($_SESSION['install'])) {
$paramList = [
'dateFormat',
'timeFormat',
'timeZone',
'weekStart',
'defaultCurrency',
'thousandSeparator',
'decimalMark',
'language',
];
$preferences = [];
foreach ($paramList as $paramName) {
if (array_key_exists($paramName, $_SESSION['install'])) {
$preferences[$paramName] = $_SESSION['install'][$paramName];
}
}
$res = $installer->savePreferences($preferences);
if (!empty($res)) {
$result['success'] = true;
} else {
$result['success'] = false;
$result['errorMsg'] = 'Cannot save preferences';
}
}
else {
$result['success'] = false;
$result['errorMsg'] = 'Cannot save preferences';
}
ob_clean();
echo json_encode($result);

View File

@@ -0,0 +1,76 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
ob_start();
$result = [
'success' => true,
'errorMsg' => '',
];
// save settings
$database = [
'dbname' => $_SESSION['install']['db-name'],
'user' => $_SESSION['install']['db-user-name'],
'password' => $_SESSION['install']['db-user-password'],
'platform' => $_SESSION['install']['db-platform'] ?? 'Mysql',
];
$host = $_SESSION['install']['host-name'];
if (!str_contains($host, ':')) {
$host .= ":";
}
[$database['host'], $database['port']] = explode(':', $host);
$saveData = [
'database' => $database,
'language' => !empty($_SESSION['install']['user-lang']) ? $_SESSION['install']['user-lang'] : 'en_US',
'siteUrl' => !empty($_SESSION['install']['site-url']) ? $_SESSION['install']['site-url'] : null,
];
if (!empty($_SESSION['install']['theme'])) {
$saveData['theme'] = $_SESSION['install']['theme'];
}
if (!empty($_SESSION['install']['default-permissions-user']) && !empty($_SESSION['install']['default-permissions-group'])) {
$saveData['defaultPermissions'] = [
'user' => $_SESSION['install']['default-permissions-user'],
'group' => $_SESSION['install']['default-permissions-group'],
];
}
if (!$installer->saveData($saveData)) {
$result['success'] = false;
$result['errorMsg'] = $langs['messages']['Can not save settings'];
}
ob_clean();
echo json_encode($result);

View File

@@ -0,0 +1,131 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
ob_start();
$result = [
'success' => true,
'errors' => [],
];
$phpRequiredList = $installer->getSystemRequirementList('php', true);
foreach ($phpRequiredList as $name => $details) {
if (!$details['acceptable']) {
switch ($details['type']) {
case 'version':
$result['success'] = false;
$result['errors']['phpVersion'] = $details['required'];
break;
default:
$result['success'] = false;
$result['errors']['phpRequires'][] = $name;
break;
}
}
}
$allPostData = $postData->getAll();
if (
$result['success'] &&
!empty($allPostData['dbName']) &&
!empty($allPostData['hostName']) &&
!empty($allPostData['dbUserName'])
) {
$connect = false;
$dbName = trim($allPostData['dbName']);
if (!str_contains($allPostData['hostName'], ':')) {
$allPostData['hostName'] .= ":";
}
[$hostName, $port] = explode(':', trim($allPostData['hostName']));
$dbUserName = trim($allPostData['dbUserName']);
$dbUserPass = trim($allPostData['dbUserPass']);
if (!$port) {
$port = null;
}
$platform = $allPostData['dbPlatform'] ?? 'Mysql';
$databaseParams = [
'platform' => $platform,
'host' => $hostName,
'port' => $port,
'user' => $dbUserName,
'password' => $dbUserPass,
'dbname' => $dbName,
];
$isConnected = true;
try {
$installer->checkDatabaseConnection($databaseParams, true);
} catch (\Exception $e) {
$isConnected = false;
$result['success'] = false;
$result['errors']['dbConnect']['errorCode'] = $e->getCode();
$result['errors']['dbConnect']['errorMsg'] = $e->getMessage();
}
if ($isConnected) {
$databaseRequiredList = $installer
->getSystemRequirementList('database', true, ['databaseParams' => $databaseParams]);
foreach ($databaseRequiredList as $name => $details) {
if (!$details['acceptable']) {
switch ($details['type']) {
case 'version':
$result['success'] = false;
$result['errors'][$name] = $details['required'];
break;
default:
$result['success'] = false;
$result['errors'][$name][] = $name;
break;
}
}
}
}
}
ob_clean();
echo json_encode($result);

View File

@@ -0,0 +1,49 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
$phpRequirementList = $installer->getSystemRequirementList('php');
$smarty->assign('phpRequirementList', $phpRequirementList);
$installData = $_SESSION['install'];
$hostData = explode(':', $installData['host-name']);
$dbConfig = [
'host' => $hostData[0] ?? '',
'port' => $hostData[1] ?? '',
'dbname' => $installData['db-name'],
'user' => $installData['db-user-name'],
'password' => $installData['db-user-password'],
'platform' => $installData['db-platform'] ?? null,
];
$mysqlRequirementList = $installer->getSystemRequirementList('database', false, ['databaseParams' => $dbConfig]);
$smarty->assign('mysqlRequirementList', $mysqlRequirementList);
$permissionRequirementList = $installer->getSystemRequirementList('permission');
$smarty->assign('permissionRequirementList', $permissionRequirementList);

View File

@@ -0,0 +1,49 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
$fields = array(
'license-agree' => array(
'default' => '0',
),
);
foreach ($fields as $fieldName => $field) {
if (isset($_SESSION['install'][$fieldName])) {
$fields[$fieldName]['value'] = $_SESSION['install'][$fieldName];
} else {
$fields[$fieldName]['value'] = (isset($fields[$fieldName]['default']))? $fields[$fieldName]['default'] : '';
}
}
$smarty->assign('fields', $fields);
if (file_exists("LICENSE.txt")) {
$license = file_get_contents('LICENSE.txt');
$smarty->assign('license', $license);
}

View File

@@ -0,0 +1,81 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
$clearedCookieList = [
'auth-token-secret',
'auth-username',
'auth-token',
];
foreach ($clearedCookieList as $cookieName) {
if (!isset($_COOKIE[$cookieName])) {
continue;
}
setcookie($cookieName, null, -1, '/');
}
$config = $installer->getConfig();
$fields = [
'db-platform' => [
'default' => $config->get('database.platform', 'Mysql'),
],
'db-driver' => [
'default' => $config->get('database.driver', ''),
],
'db-name' => [
'default' => $config->get('database.dbname', ''),
],
'host-name' => [
'default' => $config->get('database.host', '') .
($config->get('database.port') ? ':' . $config->get('database.port') : ''),
],
'db-user-name' => [
'default' => $config->get('database.user', ''),
],
'db-user-password' => [],
];
foreach ($fields as $fieldName => $field) {
if (isset($_SESSION['install'][$fieldName])) {
$fields[$fieldName]['value'] = $_SESSION['install'][$fieldName];
} else {
$fields[$fieldName]['value'] = $field['default'] ?? '';
}
}
$platforms = [
'Mysql' => 'MySQL / MariaDB',
'Postgresql' => 'PostgreSQL',
];
$smarty->assign('platforms', $platforms);
$smarty->assign('fields', $fields);

View File

@@ -0,0 +1,46 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
$fields = array(
'user-name' => array(
'default' => (isset($langs['labels']['admin']))? $langs['labels']['admin'] : 'admin',
),
'user-pass' => array(),
'user-confirm-pass' => array(),
);
foreach ($fields as $fieldName => $field) {
if (isset($_SESSION['install'][$fieldName])) {
$fields[$fieldName]['value'] = $_SESSION['install'][$fieldName];
} else {
$fields[$fieldName]['value'] = (isset($fields[$fieldName]['default']))? $fields[$fieldName]['default'] : '';
}
}
$smarty->assign('fields', $fields);

View File

@@ -0,0 +1,72 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
$config = $installer->getConfig();
$metadata = $installer->getMetadata();
$fields = [
'dateFormat' => [
'default' => $config->get('dateFormat'),
'options' => $metadata->get(['app', 'dateTime', 'dateFormatList']) ?? [],
],
'timeFormat' => [
'default'=> $config->get('timeFormat'),
'options' => $metadata->get(['app', 'dateTime', 'timeFormatList']) ?? [],
],
'timeZone' => [
'default'=> $config->get('timeZone', 'UTC'),
],
'weekStart' => [
'default'=> $config->get('weekStart', 0),
],
'defaultCurrency' => [
'default' => $config->get('defaultCurrency', 'USD'),
],
'thousandSeparator' => [
'default' => $config->get('thousandSeparator', ','),
],
'decimalMark' => [
'default' => $config->get('decimalMark', '.'),
],
'language' => [
'default' => (!empty($_SESSION['install']['user-lang'])) ?
$_SESSION['install']['user-lang'] :
$config->get('language', 'en_US'),
],
];
foreach ($fields as $fieldName => $field) {
if (isset($_SESSION['install'][$fieldName])) {
$fields[$fieldName]['value'] = $_SESSION['install'][$fieldName];
} else {
$fields[$fieldName]['value'] = isset($field['default']) ? $field['default'] : '';
}
}
$smarty->assign('fields', $fields);

View File

@@ -0,0 +1,52 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
$config = $installer->getConfig();
$fields = [
'outboundEmailFromName' => [
'default' => $config->get('outboundEmailFromName'),
],
'outboundEmailFromAddress' => [
'default' => $config->get('outboundEmailFromAddress'),
],
'outboundEmailIsShared' => [
'default' => $config->get('outboundEmailIsShared', false),
],
];
foreach ($fields as $fieldName => $field) {
if (isset($_SESSION['install'][$fieldName])) {
$fields[$fieldName]['value'] = $_SESSION['install'][$fieldName];
} else {
$fields[$fieldName]['value'] = isset($field['default']) ? $field['default'] : '';
}
}
$smarty->assign('fields', $fields);

View File

@@ -0,0 +1,30 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
return [];

View File

@@ -0,0 +1,102 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
return [
'EmailTemplate' => [
[
'name' => 'Case-to-Email auto-reply',
'subject' => 'Case has been created',
'body' => '<p>{Person.name},</p><p>Case \'{Case.name}\' has been created with number '.
'{Case.number} and assigned to {User.name}.</p>',
'isHtml ' => '1',
]
],
'ScheduledJob' => [
[
'name' => 'Check Group Email Accounts',
'job' => 'CheckInboundEmails',
'status' => 'Active',
'scheduling' => '*/2 * * * *',
],
[
'name' => 'Check Personal Email Accounts',
'job' => 'CheckEmailAccounts',
'status' => 'Active',
'scheduling' => '*/1 * * * *',
],
[
'name' => 'Send Email Reminders',
'job' => 'SendEmailReminders',
'status' => 'Active',
'scheduling' => '*/2 * * * *',
],
[
'name' => 'Send Email Notifications',
'job' => 'SendEmailNotifications',
'status' => 'Active',
'scheduling' => '*/2 * * * *',
],
[
'name' => 'Clean-up',
'job' => 'Cleanup',
'status' => 'Active',
'scheduling' => '1 1 * * 0',
],
[
'name' => 'Send Mass Emails',
'job' => 'ProcessMassEmail',
'status' => 'Active',
'scheduling' => '10,30,50 * * * *',
],
[
'name' => 'Auth Token Control',
'job' => 'AuthTokenControl',
'status' => 'Active',
'scheduling' => '*/6 * * * *',
],
[
'name' => 'Control Knowledge Base Article Status',
'job' => 'ControlKnowledgeBaseArticleStatus',
'status' => 'Active',
'scheduling' => '10 1 * * *',
],
[
'name' => 'Process Webhook Queue',
'job' => 'ProcessWebhookQueue',
'status' => 'Active',
'scheduling' => '*/2 * * * *',
],
[
'name' => 'Send Scheduled Emails',
'job' => 'SendScheduledEmails',
'status' => 'Active',
'scheduling' => '*/10 * * * *',
],
],
];

View File

@@ -0,0 +1,99 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
return [
'apiPath' => '/api/v1',
'rewriteRules' => [
'APACHE1' => 'sudo a2enmod rewrite
sudo service apache2 restart',
'APACHE2' => '&#60;Directory /PATH_TO_ESPO/&#62;
AllowOverride <b>All</b>
&#60;/Directory&#62;',
'APACHE2_PATH1' => '/etc/apache2/sites-available/ESPO_VIRTUAL_HOST.conf',
'APACHE2_PATH2' => '/etc/apache2/apache2.conf',
'APACHE2_PATH3' => '/etc/httpd/conf/httpd.conf',
'APACHE3' => 'sudo service apache2 restart',
'APACHE4' => '# RewriteBase /',
'APACHE5' => 'RewriteBase {ESPO_PATH}{API_PATH}',
'WINDOWS_APACHE1' => 'LoadModule rewrite_module modules/mod_rewrite.so',
'NGINX_PATH' => '/etc/nginx/sites-available/YOUR_SITE',
'NGINX' => 'server {
# ...
client_max_body_size 50M;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location /api/v1/ {
if (!-e $request_filename){
rewrite ^/api/v1/(.*)$ /api/v1/index.php last; break;
}
}
location /portal/ {
try_files $uri $uri/ /portal/index.php?$query_string;
}
location /api/v1/portal-access {
if (!-e $request_filename){
rewrite ^/api/v1/(.*)$ /api/v1/portal-access/index.php last; break;
}
}
location ~ /reset/?$ {
try_files /reset.html =404;
}
location ^~ (api|client)/ {
if (-e $request_filename){
return 403;
}
}
location ^~ /data/ {
deny all;
}
location ^~ /application/ {
deny all;
}
location ^~ /custom/ {
deny all;
}
location ^~ /vendor/ {
deny all;
}
location ~ /\.ht {
deny all;
}
}',
'APACHE_LINK' => 'https://www.espocrm.com/documentation/administration/apache-server-configuration/',
'NGINX_LINK' => 'https://www.espocrm.com/documentation/administration/nginx-server-configuration/',
],
];

View File

@@ -0,0 +1,146 @@
{
"labels": {
"Main page title": "مرحبا بكم في EspoCRM",
"Start page title": "اتفاقية الترخيص",
"Step1 page title": "اتفاقية الترخيص",
"License Agreement": "اتفاقية الترخيص",
"I accept the agreement": "أنا أوافق على الشروط",
"Step2 page title": "إعدادات قاعدة البيانات",
"Step3 page title": "إعداد المسؤول",
"Step4 page title": "إعدادات النظام",
"Step5 page title": "إعدادات SMTP لرسائل البريد الإلكتروني الصادرة",
"Errors page title": "الأخطاء",
"Finish page title": "اكتمل التثبيت",
"Congratulation! Welcome to EspoCRM": "تهنئة! تم تثبيت EspoCRM بنجاح.",
"More Information": "لمزيد من المعلومات، الرجاء زيارة {BLOG}، متابعتنا على {TWITTER}. <br><br> إن كان لديك إقتراحات أو أسئلة، يُرجى السؤال في {FORUM}.",
"share": "إذا كنت ترغب EspoCRM ، تقاسمها مع أصدقائك. أخبرهم عن هذا المنتج.",
"blog": "المدونة",
"twitter": "تويتر",
"forum": "المنتدى",
"Installation Guide": "دليل التثبيت",
"admin": "مسؤول",
"Locale": "محلي",
"Outbound Email Configuration": "إعدادات البريد الإلكتروني الصادر",
"Start": "إبدأ",
"Back": "الرجوع",
"Next": "التالي",
"Go to EspoCRM": "إذهب الى EspoCRM",
"Re-check": "إعادة الفحص",
"Version": "الإصدار",
"Test settings": "فحص الإتصال",
"Database Settings Description": "أدخل معلومات اتصال قاعدة بيانات ميسكل (اسم المضيف واسم المستخدم وكلمة المرور). يمكنك تحديد منفذ وحدة الخدمة لاسم المضيف مثل localhost:3306.",
"Install": "تثبيت",
"Configuration Instructions": "تعليمات التكوين",
"phpVersion": "إصدار الـPHP",
"requiredMysqlVersion": "إصدار MySQL",
"dbHostName": "اسم المضيف",
"dbName": "اسم قاعدة البيانات",
"dbUserName": "اسم مستخدم قاعدة البيانات",
"OK": "حسنا",
"SetupConfirmation page title": "متطلبات النظام",
"PHP Configuration": "إعدادات PHP",
"MySQL Configuration": "إعدادات قاعدة البيانات",
"Permission Requirements": "أذونات",
"Success": "النجاح",
"Fail": "يفشل",
"is recommended": "موصى به",
"extension is missing": "التمديد مفقود",
"headerTitle": "تركيب EspoCRM",
"Crontab setup instructions": "بدون تشغيل رسائل البريد الإلكتروني الواردة المجدولة ، لن تعمل الإشعارات والتذكيرات. هنا يمكنك قراءة {SETUP_INSTRUCTIONS}.",
"Setup instructions": "تعليمات الإعداد"
},
"fields": {
"Choose your language": "أختر لغتك",
"Database Name": "اسم قاعدة البيانات",
"Host Name": "اسم المضيف",
"Port": "البوابة",
"smtpPort": "البوابة",
"Database User Name": "اسم مستخدم قاعدة البيانات",
"Database User Password": "كلمة مرور مستخدم قاعدة البيانات",
"Database driver": "برنامج تشغيل قاعدة البيانات",
"User Name": "اسم المستخدم",
"Password": "كلمة المرور",
"smtpPassword": "كلمة المرور",
"Confirm Password": "اعادة كتابة كلمة المرور",
"From Address": "من العنوان",
"From Name": "من الاسم",
"Is Shared": "انه مشترك",
"Date Format": "من تاريخ",
"Time Format": "صيغة الوقت",
"Time Zone": "المنطقة الزمنية",
"First Day of Week": "اول ايام الاسبوع",
"Thousand Separator": "فاصل الألف",
"Decimal Mark": "علامة عشرية",
"Default Currency": "العملة الافتراضية",
"Currency List": "قائمة العملات",
"Language": "اللغة",
"smtpServer": "الخادم",
"smtpAuth": "المصادقة",
"smtpSecurity": "حماية",
"smtpUsername": "اسم المستخدم",
"emailAddress": "البريد الإلكتروني"
},
"messages": {
"1045": "الوصول مرفوض للمستخدم",
"1049": "قاعدة بيانات غير معروفة",
"2005": "خادم مضيف MySQL غير معروف",
"Some errors occurred!": "وقعت بعض الأخطاء!",
"phpVersion": "أصدار الـ PHP الخاص بك لا يدعم بواسطة EngazMedia EspoCRM, يرجي التحديث إلي {minVersion} علي الأقل",
"requiredMysqlVersion": "إصدار MySQL الخاص بك غير مدعوم من قِبل EngazMedia EspoCRM ، يرجى التحديث إلى {minVersion} على الأقل",
"The PHP extension was not found...": "خطأ PHP: لم يتم العثور على الامتداد <b> {extName} </ b>.",
"All Settings correct": "جميع الإعدادات صحيحة",
"Failed to connect to database": "فشل الاتصال بقاعدة البيانات",
"PHP version": "نسخة PHP",
"You must agree to the license agreement": "يجب أن توافق على اتفاقية الترخيص",
"Passwords do not match": "كلمة المرور غير مطابقة",
"Enable mod_rewrite in Apache server": "تفعيل Mode_rewrite في الأباتشي",
"checkWritable error": "تحقق خطأ كتابي",
"applySett error": "تطبيق خطأ",
"buildDatabase error": "خطأ في بناء قاعدة البيانات",
"createUser error": "خطأ في إنشاء مستخدم",
"Cannot create user": "لا تستطيع انشاء مستخدم",
"Permission denied": "الإذن مرفوض",
"Permission denied to": "الإذن مرفوض",
"Can not save settings": "لا يمكن حفظ الإعدادات",
"Cannot save preferences": "لا يمكن حفظ التفضيلات",
"Thousand Separator and Decimal Mark equal": "لا يمكن أن يكون الفاصل والعلامة العشرية متساويين",
"extension": "امتداد {0} مفقود",
"option": "القيمة الموصى بها هي {0}",
"mysqlSettingError": "EspoCRM يحتاج إلى إعدادات قاعدة البيانات \"{NAME}\" لتُصبح {VALUE}",
"requiredMariadbVersion": "إصدار MariaDB الخاص بك غير مدعوم من قبل EspoCRM ، يرجى التحديث إلى MariaDB {minVersion} على الأقل",
"Ajax failed": "حدث خطأ غير متوقع",
"Bad init Permission": "تم رفض الإذن للدليل \"{*}\". يرجى تعيين 775 لـ \"{*}\" أو فقط تنفيذ هذا الأمر في المحطة <pre> <b> {C} </b> </pre> هل العملية غير مسموح بها؟ جرب هذا: {CSU}",
"permissionInstruction": "<br> شغّل هذا الأمر في Terminal: <pre> <b> \"{C}\" </b> </pre>",
"operationNotPermitted": "العملية غير مسموح بها؟ جرب هذا: <br> <br> {CSU}"
},
"options": {
"db driver": {
"mysqli": "MySQLi\n"
},
"modRewriteTitle": {
"apache": "<h3> خطأ API: EspoCRM API غير متوفر. </ h3> <br> قم بالخطوات الضرورية فقط. بعد كل خطوة تحقق من حل المشكلة.",
"nginx": "<h3> خطأ API: EspoCRM API غير متوفر. </ h3>",
"microsoft-iis": "<h3> خطأ API: EspoCRM API غير متوفر. </ h3> <br> المشكلة المحتملة: تعطيل \"إعادة كتابة عنوان URL\". يرجى التحقق من وحدة \"إعادة كتابة عنوان URL\" وتمكينها في خادم IIS",
"default": "<h3> خطأ API: EspoCRM API غير متوفر. </ h3> <br> المشاكل المحتملة: تعطيل وحدة إعادة الكتابة. يرجى التحقق من وحدة إعادة الكتابة وتمكينها في الخادم الخاص بك (مثل mod_rewrite في Apache) ودعم htaccess."
},
"modRewriteInstruction": {
"apache": {
"linux": "<br> <br> <h4> 1. قم بتمكين \"mod_rewrite\". </h4> لتمكين <i> mod_rewrite </i> ، قم بتشغيل هذه الأوامر في محطة طرفية: <br> <br> <pre> {APACHE1} </pre> <hr> <h4> 2 . إذا لم تساعدك الخطوة السابقة ، فحاول تمكين دعم .htaccess. </h4> إضافة / تحرير إعدادات تهيئة الخادم <code> {APACHE2_PATH1} </code> أو <code> {APACHE2_PATH2} </code> (أو < الكود> {APACHE2_PATH3} </code>): <br> <br> <pre> {APACHE2} </pre>\n بعد ذلك قم بتشغيل هذا الأمر في المحطة: <br> <br> <pre> {APACHE3} </pre> <hr> <h4> 3. إذا لم تساعدك الخطوة السابقة ، فحاول إضافة مسار RewriteBase. </h4> افتح ملفًا <code> {API_PATH} .htaccess </code> واستبدل السطر التالي: <br> <br> <pre> { APACHE4} </pre> إلى <br> <br> <pre> {APACHE5} </pre> <hr> لمزيد من المعلومات ، يرجى زيارة الإرشادات <a href=\"{APACHE_LINK}\" target=\"_blank\"> خادم Apache تهيئة لـ EspoCRM </a>. <br>",
"windows": "<br> <br> <h4> 1. ابحث عن ملف httpd.conf. </h4> يمكن العثور عليه عادةً في مجلد يسمى \"conf\" أو \"config\" أو أي شيء من هذا القبيل. <br> <br> <h4> 2. قم بتحرير ملف httpd.conf. </h4> داخل ملف httpd.conf ، قم بإلغاء التعليق على السطر <code> {WINDOWS_APACHE1} </code> (قم بإزالة علامة الجنيه \"#\" من أمام السطر). <br> < br> <h4> 3. تحقق من المعلمات الأخرى. </ h4> تحقق أيضًا مما إذا كان السطر <code> ClearModuleList </code> غير مُعلق وتأكد من عدم تعليق السطر <code> AddModule mod_rewrite.c </code>.\n"
},
"nginx": {
"linux": "<br> أضف هذا الرمز إلى ملف تهيئة خادم Nginx <code> {NGINX_PATH} </code> داخل قسم \"الخادم\": <br> <br> <pre> {NGINX} </pre> <br> لمزيد من المعلومات يرجى زيارة التوجيه <a href=\"{NGINX_LINK}\" target=\"_blank\"> تهيئة خادم Nginx لـ EspoCRM </a>. <br> <br>"
}
}
},
"systemRequirements": {
"requiredPhpVersion": "إصدار PHP",
"requiredMysqlVersion": "نسخة MySQL ",
"host": "اسم الامستضيف",
"dbname": "اسم قاعدة البيانات",
"user": "اسم المستخدم",
"writable": "للكتابة",
"readable": "للقرأة",
"requiredMariadbVersion": "إصدار MariaDB"
}
}

View File

@@ -0,0 +1,114 @@
{
"labels": {
"Main page title": "Velkommen til EspoCRM",
"Start page title": "Lisensavtale",
"Step1 page title": "Lisensavtale",
"License Agreement": "Lisensavtale",
"I accept the agreement": "Jeg aksepterer avtalen",
"Step2 page title": "Databasekonfigurasjon",
"Step3 page title": "Administratoroppsett",
"Step4 page title": "Systeminnstillinger",
"Step5 page title": "SMTP-innstillinger for utgående epost",
"Errors page title": "Feilmeldinger",
"Finish page title": "Installasjonen er fullført",
"Congratulation! Welcome to EspoCRM": "Gratulerer! EspoCRM har blitt installert uten problemer.",
"More Information": "Besøk vår {BLOG} eller følg oss på {TWITTER} for mer informasjon.<br><br>Hvis du har forslag eller innspill kan du besøke vårt {FORUM}.",
"share": "Hvis du liker EspoCRM oppfordrer vi deg til å fortelle andre om applikasjonen.",
"blog": "blogg",
"Installation Guide": "Installasjonsveiledning",
"Locale": "Språk og nasjonalitet",
"Outbound Email Configuration": "Innstillinger for utgående epost",
"Back": "Tilbake",
"Next": "Neste",
"Go to EspoCRM": "Gå til EspoCRM",
"Re-check": "Sjekk på nytt",
"Version": "Versjon",
"Test settings": "Test tilkobling",
"Database Settings Description": "Oppgi tilkoblingsinformasjonen til MySQL-databasen (tjenernavn, brukernavn og passord). Du kan spesifisere tjenerens port slik: localhost:3306.",
"Install": "Installér",
"Configuration Instructions": "Konfigurasjonsinstruks",
"phpVersion": "PHP-versjon",
"requiredMysqlVersion": "MySQL versjon",
"dbHostName": "Tjenernavn",
"dbName": "Databasenavn",
"dbUserName": "Databasebrukernavn",
"SetupConfirmation page title": "Systemkrav",
"PHP Configuration": "PHP innstillinger",
"MySQL Configuration": "Databaseinnstillinger",
"Permission Requirements": "Tillatelser",
"Success": "Suksess",
"Fail": "Feil",
"is recommended": "er anbefalt",
"extension is missing": "utvidelse mangler",
"headerTitle": "EspoCRM Installasjon"
},
"fields": {
"Choose your language": "Velg språk",
"Database Name": "Databasenavn",
"Host Name": "Tjenernavn",
"Database User Name": "Databasebrukernavn",
"Database User Password": "Databasepassord",
"Database driver": "Databasedriver",
"User Name": "Brukernavn",
"Password": "Passord",
"smtpPassword": "Passord",
"Confirm Password": "Bekreft passordet",
"From Address": "Fra-adresse",
"From Name": "Fra-navn",
"Is Shared": "Er delt",
"Date Format": "Datoformat",
"Time Format": "Tidsformat",
"Time Zone": "Tidssone",
"First Day of Week": "Første dag i uken",
"Thousand Separator": "Tusentallsdeler",
"Decimal Mark": "Desimaltegn",
"Default Currency": "Forvalgt valuta",
"Currency List": "Valutaliste",
"Language": "Språk",
"smtpServer": "Tjener",
"smtpAuth": "Autentisering",
"smtpSecurity": "Sikkerhet",
"smtpUsername": "Brukernavn",
"emailAddress": "Epost"
},
"messages": {
"1045": "Tilgang nektet for brukeren",
"1049": "Ukjent database",
"2005": "Ukjent MySQL-tjener",
"Some errors occurred!": "Det oppstod noen feil!",
"phpVersion": "Din PHP-versjon er ikke støtte av EspoCRM, Vennligst oppgrader til {minVersion} eller nyere.",
"requiredMysqlVersion": "Din MySQL-versjon er ikke støttet av EspoCRM. Vennligst oppgrader til {minVersion} eller nyere.",
"The PHP extension was not found...": "PHP-feil: Utvidelsen <b>{extName}</b> ble ikke funnet.",
"All Settings correct": "Alle innstillingene er riktig",
"Failed to connect to database": "Klarte ikke å koble til databasen",
"PHP version": "PHP-versjon",
"You must agree to the license agreement": "Du må godta lisensavtalen før du fortsetter",
"Passwords do not match": "Passordene du har oppgitt er ikke like",
"Enable mod_rewrite in Apache server": "Aktiver mod_rewrite på Apache-tjeneren",
"checkWritable error": "checkWritable-feil",
"applySett error": "applySett-feil",
"buildDatabase error": "buildDatabase-feil",
"createUser error": "createUser-feil",
"checkAjaxPermission error": "checkAjaxPermission-feil",
"Cannot create user": "Kan ikke opprette en bruker",
"Permission denied": "Tilgang nektet",
"Permission denied to": "Tilgang nektet",
"Can not save settings": "Kan ikke lagre innstillinger",
"Cannot save preferences": "Kan ikke lagre preferanser",
"Thousand Separator and Decimal Mark equal": "Tusentallsdeler og desimaltegn kan ikke være det samme",
"extension": "{0} utvidelser mangler",
"option": "Anbefalt verdi er {0}",
"mysqlSettingError": "EspoCRM krever at MySQL-innstillingen \"{NAME}\" endres til {VALUE}",
"requiredMariadbVersion": "Din MariaDB-versjon er ikke støttet av EspoCRM. Vennligst oppgrader til {minVersion} eller nyere."
},
"systemRequirements": {
"requiredPhpVersion": "PHP-Versjon",
"requiredMysqlVersion": "MySQL versjon",
"host": "Tjenernavn",
"dbname": "Databasenavn",
"user": "Brukernavn",
"writable": "Skrivetillatelse",
"readable": "Lesbar",
"requiredMariadbVersion": "MariaDB Versjon"
}
}

View File

@@ -0,0 +1,100 @@
{
"labels": {
"Main page title": "欢迎来到EspoCRM",
"Start page title": "许可协议",
"Step1 page title": "许可协议",
"License Agreement": "许可协议",
"I accept the agreement": "我接受此协议",
"Step2 page title": "数据库配置",
"Step3 page title": "管理员设置",
"Step4 page title": "系统设置",
"Step5 page title": "外发电子邮件的SMTP设置",
"Errors page title": "错误",
"Finish page title": "安装完成",
"Congratulation! Welcome to EspoCRM": "恭喜EspoCRM已成功安装。",
"More Information": "获取更多信息,请访问我们的 {BLOG},关注我们的{TWITTER}。<br> <br>如果您有任何建议或问题,请在{FORUM}上询问。",
"share": "如果你喜欢EspoCRM与朋友分享让他们知道这个产品。",
"blog": "博客",
"twitter": "推特",
"forum": "论坛",
"Installation Guide": "安装指南",
"Locale": "语言环境",
"Outbound Email Configuration": "出站电子邮件配置",
"Start": "开始",
"Back": "上一步",
"Next": "下一步",
"Go to EspoCRM": "转到EspoCRM",
"Re-check": "重新检查",
"Version": "版本",
"Test settings": "测试连接",
"Database Settings Description": "输入您的MySQL数据库连接信息主机名用户名和密码。您可以像localhost:3306这样指定服务器地址和端口。",
"Install": "安装",
"Configuration Instructions": "配置说明",
"phpVersion": "PHP版本",
"requiredMysqlVersion": "MySQL版本",
"dbHostName": "主机名",
"dbName": "数据库名称",
"dbUserName": "数据库用户名",
"OK": "好"
},
"fields": {
"Choose your language": "选择你的语言",
"Database Name": "数据库名称",
"Host Name": "主机名",
"Port": "端口",
"smtpPort": "端口",
"Database User Name": "数据库用户名",
"Database User Password": "数据库用户密码",
"Database driver": "数据库驱动程序",
"User Name": "用户名",
"Password": "密码",
"smtpPassword": "密码",
"Confirm Password": "确认你的密码",
"From Address": "发件人地址",
"From Name": "发件人",
"Is Shared": "共享",
"Date Format": "日期格式",
"Time Format": "时间格式",
"Time Zone": "时区",
"First Day of Week": "每周始于",
"Thousand Separator": "千位分隔符",
"Decimal Mark": "小数标记",
"Default Currency": "默认货币",
"Currency List": "货币列表",
"Language": "语言",
"smtpServer": "SMTP服务器",
"smtpAuth": "验证",
"smtpSecurity": "安全协议",
"smtpUsername": "用户名",
"emailAddress": "电子邮件"
},
"messages": {
"1045": "被拒绝访问的用户",
"1049": "未知数据库",
"2005": "未知的MySQL服务器主机",
"Some errors occurred!": "发生了一些错误!",
"phpVersion": "你的PHP版本不支持EspoCRM请升级到 {minVersion} 或更高版本",
"requiredMysqlVersion": "你的PHP版本不支持EspoCRM请升级到 {minVersion} 或更高版本",
"The PHP extension was not found...": "未找到PHP错误未找到扩展名<b> {extName} </ b>。",
"All Settings correct": "所有设置正确",
"Failed to connect to database": "无法连接到数据库",
"PHP version": "PHP版本",
"You must agree to the license agreement": "您必须同意许可协议",
"Passwords do not match": "密码不匹配",
"Enable mod_rewrite in Apache server": "在Apache服务器中启用mod_rewrite",
"checkWritable error": "checkWritable错误",
"applySett error": "应用设置错误",
"buildDatabase error": "构建数据错误",
"createUser error": "创建用户错误",
"checkAjaxPermission error": "检查Ajax权限错误",
"Cannot create user": "无法创建用户",
"Permission denied": "没有权限",
"Permission denied to": "没有权限",
"Can not save settings": "无法保存设置",
"Cannot save preferences": "无法保存首选项",
"Thousand Separator and Decimal Mark equal": "千分法和小数标记不能相等",
"extension": "{0}扩展名缺失",
"option": "建议值为{0}",
"mysqlSettingError": "EspoCRM需要MySQL设置\"{NAME}\"设置为{VALUE}"
}
}

View File

@@ -0,0 +1,235 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2025 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
use Espo\Core\Utils\Client\LoaderParamsProvider;
use Espo\Core\Utils\Json;
use Espo\Core\Utils\Util;
use Espo\Core\Utils\Client\DevModeJsFileListProvider;
use Espo\Core\Utils\File\Manager as FileManager;
if (session_status() !== \PHP_SESSION_ACTIVE) {
session_start();
}
if (!isset($postData)) {
require_once('install/core/PostData.php');
$postData = new PostData();
}
$allPostData = $postData->getAll();
$action = (!empty($allPostData['action']))? $allPostData['action'] : 'main';
require_once('install/core/Utils.php');
if (!Utils::checkActionExists($action)) {
die('This page does not exist.');
}
// temp save all settings
$ignoredFields = [
'installProcess',
'dbName',
'hostName',
'dbUserName',
'dbUserPass',
'dbDriver',
];
if (!empty($allPostData)) {
foreach ($allPostData as $key => $val) {
if (!in_array($key, $ignoredFields)) {
$_SESSION['install'][$key] = trim($val);
}
}
}
// get user selected language
$userLang = (!empty($_SESSION['install']['user-lang']))? $_SESSION['install']['user-lang'] : 'en_US';
require_once 'install/core/Language.php';
$language = new Language();
$langs = $language->get($userLang);
$sanitizedLangs = Util::sanitizeHtml($langs);
//END: get user selected language
$config = include('install/core/config.php');
require_once 'install/core/SystemHelper.php';
$systemHelper = new SystemHelper();
$systemConfig = include('application/Espo/Resources/defaults/systemConfig.php');
if (
isset($systemConfig['requiredPhpVersion']) &&
version_compare(PHP_VERSION, $systemConfig['requiredPhpVersion'], '<')
) {
die(
str_replace(
"{minVersion}",
$systemConfig['requiredPhpVersion'],
$sanitizedLangs['messages']['phpVersion']
) . ".\n"
);
}
if (!$systemHelper->initWritable()) {
$dir = $systemHelper->getWritableDir();
$message = $sanitizedLangs['messages']['Bad init Permission'];
$message = str_replace('{*}', $dir, $message);
$message = str_replace('{C}', $systemHelper->getPermissionCommands([$dir, ''], '775'), $message);
$message = str_replace('{CSU}', $systemHelper->getPermissionCommands([$dir, ''], '775', true), $message);
die($message . "\n");
}
require_once 'install/vendor/smarty/libs/Smarty.class.php';
require_once 'install/core/Installer.php';
require_once 'install/core/Utils.php';
$smarty = new Smarty();
$installer = new Installer();
// check if app was installed
if ($installer->isInstalled() && !isset($_SESSION['install']['installProcess'])) {
if (isset($_SESSION['install']['redirected']) && $_SESSION['install']['redirected']) {
die('The installation is disabled. It can be enabled in config files.');
}
$url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$url = preg_replace('/install\/?/', '', $url, 1);
$url = strtok($url, '#');
$url = strtok($url, '?');
$_SESSION['install']['redirected'] = true;
header("Location: {$url}");
exit;
}
$_SESSION['install']['installProcess'] = true;
$smarty->caching = false;
$smarty->setTemplateDir('install/core/tpl');
$smarty->assign("version", $installer->getVersion());
$smarty->assign("langs", $sanitizedLangs);
$smarty->assign("langsJs", json_encode($langs));
// include actions and set tpl name
switch ($action) {
case 'main':
$smarty->assign("languageList", $installer->getLanguageList());
break;
case 'step3':
case 'errors':
case 'setupConfirmation':
$smarty->assign("apiPath", $systemHelper->getApiPath());
$modRewriteUrl = $systemHelper->getModRewriteUrl();
$smarty->assign("modRewriteUrl", $modRewriteUrl);
$serverType = $systemHelper->getServerType();
$smarty->assign("serverType", $serverType);
$os = $systemHelper->getOS();
$smarty->assign("OS", $os);
break;
case 'step4':
$defaultSettings = $installer->getDefaultSettings();
$smarty->assign("defaultSettings", $defaultSettings);
break;
case 'step5':
$defaultSettings = $installer->getDefaultSettings();
$smarty->assign("defaultSettings", $defaultSettings);
break;
}
$actionFile = 'install/core/actions/' . $action . '.php';
$tplName = $action . '.tpl';
$smarty->assign('tplName', $tplName);
$smarty->assign('action', ucfirst($action));
$smarty->assign('config', $config);
$smarty->assign('installerConfig', $installer->getInstallerConfigData());
$theme = $_SESSION['install']['theme'] ?? 'Espo';
$stylesheet = $installer->getMetadata()->get(['themes', $theme, 'stylesheet']);
$smarty->assign('stylesheet', $stylesheet);
if (Utils::checkActionExists($action)) {
include $actionFile;
}
$theme = $_SESSION['install']['theme'] ?? $installer->getConfig()->get('theme');
$smarty->assign('logoSrc', $installer->getLogoSrc($theme));
$loaderParamsProvider = $installer->getInjectableFactory()->create(LoaderParamsProvider::class);
if (!empty($actionFile) && file_exists('install/core/tpl/' . $tplName)) {
/* check if EspoCRM is built */
$isBuilt = file_exists('client/lib/espo.js');
$smarty->assign('isBuilt', $isBuilt);
$libFileList = $isBuilt ?
$installer->getMetadata()->get(['app', 'client', 'scriptList']) ?? [] :
(new DevModeJsFileListProvider(new FileManager()))->get();
$smarty->assign('libFileList', $libFileList);
$loaderParams = Json::encode([
'basePath' => '../',
'libsConfig' => $loaderParamsProvider->getLibsConfig(),
'aliasMap' => $loaderParamsProvider->getAliasMap(),
]);
$smarty->assign('loaderParams', $loaderParams);
$smarty->display('index.tpl');
}