When I install a new Symfony application, either via composer or by downloading it directly, it ships with a command line console application. I can run this application with the following command
$ php app/console help
In other systems that have developer command line applications, (Drupal's drush, Magento's n98-magerun, etc.), the application is capable of figuring out where the root folder is when you're deep in the file hierarchy, and you can run the application from anywhere
$ cd some/drupal/path
$ drush //still works!
To do something similar with Symfony's app/console, you need to construct this path yourself
$ cd some/symfony/path
$ php ../../../app/console
And even this may not work if the command relies on the PHP working directory being the root directory.
Is there a standard/well-supported way to get the "run from any folder" behavior of other CLI applications with Symfony's app/console?
I use following console script for this purpose:
#!/usr/bin/env php
<?php
function fileLocator($file =null, $maxDepth = 10, $currentDir = ".")
{
if(empty($file)){
return false;
}elseif(file_exists($currentDir . "/$file")){
return $currentDir;
}elseif(--$maxDepth){
return fileLocator($file, $maxDepth, $currentDir . "/..");
}else{
return false;
}
}
$projectDir = fileLocator('app', 10, getcwd());
if($projectDir){
$projectDir = realpath($projectDir);
if(substr($projectDir, -1) != DIRECTORY_SEPARATOR){
$projectDir .= DIRECTORY_SEPARATOR ;
}
$appDir = $projectDir . 'app';
}else {
die('You are not in symfony project');
}
// if you don't want to setup permissions the proper way, just uncomment the following PHP line
// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
//umask(0000);
set_time_limit(0);
require_once $appDir.'/bootstrap.php.cache';
require_once $appDir.'/AppKernel.php';
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Debug\Debug;
$input = new ArgvInput();
$env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');
$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod';
if ($debug) {
Debug::enable();
}
$kernel = new AppKernel($env, $debug);
$application = new Application($kernel);
$application->run($input);
For *nix users
Create console file with this code. put it in your global path of your choice(like /usr/local/bin/)
give it executable permission
sudo chmod +x /usr/local/bin/console
you are ready to go. You can run console from within any directory of a symfony2 project.
For windows users:
Assuming you have your php path in path variable so you was able to execute console like php app/console.
create a console.php file with the same code. create a console.bat file with the following script:
#ECHO OFF
php "%~dp0sf.php" %*
copy both console.php and console.bat file in your php directory. Now you are ready to go.
Enjoy!!
you need to create a symlink
sudo ln -s /full/path/to/app/console /usr/local/bin/console
sudo chmod +x /usr/local/bin/console
then you can run sudo console help
Here's a solution implemented as a Bash script, so suitable under Linux/Mac or Cygwin's bash prompt under Windows. It should work fine even if you swap regularly between projects, as it doesn't rely on environment variables.
Make a script with the following contents, make it executable (using chmod a+x) and then put it in your path:
#!/bin/sh
while [[ "`pwd`" != "/" ]]; do
app_dir=`find \`pwd\`/ -maxdepth 1 -name 'app'`
if [ -f "$app_dir/console" ]; then
php $app_dir/console $#
break
fi
cd ..
done
Then just use it anywhere within your Symfony project, and use it like you would use "php app/console". It doesn't depend on any environment variables - all it does is recursively look at parent folders from where you're located, looking for app/console, and then runs it with any and all the parameters you pass to it (that's what the $# symbol is for).
I created a Bundle for this to resolve. It is currently only a bash/fish script, which creates something like a virtual environment:
$ composer require sk/symfony-venv
// [...] wait for install
$ . vendor/bin/activate
(project) $ console
On https://github.com/skroczek/symfony-venv you can read more. Feedback is welcome. :)
Related
I'm attempting to construct a monitoring webservice using docker & PHP
I have a PHP script that when accessed performs a check to see if a number of services are running (through checking the HTTP headers for the services enpoints).
I have a functions.inc.php file and an index.php file
Here is my index.php file
<?php
header("Access-Control-Allow-Origin: *");
header("Content-type: application/json");
require('functions.inc.php');
//connect to MySQL DB
include("conn.php");
//Log file - check if it exists - create one if not
$file = "/var/www/html/logs/log".date("Y-m-d").".txt";
if (!file_exists($file)){
echo "Log file for today does not exist... creating and writing logfile\n";
$logdata = "Monitoring log for: ".date("Y/m/d"."\n");
file_put_contents($file,$logdata,FILE_APPEND);
}else{
echo "Log file for today exists\n";
}
//service.csv can be configured to add
//or remove services to the monitoring
//Open service config csv
//Check if service.CSV is openable
$services = fopen("/var/www/html/service.CSV",'r');
if($services){
//Read first line
fgetcsv($services,1000,',');
//loop through each service - perform check and write result to file
while(($value = fgetcsv($services,1000,','))!== FALSE){
$service=$value[0];
if(servicecheck($service)){
$response = "[".$service." - is running]\n";
}else{
$response = "[".$service." - is not running]\n";
}
echo $response;
file_put_contents($file,date("[h:i:sa ")."]".$response,FILE_APPEND);
}
}else{
die("Unable to open file");
}
I can currently run the script through buidling and running it through docker, making it accessible through localhost port 80.
Here is my initial Dockerfile:
FROM php:7.2-apache
COPY src/ /var/www/html/
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
RUN chmod 777 /var/www/html
This all works as intended. I can access the service through localhost:80 on my browser.
However, I want these service checks to run even when the page isn't accessed.
I found that cron would be the appropriate solution for this, and I tried to implement it. My new dockerfile looks like this-
FROM php:7.2-apache
COPY src/ /var/www/html/
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
RUN chmod 777 /var/www/html
RUN apt-get update && apt-get -y install cron
# Copy hello-cron file to the cron.d directory
COPY hello-cron /etc/cron.d/hello-cron
# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/hello-cron
# Apply cron job
RUN crontab /etc/cron.d/hello-cron
RUN chmod 777 /etc/cron.d/hello-cron
RUN touch /var/log/cron.log
CMD cron && tail -f /var/log/cron.log
This does work. In the docker terminal I can see the script running every minute. It outputs to terminal what until now has been output to the browser. However now I can't access it through localhost:80 and make the php script run manually.
heres my cronfile (hello-cron) for reference
* * * * * /usr/local/bin/php /var/www/html/index.php >> /var/log/cron.log 2>&1
# An empty line is required at the end of this file for a valid cron file.
I believe the issue lies with cron, as its the final line CMD cron && tail -f /var/log/cron.log that makes the page inaccessible.
Is there any solution for this? I'm relatively new to it all so I'm sure there is something I'm missing but I cant find anything that helps
I am making a CLI-tool for work using the symfony/console composer package. (Much like laravel/installer)
The goal of this tool is to improve the daily workflow for my coworkers.
My [COMPANY] install command installs all active repositories in the current working directory. I save this directory in a configuration file on the home directory.
I now want to add a [COMPANY] cd command which should simulate an actual cd command by changing the current directory of my terminal to the install directory. So far, I have tried the following:
What I already tried
protected function handle(): void
{
$config = new Config;
$path = $config->get('directory');
if (is_null($path)) {
$this->error("It seems like you didn't install the [COMPANY] projects. Take a look at the `[COMPANY] install` command.");
exit;
}
// These options do not work because they are executed in an isolated sub-process.
chdir($path);
exec("cd $path");
shell_exec("cd $path");
$this->info("Changed working directory to $path");
}
The chdir() method only changes the working directory of the current php script. While exec() starts a completely isolated process.
Desired behaviour
~ cd ~/Development/Company
~/Development/Company company install
~/Development/Company cd ~
~ company cd
~/Development/Company
My question: Is this kind of behavior even possible with PHP? And if so, how can I achieve this.
Thanks in advance.
No, you cannot change the working directory of a terminal by running a script in it.
cd is a command built into your shell, not an external command in e.g. /bin.
I am trying to run a function from a php file and run it from cli without having to type php deploy so have added a shebang so the cli knows how to run the script.
e.g.
#!/usr/bin/env php
<?php
if (PHP_SAPI !== 'cli') {
echo 'bin/deployer must be run as a CLI application' . "\n";
exit(1);
}
function deploy(){
echo "Deploying" . "\n";
}
foreach ($argv AS $arg){
function_exists($arg) AND call_user_func($arg);
}
File: deployer
This does work fine from root directory and running bin/deployer deploy works as expected. I'm just curious as to why if run from the directory bin: deployer deploy i get -bash: deployer: command not found
try this in inside the bin/ directory:
./deployer deploy
If you omit the ./ in front of your file, your shell will look for the command deployer in your path ($PATH), instead of treating it as a path to the file to execute.
The $PATH is a list of directories, where your shell will look for the command you typed.
To see what is in your path, try:
echo $PATH
I'm trying to automatise some Unity3D process to can call this from a PHP script.
I've already create an shell script that call some UNITY command line to create a project and for execute methods and if I use it in the terminal, works fine.
The problem is when I use it into a PHP script:
- I'm using shell_exec command to execute my script and all shell methods works (ls, mkdir, echo) but when I call to application nothing happend.
I was reading that is a permission problem into apache but after some hours I still without find a solution so.
I've mounted a server in my mac (Sierra) enabling apache and PHP 5 to test.
Regards,
Gabriel
EDIT 1
I add here my code
This is my shell_script that works fine if i execute it in a terminal.
#!/bin/bash
UNITY_EXEC=/Applications/Unity_5.6.1f1/Unity.app/Contents/MacOS/Unity
if [ -z "$2" ]; then echo "You must provide a path to the bundle assets and a path to the resulting bundle."; exit 1; fi
export UNITY_ASSET_BUNDLE_PATH=${2}
CREATION_TIME=`date +%s`
ASSET_BUNDLE_PROJECT_DIR=/tmp/AssetBundle-${CREATION_TIME}
echo "Creating temporary project.";
${UNITY_EXEC} -batchmode -quit -createProject ${ASSET_BUNDLE_PROJECT_DIR};
echo "Copying resources from source folder to assets folder.";
cd $1; cp -r . ${ASSET_BUNDLE_PROJECT_DIR}/Assets;
echo "Finding assets.";
cd ${ASSET_BUNDLE_PROJECT_DIR};
ASSETS_TO_BUNDLE=`find Assets -type f -not -name *.meta -not -name .DS_Store -not -name AssetsBundler.cs | sed 's/^.\///g' | sed 's/^/assetPathsList.Add("/g' | sed 's/$/");/g'`
mkdir ${ASSET_BUNDLE_PROJECT_DIR}/Assets/Editor/;
cat << EOT >> ${ASSET_BUNDLE_PROJECT_DIR}/Assets/Editor/AssetsBundler.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
public class AssetsBundler{
public static void Bundle(){
List<string> assetPathsList = new List<string>();
${ASSETS_TO_BUNDLE}
ArrayList assetList = new ArrayList();
foreach(string assetPath in assetPathsList)
{
UnityEngine.Object[] assets = AssetDatabase.LoadAllAssetsAtPath(assetPath);
foreach(UnityEngine.Object asset in assets)
{
assetList.Add(asset);
}
}
UnityEngine.Object[] allAssets = (UnityEngine.Object[]) assetList.ToArray(typeof(UnityEngine.Object));
BuildPipeline.BuildAssetBundle(allAssets[0], allAssets, "${UNITY_ASSET_BUNDLE_PATH}", BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets, BuildTarget.Android);
}
}
EOT
echo "Building the bundle.";
${UNITY_EXEC} -batchmode -quit -projectProject ${ASSET_BUNDLE_PROJECT_DIR} -executeMethod AssetsBundler.Bundle;
And this is my PHP_script
<?php
$old_path = getcwd();
chdir('./AssetBundleBuilder/');
$output = shell_exec('./AssetBundleBuilder ./Bundlify ./result.unity3d');
chdir($old_path);
echo $output;
?>
If i execute my PHP script from firefox, i receive as output all echo messages so thats tell me that the script is working. The thing is that the UNITY calls doesn't works.
I'll response my self.
Finally i got a solution using sockets. I've created a server socket in python to call the bash script in every connection and my client socket is in php that is the file that i call from a browser.
Thanks!
Gabriel
Issue: Initially, Through command line as a root user,I accessed a package called pandoc (/root/.cabal/bin/pandoc) which was installed in root folder. When I try to access that package through php using shell_exec(),it fails.
Question: Is there any limitation for php shell_exec() not to access root packages for security purposes? If so,how to resolve it?
I tried: Gave write permission to root folder then I could access root packages through
command line not as a root user. yet I couldn't to access it through php shell_exec().
php code:
shell_exec("cd /home/quotequadsco/public_html/pandoc_jats ; sudo -u quotequadsco
-S /root/.cabal/bin/pandoc ex.tex --filter /root/.cabal/bin/pandoc-citeproc
-t JATS.lua -o ex.xml");
and also tried,
shell_exec("cd /home/quotequadsco/public_html/pandoc_jats ;/root/.cabal/bin/pandoc
ex.tex --filter /root/.cabal/bin/pandoc-citeproc -t JATS.lua -o ex.xml");
Expectation: I need to execute pandoc root package through shell_exec() in php.
Added the following line in the /etc/sudoer file
#Defaults requiretty //commented this line
usergroup ALL=(ALL) ALL
PHP code,
shell_exec("cd /home/quotequadsco/public_html/pandoc_jats ;echo password | sudo
-S command"); //added a password for sudo command to run as a root user.
I recently published a project that allows PHP to obtain and interact with a real Bash shell (as root if requested), it solves the limitations of exec() and shell_exec(). Get it here: https://github.com/merlinthemagic/MTS
After downloading you would simply use the following code:
$shell = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$return1 = $shell->exeCmd('pandoc (/root/.cabal/bin/pandoc)');
//the return will be a string containing the return of the command
echo $return1;