📜 ⬆️ ⬇️

How I Fought Free Hosting and Composer

No one will deny that Composer is quite a handy tool, and that there are free or cheap hosting services that do not provide any console or built-in tool for working with Composer. That's exactly the kind of stack I encountered. Well, as the Jedi bequeathed, vendor is immediately added to .gitignore so as not to clutter up the repository and not to drive libraries to and from there.

The first thing that came to mind was to make the script available from the Web, which can be pulled at the right time and it will update the dependencies or install them.

For this we need to carry out some manipulations.

1. To install the composer locally, we need to download composer.phar .

2. Create a folder where it will be unpacked (let it be var ).

3. Create composer.json (well, I think about this you already know if you worked with composer).

4. Well, create the script itself to work with the composer from the Web (let it be composer.php ).

So we have the structure of our future site:

Site structure

Composer.phar itself will be as follows:

<?php use Composer\Console\Application; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\StreamOutput; //Уберём лимиты, чтоб скрипт не отвалился раньше времени 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); 


And if you are a thrill. Then after calling the script, it will expand the vendor folder.

But I didn’t turn out to be this way) The first thing that broke my plans was setting phar.readonly = On in php.ini , and you guessed it on free hosting, you usually don’t edit it. Then I started looking for workarounds.

The first thing I tried was to create a user.ini which would override the settings in php.ini , on the local machine worked) But on the hosting this functionality was stabbed.

Then I tried to use another trick. Rename composer.phar to just composer , the result is the same. On LAN worked, on the hosting - no.

Then I had to unpack the var files locally instead of the script and upload them to the server.

Also it is necessary to close the script by authorization, so that any person will not call it. Also in the final version of the script I added the choice of the command through the parameters.

 <?php use Composer\Console\Application; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; //Уберём лимиты, чтоб скрипт не отвалился раньше времени 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 = realpath(__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); //Создаем вывод в стрим $output = new BufferedOutput( OutputInterface::VERBOSITY_NORMAL //true ); //Запускаем "консольное" приложение $application = new Application(); $application->setAutoExit(false); $application->run($input, $output); $content = $output->fetch(); echo "<pre>"; //А тут должен быть вывод echo $content; echo "<br>"; echo (file_exists("{$root}/vendor/autoload.php")) ? 'Autoload <b>installed</b>' : 'Autoload <b>Missing</b>'; 

It also does not hurt to add a rule to .htaccess for forwarding an authorization header (in the case of CGI) and a redirect to HTTPS, since the authorization goes in clear text.

 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] 

Source: https://habr.com/ru/post/439424/