Last active
August 9, 2020 13:01
-
-
Save mingsai/1c781413ae5de1b38d6119a979491863 to your computer and use it in GitHub Desktop.
A curl based PHP class for CouchDB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Couch{ | |
private $options = array( | |
'host'=>'localhost', | |
'port'=>5984, | |
'ip' => '127.0.0.1', | |
'timeout' => 2, | |
'keep-alive'=> true, | |
'http-log'=> false, | |
'username'=>null, | |
'password'=>null | |
); | |
public $database; | |
public function __construct($username = null, $password = null, $db = null , $host = null, $port = null, $ip = null) { | |
$this->options['host'] = (isset($host))?(string)$host:$this->options['host']; | |
$this->options['port'] = (isset($port))?(int)$port:$this->options['port']; | |
$this->options['username'] = $username; | |
$this->options['password'] = $password; | |
$this->database = $db; | |
} | |
/* | |
*Creates a database with the name of whatever is stored in $database | |
*/ | |
public function create_db($name=null){ | |
$this->database = (!empty($name))?$name:$this->database; | |
$url = $this->build_url(); | |
$result = $this->execute_query('PUT', $url); | |
return $result; | |
} | |
/* | |
*Deletes the database currently stored in $database | |
*/ | |
public function delete_db($name=null){ | |
$this->database = (!empty($name))?$name:$this->database; | |
$url = $this->build_url(); | |
$result = $this->execute_query('DELETE', $url); | |
return $result; | |
} | |
//returns database info object | |
public function db_info(){ | |
$url = $this->build_url(); | |
$result = $this->execute_query('GET', $url); | |
return $result; | |
} | |
//returns the integer value that should be unique by adding the total docs + deleted docs | |
public function next_id(){ | |
$result = $this->db_info(); | |
$id = $result['doc_count']+$result['doc_del_count']; | |
return $id; | |
} | |
/* Creates a document in whatever database is currently set with the document ID that is set | |
* | |
* $data is an array of key value pairs | |
* | |
*/ | |
public function create_doc($data=null, $doc_id=null){ | |
if(!empty($doc_id)&&!empty($data)){ | |
$url = $this->build_url($doc_id); | |
$data = json_encode($data); | |
$result = $this->execute_query('PUT', $url, $data); | |
if(isset($result['ok'])){ | |
return $result; | |
}else{ | |
return false; | |
} | |
}else if(empty($doc_id)&&!empty($data)){ | |
$url = $this->build_url(); | |
$data = json_encode($data); | |
$result = $this->execute_query('POST', $url, $data); | |
if(isset($result['ok'])){ | |
return $result; | |
}else{ | |
return false; | |
} | |
}else return array('error'=>'Please provide a document ID and data'); | |
} | |
/* | |
* Gets a document given a document id and optionally whatever parameters in the form of an array (i.e. key="ben.guidarelli@newdigs.com") | |
*/ | |
public function get_doc($doc_id=null, $params = null){ | |
$url = $this->build_url($doc_id, $params); | |
$doc = $this->execute_query('GET', $url); | |
if(isset($doc['_id'])){ | |
return $doc; | |
}else{ | |
return false; | |
} | |
} | |
public function get_doc_by_view($design_doc=null, $view=null, $key=null, $params=null){ | |
$params['include_docs'] = 'true'; | |
if($result = $this->get_view($design_doc, $view, $key, $params)){ | |
return $result[0]['doc']; | |
}else return false; | |
} | |
public function get_all($design=false){ | |
$url = $this->build_url('_all_docs', array('include_docs'=>'true')); | |
$doc = $this->execute_query('GET', $url); | |
if(isset($doc['rows'])){ | |
if(!$design){ | |
$rows = array(); | |
foreach($doc['rows'] as $row){ | |
if(strpos($row['id'], '_design')===0){} | |
else $rows[] = $row['doc']; | |
} | |
return $rows; | |
} | |
return $doc['rows']; | |
}else{ | |
return false; | |
} | |
} | |
public function get_attributes($doc_id=null, $fields=null, $params=null){ | |
$doc = $this->get_doc($doc_id, $params); | |
$returning = array(); | |
foreach($fields as $field){ | |
$returning[$field] = $doc[$field]; | |
} | |
return $returning; | |
} | |
public function get_attribute($doc_id=null, $field=null, $params=null){ | |
$doc = $this->get_doc($doc_id, $params); | |
return $doc[$field]; | |
} | |
/* | |
*Checks to see if a document exists and is accessible with a head request. I don't remember why I added it but I'll leave it anyway | |
*/ | |
public function exists($doc_id = null){ | |
if($doc_id == null) return; | |
$result = $this->get_head($doc_id); | |
if(strpos($result['status'], '200')){ | |
return true; | |
}else { | |
return false; | |
} | |
} | |
/* | |
* So this accepts an array which is the object you want to add or merge with an existing document essentially set_attributeS | |
*/ | |
public function add_obj($doc_id, $data){ | |
$doc = $this->get_doc($doc_id); | |
$keys = array_keys($data); | |
if(isset($doc[$keys[0]])){ | |
$doc = array_merge_recursive($doc, $data); | |
}else{ | |
$doc[$keys[0]]=$data[$keys[0]]; | |
} | |
$url = $this->build_url($doc_id); | |
$data = json_encode($doc); | |
$revised = $this->execute_query('PUT', $url, $data); | |
if(isset($revised['ok'])){ | |
return $revised; | |
}else{ | |
return false; | |
} | |
} | |
public function set_attribute($doc_id=null, $field=null, $value=null){ | |
$doc = $this->get_doc($doc_id, $params); | |
$doc[$field] = $value; | |
$result = $this->save($doc); | |
return $doc[$field]; | |
} | |
/* | |
*This takes an array to be turned into an object and PUTS it to the document id you give it. This will completely overwrite whatever is there. | |
*/ | |
public function revise_doc($doc_id, $data){ | |
$url = $this->build_url($doc_id); | |
$data = json_encode($data); | |
$revised = $this->execute_query('PUT', $url, $data); | |
if(isset($revised['ok'])){ | |
return $revised; | |
}else{ | |
return false; | |
} | |
} | |
/* | |
*This takes a document that still has its _id and _rev and saves it | |
*/ | |
public function save($data=null){ | |
if($data==null) return false; | |
if(isset($data['_id'])){ $url = $this->build_url($data['_id']); $method = "PUT"; } | |
else{ $url = $this->build_url(); $method = "POST"; } | |
$data = json_encode($data); | |
$revised = $this->execute_query($method, $url, $data); | |
if(isset($revised['ok'])){ | |
return $revised; | |
}else{ | |
return false; | |
} | |
} | |
///params is the query string array with params['q'] being either a string or array of key:values | |
//if you want to make sure the key:value pair is in the lucene doc prepend the key with a + | |
//or a - if you want to make sure it is not in the doc. | |
public function text_search($design_doc, $index, $params){ | |
$string = "_fti/_design/".$design_doc."/".$index; | |
$url = $this->build_url($string); | |
$query_string = $this->build_fulltext_query($params); | |
$url .= "?".rtrim($query_string); | |
$result = $this->execute_query('GET', $url); | |
if(isset($result['rows'])){ | |
return $result; | |
}else{ | |
return false; | |
} | |
} | |
public function download_attachment($doc_id, $attachment){ | |
$string = $doc_id."/".$attachment; | |
$url = $this->build_url($string); | |
$output = $this->execute_query('GET', $url, null, false, true); | |
return $output; | |
} | |
public function upload_attachment($doc_id, $attachment_name, $data, $content_type){ | |
$rev = $this->get_head($doc_id, 'ETag'); | |
$rev = ltrim(rtrim($rev, "\""),"\""); | |
$string = $doc_id."/".$attachment_name; | |
$url = $this->build_url($string, array('rev'=>$rev)); | |
$result = $this->execute_query('PUT', $url, $data, false, true, $content_type); | |
return $result; | |
} | |
/* | |
*Deletes a document or a specific revision of a document | |
*/ | |
public function delete_doc($doc_id=null, $revision=null){ | |
if($revision=='ALL'){ | |
$url = $this->build_url($doc_id); | |
}else{ | |
$rev = (!empty($revision))?$revision:trim($this->get_head($doc_id, 'ETag'), '"');; | |
$url = $this->build_url($doc_id, array('rev'=>$rev)); | |
} | |
$result = $this->execute_query('DELETE', $url, null); | |
if(isset($result['ok'])){ | |
return $result; | |
}else{ | |
return false; | |
} | |
} | |
//takes a document id and the number of revisions you want to keep and deletes all but those | |
public function delete_revs($doc_id=null, $num=null){ | |
$data = array('revs_info'=>'true'); | |
$result = $this->get_doc($doc_id, $data); | |
if(count($result['_revs_info'])>$num){ | |
for($x=$num; $x<count($result['_revs_info']); $x++){ | |
$this->delete_doc($result['_id'], $result['_revs_info'][$x]['rev']); | |
} | |
} | |
$resulting = $this->get_doc($doc_id); | |
return $resulting; | |
} | |
/* | |
*Returns a specific revision of a document | |
*/ | |
public function get_rev($doc_id, $num){ | |
$data = array('revs_info'=>'true'); | |
$result = $this->get_doc($doc_id, $data); | |
foreach($result['_revs_info'] as $value){ | |
$rev_num = (int)substr($value['rev'], 0, 1); | |
if($rev_num===$num){ | |
if($value['status']=='available'){ | |
$dat = array('rev'=>$value['rev']); | |
$frezult = $this->get_doc($doc_id, $dat); | |
return $frezult; | |
} | |
} | |
} | |
} | |
//Takes the name of the desgin doc, the view name, and an array of parameters to find | |
public function get_view($design_doc=null, $view=null, $params=null, $include_docs=false){ | |
$url = $this->build_url($this->build_view($design_doc, $view), $params); | |
$result = $this->execute_query('GET', $url); | |
if(isset($result['rows'])&&count($result['rows'])>0){ | |
return $result['rows']; | |
}else{ | |
return false; | |
} | |
} | |
public function get_list($design_doc=null, $list=null, $view=null, $params=null){ | |
$url = $this->build_url($this->build_view($design_doc, $view), $params); | |
$result = $this->execute_query('GET', $url); | |
if(isset($result['rows'])&&count($result['rows'])>0){ | |
return $result['rows']; | |
}else{ | |
return false; | |
} | |
} | |
/* | |
*Include an array of parameters like array('since'=>25); | |
*/ | |
public function get_changes($params){ | |
$url = $this->build_url('_changes', $params); | |
$result = $this->execute_query('GET', $url); | |
return $result; | |
} | |
/* | |
*Uses PHPs Build in curl functionality to make requests to the couchdb when provided an HTTP verb(method), the RESTful URL, and a json object as the $data, the $header is for a head request | |
*/ | |
private function execute_query($method, $url, $data=null, $header=false, $file=false, $content_type=false){ | |
$ch = curl_init(); | |
curl_setopt($ch, CURLOPT_URL, $url); | |
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($ch, CURLOPT_BINARYTRANSFER, $file); | |
curl_setopt($ch, CURLOPT_NOBODY, $header); | |
curl_setopt($ch, CURLOPT_HEADER, $header); | |
if(!$file) curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json')); | |
else curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: '.$content_type)); | |
//if($this->options['password'])curl_setopt($ch, CURLOPT_USERPWD, $this->options['username'].':'.$this->options['password']); | |
if(!empty($data))curl_setopt($ch, CURLOPT_POSTFIELDS, $data); | |
$result = curl_exec($ch); | |
if($file){ | |
return $result; | |
} | |
if(!$header){ | |
$result = json_decode($result, true); | |
} | |
curl_close($ch); | |
return $result; | |
} | |
/* | |
*Makes a head request. Useful for just getting a piece of the headers. Second favorite function name. | |
*/ | |
private function get_head($doc_id, $chunk=null){ | |
$url = $this->build_url($doc_id); | |
$head = $this->execute_query('HEAD', $url, null, true); | |
$head = $this->http_parse_headers($head); | |
if(isset($chunk)){ | |
return $head[$chunk]; | |
}else{ | |
return $head; | |
} | |
} | |
/* | |
*Builds the view section of the url | |
*/ | |
private function build_view($design_doc=null, $view=null, $include_docs=false){ | |
$view = "_design/".$design_doc."/_view/".$view; | |
$view .= ($include_docs)?"?include_docs=true":""; | |
return $view; | |
} | |
/* | |
*Builds the RESTful url of what youre trying to access | |
*Can accept an array for 'key' and url encodes it correctly. I think. its worked so far for me. | |
*/ | |
private function build_url($doc_id=null, $param=null){ | |
$url = 'http://'.$this->options['host']. ':'. $this->options['port'] . '/' . $this->database; | |
$url .= ($doc_id)? '/'.$doc_id:''; | |
if($param && count($param)>0){ | |
$url .= '?'; | |
foreach($param as $key=>$value){ | |
if($key=='key'||$key=='keys'||$key=='startkey'||$key=='endkey'){ | |
if(is_array($value)){ | |
$url .= $key .'=['; | |
foreach($value as $v){ | |
$url .= '"'.urlencode($v).'",'; | |
} | |
$url = rtrim($url, ",").']&'; | |
}else{ | |
if(false/*is_numeric($value)*/){ | |
$url .= $key.'='.$value.'&'; | |
}else{ | |
$url.= $key.'="'.urlencode($value).'"&'; | |
} | |
} | |
}else{ | |
$url.= $key.'='.$value.'&'; | |
} | |
} | |
$url = rtrim($url, '&'); | |
} | |
return $url; | |
} | |
private function build_fulltext_query($params){ | |
$query_string = "q="; | |
if(isset($params['q'])){ | |
if(is_array($params['q'])){ | |
foreach($params['q'] as $key=>$value){ | |
if($value=="")continue; | |
$query_string .= urlencode($key).":".urlencode($value)." "; | |
} | |
}else{ | |
$query_string .= urlencode($params['q']); | |
} | |
}else return; | |
$query_string .= "&"; | |
foreach($params as $key=>$value){ | |
if($key!="q")$query_string .= $key."=".urlencode($value)."&"; | |
} | |
$query_string = substr($query_string, 0, -1); | |
return $query_string; | |
} | |
/* | |
*Separates the http headers into an associative array (copied from php docs with a couple changes) | |
*/ | |
private function http_parse_headers($headers=false){ | |
if($headers === false){ | |
return false; | |
} | |
$headers = explode("\r\n",$headers); | |
foreach($headers as $value){ | |
$header = explode(": ",$value); | |
if($header[0]&&!isset($header[1])){ | |
$headerdata['status'] = $header[0]; | |
} | |
else if($header[0] && isset($header[1]) && $header[1]){ | |
$headerdata[$header[0]] = $header[1]; | |
} | |
} | |
return $headerdata; | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment