<?php
/*
Core SedLex Plugin
VersionInclude : 3.0
*/
/** =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
* This PHP class enables the svn management of the plugin with the wordpress.org repository
*/
if (!class_exists("svnAdmin")) {
class svnAdmin {
var $login ;
var $mdp ;
var $host ;
var $port ;
/** ====================================================================================================================================================
* Constructor of the class
*
* @param string $host the host of the svn repository (for instance svn.wp-plugins.org)
* @param interger $port the port of the webdav repository
* @param string $login your login
* @param string $mdp your password
* @return svnAdmin the box object
*/
function svnAdmin($host, $port=80, $login='', $mdp='') {
$this->login = $login ;
$this->mdp = $mdp ;
$this->port = $port ;
$this->host = $host ;
$this->user_agent = "SVN PHP client v1.0 (SL Framework for Wordpress)" ;
}
/** ====================================================================================================================================================
* List the files and folder on the repository
*
* @param string $base the relative path of the folder to be looked into (from the repository)
* @param boolean $rec true if the listing should be reccursive (useful if you want the list of an entire repository with sub-folders)
* @param boolean $credentials true if the repository requires credentials to list files
* @return array 'isOk' => whether the request is successful, 'list' => the list of files and folders, 'raw_result' the request and the respond in an array (useful for debugging purpose)
*/
function listFilesInRepository($base, $rec=true, $credentials=false) {
$result = $this->sendSVNRequest($this->host, $base, "PROPFIND", "<?xml version=\"1.0\"?><D:propfind xmlns:D=\"DAV:\"><D:allprop/></D:propfind>", array("Depth: 1") ) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
$doc = $this->xmlContentParse($result['content']) ;
$ls=array();
//baseline-relative-path
//resourcetype
$i=-1;
foreach($doc->getElementsByTagNameNS ( 'DAV:' , 'response' ) as $response) {
$i++;
// We skip the first entry because the first entry is the folder itself
if ($i===0) {
continue;
}
// We get the name of the file/folder
$res=array();
$res['href'] = urldecode($response->getElementsByTagNameNS ( 'DAV:' , 'href' )->item(0)->textContent);
// We check if the entry is a folder
if($response->getElementsByTagNameNS ( 'DAV:' , 'collection')->length)
$res['folder']=true;
// We add to the array
$ls[] = $res ;
// reccursive
if ($rec) {
if ($res['folder']) {
$rec_files = $this->listFilesInRepository($res['href'], $rec, $credentials) ;
$ls = array_merge($ls, $rec_files['list']) ;
}
}
}
return array("isOK" => true, "list" => $ls, "raw_result" => $result);
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Get the activity collection folder (required to put/delete file in the repo)
*
* @param string $base the relative path of the folder (for instance /yourplugin/trunk/)
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'activity_folder' => the activity folder, 'raw_result' the request and the respond in an array (useful for debugging purpose)
*/
function getActivityFolder($base, $credentials=false) {
$result = $this->sendSVNRequest($this->host, $base, "OPTIONS", "<?xml version=\"1.0\" encoding=\"utf-8\"?><D:options xmlns:D=\"DAV:\"><D:activity-collection-set/></D:options>", array(), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
$xml = $this->xmlContentParse($result['content']) ;
$activity = $xml->getElementsByTagNameNS ( 'DAV:' , 'href' )->item(0)->textContent ;
return array("isOK" => true, "activity_folder" => $activity, "raw_result" => $result) ;
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Get VCC (Version Controlled Resource)
*
* @param string $base the relative path of the folder (for instance /yourplugin/trunk/)
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'vcc' => the version controlled folder, 'raw_result' the request and the respond in an array (useful for debugging purpose)
*/
function getVCC($base, $credentials=false) {
$result = $this->sendSVNRequest($this->host, $base, "PROPFIND", "<?xml version=\"1.0\" encoding=\"utf-8\"?><propfind xmlns=\"DAV:\"><prop><version-controlled-configuration xmlns=\"DAV:\"/></prop></propfind>", array("Depth: 0"), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
$xml = $this->xmlContentParse($result['content']) ;
$vcc = $xml->getElementsByTagNameNS ( 'DAV:' , 'version-controlled-configuration' )->item(0)->textContent ;
return array("isOK" => true, "vcc" => $vcc, "raw_result" => $result) ;
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Get Repository Revision
*
* @param string $base the relative path of the folder (for instance /yourplugin/trunk/)
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'revision' => the revision number, 'raw_result' the request and the respond in an array (useful for debugging purpose)
*/
function getRevision($base, $credentials=false) {
$result = $this->sendSVNRequest($this->host, $base, "PROPFIND", "<?xml version=\"1.0\" encoding=\"utf-8\"?><propfind xmlns=\"DAV:\"><prop><version-name xmlns=\"DAV:\"/></prop></propfind>", array("Depth: 0"), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
$xml = $this->xmlContentParse($result['content']) ;
$rev = $xml->getElementsByTagNameNS ( 'DAV:' , 'version-name' )->item(0)->textContent ;
return array("isOK" => true, "revision" => $rev, "raw_result" => $result) ;
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Create an activity
*
* @param string $activity_n_uuid it is the activity folder concatenated with an random UUID (composed with hexadecimal digit xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'raw_result' the request and the respond in an array (useful for debugging purpose)
* @see svnAdmin::getActivityFolder
*/
function createActivity($activity_n_uuid, $credentials=false) {
$result = $this->sendSVNRequest($this->host, $activity_n_uuid, "MKACTIVITY", "", array(), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
return array("isOK" => true, "raw_result" => $result) ;
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Get the commit comment URL
*
* @param string $vcc the VCC of the repository
* @param string $activity_n_uuid it is the activity folder concatenated with the random UUID (composed with hexadecimal digit xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'url' the comment url, 'raw_result' the request and the respond in an array (useful for debugging purpose)
* @see svnAdmin::getVCC
* @see svnAdmin::getActivityFolder
*/
function getCommitCommentURL($vcc, $activity_n_uuid, $credentials=false) {
$result = $this->sendSVNRequest($this->host, $vcc, "CHECKOUT", "<?xml version=\"1.0\" encoding=\"utf-8\"?><D:checkout xmlns:D=\"DAV:\"><D:activity-set><D:href>".$activity_n_uuid."</D:href></D:activity-set><D:apply-to-version/></D:checkout>", array(), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
$url = str_replace("http://".$this->host, "", $result["header"]["Location"]) ;
return array("isOK" => true, "url" => $url, "raw_result" => $result) ;
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Set a commit comment
*
* @param string $comment the comment to be added
* @param string $comment_url the comment url
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful,'raw_result' the request and the respond in an array (useful for debugging purpose)
* @see svnAdmin::getCommitCommentURL
*/
function setCommitComment($comment, $comment_url, $credentials=false) {
$replacements = array('<', '>');
$entities = array('<', '>');
$comment = str_replace($entities, $replacements, $comment);
$result = $this->sendSVNRequest($this->host, $comment_url, "PROPPATCH", "<?xml version=\"1.0\" encoding=\"utf-8\"?><D:propertyupdate xmlns:D=\"DAV:\" xmlns:V=\"http://subversion.tigris.org/xmlns/dav/\" xmlns:C=\"http://subversion.tigris.org/xmlns/custom/\" xmlns:S=\"http://subversion.tigris.org/xmlns/svn/\"><D:set><D:prop><S:log >".$comment."</S:log></D:prop></D:set></D:propertyupdate>", array(), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
return array("isOK" => true, "raw_result" => $result) ;
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Get the version folder
*
* @param string $base the relative path of the folder (for instance /yourplugin/trunk/)
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'version_folder' => the version folder,'raw_result' the request and the respond in an array (useful for debugging purpose)
*/
function getVersionFolder($base, $credentials=false) {
$result = $this->sendSVNRequest($this->host, $base, "PROPFIND", "<?xml version=\"1.0\" encoding=\"utf-8\"?><propfind xmlns=\"DAV:\"><prop><checked-in xmlns=\"DAV:\"/></prop></propfind>", array("Depth: 0"), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
$xml = $this->xmlContentParse($result['content']) ;
$vf = $xml->getElementsByTagNameNS ( 'DAV:' , 'checked-in' )->item(0)->firstChild->textContent ;
return array("version_folder" => $vf, "isOK" => true, "raw_result" => $result) ;
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Get the folder to put files or delete files
*
* @param string $version the version folder
* @param string $activity_n_uuid it is the activity folder concatenated with the random UUID (composed with hexadecimal digit xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'put_folder' the put url, 'raw_result' the request and the respond in an array (useful for debugging purpose)
* @see svnAdmin::getVersionFolder
* @see svnAdmin::getActivityFolder
*/
function getPutFolder($version, $activity_n_uuid, $credentials=false) {
$result = $this->sendSVNRequest($this->host, $version, "CHECKOUT", "<?xml version=\"1.0\" encoding=\"utf-8\"?><D:checkout xmlns:D=\"DAV:\"><D:activity-set><D:href>".$activity_n_uuid."</D:href></D:activity-set></D:checkout>", array(), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
$url = str_replace("http://".$this->host, "", $result["header"]["Location"]) ;
return array("put_folder" => $url, "isOK" => true, "raw_result" => $result) ;
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Put a file in the repo
*
* @param string $put_folder_n_file the put folder concatenated with the file name
* @param string $file the complete url of the file on your disk
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'svn_header' the svn header sent (useful for debugging), 'raw_result' the request and the respond in an array (useful for debugging purpose)
* @see svnAdmin::getPutFolder
*/
function putFile($put_folder_n_file, $file, $credentials=false) {
$file = file_get_contents($file) ;
$top_header = "SVN".chr(0) ; // Version 0 of the SVN diff protocol (see https://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff)
$maxsize = 102400 ; // Si un fichier est plus grand, alors ca bug !! il faut alors le découper en plusieurs "window"
$content = "" ;
$numwin = 0 ;
$info = array() ;
$info[] = array("HEADER ".$this->asc2bin("SVN".chr(0))) ;
while (strlen($file)!=0) {
$numwin ++ ;
// Taille de la window
$lenfile = min($maxsize, strlen($file) ) ;
// Instructions
$instructions = "" ;
$instructions .= chr(bindec("10"."000000")) ; // Copy from the new file
$instructions .= $this->getChr($lenfile) ; // the length to be copied (i.e. here size of the new file)
// header
$header = $this->getChr(0) ; // Source offset 0
$header .= $this->getChr(0) ; // Source length 0
$header .= $this->getChr($lenfile) ; // Target length (i.e. the size of the file)
$header .= $this->getChr(strlen($instructions)) ; // Number of instructions bytes
$header .= $this->getChr($lenfile) ; // New data length
$info[] = array("SOURCE OFFSET ".$this->asc2bin($this->getChr(0))." - SOURCE LENGTH ".$this->asc2bin($this->getChr(0) )." - TARGET LENGTH : ".$this->asc2bin($this->getChr($lenfile)) ." - INSTRUCTION LENGTH : ".$this->asc2bin($this->getChr(strlen($instructions)))." - NEW DATA LENGTH : ".$this->asc2bin($this->getChr($lenfile))." - INSTRUCTIONS : ".$this->asc2bin($instructions)) ;
$content .= $header.$instructions.substr($file, 0, $lenfile) ;
//maj du file
$file = substr($file, $lenfile) ;
}
//http://websvn.cyberspectrum.de/wsvn/tl_svn/trunk/system/modules/svnupdate/SubVersionMessageDiff.php
$result = $this->sendSVNRequest($this->host, $put_folder_n_file, "PUT", $top_header.$content, array("Content-Type: application/vnd.svn-svndiff"), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
return array("isOK" => true, "raw_result" => $result, "svn_header" => $info ) ;
} else {
return array("isOK" => false, "raw_result" => $result, "svn_header" => $info ) ;
}
}
/** ====================================================================================================================================================
* Put folder in the repository
*
* @param string $put_folder_n_folder the put folder concatenated with the folder to add
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful,'raw_result' the request and the respond in an array (useful for debugging purpose)
* @see svnAdmin::getPutFolder
*/
function putFolder($put_folder_n_folder, $credentials=true) {
$result = $this->sendSVNRequest($this->host, $put_folder_n_folder, "MKCOL", "", array(), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
return array("isOK" => true, "raw_result" => $result) ;
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Put folder in the repository
*
* @param string $put_folder_n_filefolder the put folder concatenated with the folder/file to add
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful,'raw_result' the request and the respond in an array (useful for debugging purpose)
* @see svnAdmin::getPutFolder
*/
function deleteFileFolder($put_folder_n_filefolder, $credentials=true) {
$result = $this->sendSVNRequest($this->host, $put_folder_n_filefolder, "DELETE", "", array(), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
return array("isOK" => true, "raw_result" => $result) ;
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Merge the commit ... thus all the change will be taken in account
*
* @param string $base the relative path of the folder (for instance /yourplugin/trunk/)
* @param string $activity_n_uuid it is the activity folder concatenated with the random UUID (composed with hexadecimal digit xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'commit_info' the commit information, 'raw_result' the request and the respond in an array (useful for debugging purpose)
* @see svnAdmin::getActivityFolder
*/
function merge($base, $activity_n_uuid, $credentials=false) {
$result = $this->sendSVNRequest($this->host, $base, "MERGE", "<?xml version=\"1.0\" encoding=\"utf-8\"?><D:merge xmlns:D=\"DAV:\"><D:source><D:href>".$activity_n_uuid."</D:href></D:source><D:no-auto-merge/><D:no-checkout/><D:prop><D:checked-in/><D:version-name/><D:resourcetype/><D:creationdate/><D:creator-displayname/></D:prop></D:merge>", array(), $credentials) ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
preg_match("/version-name>([^<]*)<([^>]*)version-name/", $result['content'], $rev) ;
preg_match("/creator-displayname>([^<]*)<([^>]*)creator-displayname/", $result['content'], $author) ;
return array("isOK" => true, "commit_info" => "revision n°".$rev[1]." (".$author[1].")", "raw_result" => $result) ;
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Get a single file of the repository
*
* @param string $base_file the relative path of the file to get (for instance /yourplugin/trunk/file1.txt)
* @param string $store the local path to store the file retrieved (for instance /home/foo/yourplugin/file1.txt)
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'siez' the size in bytes of the retrieved file
*/
function getFile($base_file, $store, $credentials=true) {
$replacements = array('%20');
$entities = array(' ');
$base_file = str_replace($entities, $replacements, $base_file);
$content = @file_get_contents("http://".$this->host.$base_file) ;
if ($content!==false) {
@mkdir(dirname($store), 0777, true) ;
@file_put_contents($store, $content) ;
return array("size" => strlen($content) , "isOK" => true ) ;
} else {
return array("isOK" => false) ;
}
}
/** ====================================================================================================================================================
* Get all files of the repository
*
* @param string $base the relative path of the folder (for instance /yourplugin/trunk/)
* @param string $vcc the VCC
* @param string $rev the revision number
* @param string $store the local path to store the file retrieved (for instance /home/foo/yourplugin/)
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'info' the list of retrieved files/folder, 'raw_result' the request and the respond in an array (useful for debugging purpose)
* @see svnAdmin::getVCC
* @see svnAdmin::getRevision
*/
function getAllFiles($base, $vcc, $rev, $store, $credentials=true) {
$result = $this->sendSVNRequest($this->host, $vcc, "REPORT", "<?xml version=\"1.0\" encoding=\"utf-8\"?><S:update-report send-all=\"true\" xmlns:S=\"svn:\" xmlns:D=\"DAV:\"><S:src-path>http://".$this->host.":".$this->port.$base."</S:src-path><S:target-revision>".$rev."</S:target-revision><S:depth>infinity</S:depth><S:entry rev=\"".$rev."\" depth=\"infinity\" start-empty=\"true\"></S:entry></S:update-report>", array(), $credentials) ;
$is_err = false ;
if (substr($result['header']['Return-Code-HTTP'], 0, 1)=="2") {
$xml = $this->xmlContentParse($result['content']) ;
$info = array() ;
// On s'occupe des folders
$dir = $xml->getElementsByTagNameNS ( 'svn:' , 'add-directory' );
foreach ($dir as $d) {
$url = $d->getElementsByTagNameNS ( 'DAV:' , 'checked-in' )->item(0)->firstChild->textContent ;
$tmp = explode($base, $url, 2) ;
if (count($tmp)==2) {
$url = $tmp[1] ;
}
// On crée les folders
if (@mkdir($store.$url, 0755, true)) {
$info[] = array("url"=>$url, "ok"=>true, "folder"=>true) ;
} else {
$info[] = array("url"=>$url, "ok"=>false, "folder"=>true) ;
$is_err = true ;
break ;
}
}
if (!$is_err) {
// On s'occupe des fichiers
$file = $xml->getElementsByTagNameNS ( 'svn:' , 'add-file' );
foreach ($file as $f) {
$url = $f->getElementsByTagNameNS ( 'DAV:' , 'checked-in' )->item(0)->firstChild->textContent ;
// on recupere le contenu du fichier
$content = $f->getElementsByTagNameNS ( 'svn:' , 'txdelta' )->item(0)->textContent ;
$content = base64_decode($content) ;
$true_content = "" ;
// On supprime l'entete SVN binaire (voir https://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff)
$offset = 4 ; // on passe le PHP\0
// Window
while (strlen($content)!=$offset) {
$val = $this->popInt($content, $offset) ; // Read source view offset
$val = $this->popInt($content, $val['new_offset']) ; // Read source view length
$val = $this->popInt($content, $val['new_offset']) ; // Read target view length
$val = $this->popInt($content, $val['new_offset']) ; // Read instructions length
$insl = $val['int'] ;
$val = $this->popInt($content, $val['new_offset']) ; // New data length
// After we have the instruction ($insl the number of bytes)
$data_length = $val['int'] ;
$debut_text = $val['new_offset']+$insl ;
if ($data_length==0)
break ;
$true_content .= substr($content, $debut_text, $data_length) ;
$offset = $debut_text+$data_length ;
}
$tmp = explode($base, $url, 2) ;
if (count($tmp)==2) {
$url = $tmp[1] ;
}
$replacements = array(' ');
$entities = array('%20');
$url = str_replace($entities, $replacements, $url);
// On crée les fichiers en cache
if (@file_put_contents($store.$url, $true_content)!==false) {
$info[] = array("url"=>$url, "ok"=>true, "folder"=>false , "size"=>strlen($content) ) ;
} else {
$info[] = array("url"=>$url, "ok"=>false, "folder"=>false, "size" =>strlen($content) ) ;
$is_err = true ;
break ;
}
}
}
if (!$is_err) {
return array("isOK" => true, "info" => $info, "raw_result" => $result) ;
} else {
return array("isOK" => false, "info" => $info, "raw_result" => $result) ;
}
} else {
return array("isOK" => false, "raw_result" => $result) ;
}
}
/** ====================================================================================================================================================
* Prepare the commit
*
* @param string $base the relative path of the folder (for instance /yourplugin/trunk/)
* @param string $comment the comment for the commit
* @param boolean $credentials true if the repository requires credentials
* @return array 'isOk' => whether the request is successful, 'step' indicated the step which fails, 'putFolder' the put folder , 'activityFolder' the acivity folder, 'uuid' the random uuid used for this commit, 'raw_result' the request and the respond in an array (useful for debugging purpose)
*/
function prepareCommit($base, $comment, $credentials=false) {
$activity = $this->getActivityFolder($base, $credentials) ;
if ($activity['isOK']) {
$vcc = $this->getVCC($base, $credentials) ;
if ($vcc['isOK']) {
// We generate a new random UUID
$chars = md5(rand(1, 1000).rand(1, 1000).rand(1, 1000).rand(1, 1000).rand(1, 1000).rand(1, 1000).rand(1, 1000).rand(1, 1000).rand(1, 1000));
$uuid = substr($chars,0,8) . '-';
$uuid .= substr($chars,8,4) . '-';
$uuid .= substr($chars,12,4) . '-';
$uuid .= substr($chars,16,4) . '-';
$uuid .= substr($chars,20,12) ;
$act = $this->createActivity($activity['activity_folder'].$uuid , $credentials) ;
if ($act['isOK']) {
$url_comment = $this->getCommitCommentURL($vcc['vcc'], $activity['activity_folder'].$uuid , $credentials) ;
if ($url_comment['isOK']) {
$res = $this->setCommitComment($comment, $url_comment['url'], true) ;
if ($res['isOK']) {
$versionFolder = $this->getVersionFolder($base, $credentials) ;
if ($versionFolder['isOK']) {
$urlDepot = $this->getPutFolder($versionFolder['version_folder'], $activity['activity_folder'].$uuid , $credentials) ;
if ($urlDepot['isOK']) {
return array("putFolder" => $urlDepot['put_folder'], 'activityFolder' => $activity['activity_folder'] , 'uuid' => $uuid , "isOK" => true ) ;
} else {
return array("isOK" => false, 'step' => 'GETTING THE URL TO PUT', 'raw_result' => $urlDepot['raw_result']) ;
}
} else {
return array("isOK" => false, 'step' => 'GETTING THE VERSION FOLDER', 'raw_result' => $versionFolder['raw_result']) ;
}
} else {
return array("isOK" => false, 'step' => 'SETTING COMMIT COMMENT', 'raw_result' => $res['raw_result']) ;
}
} else {
return array("isOK" => false, 'step' => 'GETTING THE COMMENT URL', 'raw_result' => $url_comment['raw_result']) ;
}
} else {
return array("isOK" => false, 'step' => 'CREATING ACTIVITY/VCC', 'raw_result' => $act['raw_result']) ;
}
} else {
return array("isOK" => false, 'step' => 'GETTING VCC', 'raw_result' => $vcc['raw_result']) ;
}
} else {
return array("isOK" => false, 'step' => 'GETTING THE ACTIVITY FOLDER', 'raw_result' => $activity['raw_result']) ;
}
}
/** ====================================================================================================================================================
* Send a SVN request
*
* @param string $host the host (for instance svn.wp-plugins.org)
* @param string $relative_uri the base url (for instance /yourplugin/trunk/)
* @param string $type the type of request (e.g. GET, PROPFIND, PROPPATCH, etc.)
* @param string $content the content of the http request
* @param array $additional_headers if addiotionnal header are required (for instance array('Content-Type: text/plain'))
* @param boolean $credentials true if the repository requires credentials
* @return array the response and the content sent
*/
function sendSVNRequest($host, $relative_uri, $type, $content, $additional_headers=array(), $credentials=false) {
$replacements = array('%20');
$entities = array(' ');
$relative_uri = str_replace($entities, $replacements, $relative_uri);
$header = $type." ".$relative_uri." HTTP/1.1\r\n" ;
$header .= "Host: ".$host."\r\n" ;
$header .= "User-Agent: ".$this->user_agent."\r\n" ;
$noContentType = false ;
foreach ($additional_headers as $h) {
if (strpos($h, "Content-Type") !== false)
$noContentType = true ;
}
if (!$noContentType)
$header .= "Content-Type: text/xml\r\n" ;
foreach ($additional_headers as $h) {
$header .= $h."\r\n" ;
}
if ($credentials)
$header .= "Authorization: Basic " . base64_encode($this->login . ":" . $this->mdp) ."\r\n" ;
$header .= "Content-Length: ".strlen($content)."\r\n" ;
$header .= "\r\n";
$fp = fsockopen($host, $this->port, $errno, $errstr, 30);
if (!$fp) {
return "$errstr ($errno)";
} else {
fwrite($fp, $header.$content);
$result = "" ;
while (!feof($fp)) {
$result .= fgets($fp, 128);
}
fclose($fp);
return array_merge(array("sent"=> array('header' => $header, 'content' => $content) ), $this->httpMessageParse($result) ) ;
}
}
/** ====================================================================================================================================================
* Parse HTTP response message (support of chuncked encoding)
*
* @param string $message the HTTP message
* @return array the parsed response
* @access private
*/
function httpMessageParse($message) {
$tmp = explode("\r\n\r\n", $message, 2) ;
$header = $tmp[0] ;
$content = $tmp[1] ;
$lh = explode("\r\n", $header) ;
$rh = array() ;
foreach ($lh as $l) {
$p = explode (":", $l, 2) ;
if (count($p)==2) {
$rh = array_merge($rh, array(trim($p[0]) => trim($p[1]) )) ;
}
}
$pl = explode(" ", $lh[0], 3) ;
if (count($pl)==3) {
$rh = array_merge($rh, array("Return-Code-HTTP" => trim($pl[1]) )) ;
} else {
$rh = array_merge($rh, array("Return-Code-HTTP" => "999" )) ;
}
// We convert the chuncked content if needed
//----------
if (strpos(strtolower($header), "transfer-encoding: chunked")) {
$in = $content ;
$content = '' ;
$lines = explode("\r\n", $in) ;
$num = 0 ;
foreach ($lines as $l) {
$num ++ ;
// La premiere ligne donne une longueur...
if ($num==1) {
$length = hexdec($l) ;
$cur_len = 0 ;
$part_content = "" ;
} else {
if ($cur_len != $length) {
if ($part_content != '') {
$part_content .= "\r\n" ;
$cur_len += 2 ;
}
$part_content .= $l ;
$cur_len += strlen($l) ;
} else {
$length = hexdec($l) ;
$cur_len = 0 ;
$content .= $part_content ;
$part_content = "" ;
}
}
}
}
return array("header" => $rh, "content" => $content) ;
}
/** ====================================================================================================================================================
* Convert plain XML text into DOM document
*
* @param string $content the plain XML text
* @return DOMdocument the parsed XML
* @access private
*/
function xmlContentParse($content) {
$doc = new DOMDocument();
$doc->loadXML($content, LIBXML_NOENT | LIBXML_NONET | LIBXML_NSCLEAN | LIBXML_NOCDATA | LIBXML_COMPACT | LIBXML_NOERROR | LIBXML_NOWARNING);
//$doc->loadXML(trim($content));
return $doc ;
}
/** ====================================================================================================================================================
* Print the raw response in order to render it into a human readeable message
*
* @param string $raw the raw message to render
* @return string the readeable message
* @access private
*/
function printRawResult($raw) {
if ($raw['header']['Return-Code-HTTP']=='401'){
return "<span style='color:#CC0000'>".__("Your credentials do not seem to be correct. Please check them!", "SL_framework")."</span>" ;
}
if ($raw['header']['Return-Code-HTTP']=='500'){
if (strpos($raw['content'], "previous representation is currently being written")===false) {
//return "<span style='color:#CC0000'>".__("This file have not been written in the repository due to server problem. Nevertheless, you should retry as it often works better with a second try !", "SL_framework")."</span>" ;
}
}
return "<span style='color:#CC0000'>".nl2br(str_replace(" ", " ", htmlentities(print_r($raw, true))))."</span>" ;
}
/** ====================================================================================================================================================
* Extract from a string one single byte
*
* @param string $string the string from which the byte should be extracted
* @param integer $offset the offset from which the byte should be extracted from the string
* @return array 'byte' is the extracted byte, "new_offset' is the new offset (i.e. the offset+1)
* @access private
*/
function pop($string, $offset){
$res=substr($string, $offset, 1);
return array('byte'=>$res, 'new_offset'=>$offset+1) ;
}
/** ====================================================================================================================================================
* Extract integers that are encoded using a variable-length format (see https://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff)
*
* @param string $string the string from which the integer should be extracted
* @param integer $offset the offset from which the integer should be extracted from the string
* @return array 'int' is the extracted integer, "new_offset' is the new offset
* @access private
*/
function popInt($string, $offset) {
$n=0;
while(true){
$res = $this->pop($string, $offset) ;
$c = $res['byte'] ;
$offset = $res['new_offset'] ;
$c=ord($c);
$n = (($n << 7)) | ($c & 0x7f);
if (!($c & 0x80))
break;
}
return array('int'=>$n, 'new_offset'=>$offset) ;
}
/** ====================================================================================================================================================
* Convert a integer in a variable-length format (see https://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff)
*
* @param integer $int the integer to convert
* @return string the bytes representing the integer in a variable-length format
* @access private
*/
function getChr($int) {
$bin = decbin($int) ;
$result = "" ;
$c = true ;
$iteration = "0" ;
while ($c) {
if (strlen($bin)>7) {
// On part de la fin ! car le premier on mets 0 puis 1
$les7DerniersCaracteres = substr($bin, strlen($bin)-7,7) ;
$lesAutresCaracteres = substr($bin, 0, strlen($bin)-7) ;
$result = chr(bindec($iteration . $les7DerniersCaracteres)) . $result ;
$iteration = "1" ;
$bin = $lesAutresCaracteres ;
} else {
$tmp = chr(bindec($iteration . substr("0000000",0,7 - strlen($bin)) . $bin)) ;
$result = $tmp . $result ;
$c = false ;
}
}
return $result ;
}
/** ====================================================================================================================================================
* Convert a byte-string into binary represention (string)
*
* @param string $ascii the byte-string to convert
* @return string the binary representation (8-blocks with space)
* @access private
*/
function asc2bin ($ascii) {
while ( strlen($ascii) > 0 ){
$byte = "";
$i = 0;
$byte = substr($ascii, 0, 1);
while ( $byte!= chr($i) ) { $i++; }
$byte = base_convert($i, 10, 2);
$byte = str_repeat("0", (8 - strlen($byte)) ) . $byte; /* This is an endian (architexture) specific line, you may need to alter it. */
$ascii = substr($ascii, 1);
$binary .= $byte." ";
}
return $binary;
}
}
}
?>