I'm trying to write a little PHP script that can spot all the changes to a local git repo on my web server and push them up to my (private) Github repo. Pushing and pulling from the Github repo using Atom works perfectly, pushing changes to the web server using a webhook works perfectly, pushing and pulling updates on the web server via the command line works perfectly, my problem is trying to commit and push updates on the web server to my Github repo using PHP. How do you do this?
If I have to change, add or even delete an entire template on the server manually I can commit those changes and push them up to Github using the command line like this no problem:
git add --all git commit -m "from server" git push -u origin master
But when I try to do this using a PHP script it never works and I get no error message (I even try with pauses):
$output = `git add --all`; echo $output; sleep(1); $output = `git commit -m "from server"`; echo $output; sleep(3); $output = `git push -u origin master`; echo $output; sleep(3);
If I run something simple like 'git --version', 'git config --list' or 'git status' it works perfectly from these scripts, so I'm at a loss.
When you run a script with php it is run by a user www-data(by default). When you connect to git repository you need to do auth. Most likely it will be done using ssh key. So you need authorize user www-data with the ssh key to allow him accessing the remote repository.
So the steps.
- Generate key
- Add the key to the remote repository
- Add the key to ssh agent locally for user www-data
- Check the enviroment where you run the command
- Enjoy
Useful link: https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/
There's also an option to use authentication via https with skipping putting credentials. You can see more here
Moreover, there's the library that does such things you may check it as well
You says:
But when I try to do this using a PHP script it never works and I get no error message (I even try with pauses):
$output = `git add --all`; echo $output; sleep(1); $output = `git commit -m "from server"`; echo $output; sleep(3); $output = `git push -u origin master`; echo $output; sleep(3);
If I run something simple like 'git --version', 'git config --list' or 'git status' it works perfectly from these scripts, so I'm at a loss.
It seems like you have no write permission here.
You can easily run following commands to check permission for git repo, login user and owner of web server.
Run command whoami
or id
to identify login user.
$ whoami gasolwu $ id uid=501(gasolwu) gid=20(staff) groups=20(staff),501(access_bpf),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),33(_appstore),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh),701(com.apple.sharepoint.group.1)
List directory to check owner and permissions for given path (git repo)
$ ls -al /path/to/repo total 16 drwxr-xr-x 5 gasolwu staff 160 Oct 15 21:50 ./ drwxr-xr-x 5 gasolwu staff 160 Oct 15 21:48 ../ drwxr-xr-x 13 gasolwu staff 416 Oct 15 21:53 .git/ -rw-r--r-- 1 gasolwu staff 196 Oct 15 21:50 git.php* -rw-r--r-- 1 gasolwu staff 79 Oct 15 21:49 git.sh*
Show process status to check user whom runs web server
$ ps auxwww | grep 'httpd\|nginx\|apache' _www 1139 0.0 0.0 4342760 3692 ?? S 9:51PM 0:00.01 /usr/sbin/httpd -D FOREGROUND _www 1138 0.0 0.0 4351976 3692 ?? S 9:51PM 0:00.02 /usr/sbin/httpd -D FOREGROUND _www 1137 0.0 0.0 4317160 1988 ?? S 9:51PM 0:00.01 /usr/sbin/httpd -D FOREGROUND _www 1129 0.0 0.0 4334568 2300 ?? S 9:51PM 0:00.01 /usr/sbin/httpd -D FOREGROUND root 1119 0.0 0.1 4316156 11772 ?? Ss 9:51PM 0:00.51 /usr/sbin/httpd -D FOREGROUND gasolwu 1465 0.0 0.0 4268036 824 s000 S+ 10:19PM 0:00.00 grep --color=auto -d skip httpd\|nginx\|apache
or check user of php-fpm if you run web sever with PHP-FPM
$ ps auxwww | grep php-fpm gasolwu 1761 0.0 0.0 4268036 812 s000 S+ 10:33PM 0:00.00 grep --color=auto -d skip php-fpm nobody 1737 0.0 0.0 4323216 724 ?? S 10:33PM 0:00.00 php-fpm nobody 1736 0.0 0.0 4323216 732 ?? S 10:33PM 0:00.00 php-fpm root 1735 0.0 0.0 4323216 920 ?? Ss 10:33PM 0:00.00 php-fpm
As you can see, It also has permission problem here, The .git
directory can only be written by user gasolwu
, not web user _www
. So when you run git operation via php script through web server. .It can't do git operation (add/commit) without write permission.
The shell_exec (is identical to the backtick
operator) function only returns stdout, It's empty here when error occurs, The stderr will be redirected to error log base on your environment, You will get similar error message log in Apache or PHP.
$ cat /var/log/apache2/error_log Mon Oct 15 21:51:06.734474 2018] [mpm_prefork:notice] [pid 1119] AH00163: Apache/2.4.34 (Unix) PHP/7.1.19 configured -- resuming normal operations [Mon Oct 15 21:51:06.734572 2018] [core:notice] [pid 1119] AH00094: Command line: '/usr/sbin/httpd -D FOREGROUND' fatal: Unable to create '/path/to/repo/.git/index.lock': Permission denied fatal: Unable to create '/path/to/repo/.git/index.lock': Permission denied error: could not lock config file .git/config: Permission denied error: Unable to write upstream branch configuration hint: hint: After fixing the error cause you may try to fix up hint: the remote tracking information by invoking hint: "git branch --set-upstream-to=origin/master". error: update_ref failed for ref 'refs/remotes/origin/master': cannot lock ref 'refs/remotes/origin/master': Unable to create '/path/to/repo/.git/refs/remotes/origin/master.lock': Permission denied Everything up-to-date error: remote unpack failed: unable to create temporary object directory To /tmp/git ! [remote rejected] master -> master (unpacker error) error: failed to push some refs to '/tmp/git'
Let's fix it by given write permission to right user (_www here).
chown -R _www /path/to/repo
After that, you can send request to http://example.com/git.php to add files, commit with message "from server" then push them to GitHub.
CAVEAT: There is some security concern for this methodology without authentication.
The problem is with the authentication. The first solution is to do like Robert said. But I think that no need to Reinvent the wheel, try to see this package :
https://github.com/kbjr/Git.php
Everything is already there.
You are literally just echoing strings, not running them.
Instead of echo()
, you can use exec()
, shell_exec()
:
http://php.net/manual/en/function.exec.php
http://php.net/manual/en/function.shell-exec.php
Here are the PHP commands that allow you to execute programs on the server:
http://php.net/manual/en/ref.exec.php