URL: https://github.com/adamjimenez/shiftedit-ajax
Edit the username and password below
*/
//set error level
error_reporting(E_ALL ^ E_NOTICE);
ini_set('display_errors', '0');
ini_set('display_startup_errors', '0');
set_error_handler('error_handler');
register_shutdown_function('shutdown');
//config
$host = '{$host}';
$username = '{$username}'; // username or ftp username
$password = '{$password}'; // password or ftp password
$dir = '{$dir}'; // path to files e.g. dirname(__FILE__).'/';
$server_type = '{$server_type}'; // local, ftp or sftp. local requires webserver to have write permissions to files.
$pasv = '{$pasv}'; // true for pasv mode / false for active mode
$port = '{$port}'; // usually 21 for ftp and 22 for sftp
$definitions = '{$definitions}'; // autocomplete definitions e.g. http://example.org/defs.json
$phpseclib_path = ''; // path to phpseclib for sftp, get from: https://github.com/phpseclib/phpseclib
$origin = $_SERVER['HTTP_ORIGIN'] ?: '{$origin}'; // CORS origin: https://shiftedit.net
// restrict access by ip
$ip_restrictions = false;
// allowed ips. get your ip from https://www.google.co.uk/search?q=ip+address
$ips = [];
// api version
$version = '1.3';
function shutdown() {
if ($error = error_get_last()) {
error_handler($error['type'], $error['message'], $error['file'], $error['line']);
}
}
function error_handler($errno, $errstr, $errfile, $errline, $errcontext = "") {
switch ($errno) {
case E_USER_ERROR:
case E_ERROR:
case E_PARSE:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
$response = [];
$response['success'] = false;
$response['error'] = $errstr.' on line '.$errline;
echo json_encode($response);
exit;
break;
}
}
//include path
if ($phpseclib_path) {
set_include_path(get_include_path() . PATH_SEPARATOR . $phpseclib_path);
}
//prevent magic quotes
if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
function stripslashes_gpc(&$value) {
$value = stripslashes($value);
}
array_walk_recursive($_GET, 'stripslashes_gpc');
array_walk_recursive($_POST, 'stripslashes_gpc');
}
// CORS Allow from shiftedit
if (isset($_SERVER['HTTP_ORIGIN'])) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400');
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
}
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
}
exit;
}
$cookie_secure = ($_SERVER['HTTPS'] === 'on');
$cookie_params = session_get_cookie_params();
if(PHP_VERSION_ID < 70300) {
session_set_cookie_params($cookie_params['lifetime'], '/; SameSite=None', $cookie_params['domain'], $cookie_secure, $cookie_params['httponly']);
} else {
session_set_cookie_params([
'lifetime' => $cookie_params['lifetime'],
'path' => '/',
'domain' => $cookie_params['domain'],
'secure' => $cookie_secure,
'httponly' => $cookie_params['httponly'],
'samesite' => 'None'
]);
}
session_start();
try {
//ip restrictions
if ($ip_restrictions and !in_array($_SERVER['REMOTE_ADDR'], $ips)) {
throw new Exception('access denied, ip restrictions in effect');
}
//authentication
if ($username and !$_SESSION['shiftedit_logged_in']) {
if ($username !== $_POST['user'] || sha1($password) !== $_POST['pass']) {
//delay to protect against brute force attack
sleep(1);
throw new Exception('Login incorrect');
}
$_SESSION['shiftedit_logged_in'] = true;
}
header('Content-Type: application/json, charset=utf-8');
abstract class server
{
function __construct() {
//max upload size
$this->max_size = 20000000;
$this->max_files = $_SESSION['prefs']['maxFiles'] ?: 1000;
$this->ftp_log = [];
$this->startedAt = 0;
$this->output_log = true;
$this->text_files = [
'css',
'htaccess',
'html',
'jade',
'java',
'js',
'json',
'less',
'md',
'php',
'pl',
'py',
'rb',
'scala',
'scss',
'sh',
'svg',
'txt',
'xml',
'yaml',
];
}
function send_msg($id, $msg) {
echo "id: $id" . PHP_EOL;
echo "data: {\n";
echo "data: \"msg\": \"$msg\", \n";
echo "data: \"id\": $id\n";
echo "data: }\n";
echo PHP_EOL;
ob_flush();
flush();
}
function log($msg) {
$this->ftp_log[] = $msg;
if ($this->startedAt) {
$this->send_msg($this->startedAt, $msg);
}
}
function chmod_num($permissions) {
$mode = 0;
if ($permissions[1] == 'r') $mode += 0400;
if ($permissions[2] == 'w') $mode += 0200;
if ($permissions[3] == 'x') $mode += 0100;
else if ($permissions[3] == 's') $mode += 04100;
else if ($permissions[3] == 'S') $mode += 04000;
if ($permissions[4] == 'r') $mode += 040;
if ($permissions[5] == 'w') $mode += 020;
if ($permissions[6] == 'x') $mode += 010;
else if ($permissions[6] == 's') $mode += 02010;
else if ($permissions[6] == 'S') $mode += 02000;
if ($permissions[7] == 'r') $mode += 04;
if ($permissions[8] == 'w') $mode += 02;
if ($permissions[9] == 'x') $mode += 01;
else if ($permissions[9] == 't') $mode += 01001;
else if ($permissions[9] == 'T') $mode += 01000;
return sprintf('%o', $mode);
}
function mkdir_recursive($path) {
$parts = explode('/', $path);
$path = '';
foreach ($parts as $part) {
$path .= $part;
if (!$this->file_exists($path)) {
$result = $this->mkdir($path);
if ($result === false) {
return false;
}
}
$path .= '/';
}
return true;
}
function close() {}
}
if ($server_type === 'local') {
class local extends server {
function __construct() {
global $dir;
// prefix dir with slash
if (strlen($dir) and substr($dir, 0, 1) != '/') {
$dir = '/'.$dir;
}
$this->dir = $dir;
}
function chdir($path) {
if ($path === $this->pwd) {
return true;
} else {
if (chdir($path)) {
$this->pwd = $path;
return true;
} else {
return false;
}
}
}
function get($remote_file) {
$path = $this->dir.$remote_file;
return file_get_contents($path);
}
function put($file, $content, $resume_pos = 0) {
if (!$file) {
return false;
}
$path = $this->dir.$file;
$fp = fopen($path, 'w');
fseek($fp, $resume_pos);
$result = fwrite($fp, $content);
fclose($fp);
return $result;
}
function last_modified($file) {
$file = $this->dir.$file;
return filemtime($file);
}
function is_dir($dir) {
$dir = $this->dir.$dir;
return is_dir($dir);
}
function file_exists($file) {
$file = $this->dir.$file;
return file_exists($file);
}
function chmod($mode, $file) {
$file = $this->dir.$file;
return chmod($mode, $file);
}
function rename($old_name, $new_name) {
$old_name = $this->dir.$old_name;
$new_name = $this->dir.$new_name;
return rename($old_name, $new_name);
}
function mkdir($dir) {
$dir = $this->dir.$dir;
return mkdir($dir);
}
function delete($file) {
if (!$file) {
$this->log[] = 'no file';
return false;
}
$path = $this->dir.$file;
if ($this->is_dir($file)) {
$list = $this->parse_raw_list($file);
if (!is_array($list)) {
return false;
}
foreach ($list as $item) {
if ($item['name'] != '..' && $item['name'] != '.') {
$this->delete($file.'/'.$item['name']);
}
}
chdir('../');
$this->log('rmdir '.$file);
if (!rmdir($path)) {
return false;
} else {
return true;
}
} else {
if ($this->file_exists($file)) {
$this->log('delete '.$file);
return unlink($path);
}
}
}
function parse_raw_list($path) {
$path = $this->dir.$path;
if ($path and !$this->chdir($path)) {
return false;
}
$d = dir($path);
if ($d === false) {
return false;
}
$items = [];
while (false !== ($entry = $d->read())) {
$items[] = array(
'name' => $entry,
'permsn' => substr(decoct(fileperms($entry)), 2),
'size' => (int)filesize($entry),
'modified' => filemtime($entry),
'type' => is_dir($entry) ? 'folder' : 'file',
);
}
$d->close();
return $items;
}
function search_nodes($s, $path) {
$list = $this->parse_raw_list($path);
if (!is_array($list)) {
return [];
}
$items = [];
foreach ($list as $v) {
if ($v['type'] != 'file') {
if ($v['name'] == '.' or $v['name'] == '..' or $v['name'] == '.svn') {
continue;
}
$arr = $this->search_nodes($s, $path.$v['name'].'/');
$items = array_merge($items, $arr);
} else {
if (strstr($v['name'], $s)) {
$items[] = $path.$v['name'];
$this->send_msg($this->startedAt, $path.$v['name']);
}
}
}
return $items;
}
function search($s, $path) {
$this->startedAt = time();
return $this->search_nodes($s, $path);
}
}
} elseif ($server_type === 'ftp') {
class ftp extends server {
function connect($host, $user, $pass, $port = 21, $dir, $options = []) {
$pasv = $options['pasv'] ? $options['pasv'] : true;
$logon_type = $options['logon_type'];
$encryption = $options['encryption'];
if (!$host) {
$this->ftp_log[] = 'No domain';
return false;
}
if (!$options['timeout']) {
$options['timeout'] = 10;
}
if (!function_exists('ftp_connect')) {
$this->ftp_log[] = 'PHP FTP module is not installed';
return false;
}
if (function_exists('ftp_ssl_connect')) {
$this->conn_id = ftp_ssl_connect($host, $port, $options['timeout']);
} else {
$this->conn_id = ftp_connect($host, $port, $options['timeout']);
}
if (!$this->conn_id) {
$this->ftp_log[] = 'connection to host failed';
return false;
}
if ($encryption) {
$result = ftp_login($this->conn_id, $user, $pass);
} else {
$this->command("USER ".$user);
$result = $this->command("PASS ".$pass);
}
if (substr($result, 0, 3) == '530') {
$this->require_password = true;
}
if ($pasv) {
ftp_pasv($this->conn_id, true);
}
// prefix dir with slash
if (strlen($dir) and substr($dir, 0, 1) != '/') {
$dir = '/'.$dir;
}
$this->dir = $dir;
if (substr($result, 0, 3) !== '230' and $result !== true) {
return false;
} elseif ($dir and !$this->chdir($dir)) {
$this->ftp_log[] = 'Dir does not exist: '.$dir;
return false;
} else {
return true;
}
}
function command($command) {
$result = ftp_raw($this->conn_id, $command);
if (substr($command, 0, 5) == 'PASS ') {
$command = 'PASS ******';
}
$this->ftp_log[] = $command;
$this->ftp_log = array_merge($this->ftp_log, $result);
return trim(end($result));
}
function chdir($path) {
if ($path === $this->pwd) {
return true;
} else {
$this->ftp_log[] = 'chdir '.$path;
if (@ftp_chdir($this->conn_id, $path)) {
$this->pwd = $path;
return true;
} else {
return false;
}
}
}
function get($remote_file, $get_file = false) {
$remote_file = $this->dir.$remote_file;
//check file size
$size = ftp_size($this->conn_id, $remote_file);
if ($size > $this->max_size) {
$this->ftp_log[] = 'File too large: '.file_size($size);
return false;
}
$tmpdir = sys_get_temp_dir() or die('failed to get tmp dir');
$tmpfname = tempnam($tmpdir, "shiftedit_ftp_") or die('failed to create tmp file');
$handle = fopen($tmpfname, "w+") or die('failed to open tmp file');
if (ftp_fget($this->conn_id, $handle, $remote_file, FTP_BINARY)) {
if ($get_file) {
fclose($handle);
return $tmpfname;
}
rewind($handle);
$data = stream_get_contents($handle, $this->max_size);
fclose($handle);
unlink($tmpfname);
return $data;
} else {
fclose($handle);
unlink($tmpfname);
return false;
}
}
function put($file, $content, $resume_pos = 0) {
$mode = FTP_BINARY;
if (!$file) {
return false;
}
$path = $this->dir.$file;
$tmp = tmpfile();
if (fwrite($tmp, $content) === false) {
$this->ftp_log[] = 'can\'t write to filesystem';
return false;
}
rewind($tmp);
$this->chdir(dirname($path));
if ($resume_pos) {
ftp_raw($this->conn_id, "REST ".$resume_pos);
}
$result = ftp_fput($this->conn_id, basename_safe($path), $tmp, $mode);
//try deleting first
if ($result === false) {
$items = $this->parse_raw_list(dirname($file));
if (!is_array($items)) {
return false;
}
$perms = 0;
foreach ($items as $v) {
if ($v['name'] == basename($file)) {
$perms = $v['permsn'];
}
}
//delete before save otherwise save does not work on some servers
$this->delete($file);
if ($perms) {
$this->chmod($perms, $file);
}
if ($resume_pos) {
ftp_raw($this->conn_id, "REST ".$resume_pos);
}
$result = ftp_fput($this->conn_id, basename_safe($path), $tmp, $mode);
}
fclose($tmp);
return $result;
}
function last_modified($file) {
$file = $this->dir.$file;
return ftp_mdtm($this->conn_id, $file);
}
function size($file) {
$file = $this->dir.$file;
return ftp_size($this->conn_id, $file);
}
function is_dir($dir) {
$dir = $this->dir.$dir;
// Get the current working directory
$origin = ftp_pwd($this->conn_id);
// Attempt to change directory, suppress errors
return ftp_size($this->conn_id, $dir) === -1;
}
function file_exists($file) {
$file = $this->dir.$file;
if (ftp_size($this->conn_id, $file) == '-1') {
//folder?
if ($this->chdir($file)) {
return true;
}
return false;
} else {
return true;
}
}
function chmod($mode, $file) {
$file = $this->dir.$file;
return ftp_chmod($this->conn_id, intval($mode, 8), $file);
}
function rename($old_name, $new_name) {
$old_name = $this->dir.$old_name;
$new_name = $this->dir.$new_name;
return ftp_rename($this->conn_id, $old_name, $new_name);
}
function mkdir($dir) {
$dir = $this->dir.$dir;
return ftp_mkdir($this->conn_id, $dir) !== false ? true : false;
}
function delete($file) {
if (!$file) {
$this->ftp_log[] = 'no file';
return false;
}
$path = $this->dir.$file;
if ($this->is_dir($file)) {
$list = $this->parse_raw_list($file);
if (!is_array($list)) {
return false;
}
foreach ($list as $item) {
if ($item['name'] != '..' && $item['name'] != '.') {
$this->delete($file.'/'.$item['name']);
}
}
if (!$this->chdir(dirname($path))) {
return false;
}
$this->log('rmdir '.$file);
if (!ftp_rmdir($this->conn_id, basename($path))) {
return false;
} else {
return true;
}
} else {
if ($this->file_exists($file)) {
$this->log('delete '.$file);
return ftp_delete($this->conn_id, $path);
}
}
}
function parse_raw_list($path) {
$path = $this->dir.$path;
$array = ftp_rawlist($this->conn_id, '-a '.$path);
if ($array === false) {
return false;
}
$items = [];
//$systype = ftp_systype($this->conn_id);
foreach ($array as $folder) {
$struc = [];
if (preg_match("/([0-9]{2})-([0-9]{2})-([0-9]+) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|
) +(.+)/", $folder, $split)) {
if (is_array($split)) {
if ($split[3] < 70) {
$split[3] += 2000;
} else {
$split[3] += 1900;
} // 4digit year fix
$struc['month'] = $split[1];
$struc['day'] = $split[2];
if (strlen($split[3]) == 4) {
$struc['year'] = $split[3];
$struc['time'] = '00:00';
} else {
$struc['year'] = date('Y');
$struc['time'] = $split[3];
if (strtotime($struc['month'].' '.$struc['day'].' '.$struc['year'].' '.$struc['time']) > time()) {
$struc['year'] -= 1;
}
}
$struc['modified'] = strtotime($struc['month'].' '.$struc['day'].' '.$struc['year'].' '.$struc['time']);
$struc['name'] = $split[8];
if ($split[7] == "") {
$struc['type'] = 'folder';
} else {
$struc['type'] = 'file';
$struc['size'] = $split[7];
}
}
} else {
$current = preg_split("/[\s]+/", $folder, 9);
$i = 0;
$struc['perms'] = $current[0];
$struc['permsn'] = $this->chmod_num($struc['perms']);
$struc['number'] = $current[1];
$struc['owner'] = $current[2];
$struc['group'] = $current[4];
$struc['size'] = $current[(count($current)-5)];
$struc['month'] = $current[(count($current)-4)];
$struc['day'] = $current[(count($current)-3)];
$date = $current[(count($current)-2)];
$struc['name'] = str_replace('//', '', end($current));
if (strlen($date) == 4) {
$struc['year'] = $date;
$struc['time'] = '00:00';
} else {
$struc['year'] = date('Y');
if (strtotime($struc['month'].' '.$struc['day']) > time()) {
$struc['year']--;
}
$struc['time'] = $date;
}
$struc['modified'] = strtotime($struc['month'].' '.$struc['day'].' '.$struc['year'].' '.$struc['time']);
$struc['raw'] = $folder;
if (substr($folder, 0, 1) == "d") {
$struc['type'] = 'folder';
} elseif (substr($folder, 0, 1) == "l") {
$struc['type'] = 'link';
continue;
} else {
$struc['type'] = 'file';
}
}
if ($struc['name']) {
$items[] = $struc;
}
}
return $items;
}
function search_nodes($s, $path) {
$list = $this->parse_raw_list($path);
if (!is_array($list)) {
return [];
}
$items = [];
foreach ($list as $v) {
$file_path = $path . $v['name'];
if ($v['type'] != 'file') {
if (in_array($v['name'], ['.', '..', '.svn', '.git'])) {
continue;
}
$arr = $this->search_nodes($s, $file_path . '/');
$items = array_merge($items, $arr);
} else {
if (strstr($v['name'], $s)) {
$items[] = $file_path;
$this->send_msg($this->startedAt, $file_path);
}
// search content of text files
if (in_array(file_ext($v['name']), $this->text_files)) {
$content = $this->get($file_path);
if (stristr($content, $s)) {
$items[] = $file_path;
$this->send_msg($this->startedAt, $file_path);
}
}
}
}
return $items;
}
function search($s, $path) {
$this->startedAt = time();
return $this->search_nodes($s, $path);
}
function close() {
ftp_close($this->conn_id);
}
}
} else if ($server_type === 'sftp') {
if ($phpseclib_path) {
class sftp extends server {
function __construct() {
$this->debug = false;
parent::__construct();
require_once('Net/SFTP.php');
if ($this->debug) {
define('NET_SSH2_LOGGING', NET_SSH2_LOG_COMPLEX);
}
}
function errorHandler($errno, $errstr, $errfile, $errline) {
if ($this->debug) {
print $errstr." in ";
print $errfile." on line ";
print $errline."\n";
}
if ($errno === E_USER_NOTICE) {
$this->ftp_log[] = $errstr;
$this->failed = true;
}
}
function connect($host, $user, $pass, $port = 22, $dir, $options = []) {
if (!$host) {
return false;
}
$this->ftp_log = [];
$this->failed = false;
$logon_type = $options['logon_type'];
if (!$options['timeout']) {
$options['timeout'] = 10;
}
set_error_handler(array($this, 'errorHandler'));
$this->sftp = new Net_SFTP($host, $port, $options['timeout']);
if (!$this->sftp) {
$this->ftp_log[] = 'connection to host failed';
$this->ftp_log[] = $this->sftp->getSFTPLog();
return false;
}
if ($this->failed) {
return;
}
if ($logon_type == 'key') {
if (!$private_key) {
$this->ftp_log[] = 'missing key - set a key from your account';
return false;
}
require_once("Crypt/RSA.php");
$pass = new Crypt_RSA();
if (!$pass->loadKey($private_key)) {
$this->ftp_log[] = 'invalid key';
return false;
}
}
if ($this->sftp->login($user, $pass) === false) {
$stars = '';
for ($i = 0; $i < strlen($pass); $i++) {
$stars .= '*';
}
$this->ftp_log[] = $this->sftp->getLog();
$this->ftp_log[] = $this->sftp->getSFTPLog();
if ($logon_type == 'key') {
$this->ftp_log[] = 'Can\'t connect with key';
} else {
$this->ftp_log[] = 'login incorrect
User: '.$user.'
Pass: '.$stars.'
'.$log;
$this->require_password = true;
}
return false;
}
$this->dir = $dir;
if (!$this->sftp) {
return false;
} elseif ($dir and !$this->sftp->stat($dir)) {
$this->ftp_log[] = 'Dir does not exist: '.$dir;
return false;
} else {
return true;
}
}
function get($remote_file) {
$remote_file = $this->dir.$remote_file;
//check file size
$size = $this->sftp->size($remote_file);
if ($size > $this->max_size) {
$this->ftp_log[] = 'File too large: '.file_size($size);
return false;
}
$data = $this->sftp->get($remote_file);
if ($data === false) {
return false;
}
return $data;
}
function put($remote_file, $content, $resume_pos = -1) {
$remote_file = $this->dir.$remote_file;
return $this->sftp->put($remote_file, $content, NET_SFTP_STRING, $resume_pos);
}
function last_modified($file) {
$file = $this->dir.$file;
$stat = $this->sftp->stat($file);
return $stat['mtime'];
}
function size($file) {
$file = $this->dir.$file;
return $this->sftp->size($file);
}
function is_dir($file) {
$file = $this->dir.$file;
$stat = $this->sftp->stat($file);
return ($stat['type'] == 2) ? true : false;
}
function file_exists($file) {
$file = $this->dir.$file;
$stat = $this->sftp->stat($file);
return $stat ? true : false;
}
function chmod($mode, $file) {
$file = $this->dir.$file;
return $this->sftp->chmod($mode, $file);
}
function rename($old_name, $new_name) {
$old_name = $this->dir.$old_name;
$new_name = $this->dir.$new_name;
return $this->sftp->rename($old_name, $new_name);
}
function mkdir($dir) {
$dir = $this->dir.$dir;
return $this->sftp->mkdir($dir);
}
function delete($file) {
if (!$file) {
return false;
}
$path = $this->dir.$file;
return $this->sftp->delete($path, true);
}
function parse_raw_list($subdir) {
$path = $this->dir.$subdir;
$items = [];
$files = $this->sftp->rawlist($path);
// List all the files
$i = 0;
foreach ($files as $file => $stat) {
if ($file != '.' and $file != '..') {
$items[$i]['name'] = $file;
$items[$i]['permsn'] = $stat['permissions'];
if ($stat['type'] == 1) {
$items[$i]['type'] = 'file';
$items[$i]['size'] = (int)$stat['size'];
} elseif ($stat['type'] == 2) {
$items[$i]['type'] = 'folder';
} else {
//ignore symlinks
continue;
}
$items[$i]['modified'] = $stat['mtime'];
}
$i++;
}
return $items;
}
function search_nodes($s, $path) {
$packet_handler = function($string) {
$items = explode("\n", trim($string));
$items = array_unique($items);
sort($items);
foreach ($items as $k => $v) {
if (strstr($v, ':')) {
continue;
}
$v = substr($v, strlen($dir));
$this->send_msg($this->startedAt, $v);
}
};
$dir = $this->dir.$path;
$this->exec("pkill grep");
$this->exec("pkill find");
$results = $this->exec('grep -Ilr '.escapeshellarg($s).' '.escapeshellarg($dir), $packet_handler);
$results .= $this->exec('find '.escapeshellarg($dir).' -name "'.escapeshellarg($s).'*"', $packet_handler);
}
function search($s, $path) {
$this->startedAt = time();
return $this->search_nodes($s, $path);
}
function close() {
if ($this->sftp) {
$this->sftp->__destruct();
}
}
}
} else if (function_exists('ssh2_connect')) {
class sftp extends server {
function connect($host, $user, $pass, $port = 22, $dir, $options = []) {
if (!function_exists('ssh2_connect')) {
$this->ftp_log[] = 'PHP SSH2 module not loaded';
return false;
}
$logon_type = $options['logon_type'];
if (!$options['timeout']) {
$options['timeout'] = 10;
}
if (!$host) {
$this->ftp_log[] = 'No domain';
return false;
}
if (!$options['timeout']) {
$options['timeout'] = 10;
}
$this->conn_id = ssh2_connect($host, $port);
if (!$this->conn_id) {
$this->ftp_log[] = 'connection to host failed';
return false;
}
$result = ssh2_auth_password($this->conn_id, $user, $pass);
if (!$result) {
$this->ftp_log[] = 'login incorrect';
$this->require_password = true;
}
//print var_dump((stream_get_contents(ssh2_exec($this->conn_id, 'pwd')))); exit;
$this->sftp = ssh2_sftp($this->conn_id);
if ($this->sftp === null) {
die('can\'t establish sftp');
}
$this->dir = $dir;
if (substr($result, 0, 3) !== '230' and $result !== true) {
return false;
} elseif ($dir and !$this->chdir($dir)) {
$this->ftp_log[] = 'Dir does not exist: '.$dir;
return false;
} else {
return true;
}
}
function chdir($path) {
if ($path === $this->pwd) {
return true;
} else {
$this->ftp_log[] = 'chdir '.$path;
if ($this->exec('cd '.$path.'; pwd').'/' === $path) {
$this->pwd = $this->exec('pwd');
return true;
} else {
return false;
}
}
}
function get($remote_file, $mode = FTP_BINARY, $resume_pos = null) {
$remote_file = $this->dir.$remote_file;
//check file size
$stat = ssh2_sftp_stat($this->sftp, $remote_file);
$size = $stat['size'];
if ($size > $this->max_size) {
$this->ftp_log[] = 'File too large: '.file_size($size);
return false;
}
$handle = fopen("ssh2.sftp://".$this->sftp."/".$remote_file, 'r');
if ($handle) {
$data = stream_get_contents($handle, $this->max_size);
fclose($handle);
return $data;
} else {
fclose($handle);
return false;
}
}
function put($file, $content, $resume_pos = -1) {
$remote_file = $this->dir.$file;
$handle = fopen("ssh2.sftp://".$this->sftp."/".$remote_file, 'w');
if ($resume_pos != -1) {
fseek($handle, $resume_pos);
}
return fwrite($handle, $content);
}
function last_modified($file) {
$remote_file = $this->dir.$file;
$stat = ssh2_sftp_stat($this->sftp, $remote_file);
return $stat['mtime'];
}
function size($file) {
$remote_file = $this->dir.$file;
$stat = ssh2_sftp_stat($this->sftp, $remote_file);
return $stat['size'];
}
function is_dir($dir) {
$dir = $this->dir.$dir;
// Get the current working directory
$origin = $this->exec('pwd');
// Attempt to change directory, suppress errors
if (@$this->chdir($dir)) {
// If the directory exists, set back to origin
$this->chdir($origin);
return true;
}
// Directory does not exist
return false;
}
function file_exists($file) {
$file = $this->dir.$file;
$stat = ssh2_sftp_stat($this->sftp, $file);
if ($stat['size'] == '-1') {
//folder?
if ($this->chdir($file)) {
return true;
}
return false;
} else {
return true;
}
}
function chmod($mode, $file) {
$file = $this->dir.$file;
return ssh2_sftp_chmod($this->sftp, $file, $mode);
}
function rename($old_name, $new_name) {
$old_name = $this->dir.$old_name;
$new_name = $this->dir.$new_name;
return ssh2_sftp_rename($this->sftp, $old_name, $new_name);
}
function mkdir($dir) {
$dir = $this->dir.$dir;
return ssh2_sftp_mkdir($this->sftp, $dir) !== false ? true : false;
}
function delete($file) {
if (!$file) {
$this->ftp_log[] = 'no file';
return false;
}
$path = $this->dir.$file;
if ($this->is_dir($file)) {
$list = $this->parse_raw_list($file);
if (!is_array($list)) {
return false;
}
foreach ($list as $item) {
if ($item['name'] != '..' && $item['name'] != '.') {
$this->delete($file.'/'.$item['name']);
}
}
if (!$this->chdir(dirname($path))) {
return false;
}
$this->ftp_log[] = 'rmdir '.$path;
if (!ssh2_sftp_rmdir($this->sftp, basename($path))) {
return false;
} else {
return true;
}
} else {
if ($this->file_exists($file)) {
$this->ftp_log[] = 'delete '.$path;
return ssh2_sftp_unlink($this->sftp, $path);
}
}
}
function parse_raw_list($subdir = '') {
$path = $this->dir.$subdir;
$items = [];
$list = $this->exec('ls -al '.escapeshellarg($path));
$files = explode("\n", $list);
// List all the files
$i = 0;
foreach ($files as $folder) {
if (preg_match("/total [\d]+/", $folder)) {
continue;
}
$struc = [];
$current = preg_split("/[\s]+/", $folder, 9);
$i = 0;
$struc['perms'] = $current[0];
$struc['permsn'] = $this->chmod_num($struc['perms']);
$struc['number'] = $current[1];
$struc['owner'] = $current[2];
$struc['group'] = $current[4];
$struc['size'] = $current[(count($current)-5)];
$struc['month'] = $current[(count($current)-4)];
$struc['day'] = $current[(count($current)-3)];
$date = $current[(count($current)-2)];
$struc['name'] = str_replace('//', '', end($current));
if (strlen($date) == 4) {
$struc['year'] = $date;
$struc['time'] = '00:00';
} else {
$struc['year'] = date('Y');
if (strtotime($struc['month'].' '.$struc['day']) > time()) {
$struc['year']--;
}
$struc['time'] = $date;
}
$struc['modified'] = strtotime($struc['month'].' '.$struc['day'].' '.$struc['year'].' '.$struc['time']);
$struc['raw'] = $folder;
if (substr($folder, 0, 1) == "d") {
$struc['type'] = 'folder';
} elseif (substr($folder, 0, 1) == "l") {
$struc['type'] = 'link';
$pos = strpos($struc['name'], ' -> ');
if ($pos) {
$struc['name'] = substr($struc['name'], 0, $pos);
}
} else {
$struc['type'] = 'file';
}
if ($struc['name']) {
$items[] = $struc;
}
$i++;
}
return $items;
}
function search_nodes($s, $path) {
$packet_handler = function($string) {
global $dir;
$items = explode("\n", trim($string));
$items = array_unique($items);
sort($items);
foreach ($items as $k => $v) {
if (strstr($v, ':')) {
continue;
}
$v = substr($v, strlen($dir));
if ($v) {
$this->send_msg($this->startedAt, $v);
}
}
};
$dir = $this->dir.$path;
$this->exec("pkill grep");
$this->exec("pkill find");
$results = $this->exec('grep -Ilr '.escapeshellarg($s).' '.escapeshellarg($dir));
$results .= $this->exec('find '.escapeshellarg($dir).' -name "'.escapeshellarg($s).'*"');
$packet_handler($results);
}
function search($s, $path) {
$this->startedAt = time();
return $this->search_nodes($s, $path);
}
function close() {}
function exec($command) {
$stream = ssh2_exec($this->conn_id, $command);
if (!$stream) {
return false;
}
stream_set_blocking($stream, true);
$result = stream_get_contents($stream);
if (substr($command, 0, 5) == 'PASS ') {
$command = 'PASS ******';
}
$this->ftp_log[] = $command;
if ($result) {
$this->ftp_log[] = $result;
}
return trim($result);
}
}
} else if (function_exists('curl_version')) {
class sftp extends server {
function cd($path) {
curl_setopt($this->curl, CURLOPT_URL, "sftp://".$this->host.':'.$this->port.'/'.$path);
}
function connect($host, $user, $pass, $port = 22, $dir, $options = []) {
$this->debug = false;
if (!function_exists('curl_version')) {
$this->log('PHP curl not loaded');
return false;
}
if (!$host) {
return false;
}
if (!$port) {
$port = 22;
}
$this->failed = false;
if (!$options['timeout']) {
$options['timeout'] = 10;
}
$this->timeout = $options['timeout'];
$this->host = $host;
$this->port = $port;
$this->dir = $dir;
$this->curl = curl_init();
$this->cd($this->dir);
curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
if ($options['logon_type'] == 'key') {
global $auth;
if (!$auth->user['private_key']) {
$this->log('missing key - set a key from your account');
return false;
}
$this->keyfile = tempnam();
file_put_contents($this->keyfile, $auth->user['private_key']);
curl_setopt($this->curl, CURLOPT_SSH_PRIVATE_KEYFILE, $this->keyfile);
curl_setopt($this->curl, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PUBLICKEY);
} else {
curl_setopt($this->curl, CURLOPT_USERPWD, $user.":".$pass);
}
return true;
}
function meta($remote_file) {
// caching
if ($this->meta[$remote_file]) {
return $this->meta[$remote_file];
}
$dir = dirname($remote_file);
if ($dir === '.') {
$dir = '';
}
$files = $this->parse_raw_list($dir);
if (!is_array($files)) {
return false;
}
foreach ($files as $v) {
$this->meta[$dir.'/'.$v['name']] = $v;
}
return $this->meta[$remote_file] ?: false;
}
function get($remote_file) {
$path = $this->dir.$remote_file;
//check file size
$size = $this->size($remote_file);
if ($size > $this->max_size) {
$this->log('File too large: '.file_size($size));
return false;
}
$this->cd($path);
$data = curl_exec($this->curl);
if ($data === false) {
return false;
}
return $data;
}
function put($remote_file, $content, $resume_pos = -1) {
$path = $this->dir.$remote_file;
$this->cd($path);
$tmp = tmpfile();
if (fwrite($tmp, $content) === false) {
$this->log('can\'t write to filesystem');
return false;
}
rewind($tmp);
curl_setopt($this->curl, CURLOPT_UPLOAD, 1);
curl_setopt($this->curl, CURLOPT_INFILE, $tmp);
curl_setopt($this->curl, CURLOPT_INFILESIZE, strlen($content));
curl_exec($this->curl);
$error_no = curl_errno($this->curl);
fclose($tmp);
$this->curl = curl_init();
curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
if ($error_no === 0) {
return true;
} else {
$this->log(curl_error($this->curl));
return false;
}
}
function last_modified($file) {
$meta = $this->meta($file);
return $meta['modified'];
}
function size($file) {
$meta = $this->meta($file);
return $meta['size'];
}
function is_dir($file) {
$meta = $this->meta($file);
return $meta['type'] === 'folder';
}
function file_exists($file) {
$meta = $this->meta($file);
return $meta !== false ? true : false;
}
function chmod($mode, $file) {
$path = $this->dir.$file;
return $this->exec('chmod '.$mode.' "'.$path.'"');
}
function rename($old_name, $new_name) {
$old_name = $this->dir.$old_name;
$new_name = $this->dir.$new_name;
return $this->exec('rename "'.$old_name.'" "'.$new_name.'"');
}
function mkdir($dir) {
$path = $this->dir.$dir;
return $this->exec('mkdir "'.$path.'"');
}
function delete($file) {
if (!$file) {
$this->log('no file');
return false;
}
$path = $this->dir.$file;
if ($this->is_dir($file)) {
$list = $this->parse_raw_list($file);
if (!is_array($list)) {
return false;
}
foreach ($list as $item) {
if ($item['name'] != '..' && $item['name'] != '.') {
return $this->exec('rm "'.$file.'/'.$item['name'].'"');
}
}
if (!$this->exec('rmdir "'.$path.'"')) {
return false;
} else {
return true;
}
} else {
if ($this->file_exists($file)) {
return $this->exec('rm "'.$path.'"');
}
}
}
function parse_raw_list($dir = '') {
$items = [];
$this->cd($this->dir.$dir.'/');
curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, 'LIST -a');
$list = curl_exec($this->curl);
if (curl_errno($this->curl)) {
$this->log(curl_error($this->curl));
return false;
}
$files = explode("\n", $list);
// List all the files
$i = 0;
foreach ($files as $folder) {
$struc = [];
$current = preg_split("/[\s]+/", $folder, 9);
$i = 0;
$struc['perms'] = $current[0];
$struc['permsn'] = $this->chmod_num($struc['perms']);
$struc['number'] = $current[1];
$struc['owner'] = $current[2];
$struc['group'] = $current[4];
$struc['size'] = $current[(count($current)-5)];
$struc['month'] = $current[(count($current)-4)];
$struc['day'] = $current[(count($current)-3)];
$date = $current[(count($current)-2)];
$struc['name'] = trim(str_replace('//', '', end($current)));
if (strlen($date) == 4) {
$struc['year'] = $date;
$struc['time'] = '00:00';
} else {
$struc['year'] = date('Y');
if (strtotime($struc['month'].' '.$struc['day']) > time()) {
$struc['year']--;
}
$struc['time'] = $date;
}
$struc['modified'] = strtotime($struc['month'].' '.$struc['day'].' '.$struc['year'].' '.$struc['time']);
$struc['raw'] = $folder;
if (substr($folder, 0, 1) == "d") {
$struc['type'] = 'folder';
} elseif (substr($folder, 0, 1) == "l") {
$struc['type'] = 'link';
if ($pos) {
$struc['name'] = substr($struc['name'], 0, $pos);
}
} else {
$struc['type'] = 'file';
}
if ($struc['name']) {
$items[] = $struc;
}
$i++;
}
return $items;
}
function search_nodes($s, $path) {
$packet_handler = function($string) {
$items = explode("\n", trim($string));
$items = array_unique($items);
sort($items);
foreach ($items as $k => $v) {
if (strstr($v, ':')) {
continue;
}
$v = substr($v, strlen($dir));
$this->send_msg($this->startedAt, $v);
}
};
$dir = $this->dir.$path;
$this->exec("pkill grep");
$this->exec("pkill find");
$results = $this->exec('grep -Ilr '.escapeshellarg($s).' '.escapeshellarg($dir), $packet_handler);
$results .= $this->exec('find '.escapeshellarg($dir).' -name "'.escapeshellarg($s).'*"', $packet_handler);
}
function search($s, $path) {
return $this->search_nodes($s, $path);
}
function close() {
if ($this->curl) {
curl_close($this->curl);
}
if ($this->keyfile) {
unlink($this->keyfile);
}
}
function exec($command) {
if (!is_array($command)) {
$command = array($command);
}
$this->log($command);
// Make curl run our command before the actual operation, ...
curl_setopt($this->curl, CURLOPT_QUOTE, $command);
// ... but do not do any operation at all
curl_setopt($this->curl, CURLOPT_NOBODY, 1);
if ($this->debug) {
curl_setopt($this->curl, CURLOPT_VERBOSE, true);
$stream_log = fopen('php://temp', 'r+b');
curl_setopt($this->curl, CURLOPT_STDERR, $stream_log);
}
$result = curl_exec($this->curl);
$error_no = curl_errno($this->curl);
if ($error_no === 0) {
return true;
} else {
if ($this->debug) {
//print_r(curl_getinfo($this->curl));
rewind($stream_log);
$this->log(stream_get_contents($stream_log));
fclose($stream_log);
} else {
$this->log(curl_error($this->curl));
}
return false;
}
}
}
} else {
throw new Exception('no sftp library found');
}
} else if ($server_type) {
throw new Exception('invalid server type: '.$server_type);
} else {
throw new Exception("missing server type in proxy file");
}
/* START OF GIT CLASS */
/**
* Git Interface Class
*
* This class enables the creating, reading, and manipulation
* of git repositories.
*
* @class Git
*/
class Git {
/**
* Git executable location
*
* @var string
*/
protected static $bin = '/usr/bin/git';
/**
* Sets git executable path
*
* @param string $path executable location
*/
public static function set_bin($path) {
self::$bin = $path;
}
/**
* Gets git executable path
*/
public static function get_bin() {
return self::$bin;
}
/**
* Sets up library for use in a default Windows environment
*/
public static function windows_mode() {
self::set_bin('git');
}
/**
* Create a new git repository
*
* Accepts a creation path, and, optionally, a source path
*
* @access public
* @param string repository path
* @param string directory to source
* @return GitRepo
*/
public static function &create($repo_path, $source = null) {
return GitRepo::create_new($repo_path, $source);
}
/**
* Open an existing git repository
*
* Accepts a repository path
*
* @access public
* @param string repository path
* @return GitRepo
*/
public static function open($repo_path) {
return new GitRepo($repo_path);
}
/**
* Clones a remote repo into a directory and then returns a GitRepo object
* for the newly created local repo
*
* Accepts a creation path and a remote to clone from
*
* @access public
* @param string repository path
* @param string remote source
* @param string reference path
* @return GitRepo
**/
public static function &clone_remote($repo_path, $remote, $reference = null) {
return GitRepo::create_new($repo_path, $remote, true, $reference);
}
/**
* Checks if a variable is an instance of GitRepo
*
* Accepts a variable
*
* @access public
* @param mixed variable
* @return bool
*/
public static function is_repo($var) {
return (get_class($var) == 'GitRepo');
}
}
// ------------------------------------------------------------------------
/**
* Git Repository Interface Class
*
* This class enables the creating, reading, and manipulation
* of a git repository
*
* @class GitRepo
*/
class GitRepo {
protected $repo_path = null;
protected $bare = false;
protected $envopts = [];
/**
* Create a new git repository
*
* Accepts a creation path, and, optionally, a source path
*
* @access public
* @param string repository path
* @param string directory to source
* @param string reference path
* @return GitRepo
*/
public static function &create_new($repo_path, $source = null, $remote_source = false, $reference = null) {
if (is_dir($repo_path) && file_exists($repo_path."/.git") && is_dir($repo_path."/.git")) {
throw new Exception('"'.$repo_path.'" is already a git repository');
} else {
$repo = new self($repo_path, true, false);
if (is_string($source)) {
if ($remote_source) {
if (!is_dir($reference) || !is_dir($reference.'/.git')) {
throw new Exception('"'.$reference.'" is not a git repository. Cannot use as reference.');
} else if (strlen($reference)) {
$reference = realpath($reference);
$reference = "--reference $reference";
}
$repo->clone_remote($source, $reference);
} else {
$repo->clone_from($source);
}
} else {
$repo->run('init');
}
return $repo;
}
}
/**
* Constructor
*
* Accepts a repository path
*
* @access public
* @param string repository path
* @param bool create if not exists?
* @return void
*/
public function __construct($repo_path = null, $create_new = false, $_init = true) {
if (is_string($repo_path)) {
$this->set_repo_path($repo_path, $create_new, $_init);
}
}
/**
* Set the repository's path
*
* Accepts the repository path
*
* @access public
* @param string repository path
* @param bool create if not exists?
* @param bool initialize new Git repo if not exists?
* @return void
*/
public function set_repo_path($repo_path, $create_new = false, $_init = true) {
if (is_string($repo_path)) {
if ($new_path = realpath($repo_path)) {
$repo_path = $new_path;
if (is_dir($repo_path)) {
// Is this a work tree?
if (file_exists($repo_path."/.git") && is_dir($repo_path."/.git")) {
$this->repo_path = $repo_path;
$this->bare = false;
if (!is_writable($repo_path."/.git")) {
$user_info = posix_getpwuid(fileowner($repo_path."/.git"));
$file_owner = $user_info['name'];
$this->command_prefix = 'sudo -u '.$file_owner.' ';
}
// Is this a bare repo?
} else if (is_file($repo_path."/config")) {
$parse_ini = parse_ini_file($repo_path."/config");
if ($parse_ini['bare']) {
$this->repo_path = $repo_path;
$this->bare = true;
}
} else {
if ($create_new) {
$this->repo_path = $repo_path;
if ($_init) {
$this->run('init');
}
} else {
throw new Exception('"'.$repo_path.'" is not a git repository');
}
}
} else {
throw new Exception('"'.$repo_path.'" is not a directory');
}
} else {
if ($create_new) {
if ($parent = realpath(dirname($repo_path))) {
mkdir($repo_path);
$this->repo_path = $repo_path;
if ($_init) $this->run('init');
} else {
throw new Exception('cannot create repository in non-existent directory');
}
} else {
throw new Exception('"'.$repo_path.'" does not exist');
}
}
}
}
/**
* Get the path to the git repo directory (eg. the ".git" directory)
*
* @access public
* @return string
*/
public function git_directory_path() {
return ($this->bare) ? $this->repo_path : $this->repo_path."/.git";
}
/**
* Tests if git is installed
*
* @access public
* @return bool
*/
public function test_git() {
$descriptorspec = array(
1 => array('pipe', 'w'),
2 => array('pipe', 'w'),
);
$pipes = [];
$resource = proc_open(Git::get_bin(), $descriptorspec, $pipes);
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
foreach ($pipes as $pipe) {
fclose($pipe);
}
$status = trim(proc_close($resource));
return ($status != 127);
}
/**
* Run a command in the git repository
*
* Accepts a shell command to run
*
* @access protected
* @param string command to run
* @return string
*/
protected function run_command($command) {
$descriptorspec = array(
1 => array('pipe', 'w'),
2 => array('pipe', 'w'),
);
$pipes = [];
/* Depending on the value of variables_order, $_ENV may be empty.
* In that case, we have to explicitly set the new variables with
* putenv, and call proc_open with env=null to inherit the reset
* of the system.
*
* This is kind of crappy because we cannot easily restore just those
* variables afterwards.
*
* If $_ENV is not empty, then we can just copy it and be done with it.
*/
if (count($_ENV) === 0) {
$env = NULL;
foreach ($this->envopts as $k => $v) {
putenv(sprintf("%s=%s", $k, $v));
}
} else {
$env = array_merge($_ENV, $this->envopts);
}
$cwd = $this->repo_path;
$resource = proc_open($command, $descriptorspec, $pipes, $cwd, $env);
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
foreach ($pipes as $pipe) {
fclose($pipe);
}
$status = trim(proc_close($resource));
if ($status) throw new Exception($stderr);
// weird issue where result is in stderr
if (!$stdout and $stderr) return $stderr;
return $stdout;
}
/**
* Run a git command in the git repository
*
* Accepts a git command to run
*
* @access public
* @param string command to run
* @return string
*/
public function run($command) {
return shell_exec($this->command_prefix.Git::get_bin() . " " . $command . ' 2>&1');
}
/**
* Runs a 'git status' call
*
* Accept a convert to HTML bool
*
* @access public
* @param bool return string with
* @return string
*/
public function status($html = false) {
$msg = $this->run("status");
if ($html == true) {
$msg = str_replace("\n", "
", $msg);
}
return $msg;
}
/**
* Runs a `git add` call
*
* Accepts a list of files to add
*
* @access public
* @param mixed files to add
* @return string
*/
public function add($files = "*") {
if (is_array($files)) {
$files = '"'.implode('" "', $files).'"';
}
return $this->run("add $files -v");
}
/**
* Runs a `git rm` call
*
* Accepts a list of files to remove
*
* @access public
* @param mixed files to remove
* @param Boolean use the --cached flag?
* @return string
*/
public function rm($files = "*", $cached = false) {
if (is_array($files)) {
$files = '"'.implode('" "', $files).'"';
}
return $this->run("rm ".($cached ? '--cached ' : '').$files);
}
/**
* Runs a `git commit` call
*
* Accepts a commit message string
*
* @access public
* @param string commit message
* @param boolean should all files be committed automatically (-a flag)
* @return string
*/
public function commit($message = "", $commit_all = true) {
$flags = $commit_all ? '-av' : '-v';
return $this->run("commit ".$flags." -m ".escapeshellarg($message));
}
/**
* Runs a `git clone` call to clone the current repository
* into a different directory
*
* Accepts a target directory
*
* @access public
* @param string target directory
* @return string
*/
public function clone_to($target) {
return $this->run("clone --local ".$this->repo_path." $target");
}
/**
* Runs a `git clone` call to clone a different repository
* into the current repository
*
* Accepts a source directory
*
* @access public
* @param string source directory
* @return string
*/
public function clone_from($source) {
return $this->run("clone --local $source ".$this->repo_path);
}
/**
* Runs a `git clone` call to clone a remote repository
* into the current repository
*
* Accepts a source url
*
* @access public
* @param string source url
* @param string reference path
* @return string
*/
public function clone_remote($source, $reference) {
return $this->run("clone $reference $source ".$this->repo_path);
}
/**
* Runs a `git clean` call
*
* Accepts a remove directories flag
*
* @access public
* @param bool delete directories?
* @param bool force clean?
* @return string
*/
public function clean($dirs = false, $force = false) {
return $this->run("clean".(($force) ? " -f" : "").(($dirs) ? " -d" : ""));
}
/**
* Runs a `git branch` call
*
* Accepts a name for the branch
*
* @access public
* @param string branch name
* @return string
*/
public function create_branch($branch) {
return $this->run("branch $branch");
}
/**
* Runs a `git branch -[d|D]` call
*
* Accepts a name for the branch
*
* @access public
* @param string branch name
* @return string
*/
public function delete_branch($branch, $force = false) {
return $this->run("branch ".(($force) ? '-D' : '-d')." $branch");
}
/**
* Runs a `git branch` call
*
* @access public
* @param bool keep asterisk mark on active branch
* @return array
*/
public function list_branches($keep_asterisk = false) {
$branchArray = explode("\n", $this->run("branch"));
foreach ($branchArray as $i => &$branch) {
$branch = trim($branch);
if (! $keep_asterisk) {
$branch = str_replace("* ", "", $branch);
}
if ($branch == "") {
unset($branchArray[$i]);
}
}
return $branchArray;
}
/**
* Lists remote branches (using `git branch -r`).
*
* Also strips out the HEAD reference (e.g. "origin/HEAD -> origin/master").
*
* @access public
* @return array
*/
public function list_remote_branches() {
$branchArray = explode("\n", $this->run("branch -r"));
foreach ($branchArray as $i => &$branch) {
$branch = trim($branch);
if ($branch == "" || strpos($branch, 'HEAD -> ') !== false) {
unset($branchArray[$i]);
}
}
return $branchArray;
}
/**
* Returns name of active branch
*
* @access public
* @param bool keep asterisk mark on branch name
* @return string
*/
public function active_branch($keep_asterisk = false) {
$branchArray = $this->list_branches(true);
$active_branch = preg_grep("/^\*/", $branchArray);
reset($active_branch);
if ($keep_asterisk) {
return current($active_branch);
} else {
return str_replace("* ", "", current($active_branch));
}
}
/**
* Runs a `git checkout` call
*
* Accepts a name for the branch
*
* @access public
* @param string branch name
* @return string
*/
public function checkout($branch) {
return $this->run('checkout "$branch"');
}
/**
* Runs a `git merge` call
*
* Accepts a name for the branch to be merged
*
* @access public
* @param string $branch
* @return string
*/
public function merge($branch) {
return $this->run("merge $branch --no-ff");
}
/**
* Runs a git fetch on the current branch
*
* @access public
* @return string
*/
public function fetch() {
return $this->run("fetch");
}
/**
* Add a new tag on the current position
*
* Accepts the name for the tag and the message
*
* @param string $tag
* @param string $message
* @return string
*/
public function add_tag($tag, $message = null) {
if ($message === null) {
$message = $tag;
}
return $this->run("tag -a $tag -m " . escapeshellarg($message));
}
/**
* List all the available repository tags.
*
* Optionally, accept a shell wildcard pattern and return only tags matching it.
*
* @access public
* @param string $pattern Shell wildcard pattern to match tags against.
* @return array Available repository tags.
*/
public function list_tags($pattern = null) {
$tagArray = explode("\n", $this->run("tag -l $pattern"));
foreach ($tagArray as $i => &$tag) {
$tag = trim($tag);
if ($tag == '') {
unset($tagArray[$i]);
}
}
return $tagArray;
}
/**
* Push specific branch to a remote
*
* Accepts the name of the remote and local branch
*
* @param string $remote
* @param string $branch
* @return string
*/
public function push($remote, $branch) {
return $this->run("push --tags $remote $branch");
}
/**
* Pull specific branch from remote
*
* Accepts the name of the remote and local branch
*
* @param string $remote
* @param string $branch
* @return string
*/
public function pull($remote, $branch) {
return $this->run("pull $remote $branch");
}
/**
* List log entries.
*
* @param strgin $format
* @return string
*/
public function log($format = null) {
if ($format === null)
return $this->run('log');
else
return $this->run('log --pretty=format:"' . $format . '"');
}
/**
* Sets the project description.
*
* @param string $new
*/
public function set_description($new) {
$path = $this->git_directory_path();
file_put_contents($path."/description", $new);
}
/**
* Gets the project description.
*
* @return string
*/
public function get_description() {
$path = $this->git_directory_path();
return file_get_contents($path."/description");
}
/**
* Sets custom environment options for calling Git
*
* @param string key
* @param string value
*/
public function setenv($key, $value) {
$this->envopts[$key] = $value;
}
}
/* END OF GIT CLASS */
function basename_safe($path) {
if (mb_strrpos($path, '/') !== false) {
return mb_substr($path, mb_strrpos($path, '/')+1);
} else {
return $path;
}
}
function file_ext($file) {
$tmp = explode('.', $file);
return strtolower(end($tmp));
}
function so($a, $b) //sort files
{
if ($a['leaf'] == $b['leaf']) {
return (strcasecmp($a['text'], $b['text']));
} else {
return $a['leaf'];
}
}
function get_nodes($path, $paths) {
global $server;
if (!$paths) {
$paths = [];
}
$list = $server->parse_raw_list($path);
if ($list === false) {
return false;
}
$files = [];
$i = 0;
foreach ($list as $v) {
$name = basename_safe($v['name']);
if ($v['type'] != 'file') {
if ($v['name'] == '.' or $v['name'] == '..' or $v['name'] == '.svn' or $v['name'] == '') {
continue;
}
$files[$i] = array(
'id' => (string)$path.$name,
'text' => (string)$name,
'type' => 'folder',
'children' => true,
'data' => array(
'perms' => $v['permsn'],
'modified' => $v['modified'],
'size' => -1
)
);
// which paths to preload
$subdir = $path.$v['name'].'/';
$expand = false;
foreach ($paths as $p) {
if (substr($p, 0, strlen($path.$v['name'])+1) == $path.$v['name'].'/') {
$expand = true;
break;
}
}
if ($expand) {
$files[$i]['state']['opened'] = true;
$files[$i]['children'] = get_nodes($path.$v['name'].'/', $paths);
}
} else {
$ext = file_ext(basename_safe($v['name']));
if ($ext == 'lck') {
continue;
}
$files[$i] = array(
'id' => (string)$path.$name,
'text' => (string)$name,
'type' => 'file',
'children' => false,
'data' => array(
'perms' => $v['permsn'],
'modified' => $v['modified'],
'size' => (int)$v['size']
)
);
}
$i++;
}
usort($files, 'so');
return $files;
}
function get_paths($path) {
global $server,
$size,
$max_size;
$list = $server->parse_raw_list($path);
if ($list === false) {
return false;
}
$items = [];
foreach ($list as $v) {
if ($v['type'] != 'file') {
if ($v['name'] == '.' or $v['name'] == '..') {
continue;
}
$size += $v['size'];
if ($size > $max_size) {
return false;
}
$arr = get_paths($path.$v['name'].'/');
$items = array_merge($items, $arr);
} else {
$items[] = $path.$v['name'];
}
}
return $items;
}
function list_nodes($path) {
global $server,
$server_src,
$id;
$list = $server_src->parse_raw_list($path);
if (!$list) {
return [];
}
$items = [];
foreach ($list as $v) {
if ($v['name'] == '') {
continue;
}
if ($v['type'] != 'file') {
if ($v['name'] == '.' or $v['name'] == '..' or $v['name'] == '.svn') {
continue;
}
$items[] = array(
'path' => $path.$v['name'],
'isDir' => true
);
$arr = list_nodes($path.$v['name'].'/', $dest.'/'.$v['name']);
$items = array_merge($items, $arr);
} else {
$items[] = array(
'path' => $path.$v['name'],
'isDir' => false
);
}
}
return $items;
}
function copy_nodes($path, $dest) {
global $server,
$server_src,
$id;
$list = $server_src->parse_raw_list($path);
if ($list === false) {
return false;
}
$server->mkdir($dest);
$i = 0;
foreach ($list as $v) {
if ($v['type'] != 'file') {
if ($v['name'] == '.' or $v['name'] == '..' or $v['name'] == '.svn') {
continue;
}
copy_nodes($path.$v['name'].'/', $dest.'/'.$v['name']);
} else {
$content = $server_src->get($path.'/'.$v['name']);
$server->put($dest.'/'.$v['name'], $content);
}
$i++;
}
}
if ($_POST['path'] == 'root') {
$_POST['path'] = '';
}
$site = $_GET['site'];
if ($_POST['server_type']) {
$options = array(
'site' => $_POST
);
}
switch ($server_type) {
case 'ftp':
$server = new ftp();
$result = $server->connect($host, $username, $password, $port, $dir, array('pasv' => $pasv));
if ($result === false) {
$response['error'] = end($server->ftp_log);
echo json_encode($response);
exit;
}
break;
case 'sftp':
$server = new sftp();
$result = $server->connect($host, $username, $password, $port, $dir);
if ($result === false) {
$response['error'] = end($server->ftp_log);
echo json_encode($response);
exit;
}
break;
default:
$server = new local();
break;
}
if ($_GET['cmd']) {
$_POST['cmd'] = $_GET['cmd'];
}
$response = [];
switch ($_POST['cmd']) {
case 'test':
$files = $server->parse_raw_list('/');
if ($files === false) {
$response['error'] = 'Dir listing failed';
}
break;
case 'save':
if ($server->put($_POST['file'], $_POST['content']) !== false) {
$response['last_modified'] = $server->last_modified($_POST['file']);
} else {
$response['error'] = 'Failed saving '.$_POST['file'];
}
if (file_ext($_POST['file']) == 'less' and file_exists('shiftedit-lessc.inc.php')) {
require_once('shiftedit-lessc.inc.php');
$less = new lessc;
$_POST['content'] = $less->compile($_POST['content']);
$file = substr($_POST['file'], 0, -5).'.css';
$server->put($file, $_POST['content'], $_POST['compileId'], $_POST['parent']);
} elseif (file_ext($_POST['file']) == 'scss' and file_exists('shiftedit-scss.inc.php')) {
require_once('shiftedit-scss.inc.php');
$scss = new scssc();
$scss->setImportPaths(dirname($_POST['file']));
$_POST['content'] = $scss->compile($_POST['content']);
$file = substr($_POST['file'], 0, -5).'.css';
$server->put($file, $_POST['content'], $_POST['compileId'], $_POST['parent']);
$response['file_id'] = $_POST['file'];
}
break;
case 'open':
$response['content'] = $server->get($_POST['file']);
break;
case 'search':
ob_end_clean();
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
//print_r(ob_get_status());
$server->search($_GET['s'], $_GET['path']);
$server->close();
exit;
break;
case 'get':
case 'list':
session_write_close();
if ($_POST['path'] and substr($_POST['path'], -1) !== '/') {
$_POST['path'] .= '/';
}
$response['files'] = [];
if ($_POST['path'] == '/') {
$_POST['path'] = '';
}
if ($_POST['path'] == '' and $_GET['path']) {
//used by save as
$response['files'] = get_nodes($_GET['path'], array(dirname($_GET['path']).'/'));
} else {
//preload paths
$response['files'] = get_nodes($_POST['path'], $_SESSION['paths']);
}
if ($response['files'] === false) {
$response['error'] = 'Error getting files: '.end($server->ftp_log);
}
break;
case 'list_all':
if ($_POST['path'] and substr($_POST['path'], -1) !== '/') {
$_POST['path'] .= '/';
}
$server_src = $server;
$response['files'] = list_nodes($_POST['path']);
break;
case 'file_exists':
$response['file_exists'] = $server->file_exists($_GET['file']);
break;
case 'rename':
$old_name = $_POST['oldname'];
$new_name = $_POST['newname'];
if (!$server->rename($old_name, $new_name)) {
$response['error'] = 'Cannot rename file';
}
break;
case 'newdir':
$dir = $_POST['dir'];
if (!$server->mkdir($dir)) {
$response['error'] = 'Cannot create dir';
}
break;
case 'newfile':
$content = '';
if (!$server->put($_POST['file'], $content)) {
$response['error'] = 'Cannot create file';
}
break;
case 'duplicate':
case 'paste':
if (!$_POST['dest'] or !$_POST['path']) {
$response['error'] = 'Cannot create file';
} else {
$server_src = $server;
if ($_POST['isDir']) {
if ($_POST['dest'] and $server->file_exists($_POST['dest'])) {} elseif ($_POST['dest'] and $server->mkdir($_POST['dest'])) {} else {
$response['error'] = 'Cannot create folder: '.$_POST['dest'];
}
} else {
$content = $server_src->get($_POST['path']);
if ($content === false) {
$response['error'] = 'Cannot read file: '.$_POST['path'];
} elseif (!$_POST['dest'] or !$server->put($_POST['dest'], $content)) {
$response['error'] = 'Cannot create file: ' . $_POST['dest'];
}
}
if ($_POST['path'] and $_POST['cut'] == 'true') {
$server_src->delete($_POST['path']);
}
}
break;
case 'delete':
$files = [];
// backcompat
if ($_GET['file']) {
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$server->startedAt = time();
$files[] = $_GET['file'];
} else if ($_POST['files']) {
if (count($_POST['files']) === 1) {
$files = $_POST['files'];
} else {
$_SESSION['del_queue'] = $_POST['files'];
$response['queue'] = 1;
}
} else if ($_GET['queue']) {
$files = $_SESSION['del_queue'];
unset($_SESSION['del_queue']);
if (!$files) {
$response['error'] = 'No files to delete';
} else {
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$server->startedAt = time();
}
}
// delete files
foreach ($files as $file) {
if (!$server->is_dir($file)) {
if (!$server->delete($file)) {
$response['error'] = 'Cannot delete file: '.end($server->ftp_log);
}
} else {
if (!$server->delete($file)) {
$response['error'] = 'Cannot delete directory: '.end($server->ftp_log);
}
}
}
break;
case 'upload':
$response = [];
if ($_POST['chunked']) {
$relative_path = $_POST['resumableRelativePath'] ?: $_POST['resumableFilename'];
if (!$relative_path) {
throw new Exception('Cannot find file path');
}
if (substr($relative_path, 0, 1) != '/') {
$relative_path = '/' . $relative_path;
}
$path = $_POST['path'] . $relative_path;
// check dir
$dir = dirname($path);
if ($dir && !$server->file_exists($dir)) {
if (false === $server->mkdir_recursive($dir)) {
throw new Exception('Cannot mkdir ' . $dir);
}
}
$resume_pos = ($_POST['resumableChunkNumber']-1) * $_POST['resumableChunkSize'];
$content = file_get_contents($_FILES['file']['tmp_name']);
if (!$server->put($path, $content, $resume_pos)) {
$response['error'] = 'Cannot save file '.$path;
}
} elseif (isset($_POST['file']) and isset($_POST['content'])) {
$content = $_POST['content'];
if (substr($content, 0, 5) == 'data:') {
$pos = strpos($content, 'base64');
if ($pos) {
$content = base64_decode(substr($content, $pos+6));
}
}
if (strstr($_POST['file'], '.')) {
if (!$server->put($_POST['file'], $content)) {
$response['error'] = 'Can\'t create file '.$file['name'];
}
} else {
if (!$server->mkdir($_POST['file'])) {
$response['error'] = 'Can\'t create folder '.$file['name'];
}
}
} else {
foreach ($_FILES as $key => $file) {
if ($file['error'] == UPLOAD_ERR_OK) {
$content = file_get_contents($file['tmp_name']);
if (!$server->put($_POST['path'].'/'.$file['name'], $content)) {
$response['error'] = 'Can\'t create file '.$file['name'];
}
} else {
$response['error'] = $error.' '.$file['name'];
}
}
}
break;
case 'download':
$response['content'] = base64_encode($server->get($_GET['file']));
break;
case 'chmod':
$file = $_GET['file'];
if (!$server->chmod($_GET['mode'], $file)) {
$response['error'] = 'Cannot chmod file';
}
break;
case 'uploadByURL':
if (substr($_POST['url'], 0, 7) != 'http://' && substr($_POST['url'], 0, 8) != 'https://') {
$response['error'] = 'Invalid URL';
} else {
$content = file_get_contents($_POST['url']);
$file = basename_safe($_POST['url']);
if (!$file) {
$response['error'] = 'Missing file name';
} else {
if (!$server->put($_POST['path'].'/'.$file, $content)) {
$response['error'] = 'Can\'t save file';
}
}
}
break;
case 'saveByURL':
if (substr($_POST['url'], 0, 7) != 'http://' && substr($_POST['url'], 0, 8) != 'https://') {
$response['error'] = 'Invalid URL';
} else {
$content = file_get_contents($_POST['url']);
if ($server->put($_POST['path'], $content)) {
//success
} else {
$response['error'] = 'Can\'t save file';
}
}
break;
case 'extract':
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$startedAt = time();
$file = $server->get($_GET['file'], true);
$pos = strpos($_GET['file'], '.');
$file_ext = substr($_GET['file'], $pos);
$tmpfname = tmpfile();
$handle = fopen($tmpfname, "w");
fwrite($handle, $data);
fclose($handle);
$za = new ZipArchive();
$za->open($file);
$server->send_msg($startedAt, $za->numFiles);
$complete = 0;
for ($i = 0; $i < $za->numFiles; $i++) {
$entry = $za->statIndex($i);
$server->send_msg($startedAt, $entry['name']);
if (substr($entry['name'], -1) == '/') {
$server->mkdir(dirname($_GET['file']).'/'.$entry['name']);
} else {
$server->put(dirname($_GET['file']).'/'.$entry['name'], $za->getFromIndex($i));
}
$complete++;
}
unlink($tmpfname);
break;
case 'compress':
if ($_POST['paths']) {
$_SESSION['paths'] = $_POST['paths'];
} else {
if ($_GET['d']) {
if ($_SESSION['download']['name']) {
header("Content-Disposition: attachment; filename=" . $_SESSION['download']['name']);
header("Content-Type: application/octet-stream");
print file_get_contents($_SESSION['download']['file']);
unlink($_SESSION['download']['file']);
unset($_SESSION['download']);
unset($_SESSION['paths']);
exit;
} else {
throw new Exception('no zip file');
}
}
header('Content-Type: text/event-stream');
$size = 0;
$max_size = 10000000;
$id = time();
$server->send_msg($id, 'Initializing');
$tmpdir = sys_get_temp_dir() or die('failed to get tmp dir');
$zip_file = tempnam($tmpdir, "shiftedit_zip_") or die('failed to create tmp file');
$zip = new ZipArchive();
if ($zip->open($zip_file, ZipArchive::CREATE) !== TRUE) {
throw new Exception("cannot open <$zip_file>\n");
}
$paths = $_SESSION['paths'];
foreach ($paths as $file) {
$is_dir = $server->is_dir($file);
if (!$is_dir) {
$files = [$file];
if ($server->size($file) > $max_size) {
$server->send_msg($id, 'File size limit exceeded '.$file);
}
} else {
$files = get_paths($file.'/');
if ($files === false) {
$server->send_msg($id, 'Error getting files');
exit;
}
$zip->addEmptyDir($file);
}
foreach ($files as $file) {
$server->send_msg($id, 'Compressing '.$file);
$dir = dirname($file);
$zip->addEmptyDir($dir);
$content = $server->get($file);
if ($content !== false) {
$zip->addFromString($file, $content);
}
}
}
$zip->close();
$zip_name = (count($paths) === 1) ? basename($paths[0]) : 'files';
$_SESSION['download'] = array(
'name' => $zip_name.'.zip',
'file' => $zip_file
);
$server->send_msg($id, 'done');
}
break;
case 'definitions':
$json = file_get_contents($definitions);
$response['definitions'] = json_decode($json);
break;
case 'save_path':
if ($_GET['path'] and substr($_GET['path'], -1) !== '/') {
$_GET['path'] .= '/';
}
if ($_GET['expand']) {
$_SESSION['paths'][] = $_GET['path'];
$_SESSION['paths'] = array_unique($_SESSION['paths']);
} else {
foreach ($_SESSION['paths'] as $k => $v) {
if (substr($v, 0, strlen($_GET['path'])) == $_GET['path']) {
unset($_SESSION['paths'][$k]);
}
}
}
break;
case 'git_info':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
// user info
$raw = $git->run('config user.name');
$response['config']['name'] = trim($raw);
$raw = $git->run('config user.email');
$response['config']['email'] = trim($raw);
// commit history
$raw = $git->run('log --pretty=format:"%H|%an|%ar|%s" --max-count=20');
$lines = explode("\n", trim($raw));
$response['commits'] = [];
foreach ($lines as $line) {
$arr = explode('|', $line);
$response['commits'][] = array(
'hash' => $arr[0],
'author' => $arr[1],
'date' => $arr[2],
'subject' => $arr[3],
);
}
// stashes
$raw = $git->run("stash list");
$lines = explode("\n", trim($raw));
$response['stashes'] = [];
foreach ($lines as $v) {
preg_match('/stash@{([0-9]+)}: (.*)/', $v, $matches);
$response['stashes'][] = array(
'index' => $matches[1],
'name' => $matches[2],
);
}
// branches
$raw = $git->run("branch -a");
if ($raw) {
$lines = explode("\n", trim($raw));
$branches = [];
foreach ($lines as $v) {
$selected = (substr($v, 0, 1) === '*');
$branch = substr($v, 0, 1) === '*' ? substr($v, 2) : trim($v);
$remote = substr($branch, 0, 8) === 'remotes/';
$branch = str_replace('remotes/origin/', '', $branch);
if (!$branches[$branch]) {
$branches[$branch] = [
'name' => $branch,
'selected' => $selected,
'remote' => $remote,
];
}
ksort($branches);
}
$response['branches'] = array_values($branches);
}
// status
$raw = $git->run('status -bs');
$raw = rtrim($raw);
if ($raw) {
$lines = explode("\n", $raw);
$response['status'] = array_shift($lines);
$response['changes'] = [];
foreach ($lines as $line) {
$path = substr($line, 3);
$response['changes'][] = array(
'path' => $path,
'status' => substr($line, 0, 2),
);
}
}
break;
case 'config':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if (trim($_GET['name']) and trim($_GET['email'])) {
$response['data'][] = $git->run('config user.name "'.trim($_GET['name']).'"');
$response['data'][] = $git->run('config user.email "'.trim($_GET['email']).'"');
}
break;
case 'clone':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if (trim($_GET['url'])) {
$response['data'] = $git->run("clone ".$_GET['url'].' .');
if (trim($_GET['name']) and trim($_GET['email'])) {
$git->run('config user.name "'.trim($_GET['name']).'"');
$git->run('config user.email "'.trim($_GET['email']).'"');
}
}
break;
case 'checkout':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if (trim($_GET['branch'])) {
$response['data'] = $git->run('checkout -q "' . $_GET['branch'] . '"');
if (substr($response['data'], 0, 5) === 'error') {
$response['error'] = $response['data'];
}
}
break;
case 'discard':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if (trim($_GET['path'])) {
$raw = $git->run('status -s');
$lines = explode("\n", rtrim($raw));
foreach ($lines as $line) {
$path = substr($line, 3);
$status = substr($line, 0, 1);
if ($path === $_GET['path']) {
try {
if ($status === '?' or $status === 'A') {
if ($status === 'A') {
$response['data'] = $git->run("reset ".$_GET['path']);
}
$response['data'] = $git->run("clean -f ".$_GET['path']);
} else {
$response['data'] = $git->run("checkout -- ".$_GET['path']);
}
} catch (exception $e) {
$response['error'] = $e->getMessage();
break 2;
}
break;
}
}
}
break;
case 'ignore':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
$raw = $git->run('rm --cached ' . $_GET['path']);
$content = $server->get('.gitignore');
if ($content) {
$content .= "\n";
}
$content .= $_GET['path'];
$result = $server->put('.gitignore', $content);
break;
case 'create_branch':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if (trim($_GET['name']) and trim($_GET['from'])) {
$raw = $git->run('checkout -b "'.$_GET['name'] . '" "' . $_GET['from'] . '"');
$raw = $git->run('push -u origin ' . $_GET['name']);
}
break;
case 'delete_branch':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if (trim($_GET['branch'])) {
$git->run("checkout -q master");
if ($_GET['force']) {
$raw = $git->run('branch -D "' . $_GET['branch'] . '"');
} else {
$raw = $git->run('branch -d "' . $_GET['branch'] . '"');
}
$response['result'] = $git->run('push origin --delete "' . $_GET['branch'] . '"');
}
break;
case 'merge':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if (trim($_GET['branch'])) {
$response['result'] = $git->run('merge "' . $_GET['branch'] . '"');
}
break;
case 'revert':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if (trim($_GET['hash'])) {
$response['result'] = $git->run('revert -m 1 ' . $_GET['hash']);
}
break;
case 'reset':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if (trim($_GET['hash'])) {
$response['result'] = $git->run('reset --hard ' . $_GET['hash']);
}
break;
case 'commit':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if (count((array)$_POST['paths']) and $_POST['subject']) {
foreach ($_POST['paths'] as $path) {
$git->run("add ".$path);
}
$response['result'] = $git->run('commit -m "'.addslashes($_POST['subject']).'" -m "'.addslashes($_POST['description']).'"');
}
break;
case 'diff':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if ($_GET['path']) {
$response['result'] = $git->run('--no-pager diff -- ' . escapeshellarg($_GET['path']));
if (!$response['result']) {
$response['result'] = $git->run('--no-pager diff -- /dev/null ' . escapeshellarg($_GET['path']));
}
}
break;
case 'show':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
if ($_GET['commit']) {
$response['result'] = $git->run('--no-pager show '.$_GET['commit']);
}
break;
case 'stash_push':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
$response['result'] = $git->run('stash push ' . ($_POST['subject'] ? '-m "'.addslashes($_POST['subject']).'"' : ''));
break;
case 'stash_show':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
$response['result'] = $git->run('--no-pager stash show -p stash@{' . (int)$_GET['index'] . '}');
break;
case 'stash_apply':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
$response['result'] = $git->run('stash apply stash@{' . (int)$_GET['index'] . '}');
break;
case 'stash_drop':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
$response['result'] = $git->run('stash drop stash@{' . (int)$_GET['index'] . '}');
break;
case 'sync':
$git = Git::open(dirname(__FILE__)); // -or- Git::create('/path/to/repo')
$response['result'] = $git->run('pull');
$response['result'] = $git->run('push');
break;
default:
$response['error'] = 'No command';
break;
}
if ($server) {
$server->close();
}
} catch (Exception $e) {
$response['error'] = $e->getMessage();
}
$response['success'] = ($response['error']) ? false : true;
print json_encode($response);