if (!$this->content_type && (string)is_file($handle) && function_exists("mime_content_type")) {
$this->content_type = @mime_content_type($handle);
if (!$this->content_type) {
throw new BadContentTypeException("Required Content-Type not set");
* String representation of the Object's public URI
* A string representing the Object's public URI assuming that it's
* parent Container is CDN-enabled.
* # ... authentication/connection/container code excluded
* # ... see previous examples
* # Print out the Object's CDN URI (if it has one) in an HTML img-tag
* print "<img src='$pic->public_uri()' />\n";
* @return string Object's public URI or NULL
if ($this->container->cdn_enabled) {
return $this->container->cdn_uri . "/" . $this->name;
* String representation of the Object's public SSL URI
* A string representing the Object's public SSL URI assuming that it's
* parent Container is CDN-enabled.
* # ... authentication/connection/container code excluded
* # ... see previous examples
* # Print out the Object's CDN SSL URI (if it has one) in an HTML img-tag
* print "<img src='$pic->public_ssl_uri()' />\n";
* @return string Object's public SSL URI or NULL
function public_ssl_uri()
if ($this->container->cdn_enabled) {
return $this->container->cdn_ssl_uri . "/" . $this->name;
* String representation of the Object's public Streaming URI
* A string representing the Object's public Streaming URI assuming that it's
* parent Container is CDN-enabled.
* # ... authentication/connection/container code excluded
* # ... see previous examples
* # Print out the Object's CDN Streaming URI (if it has one) in an HTML img-tag
* print "<img src='$pic->public_streaming_uri()' />\n";
* @return string Object's public Streaming URI or NULL
function public_streaming_uri()
if ($this->container->cdn_enabled) {
return $this->container->cdn_streaming_uri . "/" . $this->name;
* Read the remote Object's data
* Returns the Object's data. This is useful for smaller Objects such
* as images or office documents. Object's with larger content should use
* the stream() method below.
* Pass in $hdrs array to set specific custom HTTP headers such as
* If-Match, If-None-Match, If-Modified-Since, Range, etc.
* # ... authentication/connection/container code excluded
* # ... see previous examples
* $my_docs = $conn->get_container("documents");
* $doc = $my_docs->get_object("README");
* $data = $doc->read(); # read image content into a string variable
* # Or see stream() below for a different example.
* @param array $hdrs user-defined headers (Range, If-Match, etc.)
* @return string Object's data
* @throws InvalidResponseException unexpected response
function read($hdrs=array())
list($status, $reason, $data) =
$this->container->cfs_http->get_object_to_string($this, $hdrs);
#if ($status == 401 && $this->_re_auth()) {
# return $this->read($hdrs);
if (($status < 200) || ($status > 299
&& $status != 412 && $status != 304)) {
throw new InvalidResponseException("Invalid response (".$status."): "
. $this->container->cfs_http->get_error());
* Streaming read of Object's data
* Given an open PHP resource (see PHP's fopen() method), fetch the Object's
* data and write it to the open resource handle. This is useful for
* streaming an Object's content to the browser (videos, images) or for
* fetching content to a local file.
* Pass in $hdrs array to set specific custom HTTP headers such as
* If-Match, If-None-Match, If-Modified-Since, Range, etc.
* # ... authentication/connection/container code excluded
* # ... see previous examples
* # Assuming this is a web script to display the README to the
* // grab README from storage system
* $my_docs = $conn->get_container("documents");
* $doc = $my_docs->get_object("README");
* // Hand it back to user's browser with appropriate content-type
* header("Content-Type: " . $doc->content_type);
* $output = fopen("php://output", "w");
* $doc->stream($output); # stream object content to PHP's output buffer
* # See read() above for a more simple example.
* @param resource $fp open resource for writing data to
* @param array $hdrs user-defined headers (Range, If-Match, etc.)
* @return string Object's data
* @throws InvalidResponseException unexpected response
function stream(&$fp, $hdrs=array())
$this->container->cfs_http->get_object_to_stream($this,$fp,$hdrs);
#if ($status == 401 && $this->_re_auth()) {
# return $this->stream($fp, $hdrs);
if (($status < 200) || ($status > 299
&& $status != 412 && $status != 304)) {
throw new InvalidResponseException("Invalid response (".$status."): "
* Store new Object metadata
* Write's an Object's metadata to the remote Object. This will overwrite
* an prior Object metadata.
* # ... authentication/connection/container code excluded
* # ... see previous examples
* $my_docs = $conn->get_container("documents");
* $doc = $my_docs->get_object("README");
* # Define new metadata for the object
* $doc->metadata = array(
* "Subject" => "How to use the PHP tests",
* # Define additional headers for the object
* "Content-Disposition" => "attachment",
* # Push the new metadata up to the storage system
* @return boolean <kbd>True</kbd> if successful, <kbd>False</kbd> otherwise
* @throws InvalidResponseException unexpected response
if (!empty($this->metadata) || !empty($this->headers) || $this->manifest) {
$status = $this->container->cfs_http->update_object($this);
#if ($status == 401 && $this->_re_auth()) {
# return $this->sync_metadata();
throw new InvalidResponseException("Invalid response ("
.$status."): ".$this->container->cfs_http->get_error());
* Store new Object manifest
* Write's an Object's manifest to the remote Object. This will overwrite
* an prior Object manifest.
* # ... authentication/connection/container code excluded
* # ... see previous examples
* $my_docs = $conn->get_container("documents");
* $doc = $my_docs->get_object("README");
* # Define new manifest for the object
* $doc->manifest = "container/prefix";
* # Push the new manifest up to the storage system
* @return boolean <kbd>True</kbd> if successful, <kbd>False</kbd> otherwise
* @throws InvalidResponseException unexpected response
return $this->sync_metadata();
* Upload Object's data to Cloud Files
* Write data to the remote Object. The $data argument can either be a
* PHP resource open for reading (see PHP's fopen() method) or an in-memory
* variable. If passing in a PHP resource, you must also include the $bytes
* # ... authentication/connection/container code excluded
* # ... see previous examples
* $my_docs = $conn->get_container("documents");
* $doc = $my_docs->get_object("README");
* # Upload placeholder text in my README
* $doc->write("This is just placeholder text for now...");
* @param string|resource $data string or open resource
* @param float $bytes amount of data to upload (required for resources)
* @param boolean $verify generate, send, and compare MD5 checksums
* @return boolean <kbd>True</kbd> when data uploaded successfully
* @throws SyntaxException missing required parameters
* @throws BadContentTypeException if no Content-Type was/could be set
* @throws MisMatchedChecksumException $verify is set and checksums unequal
* @throws InvalidResponseException unexpected response
function write($data=NULL, $bytes=0, $verify=True)
if (!$data && !is_string($data)) {
throw new SyntaxException("Missing data source.");
if ($bytes > MAX_OBJECT_SIZE) {
throw new SyntaxException("Bytes exceeds maximum object size.");
if (!$this->_etag_override) {
$this->etag = $this->compute_md5sum($data);
if (!is_resource($data)) {
# A hack to treat string data as a file handle. php://memory feels
# like a better option, but it seems to break on Windows so use
# a temporary file instead.
$fp = fopen("php://temp", "wb+");
#$fp = fopen("php://memory", "wb+");
fwrite($fp, $data, strlen($data));
$this->content_length = (float) strlen($data);
if ($this->content_length > MAX_OBJECT_SIZE) {
throw new SyntaxException("Data exceeds maximum object size");
$ct_data = substr($data, 0, 64);
// The original Rackspace library used rewind() instead of ftell/fseek here - which meant fseek(0), which was sometimes wrong
$this->content_length = $bytes;
$ct_data = fread($data, 64);
$this->_guess_content_type($ct_data);
list($status, $reason, $etag) =
$this->container->cfs_http->put_object($this, $fp);
#if ($status == 401 && $this->_re_auth()) {
# return $this->write($data, $bytes, $verify);
if ($close_fh) { fclose($fp); }
throw new SyntaxException("Missing Content-Type header");
if ($close_fh) { fclose($fp); }
throw new MisMatchedChecksumException(
"Supplied and computed checksums do not match.");
if ($close_fh) { fclose($fp); }
throw new InvalidResponseException("Invalid response (".$status."): "
. $this->container->cfs_http->get_error());
if ($close_fh) { fclose($fp); }
* Upload Object data from local filename
* This is a convenience function to upload the data from a local file. A
* True value for $verify will cause the method to compute the Object's MD5
* checksum prior to uploading.
* # ... authentication/connection/container code excluded
* # ... see previous examples
* $my_docs = $conn->get_container("documents");
* $doc = $my_docs->get_object("README");
* # Upload my local README's content
* $doc->load_from_filename("/home/ej/cloudfiles/readme");
* @param string $filename full path to local file
* @param boolean $verify enable local/remote MD5 checksum validation
* @return boolean <kbd>True</kbd> if data uploaded successfully
* @throws SyntaxException missing required parameters
* @throws BadContentTypeException if no Content-Type was/could be set
* @throws MisMatchedChecksumException $verify is set and checksums unequal
* @throws InvalidResponseException unexpected response
* @throws IOException error opening file
function load_from_filename($filename, $verify=True)
$fp = @fopen($filename, "r");
throw new IOException("Could not open file for reading: ".$filename);
$size = (float) sprintf("%u", filesize($filename));
if ($size > MAX_OBJECT_SIZE) {
throw new SyntaxException("File size exceeds maximum object size.");
$this->_guess_content_type($filename);
$this->write($fp, $size, $verify);
* Save Object's data to local filename
* Given a local filename, the Object's data will be written to the newly
* # ... authentication/connection/container code excluded
* # ... see previous examples
* # Whoops! I deleted my local README, let me download/save it
* $my_docs = $conn->get_container("documents");
* $doc = $my_docs->get_object("README");
* $doc->save_to_filename("/home/ej/cloudfiles/readme.restored");
* @param string $filename name of local file to write data to
* @return boolean <kbd>True</kbd> if successful
* @throws IOException error opening file
* @throws InvalidResponseException unexpected response
function save_to_filename($filename)
$fp = @fopen($filename, "wb");
throw new IOException("Could not open file for writing: ".$filename);
$result = $this->stream($fp);
* Purge this Object from CDN Cache.
* # ... authentication code excluded (see previous examples) ...
* $conn = new CF_Connection($auth);
* $container = $conn->get_container("cdn_enabled");
* $obj = $container->get_object("object");
* $obj->purge_from_cdn("user@domain.com");
* $obj->purge_from_cdn();
* $obj->purge_from_cdn("user1@domain.com,user2@domain.com");
* @returns boolean True if successful
* @throws CDNNotEnabledException if CDN Is not enabled on this connection
* @throws InvalidResponseException if the response expected is not returned
function purge_from_cdn($email=null)
if (!$this->container->cfs_http->getCDNMUrl())
throw new CDNNotEnabledException(
"Authentication response did not indicate CDN availability");
$status = $this->container->cfs_http->purge_from_cdn($this->container->name . "/" . $this->name, $email);
if ($status < 199 or $status > 299) {
throw new InvalidResponseException(
"Invalid response (".$status."): ".$this->container->cfs_http->get_error());
* Set Object's MD5 checksum
* Manually set the Object's ETag. Including the ETag is mandatory for
* Cloud Files to perform end-to-end verification. Omitting the ETag forces
* the user to handle any data integrity checks.
* @param string $etag MD5 checksum hexidecimal string
$this->_etag_override = True;