Warning: chmod(): Operation not permitted in /var/www/hopeinstoughton_www/wp-content/plugins/simple-universal-google-analytics/main.php on line 8 [0] in function chmod in /var/www/hopeinstoughton_www/wp-content/plugins/simple-universal-google-analytics/main.php on line 8 [1] in function include_once in /var/www/hopeinstoughton_www/wp-settings.php on line 560 [2] in function require_once in /var/www/hopeinstoughton_www/wp-config.php on line 85 [3] in function require_once in /var/www/hopeinstoughton_www/wp-load.php on line 50 [4] in function require_once in /var/www/hopeinstoughton_www/wp-blog-header.php on line 13 [5] in function require in /var/www/hopeinstoughton_www/index.php on line 17
| Server IP : 94.177.8.99 / Your IP : 216.73.217.165 Web Server : Apache/2.4.58 (Ubuntu) System : Linux aries 6.8.0-134-generic #134-Ubuntu SMP PREEMPT_DYNAMIC Fri Jun 26 18:43:11 UTC 2026 x86_64 User : www-data ( 33) PHP Version : 8.1.34 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/patientapps_www/modules/patientapps/model/ |
Upload File : |
<?php
// Uses GIT commandline
// git clone -n git@git.patientapps.net:pai/webapp.git
// requires apt-get install zip ffmpeg
use SensioLabs\AnsiConverter\AnsiToHtmlConverter;
class PatientApps_Model extends Database_Model {
const COLLECTION = [
['key' => 'unlisted', 'value' => 'Unlisted'], // client-specific, or in Beta... added to all collections
['key' => 'main', 'value' => 'Main Collection'],
['key' => 'mininv', 'value' => 'Minimally Invasive'],
['key' => 'gyn', 'value' => 'Gynecology'],
];
private $uid;
private $x_script;
private $ansi = NULL;
private $TARGETDIR;
private $PREVIEW;
private $ALLOW_PUBLISH;
public function __construct() {
parent::__construct();
$this->uid = isset($_SESSION['current_user']) ? $_SESSION['current_user']['u_id'] : 0;
$ENV = getenv('ENV');
if ($ENV === FALSE) $ENV = '';
switch (strtoupper($ENV)) {
case 'TUCANA':
$this->TARGETDIR = '/var/www/tucana_api/.download';
$this->PREVIEW = 'version2.tucana.cc';
$this->ALLOW_PUBLISH = 0;
break;
case 'VELA':
$this->TARGETDIR = '/var/www/vela_api/.download';
$this->PREVIEW = 'version2.vela.work';
$this->ALLOW_PUBLISH = 0;
break;
default:
$this->TARGETDIR = '/var/www/patientapps_www/.download';
$this->PREVIEW = 'version2.myapp.care';
$this->ALLOW_PUBLISH = 1;
break;
}
}
public function SetAnsi($value){
$this->ansi = $value;
}
private function _LoadSettings() {
return $this->controller->GetModuleSettings();
}
public function getNavigation() {
$list = [];
$list[] = [
'caption' => 'Patient Apps Admin',
'href' => 'https://patientapps.com/admin/',
'hint' => 'PatientApps.com admin area',
'icon' => '<i class="fas fa-globe-americas"></i>',
];
$list[] = [
'caption' => 'OpenCart Admin',
'href' => 'https://store.patientapps.com/admin/',
'hint' => 'PatientApps.com admin area',
'icon' => '<i class="fas fa-globe-americas"></i>',
];
$list[] = [
'caption' => 'Webmail',
'href' => 'https://mail.google.com/a/patientappsinc.com',
'hint' => 'PatientApps Email',
'icon' => '<i class="fab fa-google"></i>',
];
$list[] = [
'caption' => 'Deploy Version 2 Site',
'href' => '/patientapps/build',
'hint' => 'Deploy a version 2 product',
'icon' => '<i class="fas fa-rocket"></i>',
];
$list[] = [
'caption' => 'Direct Build',
'href' => '/pai-word',
'hint' => 'Build a v2 Procedure Guide from sections of a Word Document',
'icon' => '<i class="far fa-file-word"></i>',
];
return $list;
}
public function GetAllBranches() {
$targetfolder = HOME . '/storage/patientapps';
$branchfile = "$targetfolder/.branches";
if (file_exists($branchfile)) {
$payload = unserialize(file_get_contents($branchfile));
} else {
$payload = [
'branch' => [],
'expiry' => 0,
];
}
if ($payload['expiry'] < time()) {
@mkdir("$targetfolder/data", 0777, TRUE);
$node = $this->_LoadSettings();
$url = $node['repo'];
$key = $node['key'] . "\n";
$hash = md5($url);
$filename_hash = $targetfolder . '/hash';
if (file_exists($filename_hash)) {
$current_hash = file_get_contents($filename_hash);
} else {
$current_hash = '';
}
if ($current_hash != $hash || $current_hash == '') {
$this->DownloadRepo($targetfolder, $url, $key); // this should run in background, and the <select> updated when task is finished
file_put_contents($filename_hash, $hash);
}
$targetfolder .= '/data';
$folder = escapeshellarg($targetfolder);
// to do: check for error "fatal: detected dubious ownership in repository at '/var/www/tucana_cms' To add an exception for this directory, call: git config --global --add safe.directory ..."
$command = "cd $folder; git fetch -p; git branch -r --sort=-committerdate"; // -p = prune = remove deleted remote branches
$output = trim(`($command)`);
$lines = explode("\n", $output);
$select = [];
foreach($lines as $item) {
$item = trim($item);
if ($item != '' && strpos($item, ' ') === FALSE) {
if (substr($item, 0, 7) == 'origin/') $item = substr($item, 7);
$select[] = $item;
}
}
$payload['branch'] = $select;
$payload['expiry'] = time() + 60;
file_put_contents($branchfile, serialize($payload));
}
return $payload['branch'];
}
private function extractHost($url) {
if (preg_match('~^(.*?)\@(.*?)\:(.*?)$~', $url, $match)) { // git@host:path
return $match[2];
}
return FALSE;
}
protected function UpdateSSHconfig($targetfolder, $url, $privatekey) {
$host = $this->extractHost($url);
file_put_contents("$targetfolder/key", $privatekey);
chmod("$targetfolder/key", 0600);
$me = posix_getuid();
$info = posix_getpwuid($me);
$dir = $info['dir'];
$this->_AddToConfigFile("$dir/.ssh/config", $host, "$targetfolder/key");
}
// info in conf file? if not, add it
private function _AddToConfigFile($config_file, $host, $privatekey_file) {
$info = $this->ConfigLoad($config_file);
if (!isset($info['host'])) {
$fp = fopen($config_file, 'a');
fwrite($fp, "\n\nHost {$host}\n\tHostname {$host}\n\tIdentityFile {$privatekey_file}\n\tStrictHostKeyChecking no");
fclose($fp);
}
}
private function ConfigLoad($filename) {
$output = [];
$section = '';
$text = file_get_contents($filename);
foreach(explode("\n", $text) as $line) {
$line = trim($line);
if ($line == '') continue;
$p = strpos($line, '=');
if ($p === FALSE) $p = strpos($line, ' ');
$key = substr($line, 0, $p);
$value = trim(substr($line, $p + 1));
$lkey = strtolower($key);
if ($lkey == 'host') {
$section = $value;
} elseif ($section == '') {
$output[$key] = $value;
} else {
$output[$section][$key] = $value;
}
}
return $output;
}
protected function DownloadRepo($targetfolder, $url, $key) {
$this->UpdateSSHconfig($targetfolder, $url, $key);
// run git command (may take a few minutes)
$folder = escapeshellarg($targetfolder . '/data');
$url = escapeshellarg($url);
$command = "git clone -n $url $folder";
$output = `$command 2>&1`;
// var_dump($output);
}
private function _header() {
echo <<<BLOCK
<html>
<head>
<style type="text/css">
body {
margin: 0;
background-color:#000;
color:#fff;
}
</style>
</head>
<body>
<pre style="padding: 10px 15px;">
BLOCK;
}
// overflow: auto;
/* new push process
lock the folder (fail if already locked)
.. process
unlock folder
*/
private function _($x) {
if ($x === FALSE) return '';
if ($this->ansi === FALSE) return $x;
if (!is_object($this->ansi)) {
$this->ansi = new AnsiToHtmlConverter();
}
return $this->ansi->convert($x); // ansi
}
private function parseHashes($text) {
$result = [];
if (preg_match_all('~([0-9a-f]{40}) refs/remotes/origin/(.*?)$~ims', $text, $matches)) {
foreach($matches[1] as $index => $hash) {
$branch = $matches[2][$index];
$result[$branch] = $hash;
}
}
return $result;
}
// assumes GetAllBranches has been run previously
public function GitStatus(&$res, $website_id = 0, $branchname = '') {
// get domain name
$info = [];
$procedure_code = $this->BranchToProcedureCode($branchname);
$domainname = $procedure_code . '.myapp.care';
$res['website'] = 'https://' . $domainname;
$res['preview'] = $this->PREVIEW;
$res['publish'] = $this->ALLOW_PUBLISH;
// download the page, extract the hash [to do: and get branch from "source: "]
$n = new \CurlObject();
$n ->Url("https://{$domainname}/")
->Redirect(1)
->Execute();
$text = $n->Body();
$hash_current = preg_match('~^\s*commit:\s*([0-9a-f]{40})$~m', $text, $match) ? $match[1] : ''; // this is commit the website is at
$elements = explode('.', $domainname);
$procedure_code = array_shift($elements);
$gitbranch = $this->BranchFromProductId($procedure_code);
// Get latest version of everything
$targetfolder = HOME . '/storage/patientapps/data';
$folder = escapeshellarg($targetfolder);
$command = "(cd $folder; git fetch; git show-ref) 2> /dev/null";
$output = `$command`;
$hashes = $this->parseHashes($output);
if (!isset($hashes[$gitbranch])) {
$res['result'] = -1501;
$res['message'] = 'Unknown Git branch';
return; // unknown branch
}
$hash_head = $hashes[$gitbranch];
$res['fullhash'] = $hash_head;
// $res['stuff'] = $branch;
if ($hash_current != '') {
$info = $this->_executeRevList($folder, "git rev-list --format=medium -n 1 {$hash_current})");
if (count($info)) $res['release'] = $info[0];
}
if ($hash_head == $hash_current) {
// up to date - show list of options that user can revert back to
$res['result'] = 0;
$res['message'] = 'Already up-to-date';
return;
}
// $hash_current = "{$hash_head}~1";
$res['list'] = $this->_executeRevList($folder, "git rev-list --format=medium --ancestry-path {$hash_current}..{$hash_head})");
$res['list'] = array_slice($res['list'], 0, 10);
}
function GetCommitDate($fullhash) {
$targetfolder = HOME . '/storage/patientapps/data';
$folder = escapeshellarg($targetfolder);
$info = $this->_executeRevList($folder, "git rev-list --format=medium -n 1 {$fullhash})");
if (count($info)) {
$dt = strtotime($info[0]['date']);
return date('Y.m.d', $dt);
}
return FALSE;
}
function _executeRevList($folder, $command) {
$command = "(cd $folder; $command 2> /dev/null";
$output = `$command`;
$blocks = explode('commit', $output);
$list = [];
foreach($blocks as $block) {
if (preg_match('~([0-9a-f]{40}).*?Author:\s+(.*?)$\s+Date:\s+(.*?)$(.*)~ism', $block, $matches)) { // may contain "Merge: 9ec0c27 fa684c5" or similar
preg_match('~^(.*?)\s+\<(.*?)\>~', $matches[2], $stuff);
$list[] = [
'hash' => substr($matches[1], 0, 9),
'name' => $stuff[1],
'date' => $matches[3],
'message' => trim($matches[4]),
'fullhash' => $matches[1],
];
}
}
return $list;
}
// what sites on the server have git updates?
public function UpdateTree(&$tree, $server_id) {
// get sites, branch and current hash by looking at the index.html page of the site.
}
public function BranchFromProductId($product_id) { // product_id = subdomain name
switch($product_id) { // these are the exceptions:
case 'pai-cld12':
return 'pai-CLD12';
case 'pai-hyot':
return 'Pai-Hyot';
case 'pai-ldn':
return 'pai-ldn1';
case 'pai-rmam':
return 'pai-rmam1';
case 'pai-lcl':
return 'pai-lc';
case 'ma1-lcl':
return 'ma1-lc';
case 'pai-ivfr':
return 'pai-ivf';
case 'umair-oah':
return 'pai-oah';
default:
return $product_id;
}
}
public function BranchToProcedureCode($branchname) {
switch($branchname) { // these are the exceptions:
case 'pai-CLD12':
return 'pai-cld12';
case 'Pai-Hyot':
return 'pai-hyot';
case 'pai-ldn1':
return 'pai-ldn';
case 'pai-rmam1':
return 'pai-rmam';
case 'pai-lc':
return 'pai-lcl';
case 'ma1-lc':
return 'ma1-lcl';
case 'pai-ivf':
return 'pai-ivfr';
}
return $branchname;
}
private function _MaxFolders($targetfolder, $n) {
$filelist = glob("$targetfolder/*");
$older = [];
foreach($filelist as $filename) {
$ft = filemtime($filename);
$older[] = [
'fn' => $filename,
'time' => $ft
]; // name and folder create date/time
}
usort($older, function($a, $b) { // newest to oldest. Oldest at end
return $b['time'] - $a['time'];
});
while (count($older) > $n) {
$item = array_pop($older);
$xdir = escapeshellarg($item['fn']);
`rm -rf $xdir`;
}
}
public function ValidateHashSource($fullhash, $product_code) {
$targetfolder = HOME . '/storage/patientapps/hashes';
@mkdir("$targetfolder", 0777, TRUE);
$foldername = "$targetfolder/$fullhash";
if (!file_exists($foldername)) {
mkdir($foldername);
$this->_downloadSrc($fullhash, $foldername, $product_code);
} else {
$xdir = escapeshellarg($foldername);
`touch $xdir`; // mark as newest
}
$this->_MaxFolders($targetfolder, 10);
}
// download GIT contents to folder, archive current version, only src folder
// we do this by
// 1. creating a zip archive from the git repo
// 2. unzip the archive
// 3. delete the zip archive
public function _downloadSrc($fullhash, $targetfolder, $product_code) {
$this->GetAllBranches();
$sourcefolder = HOME . '/storage/patientapps/data';
$folder = escapeshellarg($sourcefolder);
$target = escapeshellarg($targetfolder . '/src.zip');
$command = "cd $folder; git archive -0 -o $target $fullhash src README.md";
`$command`;
$folder = escapeshellarg($targetfolder);
$command = "cd $folder; unzip -o src.zip; rm src.zip";
`$command`;
// note current branch
file_put_contents($targetfolder . '/branch.txt', $product_code);
}
private function _branchSettings_load($procedure_code) {
$rows = $this->Query('select collection from pai_collection')
->where('procedure_code=%s', $procedure_code)
->Get();
$current = [];
foreach($rows as $row) {
$current[$row->collection] = 1;
}
return $current;
}
// return current configuration for the specified branch
public function BranchSettings_get(&$res, $procedure_code) {
$current = $this->_branchSettings_load($procedure_code);
$selection = static::COLLECTION;
foreach($selection as &$item) {
if (isset($current[$item['key']])) $item['sel'] = 1;
}
$res['list_collection'] = $selection;
// use audio?
$row = $this->Query('select * from pai_procedure')
->where('procedure_code=%s', $procedure_code)
->First();
$res['ignore_audio'] = 0;
$res['tracking'] = 0;
$res['product'] = $procedure_code;
if (!$row->empty()) {
$res['ignore_audio'] = $row->ignore_audio ? 1 : 0;
$res['tracking'] = $row->tracking ? 1 : 0;
$res['physicians'] = $row->physicians ? 1 : 0;
}
}
public function BranchSettings_update($procedure_code, $collections, $params) {
$current = $this->_branchSettings_load($procedure_code);
$this->TableName('pai_collection');
foreach($collections as $index => $item) {
if (isset($current[$item])) { // ignore unchanged
unset($current[$item]);
} else {
// insert record
$this->InsertOrUpdate([
'procedure_code' => $procedure_code,
'collection' => $item,
], []);
$this->DbErr();
}
}
// delete old
foreach($current as $collection => $unused) {
$this->Delete([
'procedure_code' => $procedure_code,
'collection' => $collection
]);
$this->DbErr();
}
// save ignore audio setting
$this->TableName('pai_procedure');
$this->InsertOrUpdate([
'procedure_code' => $procedure_code,
], $params);
}
private function getFileHashes($commands) {
// make sure all "\n" are displayed as "\\n" below:
return <<<BLOCK
#!/usr/bin/python3
import os, sys, glob, hashlib, re, gzip, tempfile, codecs
jones = tempfile.NamedTemporaryFile(delete = False)
gz = gzip.open(jones.name, 'wb')
def normalize_path(basepath, relativepath, isFile):
if relativepath[:1] == '/':
return relativepath
if isFile:
basename = os.path.basename(relativepath)
relativepath = os.path.dirname(relativepath)
else:
basename = ''
basepath = basepath.split('/')
relativepath = relativepath.split('/')
for element in relativepath:
if element == '..':
basepath.pop()
elif element != '.' and element != '':
basepath.append(element)
basepath = '/'.join(basepath)
if basename != '':
basepath += '/' + basename
return basepath
def generate_hash(filename, folder):
md5_hash = hashlib.md5()
with open(filename,'rb') as f:
for byte_block in iter(lambda: f.read(32768),b""):
md5_hash.update(byte_block)
payload = 'MD5(' + filename + ')= ' + md5_hash.hexdigest() + "\\n"
gz.write(payload.encode('cp437'))
return
try:
$commands
finally:
gz.close()
sys.stdout = codecs.getwriter('latin-1')(sys.stdout.detach())
with open(jones.name, 'rb') as f:
data = f.read()
sys.stdout.write(data.decode('latin-1'))
f.close()
os.remove(jones.name)
BLOCK;
}
private function _getTargetFiles($connection, $basefilename, $base, $tocopy) {
$folder = $this->TARGETDIR;
$commands = "\tFOLDER = '$folder'\n";
foreach($tocopy as $ext) {
$commands .= "\tgenerate_hash(FOLDER + '/$base$ext', FOLDER)\n";
}
$script = $this->getFileHashes($commands);
$output = $connection->executeScript($script, '', TRUE);
// allocate the hashes to each extension:
// MD5(/var/www/patientapps_www/.download/ma1-oah.json)= 9419fe5038619356efd3ff72f7d78a44
$result = [];
if (preg_match_all('~MD5\((.*?)\)=\s([0-9a-f]{32})~msi', $output, $matches)) {
foreach($matches[1] as $index => $filename) {
$ext = '.' . pathinfo($filename, PATHINFO_EXTENSION);
$result[$ext] = strtolower($matches[2][$index]);
}
}
return $result;
}
// copy files (.sql3, .json) from here (pegasus) to patientapps.net (sirius)
// - does not currently copy audio
// - should create a backup
public function Publish($basefilename) {
$base = basename($basefilename);
// establish a connection
$data = new \StdClass;
$data->source = 'agentLinux';
$data->server_ip = '94.177.9.99'; // condor.hostz.org
$connection = hook_execute('server.connect', FALSE, $data);
$connection->EstablishConnection(FALSE); // Login
// What files do we have, and are they already copied?
$filetypes = ['.json', '.sql3', '.wav', '.mp3'];
$tocopy = [];
foreach($filetypes as $ext) {
$source = $basefilename . $ext;
if (file_exists($source)) {
$tocopy[] = $ext;
}
}
// find out what files are present - get the md5s
$info = $this->_getTargetFiles($connection, $basefilename, $base, $tocopy);
// copy files
$copied = 0;
foreach($tocopy as $ext) {
$target = $this->TARGETDIR . "/{$base}{$ext}";
$hash_new = strtolower(md5($target));
$hash_current = isset($info[$ext]) ? $info[$ext] : '';
if ($hash_new != $hash_current) {
$connection->UploadFile($target, file_get_contents($basefilename . $ext));
$copied++;
}
}
$connection = NULL;
unset($connection);
}
public function FindFile($filename) {
$targetfolder = HOME . '/storage/patientapps/data';
// get all branches
$result = '';
$folder = escapeshellarg($targetfolder);
chdir($targetfolder);
$command = "git rev-list --all";
$commits = `$command`; // this is a list of all commits, by sha1.
foreach(explode("\n", $commits) as $hash) {
$hash = trim($hash);
if ($hash != '') {
$command = "git ls-tree -r --name-only $hash";
$output = `$command`;
if (preg_match_all('~' . $filename . '~imsu', $output, $matches)) {
$result .= $this->_getBranchAndFileInfo($hash, $matches[0]);
}
}
}
if ($result == '') return 'nothing found.';
return "<table width=\"100%\"><tr><td>Commit</td><td>Date</td><td>Branch</td><td>Filename</td></tr>$result</table>";
}
// get information about this branch and commit
private function _getBranchAndFileInfo($hash, $filenames) {
$command = "git log --decorate --no-walk $hash";
$output = `$command`;
$result = '';
$p = strpos($output, "\n\n"); $delta = 2;
if ($p === FALSE) {
$p = strpos($output, "\r\n\r\n");
$delta = 4;
}
$hash = "<span title=\"$hash\">" . substr($hash, 0, 9) . "</span>";
$date = preg_match('~^Date:\s+(.*?)$~ism', $output, $matches) ? $matches[1] : '???';
$branch = preg_match('~commit\s*([0-9a-f]{40}).*?\((.*?)\)$~ism', $output, $matches) ? $matches[2] : '-';
if ($p !== FALSE) {
$comment = trim(substr($output, $p + $delta));
$result .= "<tr><td>$hash</td><td colspan=\"3\">" . nl2br(htmlspecialchars($comment)) . "</td></tr>";
}
// $result .= "<tr><td colspan=\"4\"><pre>" . htmlspecialchars($output) . "</pre></td></tr>";
foreach($filenames as $filename) {
$result .= "<tr><td></td><td>$date</td><td>$branch</td><td>$filename</td>";
}
$result .= "<tr><td colspan=\"4\"> </td></tr>";
return $result;
}
/* visually similar images
private function _generateInfo($filename) {
$hash = hook_execute('image.hash', FALSE, $filename);
$info = getimagesize($filename);
$info['imagehash'] = $hash;
return $info;
}
// add description file - type, dimensions, imagehash
private function _getImageHashes() {
// storage/patientapps/image-cache#/.info
$result = [];
$targetfolder = HOME . '/storage/patientapps/image-cache';
$filelist = glob($targetfolder . '/*');
foreach($filelist as $filename) {
$basename = basename($filename);
$infofile = $targetfolder . '/.info/' . $basename;
if (!file_exists($infofile)) {
$text = $this->_generateInfo($filename);
file_put_contents($infofile, serialize($text));
}
// read info file
$info = unserialize(file_get_contents($infofile));
$info['basename'] = $basename;
$result[] = $info;
}
return $result;
}
public function getSimilarImages($hash) {
$hashes = $this->_getImageHashes();
$distances = [];
foreach($hashes as $info) {
$distance = hook_execute('image.distance', 0, $info['imagehash'], $hash);
$info['dim'] = $info[3]; unset($info[3]);
$info['distance'] = $distance;
$distances[] = $info;
}
usort($distances, function($a, $b) {
return $a['distance'] - $b['distance'];
});
// return $distances;
return array_slice($distances, 0, 5);
}
public function imageCache($hash) {
$targetfolder = HOME . '/storage/patientapps/image-cache';
$infofile = $targetfolder . '/.info/' . $hash;
if (!file_exists($infofile)) {
die('Not found');
}
$info = unserialize(file_get_contents($infofile));
$data = file_get_contents($targetfolder . '/' . $hash);
return [$info['mime'], $data];
}
*/
// create an archive with the latest version of the named file, from all branches
public function SpecificFile($file = 'src/pages/success/success.html') {
$targetfolder = HOME . '/storage/patientapps';
@mkdir("$targetfolder/data", 0700, TRUE);
$file = ltrim($file, '/');
$file = str_replace(['\\', '..', '&', '<', '>', '|', '*', '?'], '', $file);
$basename = basename($file);
$targetfolder .= '/data';
$folder = escapeshellarg($targetfolder);
$command = "cd $folder; git fetch -p; git branch -r -v --format='%(objectname) %(refname)' --sort=-committerdate"; // -p = prune = remove deleted remote branches
$lines = explode("\n", trim(`$command`));
// get branch name, and the last commit
$commits = [];
foreach($lines as $item) {
$item = trim($item);
if ($item != '' && strpos($item, 'origin/HEAD') === FALSE) {
if (preg_match('~^([0-9a-f]{40}) refs/remotes/origin/(.*)$~', $item, $res)) {
$commits[] = [
'branch' => $res[2],
'commit' => $res[1], // sha1
];
}
}
}
// for each branch,
// restore the file
// save to zip file
$zip = new ZipArchive;
$zipname = tempnam(sys_get_temp_dir(), 'zip');
$res = $zip->open($zipname, ZipArchive::CREATE);
foreach($commits as $info) {
$cmd = "cd $folder; git show {$info['commit']}:{$file}";
$output = `$cmd`;
$zip->addFromString("{$info['branch']}_{$basename}", $output);
}
$zip->close();
///Then download the zipped file.
header('Content-type: application/zip');
header('Content-disposition: attachment; filename=search_results.zip');
header('Content-length: ' . filesize($zipname));
readfile($zipname);
unlink($zipname);
exit;
}
}
/*
Note that "ionic_source_map_type" must be "source-map"
If this is "ionic_source_map_type": "#inline-source-map" it still triggers the error even with --generateSourceMap false
// .git/FETCH_HEAD
git show-ref
git show-branch -a ec3d4e213548fd158dd3114458b637b01b2e2a91
// current // branch head
git rev-list --format=medium --ancestry-path f05ff31f90c88a9ffa25f908d2bb5e9258d7abd9..79aa58c3897664e4551a9b931e94e493afd2b0e1
commit aebac9e8a12205ccdd4b64ad45b214f442239b15
Author: Phil Young <you@example.com>
Date: Wed Jun 5 17:16:06 2019 -0400
update formatting of credits on success page
git log --no-walk b4a366e08d350091d1886ef30414d07083bfd440
commit b4a366e08d350091d1886ef30414d07083bfd440 (origin/ma1-oak)
Author: Phil Young <phil@hostz.org>
Date: Fri Jan 31 18:54:52 2020 -0500
new images, new audio
phil@pegasus:/var/www/pkp/storage/patientapps/data$
*/