diff --git a/3rdparty/Google/LICENSE.txt b/3rdparty/Google/LICENSE.txt new file mode 100644 index 00000000000..8891c7ddc90 --- /dev/null +++ b/3rdparty/Google/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2007 Andy Smith + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/3rdparty/Google/OAuth.php b/3rdparty/Google/OAuth.php new file mode 100755 index 00000000000..c7e75dd8266 --- /dev/null +++ b/3rdparty/Google/OAuth.php @@ -0,0 +1,751 @@ +key = $key; + $this->secret = $secret; + $this->callback_url = $callback_url; + }/*}}}*/ +}/*}}}*/ + +class OAuthToken {/*{{{*/ + // access tokens and request tokens + public $key; + public $secret; + + /** + * key = the token + * secret = the token secret + */ + function __construct($key, $secret) {/*{{{*/ + $this->key = $key; + $this->secret = $secret; + }/*}}}*/ + + /** + * generates the basic string serialization of a token that a server + * would respond to request_token and access_token calls with + */ + function to_string() {/*{{{*/ + return "oauth_token=" . OAuthUtil::urlencodeRFC3986($this->key) . + "&oauth_token_secret=" . OAuthUtil::urlencodeRFC3986($this->secret); + }/*}}}*/ + + function __toString() {/*{{{*/ + return $this->to_string(); + }/*}}}*/ +}/*}}}*/ + +class OAuthSignatureMethod {/*{{{*/ + public function check_signature(&$request, $consumer, $token, $signature) { + $built = $this->build_signature($request, $consumer, $token); + return $built == $signature; + } +}/*}}}*/ + +class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {/*{{{*/ + function get_name() {/*{{{*/ + return "HMAC-SHA1"; + }/*}}}*/ + + public function build_signature($request, $consumer, $token, $privKey=NULL) {/*{{{*/ + $base_string = $request->get_signature_base_string(); + $request->base_string = $base_string; + + $key_parts = array( + $consumer->secret, + ($token) ? $token->secret : "" + ); + + $key_parts = array_map(array('OAuthUtil','urlencodeRFC3986'), $key_parts); + $key = implode('&', $key_parts); + + return base64_encode( hash_hmac('sha1', $base_string, $key, true)); + }/*}}}*/ +}/*}}}*/ + +class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {/*{{{*/ + public function get_name() {/*{{{*/ + return "RSA-SHA1"; + }/*}}}*/ + + protected function fetch_public_cert(&$request) {/*{{{*/ + // not implemented yet, ideas are: + // (1) do a lookup in a table of trusted certs keyed off of consumer + // (2) fetch via http using a url provided by the requester + // (3) some sort of specific discovery code based on request + // + // either way should return a string representation of the certificate + throw Exception("fetch_public_cert not implemented"); + }/*}}}*/ + + protected function fetch_private_cert($privKey) {//&$request) {/*{{{*/ + // not implemented yet, ideas are: + // (1) do a lookup in a table of trusted certs keyed off of consumer + // + // either way should return a string representation of the certificate + throw Exception("fetch_private_cert not implemented"); + }/*}}}*/ + + public function build_signature(&$request, $consumer, $token, $privKey) {/*{{{*/ + $base_string = $request->get_signature_base_string(); + + // Fetch the private key cert based on the request + //$cert = $this->fetch_private_cert($consumer->privKey); + + //Pull the private key ID from the certificate + //$privatekeyid = openssl_get_privatekey($cert); + + // hacked in + if ($privKey == '') { + $fp = fopen($GLOBALS['PRIV_KEY_FILE'], "r"); + $privKey = fread($fp, 8192); + fclose($fp); + } + $privatekeyid = openssl_get_privatekey($privKey); + + //Check the computer signature against the one passed in the query + $ok = openssl_sign($base_string, $signature, $privatekeyid); + + //Release the key resource + openssl_free_key($privatekeyid); + + return base64_encode($signature); + } /*}}}*/ + + public function check_signature(&$request, $consumer, $token, $signature) {/*{{{*/ + $decoded_sig = base64_decode($signature); + + $base_string = $request->get_signature_base_string(); + + // Fetch the public key cert based on the request + $cert = $this->fetch_public_cert($request); + + //Pull the public key ID from the certificate + $publickeyid = openssl_get_publickey($cert); + + //Check the computer signature against the one passed in the query + $ok = openssl_verify($base_string, $decoded_sig, $publickeyid); + + //Release the key resource + openssl_free_key($publickeyid); + + return $ok == 1; + } /*}}}*/ +}/*}}}*/ + +class OAuthRequest {/*{{{*/ + private $parameters; + private $http_method; + private $http_url; + // for debug purposes + public $base_string; + public static $version = '1.0'; + + function __construct($http_method, $http_url, $parameters=NULL) {/*{{{*/ + @$parameters or $parameters = array(); + $this->parameters = $parameters; + $this->http_method = $http_method; + $this->http_url = $http_url; + }/*}}}*/ + + + /** + * attempt to build up a request from what was passed to the server + */ + public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {/*{{{*/ + $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http' : 'https'; + @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; + + $request_headers = OAuthRequest::get_headers(); + + // let the library user override things however they'd like, if they know + // which parameters to use then go for it, for example XMLRPC might want to + // do this + if ($parameters) { + $req = new OAuthRequest($http_method, $http_url, $parameters); + } + // next check for the auth header, we need to do some extra stuff + // if that is the case, namely suck in the parameters from GET or POST + // so that we can include them in the signature + else if (@substr($request_headers['Authorization'], 0, 5) == "OAuth") { + $header_parameters = OAuthRequest::split_header($request_headers['Authorization']); + if ($http_method == "GET") { + $req_parameters = $_GET; + } + else if ($http_method = "POST") { + $req_parameters = $_POST; + } + $parameters = array_merge($header_parameters, $req_parameters); + $req = new OAuthRequest($http_method, $http_url, $parameters); + } + else if ($http_method == "GET") { + $req = new OAuthRequest($http_method, $http_url, $_GET); + } + else if ($http_method == "POST") { + $req = new OAuthRequest($http_method, $http_url, $_POST); + } + return $req; + }/*}}}*/ + + /** + * pretty much a helper function to set up the request + */ + public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {/*{{{*/ + @$parameters or $parameters = array(); + $defaults = array("oauth_version" => OAuthRequest::$version, + "oauth_nonce" => OAuthRequest::generate_nonce(), + "oauth_timestamp" => OAuthRequest::generate_timestamp(), + "oauth_consumer_key" => $consumer->key); + $parameters = array_merge($defaults, $parameters); + + if ($token) { + $parameters['oauth_token'] = $token->key; + } + + // oauth v1.0a + /*if (isset($_REQUEST['oauth_verifier'])) { + $parameters['oauth_verifier'] = $_REQUEST['oauth_verifier']; + }*/ + + + return new OAuthRequest($http_method, $http_url, $parameters); + }/*}}}*/ + + public function set_parameter($name, $value) {/*{{{*/ + $this->parameters[$name] = $value; + }/*}}}*/ + + public function get_parameter($name) {/*{{{*/ + return $this->parameters[$name]; + }/*}}}*/ + + public function get_parameters() {/*{{{*/ + return $this->parameters; + }/*}}}*/ + + /** + * Returns the normalized parameters of the request + * + * This will be all (except oauth_signature) parameters, + * sorted first by key, and if duplicate keys, then by + * value. + * + * The returned string will be all the key=value pairs + * concated by &. + * + * @return string + */ + public function get_signable_parameters() {/*{{{*/ + // Grab all parameters + $params = $this->parameters; + + // Remove oauth_signature if present + if (isset($params['oauth_signature'])) { + unset($params['oauth_signature']); + } + + // Urlencode both keys and values + $keys = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_keys($params)); + $values = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_values($params)); + $params = array_combine($keys, $values); + + // Sort by keys (natsort) + uksort($params, 'strnatcmp'); + +if(isset($params['title']) && isset($params['title-exact'])) { + $temp = $params['title-exact']; + $title = $params['title']; + + unset($params['title']); + unset($params['title-exact']); + + $params['title-exact'] = $temp; + $params['title'] = $title; +} + + // Generate key=value pairs + $pairs = array(); + foreach ($params as $key=>$value ) { + if (is_array($value)) { + // If the value is an array, it's because there are multiple + // with the same key, sort them, then add all the pairs + natsort($value); + foreach ($value as $v2) { + $pairs[] = $key . '=' . $v2; + } + } else { + $pairs[] = $key . '=' . $value; + } + } + + // Return the pairs, concated with & + return implode('&', $pairs); + }/*}}}*/ + + /** + * Returns the base string of this request + * + * The base string defined as the method, the url + * and the parameters (normalized), each urlencoded + * and the concated with &. + */ + public function get_signature_base_string() {/*{{{*/ + $parts = array( + $this->get_normalized_http_method(), + $this->get_normalized_http_url(), + $this->get_signable_parameters() + ); + + $parts = array_map(array('OAuthUtil', 'urlencodeRFC3986'), $parts); + + return implode('&', $parts); + }/*}}}*/ + + /** + * just uppercases the http method + */ + public function get_normalized_http_method() {/*{{{*/ + return strtoupper($this->http_method); + }/*}}}*/ + +/** + * parses the url and rebuilds it to be + * scheme://host/path + */ + public function get_normalized_http_url() { + $parts = parse_url($this->http_url); + + $scheme = (isset($parts['scheme'])) ? $parts['scheme'] : 'http'; + $port = (isset($parts['port'])) ? $parts['port'] : (($scheme == 'https') ? '443' : '80'); + $host = (isset($parts['host'])) ? strtolower($parts['host']) : ''; + $path = (isset($parts['path'])) ? $parts['path'] : ''; + + if (($scheme == 'https' && $port != '443') + || ($scheme == 'http' && $port != '80')) { + $host = "$host:$port"; + } + return "$scheme://$host$path"; + } + + /** + * builds a url usable for a GET request + */ + public function to_url() {/*{{{*/ + $out = $this->get_normalized_http_url() . "?"; + $out .= $this->to_postdata(); + return $out; + }/*}}}*/ + + /** + * builds the data one would send in a POST request + */ + public function to_postdata() {/*{{{*/ + $total = array(); + foreach ($this->parameters as $k => $v) { + $total[] = OAuthUtil::urlencodeRFC3986($k) . "=" . OAuthUtil::urlencodeRFC3986($v); + } + $out = implode("&", $total); + return $out; + }/*}}}*/ + + /** + * builds the Authorization: header + */ + public function to_header() {/*{{{*/ + $out ='Authorization: OAuth '; + $total = array(); + + /* + $sig = $this->parameters['oauth_signature']; + unset($this->parameters['oauth_signature']); + uksort($this->parameters, 'strnatcmp'); + $this->parameters['oauth_signature'] = $sig; + */ + + foreach ($this->parameters as $k => $v) { + if (substr($k, 0, 5) != "oauth") continue; + $out .= OAuthUtil::urlencodeRFC3986($k) . '="' . OAuthUtil::urlencodeRFC3986($v) . '", '; + } + $out = substr_replace($out, '', strlen($out) - 2); + + return $out; + }/*}}}*/ + + public function __toString() {/*{{{*/ + return $this->to_url(); + }/*}}}*/ + + + public function sign_request($signature_method, $consumer, $token, $privKey=NULL) {/*{{{*/ + $this->set_parameter("oauth_signature_method", $signature_method->get_name()); + $signature = $this->build_signature($signature_method, $consumer, $token, $privKey); + $this->set_parameter("oauth_signature", $signature); + }/*}}}*/ + + public function build_signature($signature_method, $consumer, $token, $privKey=NULL) {/*{{{*/ + $signature = $signature_method->build_signature($this, $consumer, $token, $privKey); + return $signature; + }/*}}}*/ + + /** + * util function: current timestamp + */ + private static function generate_timestamp() {/*{{{*/ + return time(); + }/*}}}*/ + + /** + * util function: current nonce + */ + private static function generate_nonce() {/*{{{*/ + $mt = microtime(); + $rand = mt_rand(); + + return md5($mt . $rand); // md5s look nicer than numbers + }/*}}}*/ + + /** + * util function for turning the Authorization: header into + * parameters, has to do some unescaping + */ + private static function split_header($header) {/*{{{*/ + // this should be a regex + // error cases: commas in parameter values + $parts = explode(",", $header); + $out = array(); + foreach ($parts as $param) { + $param = ltrim($param); + // skip the "realm" param, nobody ever uses it anyway + if (substr($param, 0, 5) != "oauth") continue; + + $param_parts = explode("=", $param); + + // rawurldecode() used because urldecode() will turn a "+" in the + // value into a space + $out[$param_parts[0]] = rawurldecode(substr($param_parts[1], 1, -1)); + } + return $out; + }/*}}}*/ + + /** + * helper to try to sort out headers for people who aren't running apache + */ + private static function get_headers() {/*{{{*/ + if (function_exists('apache_request_headers')) { + // we need this to get the actual Authorization: header + // because apache tends to tell us it doesn't exist + return apache_request_headers(); + } + // otherwise we don't have apache and are just going to have to hope + // that $_SERVER actually contains what we need + $out = array(); + foreach ($_SERVER as $key => $value) { + if (substr($key, 0, 5) == "HTTP_") { + // this is chaos, basically it is just there to capitalize the first + // letter of every word that is not an initial HTTP and strip HTTP + // code from przemek + $key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5))))); + $out[$key] = $value; + } + } + return $out; + }/*}}}*/ +}/*}}}*/ + +class OAuthServer {/*{{{*/ + protected $timestamp_threshold = 300; // in seconds, five minutes + protected $version = 1.0; // hi blaine + protected $signature_methods = array(); + + protected $data_store; + + function __construct($data_store) {/*{{{*/ + $this->data_store = $data_store; + }/*}}}*/ + + public function add_signature_method($signature_method) {/*{{{*/ + $this->signature_methods[$signature_method->get_name()] = + $signature_method; + }/*}}}*/ + + // high level functions + + /** + * process a request_token request + * returns the request token on success + */ + public function fetch_request_token(&$request) {/*{{{*/ + $this->get_version($request); + + $consumer = $this->get_consumer($request); + + // no token required for the initial token request + $token = NULL; + + $this->check_signature($request, $consumer, $token); + + $new_token = $this->data_store->new_request_token($consumer); + + return $new_token; + }/*}}}*/ + + /** + * process an access_token request + * returns the access token on success + */ + public function fetch_access_token(&$request) {/*{{{*/ + $this->get_version($request); + + $consumer = $this->get_consumer($request); + + // requires authorized request token + $token = $this->get_token($request, $consumer, "request"); + + $this->check_signature($request, $consumer, $token); + + $new_token = $this->data_store->new_access_token($token, $consumer); + + return $new_token; + }/*}}}*/ + + /** + * verify an api call, checks all the parameters + */ + public function verify_request(&$request) {/*{{{*/ + $this->get_version($request); + $consumer = $this->get_consumer($request); + $token = $this->get_token($request, $consumer, "access"); + $this->check_signature($request, $consumer, $token); + return array($consumer, $token); + }/*}}}*/ + + // Internals from here + /** + * version 1 + */ + private function get_version(&$request) {/*{{{*/ + $version = $request->get_parameter("oauth_version"); + if (!$version) { + $version = 1.0; + } + if ($version && $version != $this->version) { + throw new OAuthException("OAuth version '$version' not supported"); + } + return $version; + }/*}}}*/ + + /** + * figure out the signature with some defaults + */ + private function get_signature_method(&$request) {/*{{{*/ + $signature_method = + @$request->get_parameter("oauth_signature_method"); + if (!$signature_method) { + $signature_method = "PLAINTEXT"; + } + if (!in_array($signature_method, + array_keys($this->signature_methods))) { + throw new OAuthException( + "Signature method '$signature_method' not supported try one of the following: " . implode(", ", array_keys($this->signature_methods)) + ); + } + return $this->signature_methods[$signature_method]; + }/*}}}*/ + + /** + * try to find the consumer for the provided request's consumer key + */ + private function get_consumer(&$request) {/*{{{*/ + $consumer_key = @$request->get_parameter("oauth_consumer_key"); + if (!$consumer_key) { + throw new OAuthException("Invalid consumer key"); + } + + $consumer = $this->data_store->lookup_consumer($consumer_key); + if (!$consumer) { + throw new OAuthException("Invalid consumer"); + } + + return $consumer; + }/*}}}*/ + + /** + * try to find the token for the provided request's token key + */ + private function get_token(&$request, $consumer, $token_type="access") {/*{{{*/ + $token_field = @$request->get_parameter('oauth_token'); + $token = $this->data_store->lookup_token( + $consumer, $token_type, $token_field + ); + if (!$token) { + throw new OAuthException("Invalid $token_type token: $token_field"); + } + return $token; + }/*}}}*/ + + /** + * all-in-one function to check the signature on a request + * should guess the signature method appropriately + */ + private function check_signature(&$request, $consumer, $token) {/*{{{*/ + // this should probably be in a different method + $timestamp = @$request->get_parameter('oauth_timestamp'); + $nonce = @$request->get_parameter('oauth_nonce'); + + $this->check_timestamp($timestamp); + $this->check_nonce($consumer, $token, $nonce, $timestamp); + + $signature_method = $this->get_signature_method($request); + + $signature = $request->get_parameter('oauth_signature'); + $valid_sig = $signature_method->check_signature( + $request, + $consumer, + $token, + $signature + ); + + if (!$valid_sig) { + throw new OAuthException("Invalid signature"); + } + }/*}}}*/ + + /** + * check that the timestamp is new enough + */ + private function check_timestamp($timestamp) {/*{{{*/ + // verify that timestamp is recentish + $now = time(); + if ($now - $timestamp > $this->timestamp_threshold) { + throw new OAuthException("Expired timestamp, yours $timestamp, ours $now"); + } + }/*}}}*/ + + /** + * check that the nonce is not repeated + */ + private function check_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/ + // verify that the nonce is uniqueish + $found = $this->data_store->lookup_nonce($consumer, $token, $nonce, $timestamp); + if ($found) { + throw new OAuthException("Nonce already used: $nonce"); + } + }/*}}}*/ + + + +}/*}}}*/ + +class OAuthDataStore {/*{{{*/ + function lookup_consumer($consumer_key) {/*{{{*/ + // implement me + }/*}}}*/ + + function lookup_token($consumer, $token_type, $token) {/*{{{*/ + // implement me + }/*}}}*/ + + function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/ + // implement me + }/*}}}*/ + + function fetch_request_token($consumer) {/*{{{*/ + // return a new token attached to this consumer + }/*}}}*/ + + function fetch_access_token($token, $consumer) {/*{{{*/ + // return a new access token attached to this consumer + // for the user associated with this token if the request token + // is authorized + // should also invalidate the request token + }/*}}}*/ + +}/*}}}*/ + + +/* A very naive dbm-based oauth storage + */ +class SimpleOAuthDataStore extends OAuthDataStore {/*{{{*/ + private $dbh; + + function __construct($path = "oauth.gdbm") {/*{{{*/ + $this->dbh = dba_popen($path, 'c', 'gdbm'); + }/*}}}*/ + + function __destruct() {/*{{{*/ + dba_close($this->dbh); + }/*}}}*/ + + function lookup_consumer($consumer_key) {/*{{{*/ + $rv = dba_fetch("consumer_$consumer_key", $this->dbh); + if ($rv === FALSE) { + return NULL; + } + $obj = unserialize($rv); + if (!($obj instanceof OAuthConsumer)) { + return NULL; + } + return $obj; + }/*}}}*/ + + function lookup_token($consumer, $token_type, $token) {/*{{{*/ + $rv = dba_fetch("${token_type}_${token}", $this->dbh); + if ($rv === FALSE) { + return NULL; + } + $obj = unserialize($rv); + if (!($obj instanceof OAuthToken)) { + return NULL; + } + return $obj; + }/*}}}*/ + + function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/ + return dba_exists("nonce_$nonce", $this->dbh); + }/*}}}*/ + + function new_token($consumer, $type="request") {/*{{{*/ + $key = md5(time()); + $secret = time() + time(); + $token = new OAuthToken($key, md5(md5($secret))); + if (!dba_insert("${type}_$key", serialize($token), $this->dbh)) { + throw new OAuthException("doooom!"); + } + return $token; + }/*}}}*/ + + function new_request_token($consumer) {/*{{{*/ + return $this->new_token($consumer, "request"); + }/*}}}*/ + + function new_access_token($token, $consumer) {/*{{{*/ + + $token = $this->new_token($consumer, 'access'); + dba_delete("request_" . $token->key, $this->dbh); + return $token; + }/*}}}*/ +}/*}}}*/ + +class OAuthUtil {/*{{{*/ + public static function urlencodeRFC3986($string) {/*{{{*/ + return str_replace('%7E', '~', rawurlencode($string)); + }/*}}}*/ + + public static function urldecodeRFC3986($string) {/*{{{*/ + return rawurldecode($string); + }/*}}}*/ +}/*}}}*/ + +?> \ No newline at end of file diff --git a/3rdparty/Google/common.inc.php b/3rdparty/Google/common.inc.php new file mode 100755 index 00000000000..57185cdc4d8 --- /dev/null +++ b/3rdparty/Google/common.inc.php @@ -0,0 +1,185 @@ + + */ + +$PRIV_KEY_FILE = '/path/to/your/rsa_private_key.pem'; + +// OAuth library - http://oauth.googlecode.com/svn/code/php/ +require_once('OAuth.php'); + +// Google's accepted signature methods +$hmac_method = new OAuthSignatureMethod_HMAC_SHA1(); +$rsa_method = new OAuthSignatureMethod_RSA_SHA1(); +$SIG_METHODS = array($rsa_method->get_name() => $rsa_method, + $hmac_method->get_name() => $hmac_method); + +/** + * Makes an HTTP request to the specified URL + * + * @param string $http_method The HTTP method (GET, POST, PUT, DELETE) + * @param string $url Full URL of the resource to access + * @param array $extraHeaders (optional) Additional headers to include in each + * request. Elements are header/value pair strings ('Host: example.com') + * @param string $postData (optional) POST/PUT request body + * @param bool $returnResponseHeaders True if resp. headers should be returned. + * @return string Response body from the server + */ +function send_signed_request($http_method, $url, $extraHeaders=null, + $postData=null, $returnResponseHeaders=true) { + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FAILONERROR, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + + // Return request headers in the reponse +// curl_setopt($curl, CURLINFO_HEADER_OUT, true); + + // Return response headers ni the response? + if ($returnResponseHeaders) { + curl_setopt($curl, CURLOPT_HEADER, true); + } + + $headers = array(); + //$headers[] = 'GData-Version: 2.0'; // use GData v2 by default + if (is_array($extraHeaders)) { + $headers = array_merge($headers, $extraHeaders); + } + + // Setup default curl options for each type of HTTP request. + // This is also a great place to add additional headers for each request. + switch($http_method) { + case 'GET': + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + break; + case 'POST': + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + break; + case 'PUT': + $headers[] = 'If-Match: *'; + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + break; + case 'DELETE': + $headers[] = 'If-Match: *'; + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method); + break; + default: + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + } + + // Execute the request. If an error occures, fill the response body with it. + $response = curl_exec($curl); + if (!$response) { + $response = curl_error($curl); + } + + // Add server's response headers to our response body + $response = curl_getinfo($curl, CURLINFO_HEADER_OUT) . $response; + + curl_close($curl); + + return $response; +} + +/** +* Takes XML as a string and returns it nicely indented +* +* @param string $xml The xml to beautify +* @param boolean $html_output True if returned XML should be escaped for HTML. +* @return string The beautified xml +*/ +function xml_pretty_printer($xml, $html_output=false) { + $xml_obj = new SimpleXMLElement($xml); + $level = 2; + + // Get an array containing each XML element + $xml = explode("\n", preg_replace('/>\s*\n<", $xml_obj->asXML())); + + // Hold current indentation level + $indent = 0; + + $pretty = array(); + + // Shift off opening XML tag if present + if (count($xml) && preg_match('/^<\?\s*xml/', $xml[0])) { + $pretty[] = array_shift($xml); + } + + foreach ($xml as $el) { + if (preg_match('/^<([\w])+[^>\/]*>$/U', $el)) { + // opening tag, increase indent + $pretty[] = str_repeat(' ', $indent) . $el; + $indent += $level; + } else { + if (preg_match('/^<\/.+>$/', $el)) { + $indent -= $level; // closing tag, decrease indent + } + if ($indent < 0) { + $indent += $level; + } + $pretty[] = str_repeat(' ', $indent) . $el; + } + } + + $xml = implode("\n", $pretty); + return $html_output ? htmlentities($xml) : $xml; +} + +/** + * Joins key/value pairs by $inner_glue and each pair together by $outer_glue. + * + * Example: implode_assoc('=', '&', array('a' => 1, 'b' => 2)) === 'a=1&b=2' + * + * @param string $inner_glue What to implode each key/value pair with + * @param string $outer_glue What to impode each key/value string subset with + * @param array $array Associative array of query parameters + * @return string Urlencoded string of query parameters + */ +function implode_assoc($inner_glue, $outer_glue, $array) { + $output = array(); + foreach($array as $key => $item) { + $output[] = $key . $inner_glue . urlencode($item); + } + return implode($outer_glue, $output); +} + +/** + * Explodes a string of key/value url parameters into an associative array. + * This method performs the compliment operations of implode_assoc(). + * + * Example: explode_assoc('=', '&', 'a=1&b=2') === array('a' => 1, 'b' => 2) + * + * @param string $inner_glue What each key/value pair is joined with + * @param string $outer_glue What each set of key/value pairs is joined with. + * @param array $array Associative array of query parameters + * @return array Urlencoded string of query parameters + */ +function explode_assoc($inner_glue, $outer_glue, $params) { + $tempArr = explode($outer_glue, $params); + foreach($tempArr as $val) { + $pos = strpos($val, $inner_glue); + $key = substr($val, 0, $pos); + $array2[$key] = substr($val, $pos + 1, strlen($val)); + } + return $array2; +} + +?> \ No newline at end of file diff --git a/3rdparty/mediawiki/CSSMin.php b/3rdparty/mediawiki/CSSMin.php index 1ee2919140f..e9c2badf62b 100644 --- a/3rdparty/mediawiki/CSSMin.php +++ b/3rdparty/mediawiki/CSSMin.php @@ -172,7 +172,6 @@ class CSSMin { $type = self::getMimeType( $file ); // Detect when URLs were preceeded with embed tags, and also verify file size is // below the limit - var_dump($match['embed'], $file, filesize($file)); if ( $type && $match['embed'][1] > 0 diff --git a/3rdparty/phpass/PasswordHash.php b/3rdparty/phpass/PasswordHash.php index 12958c7f19e..84447b277df 100644 --- a/3rdparty/phpass/PasswordHash.php +++ b/3rdparty/phpass/PasswordHash.php @@ -48,7 +48,7 @@ class PasswordHash { function get_random_bytes($count) { $output = ''; - if (is_readable('/dev/urandom') && + if (@is_readable('/dev/urandom') && ($fh = @fopen('/dev/urandom', 'rb'))) { $output = fread($fh, $count); fclose($fh); diff --git a/apps/calendar/ajax/events.php b/apps/calendar/ajax/events.php index 56fa51aaff2..3f29f1e5eff 100644 --- a/apps/calendar/ajax/events.php +++ b/apps/calendar/ajax/events.php @@ -13,21 +13,19 @@ OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('calendar'); // Look for the calendar id -$calendar_id = OC_Calendar_App::getCalendar($_GET['calendar_id'], false, false); -if($calendar_id !== false){ - if(! is_numeric($calendar_id['userid']) && $calendar_id['userid'] != OCP\User::getUser()){ - OCP\JSON::error(); - exit; +$calendar_id = null; +if (strval(intval($_GET['calendar_id'])) == strval($_GET['calendar_id'])) { // integer for sure. + $id = intval($_GET['calendar_id']); + $calendarrow = OC_Calendar_App::getCalendar($id, true, false); // Let's at least security check otherwise we might as well use OC_Calendar_Calendar::find() + if($calendarrow !== false && is_int($calendar_id['userid']) && $id == $calendar_id['userid']) { + $calendar_id = $id; } } -else { - $calendar_id = $_GET['calendar_id']; -} +$calendar_id = (is_null($calendar_id)?strip_tags($_GET['calendar_id']):$calendar_id); $start = (version_compare(PHP_VERSION, '5.3.0', '>='))?DateTime::createFromFormat('U', $_GET['start']):new DateTime('@' . $_GET['start']); $end = (version_compare(PHP_VERSION, '5.3.0', '>='))?DateTime::createFromFormat('U', $_GET['end']):new DateTime('@' . $_GET['end']); $events = OC_Calendar_App::getrequestedEvents($calendar_id, $start, $end); - $output = array(); foreach($events as $event){ $output = array_merge($output, OC_Calendar_App::generateEventOutput($event, $start, $end)); diff --git a/apps/calendar/ajax/import/dropimport.php b/apps/calendar/ajax/import/dropimport.php index e98c282ef41..684eebf5fdd 100644 --- a/apps/calendar/ajax/import/dropimport.php +++ b/apps/calendar/ajax/import/dropimport.php @@ -45,7 +45,7 @@ foreach($lines as $line) { } $i++; } -$calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), 1); +$calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), true); $id = $calendars[0]['id']; foreach($uids as $uid) { $prefix=$suffix=$content=array(); diff --git a/apps/calendar/index.php b/apps/calendar/index.php index cf03a7a3cd3..4b871195927 100644 --- a/apps/calendar/index.php +++ b/apps/calendar/index.php @@ -11,15 +11,17 @@ OCP\User::checkLoggedIn(); OCP\App::checkAppEnabled('calendar'); // Create default calendar ... -$calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), 1); +$calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), false); if( count($calendars) == 0){ OC_Calendar_Calendar::addCalendar(OCP\USER::getUser(),'Default calendar'); - $calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), 1); + $calendars = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser(), true); } $eventSources = array(); foreach($calendars as $calendar){ - $eventSources[] = OC_Calendar_Calendar::getEventSourceInfo($calendar); + if($calendar['active'] == 1) { + $eventSources[] = OC_Calendar_Calendar::getEventSourceInfo($calendar); + } } $eventSources[] = array('url' => '?app=calendar&getfile=ajax/events.php?calendar_id=shared_rw', 'backgroundColor' => '#1D2D44', 'borderColor' => '#888', 'textColor' => 'white', 'editable'=>'true'); @@ -54,9 +56,9 @@ OCP\Util::addscript('contacts','jquery.multi-autocomplete'); OCP\Util::addscript('','oc-vcategories'); OCP\App::setActiveNavigationEntry('calendar_index'); $tmpl = new OCP\Template('calendar', 'calendar', 'user'); -$tmpl->assign('eventSources', $eventSources); +$tmpl->assign('eventSources', $eventSources,false); $tmpl->assign('categories', $categories); if(array_key_exists('showevent', $_GET)){ - $tmpl->assign('showevent', $_GET['showevent']); + $tmpl->assign('showevent', $_GET['showevent'], false); } $tmpl->printPage(); diff --git a/apps/calendar/js/calendar.js b/apps/calendar/js/calendar.js index 7ae4a3a6eb1..5136c3e7745 100644 --- a/apps/calendar/js/calendar.js +++ b/apps/calendar/js/calendar.js @@ -430,6 +430,7 @@ Calendar={ $('#calendar_holder').fullCalendar('removeEventSource', url); $('#choosecalendar_dialog').dialog('destroy').remove(); Calendar.UI.Calendar.overview(); + $('#calendar_holder').fullCalendar('refetchEvents'); } }); } @@ -845,7 +846,7 @@ $(document).ready(function(){ dayNamesShort: dayNamesShort, allDayText: allDayText, viewDisplay: function(view) { - $('#datecontrol_date').html(view.title); + $('#datecontrol_date').val($('

').html(view.title).text()); if (view.name != defaultView) { $.post(OC.filePath('calendar', 'ajax', 'changeview.php'), {v:view.name}); defaultView = view.name; @@ -884,6 +885,22 @@ $(document).ready(function(){ loading: Calendar.UI.loading, eventSources: eventSources }); + $('#datecontrol_date').datepicker({ + changeMonth: true, + changeYear: true, + showButtonPanel: true, + beforeShow: function(input, inst) { + var calendar_holder = $('#calendar_holder'); + var date = calendar_holder.fullCalendar('getDate'); + inst.input.datepicker('setDate', date); + inst.input.val(calendar_holder.fullCalendar('getView').title); + return inst; + }, + onSelect: function(value, inst) { + var date = inst.input.datepicker('getDate'); + $('#calendar_holder').fullCalendar('gotoDate', date); + } + }); fillWindow($('#content')); OCCategories.changed = Calendar.UI.categoriesChanged; OCCategories.app = 'calendar'; diff --git a/apps/calendar/lib/app.php b/apps/calendar/lib/app.php index 2cd28c0f782..74cf9f01037 100644 --- a/apps/calendar/lib/app.php +++ b/apps/calendar/lib/app.php @@ -50,10 +50,7 @@ class OC_Calendar_App{ return false; } } - if($calendar === false){ - return false; - } - return OC_Calendar_Calendar::find($id); + return $calendar; } /* @@ -331,26 +328,29 @@ class OC_Calendar_App{ */ public static function getrequestedEvents($calendarid, $start, $end){ $events = array(); - if($calendarid == 'shared_rw' || $_GET['calendar_id'] == 'shared_r'){ + if($calendarid == 'shared_rw' || $calendarid == 'shared_r'){ $calendars = OC_Calendar_Share::allSharedwithuser(OCP\USER::getUser(), OC_Calendar_Share::CALENDAR, 1, ($_GET['calendar_id'] == 'shared_rw')?'rw':'r'); foreach($calendars as $calendar){ $calendarevents = OC_Calendar_Object::allInPeriod($calendar['calendarid'], $start, $end); + foreach($calendarevents as $event){ + $event['summary'] .= ' (' . self::$l10n->t('by') . ' ' . OC_Calendar_Object::getowner($event['id']) . ')'; + } $events = array_merge($events, $calendarevents); } $singleevents = OC_Calendar_Share::allSharedwithuser(OCP\USER::getUser(), OC_Calendar_Share::EVENT, 1, ($_GET['calendar_id'] == 'shared_rw')?'rw':'r'); foreach($singleevents as $singleevent){ $event = OC_Calendar_Object::find($singleevent['eventid']); + $event['summary'] .= ' (' . self::$l10n->t('by') . ' ' . OC_Calendar_Object::getowner($event['id']) . ')'; $events[] = $event; } }else{ - $calendar_id = $_GET['calendar_id']; - if (is_numeric($calendar_id)) { - $calendar = self::getCalendar($calendar_id); + if (is_numeric($calendarid)) { + $calendar = self::getCalendar($calendarid); OCP\Response::enableCaching(0); OCP\Response::setETagHeader($calendar['ctag']); - $events = OC_Calendar_Object::allInPeriod($calendar_id, $start, $end); + $events = OC_Calendar_Object::allInPeriod($calendarid, $start, $end); } else { - OCP\Util::emitHook('OC_Calendar', 'getEvents', array('calendar_id' => $calendar_id, 'events' => &$events)); + OCP\Util::emitHook('OC_Calendar', 'getEvents', array('calendar_id' => $calendarid, 'events' => &$events)); } } return $events; @@ -377,8 +377,8 @@ class OC_Calendar_App{ $lastmodified = ($last_modified)?$last_modified->getDateTime()->format('U'):0; $output = array('id'=>(int)$event['id'], - 'title' => htmlspecialchars(($event['summary']!=NULL || $event['summary'] != '')?$event['summary']: self::$l10n->t('unnamed')), - 'description' => isset($vevent->DESCRIPTION)?htmlspecialchars($vevent->DESCRIPTION->value):'', + 'title' => ($event['summary']!=NULL || $event['summary'] != '')?$event['summary']: self::$l10n->t('unnamed'), + 'description' => isset($vevent->DESCRIPTION)?$vevent->DESCRIPTION->value:'', 'lastmodified'=>$lastmodified); $dtstart = $vevent->DTSTART; diff --git a/apps/calendar/lib/calendar.php b/apps/calendar/lib/calendar.php index 869b35e2e1b..0a54e7a32a6 100644 --- a/apps/calendar/lib/calendar.php +++ b/apps/calendar/lib/calendar.php @@ -44,13 +44,13 @@ class OC_Calendar_Calendar{ /** * @brief Returns the list of calendars for a specific user. * @param string $uid User ID - * @param boolean $active Only return calendars with this $active state, default(=null) is don't care + * @param boolean $active Only return calendars with this $active state, default(=false) is don't care * @return array */ - public static function allCalendars($uid, $active=null){ + public static function allCalendars($uid, $active=false){ $values = array($uid); $active_where = ''; - if (!is_null($active) && $active){ + if ($active){ $active_where = ' AND active = ?'; $values[] = $active; } @@ -198,6 +198,10 @@ class OC_Calendar_Calendar{ $stmt = OCP\DB::prepare( 'DELETE FROM *PREFIX*calendar_objects WHERE calendarid = ?' ); $stmt->execute(array($id)); + if(count(self::allCalendars()) == 0) { + self::addCalendar(OCP\USER::getUser(),'Default calendar'); + } + return true; } diff --git a/apps/calendar/lib/search.php b/apps/calendar/lib/search.php index 03516b3b70c..6526b4223ac 100644 --- a/apps/calendar/lib/search.php +++ b/apps/calendar/lib/search.php @@ -1,7 +1,7 @@

- +
diff --git a/apps/calendar/templates/part.choosecalendar.rowfields.php b/apps/calendar/templates/part.choosecalendar.rowfields.php index 268c3356011..965523f847a 100644 --- a/apps/calendar/templates/part.choosecalendar.rowfields.php +++ b/apps/calendar/templates/part.choosecalendar.rowfields.php @@ -1,8 +1,8 @@ '; -echo ''; +echo ''; echo ''; -echo ''; +echo ''; echo ''; echo ''; echo ''; diff --git a/apps/calendar/templates/part.choosecalendar.rowfields.shared.php b/apps/calendar/templates/part.choosecalendar.rowfields.shared.php index 6a212858a21..a23266da0c3 100644 --- a/apps/calendar/templates/part.choosecalendar.rowfields.shared.php +++ b/apps/calendar/templates/part.choosecalendar.rowfields.shared.php @@ -1,4 +1,4 @@ '; -echo ''; +echo ''; echo '' . $l->t('shared with you by') . ' ' . $_['share']['owner'] . ''; \ No newline at end of file diff --git a/apps/calendar/templates/part.eventform.php b/apps/calendar/templates/part.eventform.php index 2d86ce4d318..95eecf26223 100644 --- a/apps/calendar/templates/part.eventform.php +++ b/apps/calendar/templates/part.eventform.php @@ -18,7 +18,7 @@ echo 'Calendar.UI.Share.idtype = "event";' . "\n" . 'Calendar.UI.Share.currentid t("Title");?>: - " value="" maxlength="100" name="title"/> + " value="" maxlength="100" name="title"/> @@ -26,7 +26,7 @@ echo 'Calendar.UI.Share.idtype = "event";' . "\n" . 'Calendar.UI.Share.currentid t("Category");?>: - + <?php echo $l->t('Edit categories'); ?> 1) { ?> @@ -80,7 +80,7 @@ echo 'Calendar.UI.Share.idtype = "event";' . "\n" . 'Calendar.UI.Share.currentid t("Location");?>: - " value="" maxlength="100" name="location" /> + " value="" maxlength="100" name="location" /> @@ -88,7 +88,7 @@ echo 'Calendar.UI.Share.idtype = "event";' . "\n" . 'Calendar.UI.Share.currentid t("Description");?>: - + diff --git a/apps/calendar/templates/part.import.php b/apps/calendar/templates/part.import.php index b966100cc11..70ff9612157 100644 --- a/apps/calendar/templates/part.import.php +++ b/apps/calendar/templates/part.import.php @@ -9,7 +9,7 @@ $calendar_options = OC_Calendar_Calendar::allCalendars(OCP\USER::getUser()); $calendar_options[] = array('id'=>'newcal', 'displayname'=>$l->t('create a new calendar')); for($i = 0;$i'id', 'label'=>'displayname')); ?> diff --git a/apps/calendar/templates/part.showevent.php b/apps/calendar/templates/part.showevent.php index 3646baf5bb7..59684d831e5 100644 --- a/apps/calendar/templates/part.showevent.php +++ b/apps/calendar/templates/part.showevent.php @@ -10,7 +10,7 @@ t("Title");?>: - + @@ -19,26 +19,23 @@ t("Category");?>: t('No categories selected'); }else{ - echo ''; + echo ''; } ?>    t("Calendar");?>: - + t('of') . ' ' . $calendar['userid']; + ?>   @@ -79,7 +76,7 @@ t("Location");?>: - + @@ -87,7 +84,7 @@ t("Description");?>: - + diff --git a/apps/contacts/ajax/activation.php b/apps/contacts/ajax/activation.php index 388a3b5438c..74cb738ab8f 100644 --- a/apps/contacts/ajax/activation.php +++ b/apps/contacts/ajax/activation.php @@ -10,6 +10,7 @@ OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); +OCP\JSON::callCheck(); $bookid = $_POST['bookid']; $book = OC_Contacts_App::getAddressbook($bookid);// is owner access check diff --git a/apps/contacts/ajax/addcontact.php b/apps/contacts/ajax/addcontact.php index af9b2bbcc0e..e45072c9542 100644 --- a/apps/contacts/ajax/addcontact.php +++ b/apps/contacts/ajax/addcontact.php @@ -23,6 +23,7 @@ // Check if we are a user OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); +OCP\JSON::callCheck(); $aid = isset($_POST['aid'])?$_POST['aid']:null; if(!$aid) { diff --git a/apps/contacts/ajax/addproperty.php b/apps/contacts/ajax/addproperty.php index 94e09bac190..f888b94e386 100644 --- a/apps/contacts/ajax/addproperty.php +++ b/apps/contacts/ajax/addproperty.php @@ -23,6 +23,7 @@ // Check if we are a user OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); +OCP\JSON::callCheck(); function bailOut($msg) { OCP\JSON::error(array('data' => array('message' => $msg))); diff --git a/apps/contacts/ajax/createaddressbook.php b/apps/contacts/ajax/createaddressbook.php index af7c19eef51..616766bb1a0 100644 --- a/apps/contacts/ajax/createaddressbook.php +++ b/apps/contacts/ajax/createaddressbook.php @@ -11,6 +11,7 @@ // Check if we are a user OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); +OCP\JSON::callCheck(); $userid = OCP\USER::getUser(); $name = trim(strip_tags($_POST['name'])); diff --git a/apps/contacts/ajax/cropphoto.php b/apps/contacts/ajax/cropphoto.php index caba7c8c4ef..eb9f1fcdb5d 100644 --- a/apps/contacts/ajax/cropphoto.php +++ b/apps/contacts/ajax/cropphoto.php @@ -25,10 +25,12 @@ OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); $tmpkey = $_GET['tmpkey']; +$requesttoken = $_GET['requesttoken']; $id = $_GET['id']; $tmpl = new OCP\Template("contacts", "part.cropphoto"); $tmpl->assign('tmpkey', $tmpkey); $tmpl->assign('id', $id); +$tmpl->assign('requesttoken', $requesttoken); $page = $tmpl->fetchPage(); OCP\JSON::success(array('data' => array( 'page' => $page ))); diff --git a/apps/contacts/ajax/deletebook.php b/apps/contacts/ajax/deletebook.php index fe582daa00f..1b86ecf223e 100644 --- a/apps/contacts/ajax/deletebook.php +++ b/apps/contacts/ajax/deletebook.php @@ -23,6 +23,7 @@ // Check if we are a user OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); +OCP\JSON::callCheck(); //$id = $_GET['id']; $id = $_POST['id']; diff --git a/apps/contacts/ajax/deletecard.php b/apps/contacts/ajax/deletecard.php index e6d0405a240..2a6bd277d19 100644 --- a/apps/contacts/ajax/deletecard.php +++ b/apps/contacts/ajax/deletecard.php @@ -28,6 +28,17 @@ function bailOut($msg) { // Check if we are a user OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); +OCP\JSON::callCheck(); + +// foreach($_SERVER as $key=>$value) { +// OCP\Util::writeLog('contacts','ajax/saveproperty.php: _SERVER: '.$key.'=>'.$value, OCP\Util::DEBUG); +// } +foreach($_POST as $key=>$value) { + OCP\Util::writeLog('contacts','ajax/saveproperty.php: _POST: '.$key.'=>'.print_r($value, true), OCP\Util::DEBUG); +} +foreach($_GET as $key=>$value) { + OCP\Util::writeLog('contacts','ajax/saveproperty.php: _GET: '.$key.'=>'.print_r($value, true), OCP\Util::DEBUG); +} $id = isset($_POST['id'])?$_POST['id']:null; if(!$id) { diff --git a/apps/contacts/ajax/deleteproperty.php b/apps/contacts/ajax/deleteproperty.php index e6c2bd9f803..55f7e323083 100644 --- a/apps/contacts/ajax/deleteproperty.php +++ b/apps/contacts/ajax/deleteproperty.php @@ -23,6 +23,7 @@ // Check if we are a user OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); +OCP\JSON::callCheck(); $id = $_POST['id']; $checksum = $_POST['checksum']; diff --git a/apps/contacts/ajax/savecrop.php b/apps/contacts/ajax/savecrop.php index b3aab6a8810..6faf6a173d5 100644 --- a/apps/contacts/ajax/savecrop.php +++ b/apps/contacts/ajax/savecrop.php @@ -22,6 +22,7 @@ // Check if we are a user OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); +OCP\JSON::callCheck(); // Firefox and Konqueror tries to download application/json for me. --Arthur OCP\JSON::setContentTypeHeader('text/plain'); diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php index d8400734710..6ee9ec90b56 100644 --- a/apps/contacts/ajax/saveproperty.php +++ b/apps/contacts/ajax/saveproperty.php @@ -20,10 +20,6 @@ * */ -// Check if we are a user -OCP\JSON::checkLoggedIn(); -OCP\JSON::checkAppEnabled('contacts'); - function bailOut($msg) { OCP\JSON::error(array('data' => array('message' => $msg))); OCP\Util::writeLog('contacts','ajax/saveproperty.php: '.$msg, OCP\Util::DEBUG); @@ -33,6 +29,11 @@ function debug($msg) { OCP\Util::writeLog('contacts','ajax/saveproperty.php: '.$msg, OCP\Util::DEBUG); } +// Check if we are a user +OCP\JSON::checkLoggedIn(); +OCP\JSON::checkAppEnabled('contacts'); +OCP\JSON::callCheck(); + $id = isset($_POST['id'])?$_POST['id']:null; $name = isset($_POST['name'])?$_POST['name']:null; $value = isset($_POST['value'])?$_POST['value']:null; diff --git a/apps/contacts/ajax/uploadphoto.php b/apps/contacts/ajax/uploadphoto.php index 32abc6c2859..889de6a1f8b 100644 --- a/apps/contacts/ajax/uploadphoto.php +++ b/apps/contacts/ajax/uploadphoto.php @@ -23,6 +23,8 @@ // Check if we are a user OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); +OCP\JSON::callCheck(); + // Firefox and Konqueror tries to download application/json for me. --Arthur OCP\JSON::setContentTypeHeader('text/plain'); function bailOut($msg) { diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css index 8de68fbf052..dc16d9764c8 100644 --- a/apps/contacts/css/contacts.css +++ b/apps/contacts/css/contacts.css @@ -22,10 +22,10 @@ #firstrun { width: 100%; position: absolute; top: 5em; left: 0; text-align: center; font-weight:bold; font-size:1.5em; color:#777; } #firstrun #selections { font-size:0.8em; margin: 2em auto auto auto; clear: both; } -#card input[type="text"].contacts_property,input[type="email"].contacts_property { width: 14em; float: left; font-weight: bold; } +#card input[type="text"].contacts_property,input[type="email"].contacts_property,input[type="url"].contacts_property { width: 14em; float: left; font-weight: bold; } .categories { float: left; width: 16em; } -#card input[type="text"],input[type="email"],input[type="tel"],input[type="date"], select, textarea { background-color: #fefefe; border: 0 !important; -webkit-appearance:none !important; -moz-appearance:none !important; -webkit-box-sizing:none !important; -moz-box-sizing:none !important; box-sizing:none !important; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; float: left; } -#card input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active,input[type="email"]:hover,input[type="tel"]:hover,input[type="date"]:hover,input[type="date"],input[type="date"]:hover,input[type="date"]:active,input[type="date"]:active,input[type="date"]:active,input[type="email"]:active,input[type="tel"]:active, select:hover, select:focus, select:active, textarea:focus, textarea:hover { border: 0 !important; -webkit-appearance:textfield; -moz-appearance:textfield; -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; background:#fff; color:#333; border:1px solid #ddd; -moz-box-shadow:0 1px 1px #ddd, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; float: left; } +#card input[type="text"],input[type="email"],input[type="url"],input[type="tel"],input[type="date"], select, textarea { background-color: #fefefe; border: 0 !important; -webkit-appearance:none !important; -moz-appearance:none !important; -webkit-box-sizing:none !important; -moz-box-sizing:none !important; box-sizing:none !important; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; float: left; } +#card input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active,input[type="email"]:hover,input[type="url"]:hover,input[type="tel"]:hover,input[type="date"]:hover,input[type="date"],input[type="date"]:hover,input[type="date"]:active,input[type="date"]:active,input[type="date"]:active,input[type="email"]:active,input[type="url"]:active,input[type="tel"]:active, select:hover, select:focus, select:active, textarea:focus, textarea:hover { border: 0 !important; -webkit-appearance:textfield; -moz-appearance:textfield; -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; background:#fff; color:#333; border:1px solid #ddd; -moz-box-shadow:0 1px 1px #ddd, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; float: left; } textarea { width: 80%; min-height: 5em; min-width: 30em; margin: 0 !important; padding: 0 !important; outline: 0 !important;} dl.form { width: 100%; float: left; clear: right; margin: 0; padding: 0; } .form dt { display: table-cell; clear: left; float: left; width: 7em; margin: 0; padding: 0.8em 0.5em 0 0; text-align:right; text-overflow:ellipsis; o-text-overflow: ellipsis; vertical-align: text-bottom; color: #bbb;/* white-space: pre-wrap; white-space: -moz-pre-wrap !important; white-space: -pre-wrap; white-space: -o-pre-wrap;*/ } diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 6b83504c9c4..a1b9976006d 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -622,7 +622,7 @@ Contacts={ q = q + '&id=' + this.id + '&name=' + name; if(checksum != undefined && checksum != '') { // save q = q + '&checksum=' + checksum; - //console.log('Saving: ' + q); + console.log('Saving: ' + q); $(obj).attr('disabled', 'disabled'); $.post(OC.filePath('contacts', 'ajax', 'saveproperty.php'),q,function(jsondata){ if(jsondata.status == 'success'){ @@ -640,7 +640,7 @@ Contacts={ } },'json'); } else { // add - //console.log('Adding: ' + q); + console.log('Adding: ' + q); $(obj).attr('disabled', 'disabled'); $.post(OC.filePath('contacts', 'ajax', 'addproperty.php'),q,function(jsondata){ if(jsondata.status == 'success'){ @@ -1152,7 +1152,7 @@ Contacts={ }, editPhoto:function(id, tmpkey){ //alert('editPhoto: ' + tmpkey); - $.getJSON(OC.filePath('contacts', 'ajax', 'cropphoto.php'),{'tmpkey':tmpkey,'id':this.id},function(jsondata){ + $.getJSON(OC.filePath('contacts', 'ajax', 'cropphoto.php'),{'tmpkey':tmpkey,'id':this.id, 'requesttoken':requesttoken},function(jsondata){ if(jsondata.status == 'success'){ //alert(jsondata.data.page); $('#edit_photo_dialog_img').html(jsondata.data.page); @@ -1645,7 +1645,7 @@ $(document).ready(function(){ //} } }; - xhr.open('POST', OC.filePath('contacts', 'ajax', 'uploadphoto.php')+'?id='+Contacts.UI.Card.id+'&imagefile='+encodeURIComponent(file.name), true); + xhr.open('POST', OC.filePath('contacts', 'ajax', 'uploadphoto.php')+'?id='+Contacts.UI.Card.id+'&requesttoken='+requesttoken+'&imagefile='+encodeURIComponent(file.name), true); xhr.setRequestHeader('Cache-Control', 'no-cache'); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.setRequestHeader('X_FILE_NAME', encodeURIComponent(file.name)); diff --git a/apps/contacts/lib/hooks.php b/apps/contacts/lib/hooks.php index e3d5df3d51f..e74b465a47b 100644 --- a/apps/contacts/lib/hooks.php +++ b/apps/contacts/lib/hooks.php @@ -56,7 +56,7 @@ class OC_Contacts_Hooks{ static public function getBirthdayEvents($parameters) { $name = $parameters['calendar_id']; - if (strpos('birthday_', $name) != 0) { + if (strpos($name, 'birthday_') != 0) { return; } $info = explode('_', $name); diff --git a/apps/contacts/lib/search.php b/apps/contacts/lib/search.php index 144138a7c2c..19330fa9be1 100644 --- a/apps/contacts/lib/search.php +++ b/apps/contacts/lib/search.php @@ -2,17 +2,10 @@ class OC_Search_Provider_Contacts extends OC_Search_Provider{ function search($query){ $addressbooks = OC_Contacts_Addressbook::all(OCP\USER::getUser(), 1); -// if(count($calendars)==0 || !OCP\App::isEnabled('contacts')){ -// //return false; -// } - // NOTE: Does the following do anything - $results=array(); - $searchquery=array(); - if(substr_count($query, ' ') > 0){ - $searchquery = explode(' ', $query); - }else{ - $searchquery[] = $query; + if(count($addressbooks)==0 || !OCP\App::isEnabled('contacts')){ + return array(); } + $results=array(); $l = new OC_l10n('contacts'); foreach($addressbooks as $addressbook){ $vcards = OC_Contacts_VCard::all($addressbook['id']); diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index c1ba1ccdc21..0a930949eb7 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -3,6 +3,7 @@ $id = isset($_['id']) ? $_['id'] : ''; ?>
+ @@ -23,6 +24,7 @@ $id = isset($_['id']) ? $_['id'] : '';
+
@@ -35,7 +37,7 @@ $id = isset($_['id']) ? $_['id'] : ''; - + diff --git a/apps/contacts/templates/part.contacts.php b/apps/contacts/templates/part.contacts.php index 57517505405..00a61f72fdd 100644 --- a/apps/contacts/templates/part.contacts.php +++ b/apps/contacts/templates/part.contacts.php @@ -8,5 +8,5 @@ } } ?> -
  • +
  • diff --git a/apps/contacts/templates/part.cropphoto.php b/apps/contacts/templates/part.cropphoto.php index d7f0efc57d7..1079afc808a 100644 --- a/apps/contacts/templates/part.cropphoto.php +++ b/apps/contacts/templates/part.cropphoto.php @@ -1,6 +1,7 @@ diff --git a/core/templates/login.php b/core/templates/login.php index 41d6ba41ef8..a40bf5c330a 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -1,7 +1,7 @@
    - '; } ?> + '; } ?> t('Lost your password?'); ?> diff --git a/index.php b/index.php index b90b1b310a9..32b3c88df1d 100755 --- a/index.php +++ b/index.php @@ -121,7 +121,7 @@ elseif(OC_User::isLoggedIn()) { if(!array_key_exists('sectoken', $_SESSION) || (array_key_exists('sectoken', $_SESSION) && is_null(OC::$REQUESTEDFILE)) || substr(OC::$REQUESTEDFILE, -3) == 'php'){ $sectoken=rand(1000000,9999999); $_SESSION['sectoken']=$sectoken; - $redirect_url = (isset($_REQUEST['redirect_url'])) ? $_REQUEST['redirect_url'] : $_SERVER['REQUEST_URI']; + $redirect_url = (isset($_REQUEST['redirect_url'])) ? strip_tags($_REQUEST['redirect_url']) : $_SERVER['REQUEST_URI']; OC_Template::printGuestPage('', 'login', array('error' => $error, 'sectoken' => $sectoken, 'redirect' => $redirect_url)); } } diff --git a/lib/app.php b/lib/app.php index 0c51e3c5532..7fdfc93138f 100755 --- a/lib/app.php +++ b/lib/app.php @@ -542,6 +542,7 @@ class OC_App{ return; } if(file_exists(OC::$APPSROOT.'/apps/'.$appid.'/appinfo/update.php')){ + self::loadApp($appid); include OC::$APPSROOT.'/apps/'.$appid.'/appinfo/update.php'; } diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php index e74d832cb00..5aa70392d76 100644 --- a/lib/connector/sabre/directory.php +++ b/lib/connector/sabre/directory.php @@ -59,19 +59,22 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa * @throws Sabre_DAV_Exception_FileNotFound * @return Sabre_DAV_INode */ - public function getChild($name) { + public function getChild($name, $info = null) { $path = $this->path . '/' . $name; + if (is_null($info)) { + $info = OC_FileCache::get($path); + } - if (!OC_Filesystem::file_exists($path)) throw new Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); + if (!$info) throw new Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); - if (OC_Filesystem::is_dir($path)) { + if ($info['mimetype'] == 'httpd/unix-directory') { - return new OC_Connector_Sabre_Directory($path); + return new OC_Connector_Sabre_Directory($path, $info); } else { - return new OC_Connector_Sabre_File($path); + return new OC_Connector_Sabre_File($path, $info); } @@ -85,17 +88,11 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa public function getChildren() { $nodes = array(); - // foreach(scandir($this->path) as $node) if($node!='.' && $node!='..') $nodes[] = $this->getChild($node); - if( OC_Filesystem::is_dir($this->path . '/')){ - $dh = OC_Filesystem::opendir($this->path . '/'); - while(( $node = readdir($dh)) !== false ){ - if($node!='.' && $node!='..'){ - $nodes[] = $this->getChild($node); - } - } + $folder_content = OC_FileCache::getFolderContent($this->path); + foreach($folder_content as $info) { + $nodes[] = $this->getChild($info['name'], $info); } return $nodes; - } /** diff --git a/lib/connector/sabre/file.php b/lib/connector/sabre/file.php index 3ba1b3355f2..dd25df78c29 100644 --- a/lib/connector/sabre/file.php +++ b/lib/connector/sabre/file.php @@ -63,8 +63,8 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D * @return int */ public function getSize() { - $this->stat(); - return $this->stat_cache['size']; + $this->getFileinfoCache(); + return $this->fileinfo_cache['size']; } @@ -92,6 +92,9 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D * @return mixed */ public function getContentType() { + if (isset($this->fileinfo_cache['mimetype'])) { + return $this->fileinfo_cache['mimetype']; + } return OC_Filesystem::getMimeType($this->path); diff --git a/lib/connector/sabre/node.php b/lib/connector/sabre/node.php index e7bcea3171d..e5c059f0c8a 100644 --- a/lib/connector/sabre/node.php +++ b/lib/connector/sabre/node.php @@ -33,7 +33,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * file stat cache * @var array */ - protected $stat_cache; + protected $fileinfo_cache; /** * Sets up the node, expects a full path name @@ -41,8 +41,11 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * @param string $path * @return void */ - public function __construct($path) { + public function __construct($path, $fileinfo_cache = null) { $this->path = $path; + if ($fileinfo_cache) { + $this->fileinfo_cache = $fileinfo_cache; + } } @@ -85,9 +88,14 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr /** * Set the stat cache */ - protected function stat() { - if (!isset($this->stat_cache)) { - $this->stat_cache = OC_Filesystem::stat($this->path); + protected function getFileinfoCache() { + if (!isset($this->fileinfo_cache)) { + if ($fileinfo_cache = OC_FileCache::get($this->path)) { + } else { + $fileinfo_cache = OC_Filesystem::stat($this->path); + } + + $this->fileinfo_cache = $fileinfo_cache; } } @@ -97,8 +105,8 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * @return int */ public function getLastModified() { - $this->stat(); - return $this->stat_cache['mtime']; + $this->getFileinfoCache(); + return $this->fileinfo_cache['mtime']; } diff --git a/lib/filecache.php b/lib/filecache.php index 3fb8e4113cb..7c9c4dc41ff 100644 --- a/lib/filecache.php +++ b/lib/filecache.php @@ -28,8 +28,6 @@ * It will try to keep the data up to date but changes from outside ownCloud can invalidate the cache */ class OC_FileCache{ - private static $savedData=array(); - /** * get the filesystem info from the cache * @param string path @@ -44,29 +42,15 @@ class OC_FileCache{ * - encrypted * - versioned */ - public static function get($path,$root=''){ - if(self::isUpdated($path,$root)){ - if(!$root){//filesystem hooks are only valid for the default root + public static function get($path,$root=false){ + if(OC_FileCache_Update::hasUpdated($path,$root)){ + if($root===false){//filesystem hooks are only valid for the default root OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$path)); }else{ - self::fileSystemWatcherWrite(array('path'=>$path),$root); + OC_FileCache_Update::update($path,$root); } } - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $path=$root.$path; - $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?'); - $result=$query->execute(array(md5($path)))->fetchRow(); - if(is_array($result)){ - return $result; - }else{ - OC_Log::write('files','get(): file not found in cache ('.$path.')',OC_Log::DEBUG); - return false; - } + return OC_FileCache_Cached::get($path,$root); } /** @@ -77,30 +61,23 @@ class OC_FileCache{ * * $data is an assiciative array in the same format as returned by get */ - public static function put($path,$data,$root=''){ - if(!$root){ + public static function put($path,$data,$root=false){ + if($root===false){ $root=OC_Filesystem::getRoot(); } - if($root=='/'){ - $root=''; - } $path=$root.$path; - if($path=='/'){ - $parent=-1; - }else{ - $parent=self::getFileId(dirname($path)); - } - $id=self::getFileId($path); + $parent=self::getParentId($path); + $id=self::getId($path,''); if($id!=-1){ self::update($id,$data); return; } - if(isset(self::$savedData[$path])){ - $data=array_merge($data,self::$savedData[$path]); - unset(self::$savedData[$path]); + if(isset(OC_FileCache_Cached::$savedData[$path])){ + $data=array_merge($data,OC_FileCache_Cached::$savedData[$path]); + unset(OC_FileCache_Cached::$savedData[$path]); } if(!isset($data['size']) or !isset($data['mtime'])){//save incomplete data for the next time we write it - self::$savedData[$path]=$data; + OC_FileCache_Cached::$savedData[$path]=$data; return; } if(!isset($data['encrypted'])){ @@ -157,13 +134,10 @@ class OC_FileCache{ * @param string newPath * @param string root (optional) */ - public static function move($oldPath,$newPath,$root=''){ - if(!$root){ + public static function move($oldPath,$newPath,$root=false){ + if($root===false){ $root=OC_Filesystem::getRoot(); } - if($root=='/'){ - $root=''; - } $oldPath=$root.$oldPath; $newPath=$root.$newPath; $newParent=self::getParentId($newPath); @@ -182,28 +156,19 @@ class OC_FileCache{ /** * delete info from the cache - * @param string/int $file + * @param string path * @param string root (optional) */ - public static function delete($file,$root=''){ - if(!is_numeric($file)){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $path=$root.$file; - self::delete(self::getFileId($path)); - }elseif($file!=-1){ - $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE parent=?'); - $result=$query->execute(array($file)); - while($child=$result->fetchRow()){ - self::delete(intval($child['id'])); - } - $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE id=?'); - $query->execute(array($file)); + public static function delete($path,$root=false){ + if($root===false){ + $root=OC_Filesystem::getRoot(); } + $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE path_hash=?'); + $query->execute(array(md5($root.$path))); + + //delete everything inside the folder + $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE path LIKE ?'); + $query->execute(array($root.$path.'/%')); } /** @@ -213,13 +178,10 @@ class OC_FileCache{ * @param string root (optional) * @return array of filepaths */ - public static function search($search,$returnData=false,$root=''){ - if(!$root){ + public static function search($search,$returnData=false,$root=false){ + if($root===false){ $root=OC_Filesystem::getRoot(); } - if($root=='/'){ - $root=''; - } $rootLen=strlen($root); if(!$returnData){ $query=OC_DB::prepare('SELECT path FROM *PREFIX*fscache WHERE name LIKE ? AND `user`=?'); @@ -254,26 +216,11 @@ class OC_FileCache{ * - encrypted * - versioned */ - public static function getFolderContent($path,$root='',$mimetype_filter=''){ - if(self::isUpdated($path,$root)){ - self::updateFolder($path,$root); - } - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $path=$root.$path; - $parent=self::getFileId($path); - $query=OC_DB::prepare('SELECT name,ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE parent=? AND (mimetype LIKE ? OR mimetype = ?)'); - $result=$query->execute(array($parent, $mimetype_filter.'%', 'httpd/unix-directory'))->fetchAll(); - if(is_array($result)){ - return $result; - }else{ - OC_Log::write('files','getFolderContent(): file not found in cache ('.$path.')',OC_Log::DEBUG); - return false; + public static function getFolderContent($path,$root=false,$mimetype_filter=''){ + if(OC_FileCache_Update::hasUpdated($path,$root)){ + OC_FileCache_Update::updateFolder($path,$root); } + return OC_FileCache_Cached::getFolderContent($path,$root,$mimetype_filter); } /** @@ -282,58 +229,34 @@ class OC_FileCache{ * @param string root (optional) * @return bool */ - public static function inCache($path,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $path=$root.$path; - return self::getFileId($path)!=-1; + public static function inCache($path,$root=false){ + return self::getId($path,$root)!=-1; } - /** - * get the file id as used in the cache - * unlike the public getId, full paths are used here (/usename/files/foo instead of /foo) - * @param string $path - * @return int - */ - private static function getFileId($path){ - $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE path_hash=?'); - if(OC_DB::isError($query)){ - OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR); - return -1; - } - $result=$query->execute(array(md5($path))); - if(OC_DB::isError($result)){ - OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR); - return -1; - } - $result=$result->fetchRow(); - if(is_array($result)){ - return $result['id']; - }else{ - OC_Log::write('files','getFileId(): file not found in cache ('.$path.')',OC_Log::DEBUG); - return -1; - } - } - /** * get the file id as used in the cache * @param string path * @param string root (optional) * @return int */ - public static function getId($path,$root=''){ - if(!$root){ + public static function getId($path,$root=false){ + if($root===false){ $root=OC_Filesystem::getRoot(); } - if($root=='/'){ - $root=''; + + $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE path_hash=?'); + $result=$query->execute(array(md5($root.$path))); + if(OC_DB::isError($result)){ + OC_Log::write('files','error while getting file id of '.$path,OC_Log::ERROR); + return -1; + } + + $result=$result->fetchRow(); + if(is_array($result)){ + return $result['id']; + }else{ + return -1; } - $path=$root.$path; - return self::getFileId($path); } /** @@ -366,154 +289,23 @@ class OC_FileCache{ if($path=='/'){ return -1; }else{ - return self::getFileId(dirname($path)); - } - } - - /** - * called when changes are made to files - * @param array $params - * @param string root (optional) - */ - public static function fileSystemWatcherWrite($params,$root=''){ - if(!$root){ - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView(($root=='/')?'':$root); - } - - $path=$params['path']; - $fullPath=$view->getRoot().$path; - $mimetype=$view->getMimeType($path); - $dir=$view->is_dir($path.'/'); - //dont use self::get here, we don't want inifinte loops when a file has changed - $cachedSize=self::getCachedSize($path,$root); - $size=0; - if($dir){ - if(self::inCache($path,$root)){ - $parent=self::getFileId($fullPath); - $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE parent=?'); - $result=$query->execute(array($parent)); - while($row=$result->fetchRow()){ - $size+=$row['size']; - } - $mtime=$view->filemtime($path); - $ctime=$view->filectime($path); - $writable=$view->is_writable($path); - self::put($path,array('size'=>$size,'mtime'=>$mtime,'ctime'=>$ctime,'mimetype'=>$mimetype,'writable'=>$writable)); - }else{ - $count=0; - self::scan($path,null,$count,$root); - } - }else{ - $size=self::scanFile($path,$root); - } - self::increaseSize(dirname($fullPath),$size-$cachedSize); - } - - public static function getCached($path,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - }else{ - if($root=='/'){ - $root=''; - } - } - $path=$root.$path; - $query=OC_DB::prepare('SELECT ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?'); - $result=$query->execute(array(md5($path)))->fetchRow(); - if(is_array($result)){ - if(isset(self::$savedData[$path])){ - $result=array_merge($result,self::$savedData[$path]); - } - return $result; - }else{ - OC_Log::write('files','getCached(): file not found in cache ('.$path.')',OC_Log::DEBUG); - if(isset(self::$savedData[$path])){ - return self::$savedData[$path]; - }else{ - return array(); - } + return self::getId(dirname($path),''); } } - private static function getCachedSize($path,$root){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - }else{ - if($root=='/'){ - $root=''; - } - } - $path=$root.$path; - $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE path_hash=?'); - $result=$query->execute(array(md5($path))); - if($row=$result->fetchRow()){ - return $row['size']; - }else{//file not in cache - return 0; - } - } - - /** - * called when files are deleted - * @param array $params - * @param string root (optional) - */ - public static function fileSystemWatcherDelete($params,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $path=$params['path']; - $fullPath=$root.$path; - if(self::getFileId($fullPath)==-1){ - return; - } - $size=self::getCachedSize($path,$root); - self::increaseSize(dirname($fullPath),-$size); - self::delete($path); - } - - /** - * called when files are deleted - * @param array $params - * @param string root (optional) - */ - public static function fileSystemWatcherRename($params,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - } - if($root=='/'){ - $root=''; - } - $oldPath=$params['oldpath']; - $newPath=$params['newpath']; - $fullOldPath=$root.$oldPath; - $fullNewPath=$root.$newPath; - if(($id=self::getFileId($fullOldPath))!=-1){ - $oldSize=self::getCachedSize($oldPath,$root); - }else{ - return; - } - $size=OC_Filesystem::filesize($newPath); - self::increaseSize(dirname($fullOldPath),-$oldSize); - self::increaseSize(dirname($fullNewPath),$oldSize); - self::move($oldPath,$newPath); - } - /** * adjust the size of the parent folders * @param string $path * @param int $sizeDiff + * @param string root (optinal) */ - private static function increaseSize($path,$sizeDiff){ + public static function increaseSize($path,$sizeDiff, $root=false){ if($sizeDiff==0) return; - while(($id=self::getFileId($path))!=-1){//walk up the filetree increasing the size of all parent folders + $id=self::getId($path,''); + while($id!=-1){//walk up the filetree increasing the size of all parent folders $query=OC_DB::prepare('UPDATE *PREFIX*fscache SET size=size+? WHERE id=?'); $query->execute(array($sizeDiff,$id)); + $id=self::getParentId($path); $path=dirname($path); } } @@ -525,15 +317,15 @@ class OC_FileCache{ * @param int count (optional) * @param string root (optionak) */ - public static function scan($path,$eventSource=false,&$count=0,$root=''){ + public static function scan($path,$eventSource=false,&$count=0,$root=false){ if($eventSource){ $eventSource->send('scanning',array('file'=>$path,'count'=>$count)); } $lastSend=$count; - if(!$root){ + if($root===false){ $view=OC_Filesystem::getView(); }else{ - $view=new OC_FilesystemView(($root=='/')?'':$root); + $view=new OC_FilesystemView($root); } self::scanFile($path,$root); $dh=$view->opendir($path.'/'); @@ -555,8 +347,9 @@ class OC_FileCache{ } } } - self::cleanFolder($path,$root); - self::increaseSize($view->getRoot().$path,$totalSize); + + OC_FileCache_Update::cleanFolder($path,$root); + self::increaseSize($path,$totalSize,$root); } /** @@ -565,11 +358,11 @@ class OC_FileCache{ * @param string root (optional) * @return int size of the scanned file */ - public static function scanFile($path,$root=''){ - if(!$root){ + public static function scanFile($path,$root=false){ + if($root===false){ $view=OC_Filesystem::getView(); }else{ - $view=new OC_FilesystemView(($root=='/')?'':$root); + $view=new OC_FilesystemView($root); } if(!$view->is_readable($path)) return; //cant read, nothing we can do clearstatcache(); @@ -602,11 +395,9 @@ class OC_FileCache{ * seccond mimetype part can be ommited * e.g. searchByMime('audio') */ - public static function searchByMime($part1,$part2=null,$root=null){ - if(!$root){ + public static function searchByMime($part1,$part2=null,$root=false){ + if($root===false){ $root=OC_Filesystem::getRoot(); - }elseif($root=='/'){ - $root=''; } $rootLen=strlen($root); $root .= '%'; @@ -625,103 +416,6 @@ class OC_FileCache{ return $names; } - /** - * check if a file or folder is updated outside owncloud - * @param string path - * @param string root (optional) - * @return bool - */ - public static function isUpdated($path,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); - $view=OC_Filesystem::getView(); - }else{ - if($root=='/'){ - $root=''; - } - $view=new OC_FilesystemView($root); - } - if(!$view->file_exists($path)){ - return false; - } - $mtime=$view->filemtime($path); - $isDir=$view->is_dir($path); - $fullPath=$root.$path; - $query=OC_DB::prepare('SELECT mtime FROM *PREFIX*fscache WHERE path_hash=?'); - $result=$query->execute(array(md5($fullPath))); - if($row=$result->fetchRow()){ - $cachedMTime=$row['mtime']; - return ($mtime>$cachedMTime); - }else{//file not in cache, so it has to be updated - if($path=='/' or $path==''){//dont auto update the root folder, it will be scanned - return false; - } - return true; - } - } - - /** - * update the cache according to changes in the folder - * @param string path - * @param string root (optional) - */ - private static function updateFolder($path,$root=''){ - if(!$root){ - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView(($root=='/')?'':$root); - } - $dh=$view->opendir($path.'/'); - if($dh){//check for changed/new files - while (($filename = readdir($dh)) !== false) { - if($filename != '.' and $filename != '..'){ - $file=$path.'/'.$filename; - if(self::isUpdated($file,$root)){ - if(!$root){//filesystem hooks are only valid for the default root - OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$file)); - }else{ - self::fileSystemWatcherWrite(array('path'=>$file),$root); - } - } - } - } - } - - self::cleanFolder($path,$root); - - //update the folder last, so we can calculate the size correctly - if(!$root){//filesystem hooks are only valid for the default root - OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$path)); - }else{ - self::fileSystemWatcherWrite(array('path'=>$path),$root); - } - } - - /** - * delete non existing files from the cache - */ - private static function cleanFolder($path,$root=''){ - if(!$root){ - $view=OC_Filesystem::getView(); - }else{ - $view=new OC_FilesystemView(($root=='/')?'':$root); - } - //check for removed files, not using getFolderContent to prevent loops - $parent=self::getFileId($view->getRoot().$path); - $query=OC_DB::prepare('SELECT name FROM *PREFIX*fscache WHERE parent=?'); - $result=$query->execute(array($parent)); - while($row=$result->fetchRow()){ - $file=$path.'/'.$row['name']; - if(!$view->file_exists($file)){ - if(!$root){//filesystem hooks are only valid for the default root - OC_Hook::emit('OC_Filesystem','post_delete',array('path'=>$file)); - }else{ - self::fileSystemWatcherDelete(array('path'=>$file),$root); - } - } - } - } - /** * clean old pre-path_hash entries */ @@ -732,6 +426,6 @@ class OC_FileCache{ } //watch for changes and try to keep the cache up to date -OC_Hook::connect('OC_Filesystem','post_write','OC_FileCache','fileSystemWatcherWrite'); -OC_Hook::connect('OC_Filesystem','post_delete','OC_FileCache','fileSystemWatcherDelete'); -OC_Hook::connect('OC_Filesystem','post_rename','OC_FileCache','fileSystemWatcherRename'); +OC_Hook::connect('OC_Filesystem','post_write','OC_FileCache_Update','fileSystemWatcherWrite'); +OC_Hook::connect('OC_Filesystem','post_delete','OC_FileCache_Update','fileSystemWatcherDelete'); +OC_Hook::connect('OC_Filesystem','post_rename','OC_FileCache_Update','fileSystemWatcherRename'); diff --git a/lib/filecache/cached.php b/lib/filecache/cached.php new file mode 100644 index 00000000000..a22adad4528 --- /dev/null +++ b/lib/filecache/cached.php @@ -0,0 +1,67 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +/** + * get data from the filecache without checking for updates + */ +class OC_FileCache_Cached{ + public static $savedData=array(); + + public static function get($path,$root=false){ + if($root===false){ + $root=OC_Filesystem::getRoot(); + } + $path=$root.$path; + $query=OC_DB::prepare('SELECT path,ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE path_hash=?'); + $result=$query->execute(array(md5($path)))->fetchRow(); + if(is_array($result)){ + if(isset(self::$savedData[$path])){ + $result=array_merge($result,self::$savedData[$path]); + } + return $result; + }else{ + if(isset(self::$savedData[$path])){ + return self::$savedData[$path]; + }else{ + return array(); + } + } + } + + /** + * get all files and folders in a folder + * @param string path + * @param string root (optional) + * @return array + * + * returns an array of assiciative arrays with the following keys: + * - path + * - name + * - size + * - mtime + * - ctime + * - mimetype + * - encrypted + * - versioned + */ + public static function getFolderContent($path,$root=false,$mimetype_filter=''){ + if($root===false){ + $root=OC_Filesystem::getRoot(); + } + $parent=OC_FileCache::getId($path,$root); + $query=OC_DB::prepare('SELECT path,name,ctime,mtime,mimetype,size,encrypted,versioned,writable FROM *PREFIX*fscache WHERE parent=? AND (mimetype LIKE ? OR mimetype = ?)'); + $result=$query->execute(array($parent, $mimetype_filter.'%', 'httpd/unix-directory'))->fetchAll(); + if(is_array($result)){ + return $result; + }else{ + OC_Log::write('files','getFolderContent(): file not found in cache ('.$path.')',OC_Log::DEBUG); + return false; + } + } +} \ No newline at end of file diff --git a/lib/filecache/update.php b/lib/filecache/update.php new file mode 100644 index 00000000000..9e23c6dfe7b --- /dev/null +++ b/lib/filecache/update.php @@ -0,0 +1,210 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + + +/** + * handles updating the filecache according to outside changes + */ +class OC_FileCache_Update{ + /** + * check if a file or folder is updated outside owncloud + * @param string path + * @param string root (optional) + * @return bool + */ + public static function hasUpdated($path,$root=false){ + if($root===false){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView($root); + } + if(!$view->file_exists($path)){ + return false; + } + $cachedData=OC_FileCache_Cached::get($path,$root); + if(isset($cachedData['mtime'])){ + $cachedMTime=$cachedData['mtime']; + return $view->hasUpdated($path,$cachedMTime); + }else{//file not in cache, so it has to be updated + if(($path=='/' or $path=='') and $root===false){//dont auto update the home folder, it will be scanned + return false; + } + return true; + } + } + + /** + * delete non existing files from the cache + */ + public static function cleanFolder($path,$root=false){ + if($root===false){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView($root); + } + + $cachedContent=OC_FileCache_Cached::getFolderContent($path,$root); + foreach($cachedContent as $fileData){ + $path=$fileData['path']; + $file=$view->getRelativePath($path); + if(!$view->file_exists($file)){ + if($root===false){//filesystem hooks are only valid for the default root + OC_Hook::emit('OC_Filesystem','post_delete',array('path'=>$file)); + }else{ + self::delete($file,$root); + } + } + } + } + + /** + * update the cache according to changes in the folder + * @param string path + * @param string root (optional) + */ + public static function updateFolder($path,$root=false){ + if($root===false){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView($root); + } + $dh=$view->opendir($path.'/'); + if($dh){//check for changed/new files + while (($filename = readdir($dh)) !== false) { + if($filename != '.' and $filename != '..'){ + $file=$path.'/'.$filename; + if(self::hasUpdated($file,$root)){ + if($root===false){//filesystem hooks are only valid for the default root + OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$file)); + }else{ + self::update($file,$root); + } + } + } + } + } + + self::cleanFolder($path,$root); + + //update the folder last, so we can calculate the size correctly + if($root===false){//filesystem hooks are only valid for the default root + OC_Hook::emit('OC_Filesystem','post_write',array('path'=>$path)); + }else{ + self::update($path,$root); + } + } + + /** + * called when changes are made to files + * @param array $params + * @param string root (optional) + */ + public static function fileSystemWatcherWrite($params){ + $path=$params['path']; + self::update($path); + } + + /** + * called when files are deleted + * @param array $params + * @param string root (optional) + */ + public static function fileSystemWatcherDelete($params){ + $path=$params['path']; + self::delete($path); + } + + /** + * called when files are deleted + * @param array $params + * @param string root (optional) + */ + public static function fileSystemWatcherRename($params){ + $oldPath=$params['oldpath']; + $newPath=$params['newpath']; + self::rename($oldPath,$newPath); + } + + /** + * update the filecache according to changes to the fileysystem + * @param string path + * @param string root (optional) + */ + public static function update($path,$root=false){ + if($root===false){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView($root); + } + + $mimetype=$view->getMimeType($path); + + $size=0; + $cached=OC_FileCache_Cached::get($path,$root); + $cachedSize=isset($cached['size'])?$cached['size']:0; + + if($mimetype=='httpd/unix-directory'){ + if(OC_FileCache::inCache($path,$root)){ + $cachedContent=OC_FileCache_Cached::getFolderContent($path,$root); + foreach($cachedContent as $file){ + $size+=$file['size']; + } + $mtime=$view->filemtime($path); + $ctime=$view->filectime($path); + $writable=$view->is_writable($path); + OC_FileCache::put($path,array('size'=>$size,'mtime'=>$mtime,'ctime'=>$ctime,'mimetype'=>$mimetype,'writable'=>$writable)); + }else{ + $count=0; + OC_FileCache::scan($path,null,$count,$root); + return; //increaseSize is already called inside scan + } + }else{ + $size=OC_FileCache::scanFile($path,$root); + } + OC_FileCache::increaseSize(dirname($path),$size-$cachedSize,$root); + } + + /** + * update the filesystem after a delete has been detected + * @param string path + * @param string root (optional) + */ + public static function delete($path,$root=false){ + $cached=OC_FileCache_Cached::get($path,$root); + if(!isset($cached['size'])){ + return; + } + $size=$cached['size']; + OC_FileCache::increaseSize(dirname($path),-$size,$root); + OC_FileCache::delete($path,$root); + } + + /** + * update the filesystem after a rename has been detected + * @param string oldPath + * @param string newPath + * @param string root (optional) + */ + public static function rename($oldPath,$newPath,$root=false){ + if(!OC_FileCache::inCache($oldPath,$root)){ + return; + } + if($root===false){ + $view=OC_Filesystem::getView(); + }else{ + $view=new OC_FilesystemView($root); + } + + $cached=OC_FileCache_Cached::get($oldPath,$root); + $oldSize=$cached['size']; + $size=$view->filesize($newPath); + OC_FileCache::increaseSize(dirname($oldPath),-$oldSize,$root); + OC_FileCache::increaseSize(dirname($newPath),$oldSize,$root); + OC_FileCache::move($oldPath,$newPath); + } +} \ No newline at end of file diff --git a/lib/fileproxy/quota.php b/lib/fileproxy/quota.php index 9e4c2d0643e..f061d48219b 100644 --- a/lib/fileproxy/quota.php +++ b/lib/fileproxy/quota.php @@ -54,8 +54,8 @@ class OC_FileProxy_Quota extends OC_FileProxy{ * @return int */ private function getFreeSpace(){ - $rootInfo=OC_FileCache::get(''); - $usedSpace=$rootInfo['size']; + $rootInfo=OC_FileCache_Cached::get(''); + $usedSpace=isset($rootInfo['size'])?$rootInfo['size']:0; $totalSpace=$this->getQuota(); if($totalSpace==0){ return 0; diff --git a/lib/files.php b/lib/files.php index 705b7a6ca66..3ecf08739b0 100644 --- a/lib/files.php +++ b/lib/files.php @@ -36,7 +36,7 @@ class OC_Files { if(strpos($directory,OC::$CONFIG_DATADIRECTORY)===0){ $directory=substr($directory,strlen(OC::$CONFIG_DATADIRECTORY)); } - $files=OC_FileCache::getFolderContent($directory, '', $mimetype_filter); + $files=OC_FileCache::getFolderContent($directory, false, $mimetype_filter); foreach($files as &$file){ $file['directory']=$directory; $file['type']=($file['mimetype']=='httpd/unix-directory')?'dir':'file'; diff --git a/lib/filestorage.php b/lib/filestorage.php index 1d7e004af3b..71ef4aed00b 100644 --- a/lib/filestorage.php +++ b/lib/filestorage.php @@ -50,4 +50,13 @@ abstract class OC_Filestorage{ abstract public function search($query); abstract public function touch($path, $mtime=null); abstract public function getLocalFile($path);// get a path to a local version of the file, whether the original file is local or remote + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + * + * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. + * returning true for other changes in the folder is optional + */ + abstract public function hasUpdated($path,$time); } diff --git a/lib/filestorage/common.php b/lib/filestorage/common.php index f0bfc064cb5..f2a5775fd19 100644 --- a/lib/filestorage/common.php +++ b/lib/filestorage/common.php @@ -156,4 +156,13 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { } return $files; } + + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + */ + public function hasUpdated($path,$time){ + return $this->filemtime($path)>$time; + } } diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php index ea9a9070263..44a2ab0f634 100644 --- a/lib/filestorage/local.php +++ b/lib/filestorage/local.php @@ -194,4 +194,13 @@ class OC_Filestorage_Local extends OC_Filestorage{ public function getFolderSize($path){ return 0;//depricated, use OC_FileCach instead } + + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + */ + public function hasUpdated($path,$time){ + return $this->filemtime($path)>$time; + } } diff --git a/lib/filesystem.php b/lib/filesystem.php index dd74daffa4e..89de533d725 100644 --- a/lib/filesystem.php +++ b/lib/filesystem.php @@ -319,7 +319,7 @@ class OC_Filesystem{ if(substr($mountpoint,-1)!=='/'){ $mountpoint=$mountpoint.'/'; } - if (self::getView() != null && $mountpoint != '/' && !self::is_dir(basename($mountpoint))) { + if (self::getView() != null && $mountpoint != '/' && !self::is_dir(basename($mountpoint))) { self::mkdir(basename($mountpoint)); } self::$mounts[$mountpoint]=array('class'=>$class,'arguments'=>$arguments); @@ -474,6 +474,15 @@ class OC_Filesystem{ static public function search($query){ return OC_FileCache::search($query); } + + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + */ + static public function hasUpdated($path,$time){ + return self::$defaultInstance->hasUpdated($path); + } } require_once('filecache.php'); diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 58657671b98..813a87cd74e 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -444,4 +444,13 @@ class OC_FilesystemView { } return null; } + + /** + * check if a file or folder has been updated since $time + * @param int $time + * @return bool + */ + public function hasUpdated($path,$time){ + return $this->basicOperation('hasUpdated',$path,array(),$time); + } } diff --git a/lib/helper.php b/lib/helper.php index decc1d61336..2ded7b13c38 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -90,12 +90,12 @@ class OC_Helper { } - /** - * @brief Returns the server protocol - * @returns the server protocol - * - * Returns the server protocol. It respects reverse proxy servers and load balancers - */ + /** + * @brief Returns the server protocol + * @returns the server protocol + * + * Returns the server protocol. It respects reverse proxy servers and load balancers + */ public static function serverProtocol() { if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { $proto = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']); @@ -132,7 +132,7 @@ class OC_Helper { * Returns a absolute url to the given service. */ public static function linkToRemote( $service, $add_slash = true ) { - return self::linkToAbsolute( '', 'remote.php') . '/' . $service . ($add_slash?'/':''); + return self::linkToAbsolute( '', 'remote.php') . '/' . $service . (($add_slash && $service[strlen($service)-1]!='/')?'/':''); } /** @@ -143,7 +143,7 @@ class OC_Helper { * * Returns the path to the image. */ - public static function imagePath( $app, $image ){ + public static function imagePath( $app, $image ){ // Read the selected theme from the config file $theme=OC_Config::getValue( "theme" ); @@ -551,35 +551,35 @@ class OC_Helper { } } - /** - * Adds a suffix to the name in case the file exists - * - * @param $path - * @param $filename - * @return string - */ - public static function buildNotExistingFileName($path, $filename){ - if($path==='/'){ - $path=''; - } - if ($pos = strrpos($filename, '.')) { - $name = substr($filename, 0, $pos); - $ext = substr($filename, $pos); - } else { - $name = $filename; - } + /** + * Adds a suffix to the name in case the file exists + * + * @param $path + * @param $filename + * @return string + */ + public static function buildNotExistingFileName($path, $filename){ + if($path==='/'){ + $path=''; + } + if ($pos = strrpos($filename, '.')) { + $name = substr($filename, 0, $pos); + $ext = substr($filename, $pos); + } else { + $name = $filename; + } - $newpath = $path . '/' . $filename; - $newname = $filename; - $counter = 2; - while (OC_Filesystem::file_exists($newpath)) { - $newname = $name . ' (' . $counter . ')' . $ext; - $newpath = $path . '/' . $newname; - $counter++; - } + $newpath = $path . '/' . $filename; + $newname = $filename; + $counter = 2; + while (OC_Filesystem::file_exists($newpath)) { + $newname = $name . ' (' . $counter . ')' . $ext; + $newpath = $path . '/' . $newname; + $counter++; + } - return $newpath; - } + return $newpath; + } /* * checks if $sub is a subdirectory of $parent diff --git a/lib/json.php b/lib/json.php index f3bbe9ac899..dfc0a7b894e 100644 --- a/lib/json.php +++ b/lib/json.php @@ -41,6 +41,18 @@ class OC_JSON{ } } + /** + * @brief Check an ajax get/post call if the request token is valid. + * @return json Error msg if not valid. + */ + public static function callCheck(){ + if( !OC_Util::isCallRegistered()){ + $l = OC_L10N::get('core'); + self::error(array( 'data' => array( 'message' => $l->t('Token expired. Please reload page.') ))); + exit(); + } + } + /** * Check if the user is a admin, send json error msg if not */ diff --git a/lib/minimizer/css.php b/lib/minimizer/css.php index 4637417579e..09a0efdc3a7 100644 --- a/lib/minimizer/css.php +++ b/lib/minimizer/css.php @@ -67,7 +67,9 @@ class OC_Minimizer_CSS extends OC_Minimizer $remote .= dirname($file_info[2]); $css_out .= CSSMin::remap($css, dirname($file), $remote, true); } - $css_out = CSSMin::minify($css_out); + if (!defined('DEBUG') || !DEBUG){ + $css_out = CSSMin::minify($css_out); + } return $css_out; } } diff --git a/lib/minimizer/js.php b/lib/minimizer/js.php index 4ddaa79d81a..b9a023e0686 100644 --- a/lib/minimizer/js.php +++ b/lib/minimizer/js.php @@ -56,7 +56,9 @@ class OC_Minimizer_JS extends OC_Minimizer $js_out .= '/* ' . $file . ' */' . "\n"; $js_out .= file_get_contents($file); } - $js_out = JavaScriptMinifier::minify($js_out); + if (!defined('DEBUG') || !DEBUG){ + $js_out = JavaScriptMinifier::minify($js_out); + } return $js_out; } } diff --git a/lib/public/json.php b/lib/public/json.php index a8554671d10..b6edbd65bd5 100644 --- a/lib/public/json.php +++ b/lib/public/json.php @@ -53,6 +53,13 @@ class JSON { return(\OC_JSON::checkLoggedIn()); } + /** + * @brief Check an ajax get/post call if the request token is valid. + * @return json Error msg if not valid. + */ + public static function callCheck(){ + return(\OC_JSON::callCheck()); + } /** * @brief Send json success msg diff --git a/lib/public/util.php b/lib/public/util.php index 995161e2abe..d79d3f26b1e 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -145,15 +145,15 @@ class Util { } - /** - * @brief Creates an url - * @param $app app - * @param $file file - * @returns the url - * - * Returns a url to the given app and file. - */ - public static function linkTo( $app, $file ){ + /** + * @brief Creates an url + * @param $app app + * @param $file file + * @returns the url + * + * Returns a url to the given app and file. + */ + public static function linkTo( $app, $file ){ return(\OC_Helper::linkTo( $app, $file )); } @@ -264,10 +264,6 @@ class Util { public static function callCheck(){ return(\OC_Util::callCheck()); } - - - - } ?> diff --git a/lib/template.php b/lib/template.php index 14833a1e5b5..a3700e133e7 100644 --- a/lib/template.php +++ b/lib/template.php @@ -155,6 +155,9 @@ class OC_Template{ $this->renderas = $renderas; $this->application = $app; $this->vars = array(); + if($renderas == 'user') { + $this->vars['requesttoken'] = OC_Util::callRegister(); + } $this->l10n = OC_L10N::get($app); header('X-Frame-Options: Sameorigin'); header('X-XSS-Protection: 1; mode=block'); @@ -259,6 +262,7 @@ class OC_Template{ * @brief Assign variables * @param $key key * @param $value value + * @param $sanitizeHTML false, if data shouldn't get passed through htmlentities * @returns true * * This function assigns a variable. It can be accessed via $_[$key] in @@ -266,11 +270,29 @@ class OC_Template{ * * If the key existed before, it will be overwritten */ - public function assign( $key, $value ){ + public function assign( $key, $value, $sanitizeHTML=true ){ + if($sanitizeHTML == true) { + if(is_array($value)) { + array_walk_recursive($value,'OC_Template::sanitizeHTML'); + } else { + $value = OC_Template::sanitizeHTML($value); + } + } $this->vars[$key] = $value; return true; } + + /** + * @brief Internaly used to sanitze HTML + * + * This function is internally used to sanitize HTML. + */ + private static function sanitizeHTML( &$value ){ + $value = htmlentities( $value ); + return $value; + } + /** * @brief Appends a variable * @param $key key @@ -354,20 +376,21 @@ class OC_Template{ // Decide which page we show if( $this->renderas == "user" ){ $page = new OC_Template( "core", "layout.user" ); - $page->assign('searchurl',OC_Helper::linkTo( 'search', 'index.php' )); + $page->assign('searchurl',OC_Helper::linkTo( 'search', 'index.php' ), false); + $page->assign('requesttoken', $this->vars['requesttoken']); if(array_search(OC_APP::getCurrentApp(),array('settings','admin','help'))!==false){ - $page->assign('bodyid','body-settings'); + $page->assign('bodyid','body-settings', false); }else{ - $page->assign('bodyid','body-user'); + $page->assign('bodyid','body-user', false); } // Add navigation entry $navigation = OC_App::getNavigation(); - $page->assign( "navigation", $navigation); - $page->assign( "settingsnavigation", OC_App::getSettingsNavigation()); + $page->assign( "navigation", $navigation, false); + $page->assign( "settingsnavigation", OC_App::getSettingsNavigation(), false); foreach($navigation as $entry) { if ($entry['active']) { - $page->assign( 'application', $entry['name'] ); + $page->assign( 'application', $entry['name'], false ); break; } } @@ -381,7 +404,7 @@ class OC_Template{ // Read the detected formfactor and use the right file name. $fext = self::getFormFactorExtension(); - $page->assign('jsfiles', array()); + $page->assign('jsfiles', array(), false); // Add the core js files or the js files provided by the selected theme foreach(OC_Util::$scripts as $script){ // Is it in 3rd party? @@ -456,13 +479,13 @@ class OC_Template{ } // Add custom headers - $page->assign('headers',$this->headers); + $page->assign('headers',$this->headers, false); foreach(OC_Util::$headers as $header){ $page->append('headers',$header); } // Add css files and js files - $page->assign( "content", $data ); + $page->assign( "content", $data, false ); return $page->fetchPage(); } else{ @@ -507,13 +530,13 @@ class OC_Template{ $_ = array_merge( $additionalparams, $this->vars ); } - // Einbinden + // Include ob_start(); include( $this->path.$file.'.php' ); $data = ob_get_contents(); @ob_end_clean(); - // Daten zurückgeben + // Return data return $data; } @@ -527,7 +550,7 @@ class OC_Template{ public static function printUserPage( $application, $name, $parameters = array() ){ $content = new OC_Template( $application, $name, "user" ); foreach( $parameters as $key => $value ){ - $content->assign( $key, $value ); + $content->assign( $key, $value, false ); } print $content->printPage(); } @@ -542,7 +565,7 @@ class OC_Template{ public static function printAdminPage( $application, $name, $parameters = array() ){ $content = new OC_Template( $application, $name, "admin" ); foreach( $parameters as $key => $value ){ - $content->assign( $key, $value ); + $content->assign( $key, $value, false ); } return $content->printPage(); } @@ -557,7 +580,7 @@ class OC_Template{ public static function printGuestPage( $application, $name, $parameters = array() ){ $content = new OC_Template( $application, $name, "guest" ); foreach( $parameters as $key => $value ){ - $content->assign( $key, $value ); + $content->assign( $key, $value,false ); } return $content->printPage(); } diff --git a/lib/util.php b/lib/util.php index d1d5983dcfb..0266a8ecc5f 100755 --- a/lib/util.php +++ b/lib/util.php @@ -355,8 +355,9 @@ class OC_Util { } /** - * Register an get/post call. This is important to prevent CSRF attacks + * @brief Register an get/post call. This is important to prevent CSRF attacks * Todo: Write howto + * @return $token Generated token. */ public static function callRegister(){ //mamimum time before token exires @@ -381,50 +382,48 @@ class OC_Util { } } } - - // return the token return($token); } /** - * Check an ajax get/post call if the request token is valid. exit if not. - * Todo: Write howto + * @brief Check an ajax get/post call if the request token is valid. + * @return boolean False if request token is not set or is invalid. */ - public static function callCheck(){ + public static function isCallRegistered(){ //mamimum time before token exires $maxtime=(60*60); // 1 hour - - // searches in the get and post arrays for the token. if(isset($_GET['requesttoken'])) { $token=$_GET['requesttoken']; }elseif(isset($_POST['requesttoken'])){ $token=$_POST['requesttoken']; + }elseif(isset($_SERVER['HTTP_REQUESTTOKEN'])){ + $token=$_SERVER['HTTP_REQUESTTOKEN']; }else{ - //no token found. exiting - exit; + //no token found. + return false; } - - // check if the token is in the user session and if the timestamp is from the last hour. if(isset($_SESSION['requesttoken-'.$token])) { $timestamp=$_SESSION['requesttoken-'.$token]; - if($timestamp+$maxtimeassign('loglevel',OC_Config::getValue( "loglevel", 2 )); -$tmpl->assign('entries',$entries); +$tmpl->assign('entries',$entries,false); $tmpl->assign('forms',array()); foreach($forms as $form){ $tmpl->append('forms',$form); diff --git a/settings/apps.php b/settings/apps.php index 7908e6cc18b..f85b28158f5 100644 --- a/settings/apps.php +++ b/settings/apps.php @@ -92,7 +92,7 @@ usort($apps, 'app_sort'); $tmpl = new OC_Template( "settings", "apps", "user" ); -$tmpl->assign('apps',$apps); +$tmpl->assign('apps',$apps, false); $tmpl->printPage(); diff --git a/settings/templates/admin.php b/settings/templates/admin.php index d167f2780ef..38c6042c82a 100644 --- a/settings/templates/admin.php +++ b/settings/templates/admin.php @@ -29,7 +29,7 @@ $levels=array('Debug','Info','Warning','Error','Fatal'); app;?> - message);?> + message;?> time);?> diff --git a/settings/templates/help.php b/settings/templates/help.php index cf61207e601..a53ec76d681 100644 --- a/settings/templates/help.php +++ b/settings/templates/help.php @@ -26,9 +26,9 @@
    "") { echo(''); } ?> - '') echo('

    '.htmlentities($kb["name"]).'

    ');?> -

    - '') echo('

    '.$l->t('Answer').':

    '.htmlentities($kb['answer']).'

    ');?> + '') echo('

    '.$kb["name"].'

    ');?> +

    + '') echo('

    '.$l->t('Answer').':

    '.$kb['answer'].'

    ');?>
    diff --git a/tests/lib/filestorage.php b/tests/lib/filestorage.php index f71b658253a..00f37b9f1a2 100644 --- a/tests/lib/filestorage.php +++ b/tests/lib/filestorage.php @@ -149,6 +149,9 @@ abstract class Test_FileStorage extends UnitTestCase { $this->assertTrue(($ctimeStart-1)<=$cTime); $this->assertTrue($cTime<=($ctimeEnd+1)); } + $this->assertTrue($this->instance->hasUpdated('/lorem.txt',$ctimeStart-1)); + $this->assertTrue($this->instance->hasUpdated('/',$ctimeStart-1)); + $this->assertTrue(($ctimeStart-1)<=$mTime); $this->assertTrue($mTime<=($ctimeEnd+1)); $this->assertEqual(filesize($textFile),$this->instance->filesize('/lorem.txt')); @@ -168,6 +171,8 @@ abstract class Test_FileStorage extends UnitTestCase { $this->assertTrue(($mtimeStart-1)<=$mTime); $this->assertTrue($mTime<=($mtimeEnd+1)); $this->assertEqual($cTime,$originalCTime); + + $this->assertTrue($this->instance->hasUpdated('/lorem.txt',$mtimeStart-1)); if($this->instance->touch('/lorem.txt',100)!==false){ $mTime=$this->instance->filemtime('/lorem.txt'); @@ -184,6 +189,9 @@ abstract class Test_FileStorage extends UnitTestCase { $mTime=$this->instance->filemtime('/lorem.txt'); $this->assertTrue(($mtimeStart-1)<=$mTime); $this->assertTrue($mTime<=($mtimeEnd+1)); + + $this->instance->unlink('/lorem.txt'); + $this->assertTrue($this->instance->hasUpdated('/',$mtimeStart-1)); } public function testSearch(){