Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
Improve this question
For a project I am working on, we want to use git as a revision tracker for certain data we modify often. We are using php for the web frontend and we need a goo php git client to use. I have come across a handful on the internet and they all tend to have the same limitation...
There is no support for HTTP. We need to be able to push/pull to remote repositories. We also need to clone.
Ideally I am looking for something that does not use the git command (ie: wrapers to exec()) but I am willing to settle if the class works well. I have seen a C library which appears to do what I want, however the php language binding is incomplete and the http functions are labeled experimental.
Does anyone have any insight into using git and http through php?
https://github.com/kbjr/Git.php
Git.php is a wrapper class around git calls that uses proc_open instead of exec to run the commands. While it does not have push/pull methods, it does have a general run method for running custom git commands, so it could be used something like this:
$repo = Git::open('/path/to/repo');
$repo->run('push origin master');
It also does have methods for cloning (clone_to and clone_from which do local cloning and clone_remote for remote cloning).
One possibility is to use PHP's SSH library to perform those actions by connecting back to the web server?
Or I found this set of classes which allow you to you to clone and read other metadata over HTTP, but not push nor pull. However it could be a starting point if you're brave enough to extend them to do that. I can imagine it would be a lot of work to replicate these processes and keep them compliant with various server versions etc.
[UPDATED 23/03/2014, after receiving an upvote - thanks!]
I did get some way trying to implement the above (I was searching for an implementation, drew a blank so tried to write my own), and it was hard as I thought! I actually abandoned it as I found a simpler way to achieve this in a different architecture, but here's the class I wrote trying. It essentially works, but was brittle to the environmental variations I was working in (i.e. it doesn't cope very well with errors or problems).
It uses:
herzult/php-ssh
an ssh config file - a trick to simplify setting up authentication credentials in code
(Note - I had to quickly strip out a few details from the code to post it. So you'll need to fiddle about a bit to integrate it into your app/namespace etc.)
<?php
/**
* #author: scipilot
* #since: 31/12/2013
*/
/**
* Class GitSSH allows you to perform Git functions over an SSH session.
* i.e. you are using the command-line Git commands after SSHing to a host which has the Git client.
*
* You don't need to know about the SSH to use the class, other than the fact you will need access
* to a server via SSH which has the Git client installed. Its likely this is the local web server.
*
* This was made because PHP has no good native Git client.
*
* Requires herzult/php-ssh
*
* Example php-ssh config file would be
*
* <code>
* Host localhost
* User git
* IdentityFile id_rsa
*
* Host your.host.domain.com
* User whoever
* IdentityFile ~/.ssh/WhoeverGit
*</code>
*/
class GitSSH {
protected $config;
protected $session;
protected $sPath;
/**
* #var string
*/
protected $sConfigPath = '~/.ssh/config';
/**
* Connects to the specified host, ready for further commands.
*
* #param string $sHost Host (entry in the config file) to connect to.
* #param string $sConfigPath Optional; config file path. Defaults to ~/.ssh/config,
* which is probably inaccessible for web apps.
*/
function __construct($sHost, $sConfigPath=null){
\Log::info('New GitSSH '.$sHost.', '.$sConfigPath);
if(isset($sConfigPath)) $this->sConfigPath = $sConfigPath;
$this->config = new \Ssh\SshConfigFileConfiguration($this->sConfigPath, $sHost);
$this->session = new \Ssh\Session($this->config, $this->config->getAuthentication());
}
public function __destruct() {
$this->disconnect();
}
/**
* Thanks to Steve Kamerman, as there isn't a native disconnect.
*/
public function disconnect() {
$this->exec('echo "EXITING" && exit;');
$this->session = null;
}
/**
* Run a command (in the current working directory set by cd)
* #param $sCommand
* #return string
*/
protected function exec($sCommand) {
//echo "\n".$sCommand."\n";
$exec = $this->session->getExec();
$result = $exec->run('cd '.$this->sPath.'; '.$sCommand);
// todo: parse/scrape the result, return a Result object?
return $result;
}
/**
* CD to a folder. (This not an 'incremental' cd!)
* Devnote: we don't really execute the cd now, it's appended to other commands. Each command seems to re-login?
*
* #param string $sPath Absolute filesystem path, or relative from user home
*/
public function cd($sPath){
$this->sPath = $sPath;
// #todo this is useless! each command seems to run in a separate login?
//$result = $this->exec('cd'); // /; ls');
//return $result;
}
/**
* #return string
*/
public function ls(){
$result = $this->exec('ls ');
return $result;
}
public function gitAdd($sOptions=null, array $aFiles=null){
$result = $this->exec('git add '
.(empty($sOptions) ? '' : ' '.$sOptions)
.(empty($aFiles) ? '' : ' '.implode(' ', $aFiles))
);
return $result;
}
public function gitClone($sRepo, $sBranch=null, $sTarget=null){
\Log::info('GitSSH::clone '.$sRepo.', '.$sBranch.', '.$sTarget);
$result = $this->exec('git clone '
.(empty($sBranch) ? '' : ' --branch '.$sBranch)
.' '.$sRepo
.' '.$sTarget);
return $result;
}
public function gitCommit($sMessage, $sOptions=null, array $aFiles=null){
$result = $this->exec('git commit '
.'-m "'.addcslashes($sMessage, '"').'"'
.(empty($sOptions) ? '' : ' '.$sOptions)
.(empty($aFiles) ? '' : ' '.implode(' ', $aFiles))
);
return $result;
}
public function gitPull($sOptions=null, $sRepo=null, $sRefspec=null){
$result = $this->exec('git pull '
.(empty($sOptions) ? '' : ' '.$sOptions)
.(empty($sRepo) ? '' : ' '.$sRepo)
.(empty($sRefspec) ? '' : ' '.$sRefspec)
);
return $result;
}
public function gitPush($sOptions=null, $sRepo=null, $sRefspec=null){
$result = $this->exec('git push '
.(empty($sOptions) ? '' : ' '.$sOptions)
.(empty($sRepo) ? '' : ' '.$sRepo)
.(empty($sRefspec) ? '' : ' '.$sRefspec)
);
return $result;
}
/**
* #return string the raw result from git status
*/
public function gitStatus(){
$result = $this->exec('git status');
return $result;
}
}
This looks promising: http://gitphp.org (broken link; see an archived version)
I think that will do it for you. Here is the description of it:
GitPHP is a web frontend for git repositories. It emulates the look of standard gitweb, but is written in PHP and makes use of Smarty templates for customization. It has a couple extras, including syntax highlighting through the GeSHi PHP class and project category support. It works with standard git as well as msysgit on Windows.
Setup should be fairly simple – just extract the tarball where you want to install it, copy config/gitphp.conf.php.example to config/gitphp.conf.php, and set the projectroot in the conf to point to your directory where your bare git repositories are, and make the templates_c directory writeable by the webserver if it’s not already.
You can look through all the available options and defaults in config/gitphp.conf.defaults.php, and copy an option into your config file if you want to override the default. You can also copy config/projects.conf.php.example to config/projects.conf.php and edit it if you want more advanced control over your projects, such as defining categories for projects or loading projects from a text file. More detailed instructions are in the included README.
Note: if you’re upgrading your existing gitphp.conf.php will not be overwritten, but I recommend checking gitphp.conf.defaults.php for new configuration options that may have been added.
You can view the live copy running on this site.
Related
Background: I have installed composer installed zircote/swagger-php and have installed openapi-generator-cli with apt-get.
I am not sure whether or not I am attempting to use these tools correctly, however I've been unable to find documentation pointing me in any direction.
I have a controller file with a whole bunch of code in it. I want to test whether or not I can generate a json file from it using open api annotation.
Here's a sample of my code (I've cut out unrelated chunks of it):
<?php
/**
* #OA\Info(title="My First API", version="0.1")
*/
class Apiv1_LocationController extends App_Controller_API
{
/* Publicly exposed attributes and the field type for filtering */
protected $_exported = array('id','created','modified','name','address','phone','external_id','postcode','country','timezone','date_format','lacps','staff_count');
protected $_schematypes = array(
'string' => ['name','address','phone','external_id','postcode','country','timezone','date_format'],
'int' => ['id','staff_count'],
'timestamp' => ['created','modified'],
'complex'=> ['lacps'],
);
{more unrelated code...}
/**
* #OA\Get(
* path="/api/resource.json",
* #OA\Response(response="200", description="An example resource")
* )
*/
public function getAction()
{
{code inside action...}
}
}
The cli command I use:
openapi-generator-cli generate -g php -i <path_to_LocationController>
I get the following error:
[main] INFO o.o.c.ignore.CodegenIgnoreProcessor - No .openapi-generator-ignore file found.
Exception in thread "main" java.lang.RuntimeException: Issues with the OpenAPI input. Possible causes: invalid/missing spec, malformed JSON/YAML files, etc.
This leads me to believe I am using the openapi-generator-cli tool incorrectly, since I wouldn't be expecting to need a JSON or YAML file, I am trying to generate that file.
I'll keep trying, but if someone could help me realized what I'm doing wrong or how I'm misunderstanding the tool, I'd really appreciate it.
So I realized I'd been going about this in entirely the wrong way.
I used the zircote/swagger-php library to generate the JSON file I required with the following command (In the directory where I wanted the JSON to be generated):
./<path_to_vendor_directory>/vendor/zircote/swagger-php/bin/openapi --pattern "*Controller.php" --output <name_of_file>.json --format json <location_to_search_from_recursively>
I have the class file ex: Stats.php when i want to give an array with information from another method in another application and class file ex: Information.php.
File Stats.php
public function getStats()
{
$myInformations = // here i want to get information from Information.php
.
.
.
return $myInformations;
}
In different application.
File Informations.php
/**
* Get all locales
* #FOS\View()
* #FOS\Get("/locales")
* #param ParamFetcherInterface $paramFetcher
* #return mixed
*/
public function getLocales(ParamFetcherInterface $paramFetcher)
{
.
.
.
return $locales;
}
How I call function getLocales from url: http://myhost.com/api/locales in function getStatus()?
When you are using the GuzzleBundle as mentioned in your comment. You can just inject a client into the class containing getStats() or by making it ContainerAware and retrieving the guzzle-client by its service id from the container. If you don't have to set default options for your client, i.e. you just want to access a url you assume is always available for all environments from all places you could just create a new client with default values:
$guzzleClient = new GuzzleHttp\Client();
Making a request with the client is described in the guzzle docs in the Quickstart in section Sending Requests:
$response = $guzzleClient->get('http://myhost.com/api/locales')
When the request was successful you can retrieve the locales by calling:
$content = $response->getBody()->getContent();
Either casting getBody() to string or using getContent() is important here. Again refer to Guzzle's documentation particularly the section on using responses.
For example if you send a json-encoded string you can do something like:
$encodedLocales = $response->getBody()->getContent();
$decodedLocales = json_decode($encodedLocales, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \Exception(json_last_error_msg());
}
There are many things that should be said about this approach such as it's fragile because it relies on a working network connection possibly to a different server, it's not easily testable, transfer exceptions are not handled gracefully, etc. pp. but for a simple proof of concept or asa starting point this should suffice.
I'm trying to attempt using a webhook script so that I can just commit locally and have the script triggered server-side and pull in any change.
Now if I login to the server via SSH and run php webhook.php the cript is triggered successfully and the files are updated. So I know the file does work. But if I make edits to the files, commit and push to master, I'm not seeing the files updated.
The log file produced by the script suggests everything is fine, but clearly it's not.
My file structure is like this:
var
www
my-project
- webhook.php
repo-folder
So the file should be pulling the files into repo-folder and the webhook.php is set as the webhook via the bitbucket control panel. If I view the log within bitbucket, it's showing a successful request every time I push a commit.
The script:
<?php
date_default_timezone_set('Europe/London');
class Deploy {
/**
* A callback function to call after the deploy has finished.
*
* #var callback
*/
public $post_deploy;
/**
* The name of the file that will be used for logging deployments. Set to
* FALSE to disable logging.
*
* #var string
*/
private $_log = 'deployments.log';
/**
* The timestamp format used for logging.
*
* #link http://www.php.net/manual/en/function.date.php
* #var string
*/
private $_date_format = 'Y-m-d H:i:sP';
/**
* The name of the branch to pull from.
*
* #var string
*/
private $_branch = 'master';
/**
* The name of the remote to pull from.
*
* #var string
*/
private $_remote = 'origin';
/**
* The directory where your website and git repository are located, can be
* a relative or absolute path
*
* #var string
*/
private $_directory;
/**
* Sets up defaults.
*
* #param string $directory Directory where your website is located
* #param array $data Information about the deployment
*/
public function __construct($directory, $options = array())
{
// Determine the directory path
$this->_directory = realpath($directory).DIRECTORY_SEPARATOR;
$available_options = array('log', 'date_format', 'branch', 'remote');
foreach ($options as $option => $value)
{
if (in_array($option, $available_options))
{
$this->{'_'.$option} = $value;
}
}
$this->log('Attempting deployment...');
}
/**
* Writes a message to the log file.
*
* #param string $message The message to write
* #param string $type The type of log message (e.g. INFO, DEBUG, ERROR, etc.)
*/
public function log($message, $type = 'INFO')
{
if ($this->_log)
{
// Set the name of the log file
$filename = $this->_log;
if ( ! file_exists($filename))
{
// Create the log file
file_put_contents($filename, '');
// Allow anyone to write to log files
chmod($filename, 0666);
}
// Write the message into the log file
// Format: time --- type: message
file_put_contents($filename, date($this->_date_format).' --- '.$type.': '.$message.PHP_EOL, FILE_APPEND);
}
}
/**
* Executes the necessary commands to deploy the website.
*/
public function execute()
{
try
{
// Make sure we're in the right directory
chdir($this->_directory);
$this->log('Changing working directory... ');
// Discard any changes to tracked files since our last deploy
exec('git reset --hard HEAD', $output);
$this->log('Reseting repository... '.implode(' ', $output));
// Update the local repository
exec('git pull '.$this->_remote.' '.$this->_branch, $output);
$this->log('Pulling in changes... '.implode(' ', $output));
// Secure the .git directory
exec('chmod -R og-rx .git');
$this->log('Securing .git directory... ');
if (is_callable($this->post_deploy))
{
call_user_func($this->post_deploy, $this->_data);
}
$this->log('Deployment successful.');
}
catch (Exception $e)
{
$this->log($e, 'ERROR');
}
}
}
// This is just an example
$deploy = new Deploy('/var/www/site-name/repo-name');
$deploy->execute();
?>
i was researching this more and the best way you can do is like i mention find out what is the user being used by apache server by building a php script and run the shell_exec('whoami'); and run on your browser to see that user it is.
Then on your document root for your website mine per example is /var/www you would need to create shh keys for this directory when you do that also add a config file with the host bitbucket and reference to the key you created.
Add the key to bitbucket
then you would need to add permission for apache to run the git command run the command visudo and add:
yourapacheuser ALL=(yourapacheuser) NOPASSWD: /usr/bin/ #the /usr/bin in my case is where i have installed git so you need to see what is the directory path where you install git.
After that you should be able to run your script without problems, in case it complains about a requiretty message then on visudo again add: Defaults:yourapacheuser !requiretty
hope it helps
did you configure SSH keys for the server you are using in bitbucket and add the webhook with the url of your script?
As user1361389 wrote you need to know what users are running the different processes. This is how I did on an Amazon Ubuntu instance.
I have a php file that calls a bash script:
shell_exec("sudo -u ubuntu /home/ubuntu/gitpull.sh");
Create SSH keys for user ubuntu and uploaded the public key to bitbucket.
Also, make sure that the php files on your server are owned by the correct user. In my case ubuntu.
You then need to impersonate ubuntu when calling the php file to deploy code. Add this line in the sudoer file (>sudo visudo )
www-data ALL=(ubuntu) NOPASSWD: /path/to/gitpull.sh
Then in bitbucket add the URL to your hook.
Hi i'm trying to use hhvm to run all of the background PHP workers that are currently there in my application. I don't want to run hhvm as a server as Apache is already taking care of it , all i want to do is to run my php codes with hhvm, instead of the regular Zend engine.
Ok here are the codes which i want to run.
This is the entry point of the computationally intensive modules that i want to run
-------------**RunRenderer.php**--------------
#!/usr/bin/php
<?php
require_once 'Config.php';
require_once 'Renderer.php';
Renderer::getInstance()->run();
?>
Here is just a small a portion of the main controller that controls/forks/manages thousands of php tasks/processes.
----------------------------Renderer.php---------------------
<?php
require 'Workers/BumpMapsCalc.php';
/**
* Main Entry class of the Map rendering module
*
* Create workers for all of the different maps calc sub routines
*
*
*
*/
class Renderer extends \Core_Daemon {
/**
* the interval at which the execute method will run
*
* Interval : 10 min
*
*/
protected $loop_interval = 600;
/**
* Set the chunk size
*/
protected $chunkSize = 500;
/**
* Loop counter
*/
protected $loopCounter;
/**
* Low limit and the high limit
*/
protected $lowLimit;
protected $highLimit;
/**
* set the plugins for lock file and settings ini files
*
*/
protected function setup_plugins() {
$this->plugin('Lock_File');
$this->plugin('settings', new \Core_Plugin_Ini());
$this->settings->filename = BASE_PATH . "/Config/settings.ini";
$this->settings->required_sections = array('geometry');
}
protected function setup() {
$this->log("Computing Bumps Maps");
}
/**
* Create multiple separate task that will run in parallel
* Provide the low limit and the high limit which should effectively partition
* the whole table into more manageable chunks , thus making importing and
* storing data much faster and finished within 10 min
*
*/
protected function execute() {
for ($this->loopCounter = 1 ; $this->loopCounter <= $this->settings['geometry']['number'] ; $this->loopCounter += $this->chunkSize) {
$this->lowLimit = $this->loopCounter;
$this->highLimit = $this->loopCounter + $this->chunkSize;
$this->task(new LocalBumpMaps($this->lowLimit, $this->highLimit));
}
}
protected function log_file() {
$dir = BASE_PATH . "/Logs";
if (#file_exists($dir) == false)
#mkdir($dir, 0777, true);
return $dir . '/log_' . date('Y-m-d');
}
}
?>
So normally i would run the program as
php RunRenderer.php -d -p ./pid/pid $1
which would invoke the default zend engine and Renderer.php would fork around thousands of instances of LocalBumpMaps ( along with 100 other map rendering classes ). Now with each of this subtasks taking around 20-30 mb all of the memory in the workstation gets exhausted pretty quickly thus causing the system to screech to a halt.
Of course the main rendering engine is written in C++, but due to some weird requirement the whole front end is in PHP. And the php modules needs to perform around billions of calculations per second. So the only options that was left was to use HHVM in hopes of some significant increase in performance and efficiency.
But the problem is i can't get this code to run with hhvm. This is what i'm trying
hhvm RunRenderer.php -p ./pid $1
This doesn't do anything at all. No processes are forked, no output, nothing happens. So can anyone please tell me how do i run the php scripts with hhvm instead of zend.
I hope my question makes sense, and i would really appreciate any help.
Thanks,
Maxx
Just run the following line first without forking a process:
hhvm RunRenderer.php
If you see console output, and that you can Ctrl+C to terminate the process, then you can demonize the process with an Upstart script. Create a file called /etc/init/renderer.conf:
start on startup
stop on shutdown
respawn
script
hhvm RunRenderer.php
end script
Then you can manually start and stop the process by running:
start renderer
and
stop renderer
If you are running Ubuntu 12.04LTS and above, a log file will be created for you automatically under the name /var/log/upstart/renderer.log. You can fetch live output by tailing the file:
tail -f /var/log/upstart/renderer.log
I was not able to find a good resource which is describing the following Zend_Tool command:
zf create project path name-of-profile file-of-profile
Not even here:
http://framework.zend.com/manual/en/zend.tool.usage.cli.html
Does somebody know a good resource regarding this command?
Note: I'm interested in the name-of-profile and file-of-profile part. Usage, examples, etc.
Maybe even a visual approach like in this references:
http://marklodato.github.com/visual-git-guide/index-en.html
http://osteele.com/archives/2008/05/commit-policies
I am not familiar enough with the internals of ZF Tool Project, but have a look at
http://framework.zend.com/manual/en/zend.tool.project.create-a-project.html
http://framework.zend.com/svn/framework/standard/trunk/library/Zend/Tool/Project/Provider/Project.php
Afaik (which is not much) Zend Tool maintains an XML file to keep track of your project. This is required for any subsequent actions to be applied correctly to your project through Zend Tool.
The DocBlock for the create action in the Project Provider says:
/**
* create()
*
* #param string $path
* #param string $nameOfProfile shortName=n
* #param string $fileOfProfile shortName=f
*/
When run without the two optional arguments, the method will eventually create a new project file with
$newProfile = new Zend_Tool_Project_Profile(array(
'projectDirectory' => $path,
'profileData' => $profileData
));
with $profileDate being the content of the default configuration file. If you specify $fileOfProfile, you can override the configuration file and supply your own file, e.g.
if ($fileOfProfile != null && file_exists($fileOfProfile)) {
$profileData = file_get_contents($fileOfProfile);
}
Obviously, you have to supply a full path to the file for this to work. The alternative is to supply a file identifier, which Zend Tool will then try to find in a predefined location, e.g.
$storage = $this->_registry->getStorage();
if ($profileData == '' && $nameOfProfile != null && $storage->isEnabled()) {
$profileData = $storage->get('project/profiles/' . $nameOfProfile . '.xml');
}
I have no clue what the storage part is about. Like I said, I am not familiar with Zend Tool's inner workings. If I understand correctly, you can use the additional two arguments to load an existing project in a new location or customize the default one.
You might want to browse the ChangeLog to find out more about it.