I've run into an issue with the php zip library causing an error 500 if the file is growing to larger than 500MB, probably memory related...
But I tried to cmd line the zip creation, which works well on my server.
<?php
set_time_limit(10000);
// Make Zip name
$zipname = "main_backup.zip";
// Make a zip file
$cmd = `zip -r $zipname * -x filelist.php -x $zipname`;
if($cmd){
echo 'zip created';
}
else{
echo 'failed';
}
unlink(__FILE__);
?>
I know how to exclude files and folders, but is there a way to zip only files based on the modified time using this approach?
I've googled for hours and came up empty.
for the sake of it, here's the code that was creating the error 500. My site is about 1.8GB, it always errors at 500MB~. I should note the error log is blank, so the cause of the error I'm just assuming to be RAM limit problems.
<?php
$zip = new ZipArchive;
$zip_name = "test.zip";
$res = $zip->open($zip_name, ZipArchive::CREATE);
/**
* Real Recursive Directory Iterator
*/
class RRDI extends RecursiveIteratorIterator {
/**
* Creates Real Recursive Directory Iterator
* #param string $path
* #param int $flags
* #return DirectoryIterator
*/
public function __construct($path, $flags = 0) {
parent::__construct(new RecursiveDirectoryIterator($path, $flags));
}
}
/**
* Real RecursiveDirectoryIterator Filtered Class
* Returns only those items which filenames match given regex
*/
class AdvancedDirectoryIterator extends FilterIterator {
/**
* Regex storage
* #var string
*/
private $regex;
/**
* Creates new AdvancedDirectoryIterator
* #param string $path, prefix with '-R ' for recursive, postfix with /[wildcards] for matching
* #param int $flags
* #return DirectoryIterator
*/
public function __construct($path, $flags = 0) {
if (strpos($path, '-R ') === 0) { $recursive = true; $path = substr($path, 3); }
if (preg_match('~/?([^/]*\*[^/]*)$~', $path, $matches)) { // matched wildcards in filename
$path = substr($path, 0, -strlen($matches[1]) - 1); // strip wildcards part from path
$this->regex = '~^' . str_replace('*', '.*', str_replace('.', '\.', $matches[1])) . '$~'; // convert wildcards to regex
if (!$path) $path = '.'; // if no path given, we assume CWD
}
parent::__construct($recursive ? new RRDI($path, $flags) : new DirectoryIterator($path));
}
/**
* Checks for regex in current filename, or matches all if no regex specified
* #return bool
*/
public function accept() { // FilterIterator method
return $this->regex === null ? true : preg_match($this->regex, $this->getInnerIterator()->getFilename());
}
}
foreach (new AdvancedDirectoryIterator('-R *') as $i){
//$fullpath = str_replace(',','',$i->getPath()).'/'.$i->getFilename();
//echo $fullpath.'<br />';
if ($i->isFile() && $i->getFilename()!='filelist.php') {
//echo $i->getFilename() . " " . $i->getMTime() . "<br />";
if($i->getMTime()>='0'){
$array[] = substr($i->getPathname(), 2);
}
}
};
// will output all php files in CWD and all subdirectories
foreach($array as $files) {
$zip_array[] = files;
$zip->addFile($files);
}
$zip->close();
echo 'done';
?>
You can use the -t or -tt option for the zip command and have your modifed date stored as a variable or just pass one in.
-t with the format mmddyyyy for from-date
-tt with the format mmddyyyy for before-date
//Zips up all files in current directory that were dated 08152013 or later
zip -r -t 08152013 $zipname * -x filelist.php -x $zipname
Related
I have a php artisan command that I created, and executed as bheng user
php /home/forge/site.com/artisan products:exportdiff --env=production
that export the file into my /files/product-exports/ directory
Also, I've already did
chmod -R 777 files/product-exports/
Result
The export part is working fine, I got the file exported as you can see in the image below
But I kept getting this
What is the different between white and green color code ?
Why does it place under the dot . ? Does it mean anything at all ?
Is this something that have to do with the permission ?
Update
As requested from #Tensibai
cd /home/forge/site.com/ && pwd && php /home/forge/site.com/artisan products:exportdiff --env=production
/home/forge/site.com
.
Export created successfully. Export ID is 1085
Source: /home/forge/site/files/product-exports/export1085_2016-11-23.csv
Destination: /Site/inbound/products/productexport1085_2016-11-23.csv
$source NOT exist !
[Exception]
Could not open local file: /home/forge/site/files/product-exports/export1085_2016-11-23.csv.
products:exportdiff
Update2
$source = /home/forge/site/files/product-exports/export1088_2016-11-23.csv
I've tried dd(file_exists($source));
It kept return bool(false)
Is it because of the way I check for file_exists ?
Update3
Here is my whole PHP code for ExportProductsDiff.php
<?php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class ExportProductsDiff extends Command {
/**
* The console command name.
*
* #var string
*/
protected $name = 'products:exportdiff';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Export all products to Diff.';
/**
* The system export message.
*
* #var string
*/
protected $system_message = '[System Diff Export]';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function fire()
{
// Export the products by calling the ExportProducts Command
$options = [
'--format' => "distributor",
'--encoding' => "standard csv",
'--categories' => "all categories",
'--conjugate' => 1,
'--include_disabled'=> 1,
'--export_notes' => $this->system_message
];
// Run the export
$this->call('products:export', $options);
$last_run_export = ProductExport::where('notes', '=', $this->system_message)
->where('status', '=', 'finished')
->where('format', '=', 'distributor')
->orderBy('id', 'desc')
->firstOrFail();
$this->info('Export created successfully. Export ID is ' . $last_run_export->id);
$env = $this->option('env');
if ($env == 'production'){
$localdomain = '*******';
}else{
$env = 'development';
$localdomain = '*******';
}
$sftp_server = '*******';
$sftp_user_name = '*******';
$sftp_user_pass = '*******';
// Open the SFTP connection
$connection = #ssh2_connect($sftp_server);
if (!$connection)
{
throw new Exception("Could not connect to $sftp_server.");
}
// Login to the SFTP server
if (! #ssh2_auth_password($connection, $sftp_user_name, $sftp_user_pass))
{
throw new Exception("Could not authenticate with username $sftp_user_name " .
"and password $sftp_user_pass.");
}
$sftp = #ssh2_sftp($connection);
if (!$sftp)
{
throw new Exception("Could not initialize SFTP subsystem.");
}
// Prepare the files
$source = '/home/forge/site/files/product-exports/' . $last_run_export->file_name;
/////////////////////////////////////
//The bug is here
// update site to site.com
/////////////////////////////////////
$destination = '/Site/inbound/products/product' . $last_run_export->file_name;
$this->info('Source: ' . $source);
$this->info('Destination: ' . $destination);
if (!file_exists('/Site/inbound/products/')) {
ssh2_sftp_mkdir($sftp, '/Site/inbound/products/', 0775, true);
}
dd(file_exists($source));
if (file_exists($source)) {
chmod($source, 0775);
}else{
$this->info('$source NOT exist !');
}
// Upload the file
$stream = #fopen("ssh2.sftp://$sftp$destination", 'w');
if (!$stream)
{
throw new Exception("Could not open file: $destination");
}
$data_to_send = #file_get_contents($source);
if ($data_to_send === false)
{
throw new Exception("Could not open local file: $source.");
}
if (#fwrite($stream, $data_to_send) === false)
{
throw new Exception("Could not send data from file: $source.");
}
#fclose($stream);
// Delete the export when finished
if (file_exists(base_path() . ProductExport::path . $last_run_export->file_name))
{
unlink(base_path() . ProductExport::path . $last_run_export->file_name);
}
$last_run_export->delete();
}
/**
* Get the console command arguments.
*
* #return array
*/
protected function getArguments()
{
return array();
}
/**
* Get the console command options.
*
* #return array
*/
protected function getOptions()
{
return array();
}
}
What is the different between white and green color code ?
green is for files executable (+x), due to your previous chmod 777
Why does it place under the dot . ?
I assume you did a ls -altr wich sort the entries by modification time in ascending order, each time a file is created, the directory inode is modified, so it's listed just before your file (directory modified at file creation, file modified when all text has been written)
Does it mean anything at all ?
Well, generally speaking yes, for your error in particular, we have no clue from wich directory you're starting from, if it writes relative to where you are, it's normal you don't find the files.
Try ls /home/forge/biossantibodies.com/files/product-exports/and if you get an error, cd /home/forge/biossantibodies.com/ and rerun your php command.
Executable files: Green
Directory: Blue
Image files(jpg, gif, bmp, png, tif): Magenta
Symbolic links: Cyan
Pipe: Yellow
Socket: Magenta
Orphaned symbolic links: Blinking Bold white with red
background
Block device driver: Bold yellow foreground, with black
background
Missing links along with files they point to: Blinking Bold white
with red background
Archives or compressed files(like tar,gz,zip,rpm): Red
The directory has a link to itself in the . entry
Each of its sub-directories has a link back via ..
So it doesn't seem anything special with the file permission please check the way you are accessing the file or share code.
This question already has answers here:
How to use return inside a recursive function in PHP
(4 answers)
Closed 9 months ago.
I have this PHP code, but I have only written one recursive function before. I want to begin in a particular subdirectory and check for the presence of a file. If it doesn't exist in the directory I want to check the parent folder for the file and then recursively go on until I either don't find the file and return "" or find the file and return its contents. Here is my function:
/**
* Recursive function to get sidebar from path and look up tree until we either
* find it or return blank.
*/
class MyClass{
public function findSidebarFromPath($path){
if(file_exists($_SERVER["DOCUMENT_ROOT"] . implode("/", $path) . "/sidebar.html")){
return file_get_contents($_SERVER["DOCUMENT_ROOT"] . implode("/", $path) . "/sidebar.html");
} else {
if(count($path) > 0){
# Pop element off end of array.
$discard = array_pop($path);
$this->findSidebarFromPath($path);
} else {
return "";
}
}
}
}
So when I call it, I do this:
$myclass = new MyClass();
$myclass->findSidebarFromPath(array("segment1", "segment2", "segment3"));
Let's say the file I am trying to find is in a directory called "segment2". The function never finds it. The array_pop function doesn't pop off the element off the end of the array and then call the findSidebarFromPath function.
If you write this as a standalone function, it will probably be more useful to you in other areas. After we understand how it works, we'll show you how you can add a public function to your class that can utilize it.
/**
* #param $root string - the shallowest path to search in
* #param $path string - the deepest path to search; this gets appended to $root
* #param $filename string - the file to search for
* #return mixed - string file contents or false if no file is found
*/
function findFile($root, $path, $filename) {
// create auxiliary function that takes args in format we want
$findFileAux = function($cwd, $filename) use (&$findFileAux, $root) {
// resolve the complete filename
$file = "{$cwd}/{$filename}";
// if the file exists, return the contents
if (file_exists($file)) return file_get_contents($file);
// if the cwd has already reached the root, do not go up a directory; return false instead
if ($cwd === $root) return false;
// otherwise check the above directory
return $findFileAux(dirname($cwd), $filename);
};
// starting checking for the file at the deepest segment
return $findFileAux("{$root}/{$path}", $filename);
}
Check the example output on ideone.
So here's how to use it
findFile($_SERVER["DOCUMENT_ROOT"], "foo/bar/qux", "sidebar.html");
Here's how you would integrate it with your class. Notice that this public function has the same API as in your original code
class MyClass {
/**
* #param $path array - path segments to search in
* #return mixed - string file contents or false if sidebar is not found
*/
public function findSidebarFromPath($path) {
// Here we call upon the function we wrote above
// making sure to `join` the path segments into a string
return findFile($_SERVER["DOCUMENT_ROOT"], join("/", $path), "sidebar.html";
}
}
Additional explanation
If $_SERVER["DOCUMENT_ROOT"] is /var/www...
Check /var/www/foo/bar/qux/sidebar.html, return if exists
Check /var/www/foo/bar/sidebar.html, return if exists
Check /var/www/foo/sidebar.html, return if exists
Check /var/www/sidebar.html, return if exists
Because we got to the root (/var/www) no further searches will happen
return false if sidebar.html did not exist in any of the above
Here's the same function with the explanatory comments removed
/**
* #param $root string - the shallowest path to search in
* #param $path string - the deepest path to search; this gets appended to $root
* #param $filename string - the file to search for
* #return mixed - string file contents or false if no file is found
*/
function findFile($root, $path, $filename) {
$findFileAux = function($cwd, $filename) use (&$findFileAux, $root) {
$file = "{$cwd}/{$filename}";
if (file_exists($file)) return file_get_contents($file);
if ($cwd === $root) return false;
return $findFileAux(dirname($cwd), $filename);
};
return $findFileAux("{$root}/{$path}", $filename);
}
You might also want to consider using DIRECTORY_SEPARATOR instead of the hard-coded "/" so that this code could be used reliably on a variety of platforms.
I'm trying to integrate Evernote SDK to my CodeIgniter web application and some classes from the library are loaded and others not, :-S I can't see why.
I have that simple piece of code:
$access_token = 'my validated access token ';
// Get User Store
$userStoreTrans;
try{
$userStoreTrans = new THttpClient(USER_STORE_HOST, USER_STORE_PORT, USER_STORE_URL, USER_STORE_PROTO);
}
catch(TTransportException $e)
{
print $e->errorCode.' Message:'.$e->parameter;
}
$userStoreProt = new TBinaryProtocol($userStoreTrans);
$userStoreClient = new UserStoreClient($userStoreProt, $userStoreProt);
While $userStoreTrans and $userStoreProt are created correctly, a THttpClient and TBinaryProtocol classes from Evernote SDK, $userStoreClient throws a Class 'UserStoreClient' not found in .../home.php
I don't understand why some classes are recognized and some others not, the main difference that I can see is that "TClasses" are under evernote-sdk-php/lib/transport/*.php and evernote-sdk-php/lib/protocol/*.php and UserStoreClient has an extra folder evernote-sdk-php/lib/packages/UserStore/*.php
I'll explain how I'm including evernote-sdk-php to my CodeIgniter installation:
This is my CodeIgniter config/autoload.php
$autoload['libraries'] = array('database','session','form_validation','security','tank_auth','Evernote_bootstrap');
This is my Evernote_bootstrap.php file
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
define("EVERNOTE_LIBS", dirname(__FILE__) . DIRECTORY_SEPARATOR . "evernote-sdk-php/lib");
// add ourselves to include path
ini_set("include_path", ini_get("include_path") . ":" . EVERNOTE_LIBS);
require_once("evernote-sdk-php/lib/autoload.php");
require_once("evernote-oauth/functions.php");
class Evernote_Bootstrap
{
function __construct()
{
// log_message('debug','Evernote_Bootstrap');
}
}
?>
The main purpose of Evernote_Bootstrap class is the require_once of evernote-sdk-php/lib/autoload.php, this class is auto-generated using the -phpa Thrift generator flag, I only add some logging to see the problem.
autoload.php:
<?php
/**
* Copyright (c) 2006- Facebook
* Distributed under the Thrift Software License
*
* See accompanying file LICENSE or visit the Thrift site at:
* http://developers.facebook.com/thrift/
*
* #package thrift
* #author Mark Slee <mcslee#facebook.com>
*/
/**
* Include this file if you wish to use autoload with your PHP generated Thrift
* code. The generated code will *not* include any defined Thrift classes by
* default, except for the service interfaces. The generated code will populate
* values into $GLOBALS['THRIFT_AUTOLOAD'] which can be used by the autoload
* method below. If you have your own autoload system already in place, rename your
* __autoload function to something else and then do:
* $GLOBALS['AUTOLOAD_HOOKS'][] = 'my_autoload_func';
*
* Generate this code using the -phpa Thrift generator flag.
*/
/**
* This parses a given filename for classnames and populates
* $GLOBALS['THRIFT_AUTOLOAD'] with key => value pairs
* where key is lower-case'd classname and value is full path to containing file.
*
* #param String $filename Full path to the filename to parse
*/
function scrapeClasses($filename) {
$fh = fopen($filename, "r");
while ($line = fgets($fh)) {
$matches = array();
if ( preg_match("/^\s*class\s+([^\s]+)/", $line, $matches)) {
if (count($matches) > 1)
$GLOBALS['THRIFT_AUTOLOAD'][strtolower($matches[1])] = $filename;
}
}
}
function findFiles($dir, $pattern, &$finds) {
if (! is_dir($dir))
return;
if (empty($pattern))
$pattern = "/^[^\.][^\.]?$/";
$files = scandir($dir);
if (!empty($files)) {
foreach ($files as $f) {
if ($f == "." || $f == "..")
continue;
if ( is_file($dir . DIRECTORY_SEPARATOR . $f) && preg_match($pattern, $f)) {
$finds[] = $dir . DIRECTORY_SEPARATOR . $f;
} else if ( is_dir($dir . DIRECTORY_SEPARATOR . $f) && substr($f, 0, 1) != ".") {
findFiles($dir . DIRECTORY_SEPARATOR . $f, $pattern, $finds);
}
}
}
}
function str_var_dump($object)
{
ob_start();
var_dump($object);
$dump = ob_get_clean();
return $dump;
}
// require Thrift core
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . "Thrift.php");
if (! isset($GLOBALS['THRIFT_ROOT']))
$GLOBALS['THRIFT_ROOT'] = dirname(__FILE__);
log_message('debug','bootstrap autoload.php is executing');
// stuff for managing autoloading of classes
$GLOBALS['THRIFT_AUTOLOAD'] = array();
$GLOBALS['AUTOLOAD_HOOKS'] = array();
$THRIFT_AUTOLOAD =& $GLOBALS['THRIFT_AUTOLOAD'];
// only populate if not done so already
if (empty($GLOBALS['THRIFT_AUTOLOAD'])) {
//$allLibs = glob( dirname(__FILE__) . "/**/*.php"); // oh poor winblows users can't use glob recursively
$allLibs = array();
findFiles( dirname(__FILE__), "/\.php$/i", $allLibs);
log_message('debug',str_var_dump($allLibs));
if (!empty($allLibs)) {
foreach ($allLibs as $libFile) {
scrapeClasses($libFile);
}
log_message('debug','all scrapped classes: ' . str_var_dump($GLOBALS['THRIFT_AUTOLOAD']));
}
}else{
log_message('debug','$GLOBALS[THRIFT_AUTOLOAD] already defined');
}
// main autoloading
if (!function_exists('__autoload')) {
function __autoload($class) {
log_message('debug','__autoload');
global $THRIFT_AUTOLOAD;
$classl = strtolower($class);
if (isset($THRIFT_AUTOLOAD[$classl])) {
// log_message('debug','$THRIFT_AUTOLOAD[$classl] is set, do require_once');
//include_once $GLOBALS['THRIFT_ROOT'].'/packages/'.$THRIFT_AUTOLOAD[$classl];
require_once($THRIFT_AUTOLOAD[$classl]);
} else if (!empty($GLOBALS['AUTOLOAD_HOOKS'])) {
log_message('debug','$GLOBALS[AUTOLOAD_HOOKS]is no empty, lets foreach');
foreach ($GLOBALS['AUTOLOAD_HOOKS'] as $hook) {
// log_message('debug','iterate');
$hook($class);
}
} else {
log_message('debug','nothing to do');
}
}
}
Then I logged that library and seems to work fine. You can see the main important logs: log_message('debug',str_var_dump($allLibs)); and log_message('debug','all scrapped classes: ' . str_var_dump($GLOBALS['THRIFT_AUTOLOAD'])); and the output: http://pastebin.com/8w1MCKx9:
As you can see, UserStore class seems to be equally fine loaded than THttpClient or TBinaryProtocol... any idea about the problem?
I don't know if is important but I notice that $GLOBALS['THRIFT_ROOT'], defined on autoload.php, is not accesible from a CI Controller. Probably I'm missing something about CI architecture.
As of our lastest SDK updates, UserStoreClient (and the other SDK classes) are in appropriate namespaces. Assuming that you're using our generated code, have you imported the classes you're using? E.g.
use EDAM\UserStore\UserStoreClient;
Here's my situation:
I develop locally on my Mac using MAMP (PHP). My sites are under Git version control, and I point my dev servers to the root of the site under version control on disk.
File structure:
--mysitehere/
---.git/ (.git folder is here versioning everything below)
---src/ (<-- web server root)
----index.php (need the codez here for displaying current git branch)
Anyone have example code that I could use that looks in the .git folder and sees what the current branch is, and output it on the index.php page (and a ruby solution for RoR dev)? This would be super useful when I switch branches, and in my browser when I refresh, I see that I would be on 'master' at the top of the page, or 'your-topic-branch-name-here'.
I'm willing to use a third-party library that accesses git programmatically in PHP, or something that gets the right 'current-branch' variable from a file on disk from within .git.
This worked for me in PHP, including it in the top of my site:
/**
* #filename: currentgitbranch.php
* #usage: Include this file after the '<body>' tag in your project
* #author Kevin Ridgway
*/
$stringfromfile = file('.git/HEAD', FILE_USE_INCLUDE_PATH);
$firstLine = $stringfromfile[0]; //get the string from the array
$explodedstring = explode("/", $firstLine, 3); //seperate out by the "/" in the string
$branchname = $explodedstring[2]; //get the one that is always the branch name
echo "<div style='clear: both; width: 100%; font-size: 14px; font-family: Helvetica; color: #30121d; background: #bcbf77; padding: 20px; text-align: center;'>Current branch: <span style='color:#fff; font-weight: bold; text-transform: uppercase;'>" . $branchname . "</span></div>"; //show it on the page
Branch, last commit date and hash
<?php
$gitBasePath = '.git'; // e.g in laravel: base_path().'/.git';
$gitStr = file_get_contents($gitBasePath.'/HEAD');
$gitBranchName = rtrim(preg_replace("/(.*?\/){2}/", '', $gitStr));
$gitPathBranch = $gitBasePath.'/refs/heads/'.$gitBranchName;
$gitHash = file_get_contents($gitPathBranch);
$gitDate = date(DATE_ATOM, filemtime($gitPathBranch));
echo "version date: ".$gitDate."<br>branch: ".$gitBranchName."<br> commit: ".$gitHash;
?>
Example Output:
version date: 2018-10-31T23:52:49+01:00
branch: dev
commit: 2a52054ef38ba4b76d2c14850fa81ceb25847bab
Modification date of file refs/heads/your_branch is (acceptable) approximation of last commit date (especially fo testing/staging environment where we assume that we will deploy fresh commits (no old ones)).
I use this function:
protected function getGitBranch()
{
$shellOutput = [];
exec('git branch | ' . "grep ' * '", $shellOutput);
foreach ($shellOutput as $line) {
if (strpos($line, '* ') !== false) {
return trim(strtolower(str_replace('* ', '', $line)));
}
}
return null;
}
Simple way in PHP:
Short hash: $rev = exec('git rev-parse --short HEAD');
Full hash: $rev = exec('git rev-parse HEAD');
To extend on program247365's answer, I've written a helper class for this, which also useful for those using Git Flow.
class GitBranch
{
/**
* #var string
*/
private $branch;
const MASTER = 'master';
const DEVELOP = 'develop';
const HOTFIX = 'hotfix';
const FEATURE = 'feature';
/**
* #param \SplFileObject $gitHeadFile
*/
public function __construct(\SplFileObject $gitHeadFile)
{
$ref = explode("/", $gitHeadFile->current(), 3);
$this->branch = rtrim($ref[2]);
}
/**
* #param string $dir
*
* #return static
*/
public static function createFromGitRootDir($dir)
{
try {
$gitHeadFile = new \SplFileObject($dir.'/.git/HEAD', 'r');
} catch (\RuntimeException $e) {
throw new \RuntimeException(sprintf('Directory "%s" is not a Git repository.', $dir));
}
return new static($gitHeadFile);
}
/**
* #return string
*/
public function getName()
{
return $this->branch;
}
/**
* #return boolean
*/
public function isBasedOnMaster()
{
return $this->getFlowType() === self::HOTFIX || $this->getFlowType() === self::MASTER;
}
/**
* #return boolean
*/
public function isBasedOnDevelop()
{
return $this->getFlowType() === self::FEATURE || $this->getFlowType() === self::DEVELOP;
}
/**
* #return string
*/
private function getFlowType()
{
$name = explode('/', $this->branch);
return $name[0];
}
}
You can use it like:
echo GitBranch::createFromGitRootDir(__DIR__)->getName();
Git Library in PHP (GLIP) is a PHP library for interacting with Git repositories. It does not require Git to be installed on your server and can be found on GitHub.
Quick and dirty option if you're in any subdirectory of the repo:
$dir = __DIR__;
exec( "cd '$dir'; git br", $lines );
$branch = '';
foreach ( $lines as $line ) {
if ( strpos( $line, '*' ) === 0 ) {
$branch = ltrim( $line, '* ' );
break;
}
}
Gist: https://gist.github.com/reiaguilera/82d164c7211e299d63ac
<?php
// forked from lukeoliff/QuickGit.php
class QuickGit {
private $version;
function __construct() {
exec('git describe --always',$version_mini_hash);
exec('git rev-list HEAD | wc -l',$version_number);
exec('git log -1',$line);
$this->version['short'] = "v1.".trim($version_number[0]).".".$version_mini_hash[0];
$this->version['full'] = "v1.".trim($version_number[0]).".$version_mini_hash[0] (".str_replace('commit ','',$line[0]).")";
}
public function output() {
return $this->version;
}
public function show() {
echo $this->version;
}
}
The given solutions that read .git/HEAD file causes my pipeline to fail.
Inspired by this question: How to programmatically determine the current checked out Git branch
You can get the git branch name with :
$gitBranchName = trim(shell_exec("git rev-parse --abbrev-ref HEAD"));
I need to create CRX file on the fly. It's for my CMS backend, so it will be just for authenticated users who can install CMS backend as webapp and offer some more privileges to the web app. The problem is, that the backend is used for many domains so creating CRX file for each of them is quite a work. So I figured that it would be easier to just create CRX file on demand which would be generated by PHP using its own domain and probably custom icon.
On the documentation page, they explain the CRX package format. There are many third party libraries that implemented that format. In the following page, you can learn the format and either download a Ruby / Bash script (you can find others too online), and if you want to implement your own packager, you can follow the format described there.
https://developer.chrome.com/extensions/crx
If you really don't want to follow the format, you can let your PHP script do one of the following:
Use Chrome binary chrome.exe --pack-extension=c:\myext --pack-extension-key=c:\myext.pem
Use the Ruby or Bash script from PHP (you can call system commands)
Hope that helps!
Also, for anyone still looking for a way to create a CTX in PHP, look at this question: Create Google Chrome Crx file with PHP
This works for me :D I just change from real path to null without that changes won't work on new chrome :D
/**
* Class CrxGenerator
*
* Create Chrome Extension CRX packages from
* folder & pem private key
*
* Based on CRX format documentation: http://developer.chrome.com/extensions/crx.html
*
* #author: Tomasz Banasiak
* #license: MIT
* #date: 2013-11-03
*/
class CrxGenerator {
const TEMP_ARCHIVE_EXT = '.zip';
private $sourceDir = null;
private $cacheDir = '';
private $privateKeyContents = null;
private $publicKeyContents = null;
private $privateKey = null;
private $publicKey = null;
/**
* #param $file Path to PEM key
* #throws Exception
*/
public function setPrivateKey($file) {
if (!file_exists($file)) {
throw new Exception('Private key file does not exist');
}
$this->privateKeyContents = file_get_contents($file);
$this->privateKey = $file;
}
/**
* #param $file Path to PUB key
* #throws Exception
*/
public function setPublicKey($file) {
if (!file_exists($file)) {
throw new Exception('Private key file does not exist');
}
$this->publicKeyContents = file_get_contents($file);
$this->publicKey = $file;
}
/**
* #param $cacheDir dir specified for caching temporary archives
* #throws Exception
*/
public function setCacheDir($cacheDir) {
if (!is_dir($cacheDir)) {
throw new Exception('Cache dir does not exist!');
}
$this->cacheDir = $cacheDir;
}
/**
* #param $sourceDir Extension source directory
*/
public function setSourceDir($sourceDir) {
$this->sourceDir = $sourceDir;
}
/**
* #param $outputFile path to output file
* #throws Exception
*/
public function generateCrx($outputFile) {
$basename = basename($outputFile);
// First step - create ZIP archive
$zipArchive = $this->cacheDir . DIRECTORY_SEPARATOR . $basename . self::TEMP_ARCHIVE_EXT;
$result = $this->createZipArchive(
$this->sourceDir,
$zipArchive
);
if (!$result) {
throw new Exception('ZIP creation failed');
}
$zipContents = file_get_contents($zipArchive);
// Second step - create file signature
$privateKey = openssl_pkey_get_private($this->privateKeyContents);
openssl_sign($zipContents, $signature, $privateKey, 'sha1');
openssl_free_key($privateKey);
// Create output file
$crx = fopen($outputFile, 'wb');
fwrite($crx, 'Cr24');
fwrite($crx, pack('V', 2));
fwrite($crx, pack('V', strlen($this->publicKeyContents)));
fwrite($crx, pack('V', strlen($signature)));
fwrite($crx, $this->publicKeyContents);
fwrite($crx, $signature);
fwrite($crx, $zipContents);
fclose($crx);
// Clear cache
unset($zipArchive);
}
/**
* #param $source - source dir
* #param $outputFile - output file
* #return bool - success?
*/
private function createZipArchive($source, $outputFile) {
if (!extension_loaded('zip') || !file_exists($source)) {
return false;
}
$zip = new ZipArchive();
if (!$zip->open($outputFile, ZIPARCHIVE::CREATE)) {
return false;
}
$source = str_replace('\\', '/', realpath($source));
if (is_dir($source) === true) {
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file) {
$file = str_replace('\\', '/', $file);
// Exclude "." and ".." folders
if( in_array(substr($file, strrpos($file, '/') + 1), array('.', '..')) ) {
continue;
}
$file = $file;
if (is_dir($file) === true) {
$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
}
else if (is_file($file) === true) {
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
}
}
}
else if (is_file($source) === true) {
$zip->file_get_contents($source);
echo $source;
}
return $zip->close();
}
}
Looks like I have found exactly what I was looking for. Chrome team has made this option to create CRX-less web apps, just by using simple manifest file.
Much easier to create own webapp and publish it on website for installation. And it also solves my problem when I have many websites with a lot of domains and I don't have to create custom CRX file for each domain. I just create small PHP script which creates manifest files on the fly for each domain.