- PVSM.RU - https://www.pvsm.ru -

Как я боролся с бесплатным хостингом и Composer

Никто не будет отрицать что Composer довольно удобный инструмент, и что есть бесплатные или дешевые хостинги которые не предоставляют какую либо консольку или встроенного инструмента для работы с Composer. Вот как раз с таким стеком я и столкнулся. Ну и как завещали джедаи, vendor сразу же добавляется в .gitignore чтоб не засорять им репозиторий и не гонять туда/сюда библиотеки.

Первое что пришло в голову это сделать скрипт доступный из Web, который можно дёрнуть в нужный момент и он обновит зависимости или установит их.

Для этого нам нужно провести некоторые манипуляции.

1. Для установки композера локально нам необходимо скачать composer.phar [1].

2. Создать папку куда он распакуется (пусть будет var).

3. Создать composer.json (ну про этот я думаю вы уже и так знаете если работали с composer).

4. Ну и создать сам скрипт для работы с композером из Web (пусть будет composer.php).

Итак мы имеем такую структуру нашего будущего сайта:

структура сайта

Сам же composer.phar будет следующим:

<?php

use ComposerConsoleApplication;
use SymfonyComponentConsoleInputArrayInput;
use SymfonyComponentConsoleOutputStreamOutput;

//Уберём лимиты, чтоб скрипт не отвалился раньше времени
ini_set("memory_limit", -1);
ini_set("max_execution_time", 0);

//Корень проекта
$root = __DIR__ . "/../";

//Папка для разархивирования
$dir = "{$root}/var";

//Смотрим если Phar архив еще не распакован, то распакуем его
if (file_exists("{$dir}/vendor/autoload.php") === false) {
	$composerPhar = new Phar("{$root}/composer.phar");
	$composerPhar->extractTo($dir);
}

//Подключим автолоадер для использования классов композера
require_once("{$dir}/vendor/autoload.php" . '');

//Обьявим переменную окружения чтоб обозначить где хранится сам композер
putenv("COMPOSER_HOME={$dir}/bin/composer");

//Изменим папку на корень чтоб vendor хранился на том же уровне что и WebRoot
chdir($root);

//Подготавливаем комманду установки
$input = new ArrayInput(['command' => 'install']);

//Создаем вывод в стрим
$stream = fopen('php://temp', 'w+');
$output = new StreamOutput($stream);

//Запускаем "консольное" приложение
$application = new Application();
$application->setAutoExit(false);
$application->run($input, $output);

//А тут должен быть вывод
echo stream_get_contents($stream);

И если вы счатливчик. То после вызова скрипта, он развернёт папку vendor.

Но я таким не оказался) Первое что сломало мои планы это настройка phar.readonly = On в php.ini, и как вы уже догадались на бесплатных хостингах править его обычно нельзя. Тогда я начал искать пути обхода.

Первое что попробовал это создать user.ini который переопределит настройки в php.ini, на локальной машине сработало) А вот на хостинге [2] этот функционал зарезан был.

Тогда я попробовал использовать еще один трюк. Переименовать composer.phar в просто composer, результат то же. На локалке сработало, на хостинге [2] — нет.

Тогда пришлось всё таки вместо скрипта распаковать в var файлы локально и залить их на сервер.

Также стоит закрыть скрипт авторизацией, чтоб всякие персоны не вызывали его. Также в конечную версию скрипта я добавил выбор команды через параметры.

<?php

use ComposerConsoleApplication;
use SymfonyComponentConsoleInputArrayInput;
use SymfonyComponentConsoleOutputStreamOutput;

//Уберём лимиты, чтоб скрипт не отвалился раньше времени
ini_set("memory_limit", -1);
ini_set("max_execution_time", 0);

//Негоже в Web хранить скрипты не закрытые паролем, чтоб кто-то посторонний мог их вызвать
if (isset($_SERVER['HTTP_AUTHORIZATION']) AND !empty($_SERVER['HTTP_AUTHORIZATION'])) {
	list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)), 2);
} elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) AND !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
	list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['REDIRECT_HTTP_AUTHORIZATION'], 6)), 2);
}

//Детали для авторизации, не забудьте поменять на что-то более секьюрное
$config = [
	'user' => 'admin',
	'password' => 'admin',
];

//Пускаем или не пускаем пользователя дальше
if ((isset($_SERVER['PHP_AUTH_USER']) && $_SERVER['PHP_AUTH_USER'] == $config['user'] && isset($_SERVER['PHP_AUTH_PW']) && $_SERVER['PHP_AUTH_PW'] == $config['password'])) {
	unset($_SERVER['PHP_AUTH_USER']);
	unset($_SERVER['PHP_AUTH_PW']);
} else {
	$uniqueID = uniqid();
	header("WWW-Authenticate: Basic realm='{$uniqueID}'");
	header('HTTP/1.0 401 Unauthorized');

	exit();
}

//Корень проекта
$root = __DIR__ . "/../";

//Папка для разархивирования
$dir = "{$root}/var";

//Смотрим если Phar архив еще не распакован, то распакуем его
if (file_exists("{$dir}/vendor/autoload.php") === false) {
	$composerPhar = new Phar("{$root}/composer.phar");
	$composerPhar->extractTo($dir);
}

//Подключим автолоадер для использования классов композера
require_once("{$dir}/vendor/autoload.php" . '');

//Обьявим переменную окружения чтоб обозначить где хранится сам композер
putenv("COMPOSER_HOME={$dir}/bin/composer");

//Изменим папку на корень чтоб vendor хранился на том же уровне что и WebRoot
chdir($root);

//Не очень то хорошо, но будем надеятся что пароль знает только человек который знает что он делает, и делает это во имя добра)
//По умолчанию composer update, так как он используется чаще чем ?command=install
$params = !empty($_GET) ? $_GET : ['command' => 'update'];

//Подготавливаем комманду установки.
$input = new ArrayInput($params);

//Создаем вывод в стрим
$stream = fopen('php://temp', 'w+');
$output = new StreamOutput($stream);

//Запускаем "консольное" приложение
$application = new Application();
$application->setAutoExit(false);
$application->run($input, $output);

//А тут должен быть вывод
echo stream_get_contents($stream);

Также не помешает добавить в .htaccess правило для проброса заголовка авторизации (в случае с CGI) и редиректа на HTTPS, так как авторизация уходит в открытом виде.

RewriteEngine On

#Если у вас CGI, то заголовок авторизации потеряется, поэтому нужно его принудительно добавить
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

#Переадресация на HTTPS, так как авторизация уходит в незашифрованном виде
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:SSL} !=1 [NC]
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L]

Автор: Ninazu

Источник [3]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/php-2/308091

Ссылки в тексте:

[1] необходимо скачать composer.phar: https://getcomposer.org/composer.phar

[2] хостинге: https://www.reg.ru/?rlink=reflink-717

[3] Источник: https://habr.com/ru/post/439424/?utm_campaign=439424