Index: trunk/extensions/SwiftMedia/php-cloudfiles/cloudfiles.php |
— | — | @@ -208,7 +208,7 @@ |
209 | 209 | if ($status == 401) { |
210 | 210 | throw new AuthenticationException("Invalid username or access key."); |
211 | 211 | } |
212 | | - if ($status != 204 && $status != 200) { |
| 212 | + if ($status < 200 || $status > 299) { |
213 | 213 | throw new InvalidResponseException( |
214 | 214 | "Unexpected response (".$status."): ".$reason); |
215 | 215 | } |
— | — | @@ -923,6 +923,7 @@ |
924 | 924 | public $bytes_used; |
925 | 925 | |
926 | 926 | public $cdn_enabled; |
| 927 | + public $cdn_streaming_uri; |
927 | 928 | public $cdn_ssl_uri; |
928 | 929 | public $cdn_uri; |
929 | 930 | public $cdn_ttl; |
— | — | @@ -961,6 +962,7 @@ |
962 | 963 | $this->cdn_enabled = NULL; |
963 | 964 | $this->cdn_uri = NULL; |
964 | 965 | $this->cdn_ssl_uri = NULL; |
| 966 | + $this->cdn_streaming_uri = NULL; |
965 | 967 | $this->cdn_ttl = NULL; |
966 | 968 | $this->cdn_log_retention = NULL; |
967 | 969 | $this->cdn_acl_user_agent = NULL; |
— | — | @@ -1276,6 +1278,7 @@ |
1277 | 1279 | $this->cdn_ttl = NULL; |
1278 | 1280 | $this->cdn_uri = NULL; |
1279 | 1281 | $this->cdn_ssl_uri = NULL; |
| 1282 | + $this->cdn_streaming_uri - NULL; |
1280 | 1283 | $this->cdn_log_retention = NULL; |
1281 | 1284 | $this->cdn_acl_user_agent = NULL; |
1282 | 1285 | $this->cdn_acl_referrer = NULL; |
— | — | @@ -1493,6 +1496,235 @@ |
1494 | 1497 | } |
1495 | 1498 | |
1496 | 1499 | /** |
| 1500 | + * Copy a remote storage Object to a target Container |
| 1501 | + * |
| 1502 | + * Given an Object instance or name and a target Container instance or name, copy copies the remote Object |
| 1503 | + * and all associated metadata. |
| 1504 | + * |
| 1505 | + * Example: |
| 1506 | + * <code> |
| 1507 | + * # ... authentication code excluded (see previous examples) ... |
| 1508 | + * # |
| 1509 | + * $conn = new CF_Authentication($auth); |
| 1510 | + * |
| 1511 | + * $images = $conn->get_container("my photos"); |
| 1512 | + * |
| 1513 | + * # Copy specific object |
| 1514 | + * # |
| 1515 | + * $images->copy_object_to("disco_dancing.jpg","container_target"); |
| 1516 | + * </code> |
| 1517 | + * |
| 1518 | + * @param obj $obj name or instance of Object to copy |
| 1519 | + * @param obj $container_target name or instance of target Container |
| 1520 | + * @param string $dest_obj_name name of target object (optional - uses source name if omitted) |
| 1521 | + * @param array $metadata metadata array for new object (optional) |
| 1522 | + * @param array $headers header fields array for the new object (optional) |
| 1523 | + * @return boolean <kbd>true</kbd> if successfully copied |
| 1524 | + * @throws SyntaxException invalid Object/Container name |
| 1525 | + * @throws NoSuchObjectException remote Object does not exist |
| 1526 | + * @throws InvalidResponseException unexpected response |
| 1527 | + */ |
| 1528 | + function copy_object_to($obj,$container_target,$dest_obj_name=NULL,$metadata=NULL,$headers=NULL) |
| 1529 | + { |
| 1530 | + $obj_name = NULL; |
| 1531 | + if (is_object($obj)) { |
| 1532 | + if (get_class($obj) == "CF_Object") { |
| 1533 | + $obj_name = $obj->name; |
| 1534 | + } |
| 1535 | + } |
| 1536 | + if (is_string($obj)) { |
| 1537 | + $obj_name = $obj; |
| 1538 | + } |
| 1539 | + if (!$obj_name) { |
| 1540 | + throw new SyntaxException("Object name not set."); |
| 1541 | + } |
| 1542 | + |
| 1543 | + if ($dest_obj_name === NULL) { |
| 1544 | + $dest_obj_name = $obj_name; |
| 1545 | + } |
| 1546 | + |
| 1547 | + $container_name_target = NULL; |
| 1548 | + if (is_object($container_target)) { |
| 1549 | + if (get_class($container_target) == "CF_Container") { |
| 1550 | + $container_name_target = $container_target->name; |
| 1551 | + } |
| 1552 | + } |
| 1553 | + if (is_string($container_target)) { |
| 1554 | + $container_name_target = $container_target; |
| 1555 | + } |
| 1556 | + if (!$container_name_target) { |
| 1557 | + throw new SyntaxException("Container name target not set."); |
| 1558 | + } |
| 1559 | + |
| 1560 | + $status = $this->cfs_http->copy_object($obj_name,$dest_obj_name,$this->name,$container_name_target,$metadata,$headers); |
| 1561 | + if ($status == 404) { |
| 1562 | + $m = "Specified object '".$this->name."/".$obj_name; |
| 1563 | + $m.= "' did not exist as source to copy from or '".$container_name_target."' did not exist as target to copy to."; |
| 1564 | + throw new NoSuchObjectException($m); |
| 1565 | + } |
| 1566 | + if ($status < 200 || $status > 299) { |
| 1567 | + throw new InvalidResponseException( |
| 1568 | + "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
| 1569 | + } |
| 1570 | + return true; |
| 1571 | + } |
| 1572 | + |
| 1573 | + /** |
| 1574 | + * Copy a remote storage Object from a source Container |
| 1575 | + * |
| 1576 | + * Given an Object instance or name and a source Container instance or name, copy copies the remote Object |
| 1577 | + * and all associated metadata. |
| 1578 | + * |
| 1579 | + * Example: |
| 1580 | + * <code> |
| 1581 | + * # ... authentication code excluded (see previous examples) ... |
| 1582 | + * # |
| 1583 | + * $conn = new CF_Authentication($auth); |
| 1584 | + * |
| 1585 | + * $images = $conn->get_container("my photos"); |
| 1586 | + * |
| 1587 | + * # Copy specific object |
| 1588 | + * # |
| 1589 | + * $images->copy_object_from("disco_dancing.jpg","container_source"); |
| 1590 | + * </code> |
| 1591 | + * |
| 1592 | + * @param obj $obj name or instance of Object to copy |
| 1593 | + * @param obj $container_source name or instance of source Container |
| 1594 | + * @param string $dest_obj_name name of target object (optional - uses source name if omitted) |
| 1595 | + * @param array $metadata metadata array for new object (optional) |
| 1596 | + * @param array $headers header fields array for the new object (optional) |
| 1597 | + * @return boolean <kbd>true</kbd> if successfully copied |
| 1598 | + * @throws SyntaxException invalid Object/Container name |
| 1599 | + * @throws NoSuchObjectException remote Object does not exist |
| 1600 | + * @throws InvalidResponseException unexpected response |
| 1601 | + */ |
| 1602 | + function copy_object_from($obj,$container_source,$dest_obj_name=NULL,$metadata=NULL,$headers=NULL) |
| 1603 | + { |
| 1604 | + $obj_name = NULL; |
| 1605 | + if (is_object($obj)) { |
| 1606 | + if (get_class($obj) == "CF_Object") { |
| 1607 | + $obj_name = $obj->name; |
| 1608 | + } |
| 1609 | + } |
| 1610 | + if (is_string($obj)) { |
| 1611 | + $obj_name = $obj; |
| 1612 | + } |
| 1613 | + if (!$obj_name) { |
| 1614 | + throw new SyntaxException("Object name not set."); |
| 1615 | + } |
| 1616 | + |
| 1617 | + if ($dest_obj_name === NULL) { |
| 1618 | + $dest_obj_name = $obj_name; |
| 1619 | + } |
| 1620 | + |
| 1621 | + $container_name_source = NULL; |
| 1622 | + if (is_object($container_source)) { |
| 1623 | + if (get_class($container_source) == "CF_Container") { |
| 1624 | + $container_name_source = $container_source->name; |
| 1625 | + } |
| 1626 | + } |
| 1627 | + if (is_string($container_source)) { |
| 1628 | + $container_name_source = $container_source; |
| 1629 | + } |
| 1630 | + if (!$container_name_source) { |
| 1631 | + throw new SyntaxException("Container name source not set."); |
| 1632 | + } |
| 1633 | + |
| 1634 | + $status = $this->cfs_http->copy_object($obj_name,$dest_obj_name,$container_name_source,$this->name,$metadata,$headers); |
| 1635 | + if ($status == 404) { |
| 1636 | + $m = "Specified object '".$container_name_source."/".$obj_name; |
| 1637 | + $m.= "' did not exist as source to copy from or '".$this->name."/".$obj_name."' did not exist as target to copy to."; |
| 1638 | + throw new NoSuchObjectException($m); |
| 1639 | + } |
| 1640 | + if ($status < 200 || $status > 299) { |
| 1641 | + throw new InvalidResponseException( |
| 1642 | + "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
| 1643 | + } |
| 1644 | + |
| 1645 | + return true; |
| 1646 | + } |
| 1647 | + |
| 1648 | + /** |
| 1649 | + * Move a remote storage Object to a target Container |
| 1650 | + * |
| 1651 | + * Given an Object instance or name and a target Container instance or name, move copies the remote Object |
| 1652 | + * and all associated metadata and deletes the source Object afterwards |
| 1653 | + * |
| 1654 | + * Example: |
| 1655 | + * <code> |
| 1656 | + * # ... authentication code excluded (see previous examples) ... |
| 1657 | + * # |
| 1658 | + * $conn = new CF_Authentication($auth); |
| 1659 | + * |
| 1660 | + * $images = $conn->get_container("my photos"); |
| 1661 | + * |
| 1662 | + * # Move specific object |
| 1663 | + * # |
| 1664 | + * $images->move_object_to("disco_dancing.jpg","container_target"); |
| 1665 | + * </code> |
| 1666 | + * |
| 1667 | + * @param obj $obj name or instance of Object to move |
| 1668 | + * @param obj $container_target name or instance of target Container |
| 1669 | + * @param string $dest_obj_name name of target object (optional - uses source name if omitted) |
| 1670 | + * @param array $metadata metadata array for new object (optional) |
| 1671 | + * @param array $headers header fields array for the new object (optional) |
| 1672 | + * @return boolean <kbd>true</kbd> if successfully moved |
| 1673 | + * @throws SyntaxException invalid Object/Container name |
| 1674 | + * @throws NoSuchObjectException remote Object does not exist |
| 1675 | + * @throws InvalidResponseException unexpected response |
| 1676 | + */ |
| 1677 | + function move_object_to($obj,$container_target,$dest_obj_name=NULL,$metadata=NULL,$headers=NULL) |
| 1678 | + { |
| 1679 | + $retVal = false; |
| 1680 | + |
| 1681 | + if(self::copy_object_to($obj,$container_target,$dest_obj_name,$metadata,$headers)) { |
| 1682 | + $retVal = self::delete_object($obj,$this->name); |
| 1683 | + } |
| 1684 | + |
| 1685 | + return $retVal; |
| 1686 | + } |
| 1687 | + |
| 1688 | + /** |
| 1689 | + * Move a remote storage Object from a source Container |
| 1690 | + * |
| 1691 | + * Given an Object instance or name and a source Container instance or name, move copies the remote Object |
| 1692 | + * and all associated metadata and deletes the source Object afterwards |
| 1693 | + * |
| 1694 | + * Example: |
| 1695 | + * <code> |
| 1696 | + * # ... authentication code excluded (see previous examples) ... |
| 1697 | + * # |
| 1698 | + * $conn = new CF_Authentication($auth); |
| 1699 | + * |
| 1700 | + * $images = $conn->get_container("my photos"); |
| 1701 | + * |
| 1702 | + * # Move specific object |
| 1703 | + * # |
| 1704 | + * $images->move_object_from("disco_dancing.jpg","container_target"); |
| 1705 | + * </code> |
| 1706 | + * |
| 1707 | + * @param obj $obj name or instance of Object to move |
| 1708 | + * @param obj $container_source name or instance of target Container |
| 1709 | + * @param string $dest_obj_name name of target object (optional - uses source name if omitted) |
| 1710 | + * @param array $metadata metadata array for new object (optional) |
| 1711 | + * @param array $headers header fields array for the new object (optional) |
| 1712 | + * @return boolean <kbd>true</kbd> if successfully moved |
| 1713 | + * @throws SyntaxException invalid Object/Container name |
| 1714 | + * @throws NoSuchObjectException remote Object does not exist |
| 1715 | + * @throws InvalidResponseException unexpected response |
| 1716 | + */ |
| 1717 | + function move_object_from($obj,$container_source,$dest_obj_name=NULL,$metadata=NULL,$headers=NULL) |
| 1718 | + { |
| 1719 | + $retVal = false; |
| 1720 | + |
| 1721 | + if(self::copy_object_from($obj,$container_source,$dest_obj_name,$metadata,$headers)) { |
| 1722 | + $retVal = self::delete_object($obj,$container_source); |
| 1723 | + } |
| 1724 | + |
| 1725 | + return $retVal; |
| 1726 | + } |
| 1727 | + |
| 1728 | + /** |
1497 | 1729 | * Delete a remote storage Object |
1498 | 1730 | * |
1499 | 1731 | * Given an Object instance or name, permanently remove the remote Object |
— | — | @@ -1512,12 +1744,13 @@ |
1513 | 1745 | * </code> |
1514 | 1746 | * |
1515 | 1747 | * @param obj $obj name or instance of Object to delete |
| 1748 | + * @param obj $container name or instance of Container in which the object resides (optional) |
1516 | 1749 | * @return boolean <kbd>True</kbd> if successfully removed |
1517 | 1750 | * @throws SyntaxException invalid Object name |
1518 | 1751 | * @throws NoSuchObjectException remote Object does not exist |
1519 | 1752 | * @throws InvalidResponseException unexpected response |
1520 | 1753 | */ |
1521 | | - function delete_object($obj) |
| 1754 | + function delete_object($obj,$container=NULL) |
1522 | 1755 | { |
1523 | 1756 | $obj_name = NULL; |
1524 | 1757 | if (is_object($obj)) { |
— | — | @@ -1531,12 +1764,32 @@ |
1532 | 1765 | if (!$obj_name) { |
1533 | 1766 | throw new SyntaxException("Object name not set."); |
1534 | 1767 | } |
1535 | | - $status = $this->cfs_http->delete_object($this->name, $obj_name); |
| 1768 | + |
| 1769 | + $container_name = NULL; |
| 1770 | + |
| 1771 | + if($container === NULL) { |
| 1772 | + $container_name = $this->name; |
| 1773 | + } |
| 1774 | + else { |
| 1775 | + if (is_object($container)) { |
| 1776 | + if (get_class($container) == "CF_Container") { |
| 1777 | + $container_name = $container->name; |
| 1778 | + } |
| 1779 | + } |
| 1780 | + if (is_string($container)) { |
| 1781 | + $container_name = $container; |
| 1782 | + } |
| 1783 | + if (!$container_name) { |
| 1784 | + throw new SyntaxException("Container name source not set."); |
| 1785 | + } |
| 1786 | + } |
| 1787 | + |
| 1788 | + $status = $this->cfs_http->delete_object($container_name, $obj_name); |
1536 | 1789 | #if ($status == 401 && $this->_re_auth()) { |
1537 | 1790 | # return $this->delete_object($obj); |
1538 | 1791 | #} |
1539 | 1792 | if ($status == 404) { |
1540 | | - $m = "Specified object '".$this->name."/".$obj_name; |
| 1793 | + $m = "Specified object '".$container_name."/".$obj_name; |
1541 | 1794 | $m.= "' did not exist to delete."; |
1542 | 1795 | throw new NoSuchObjectException($m); |
1543 | 1796 | } |
— | — | @@ -1552,7 +1805,7 @@ |
1553 | 1806 | * |
1554 | 1807 | * Given an Object whos name contains '/' path separators, this function |
1555 | 1808 | * will create the "directory marker" Objects of one byte with the |
1556 | | - * Content-Type of "application/folder". |
| 1809 | + * Content-Type of "application/directory". |
1557 | 1810 | * |
1558 | 1811 | * It assumes the last element of the full path is the "real" Object |
1559 | 1812 | * and does NOT create a remote storage Object for that last element. |
— | — | @@ -1583,7 +1836,7 @@ |
1584 | 1837 | */ |
1585 | 1838 | private function _cdn_initialize() |
1586 | 1839 | { |
1587 | | - list($status, $reason, $cdn_enabled, $cdn_ssl_uri, $cdn_uri, $cdn_ttl, |
| 1840 | + list($status, $reason, $cdn_enabled, $cdn_ssl_uri, $cdn_streaming_uri, $cdn_uri, $cdn_ttl, |
1588 | 1841 | $cdn_log_retention, $cdn_acl_user_agent, $cdn_acl_referrer) = |
1589 | 1842 | $this->cfs_http->head_cdn_container($this->name); |
1590 | 1843 | #if ($status == 401 && $this->_re_auth()) { |
— | — | @@ -1594,6 +1847,7 @@ |
1595 | 1848 | "Invalid response (".$status."): ".$this->cfs_http->get_error()); |
1596 | 1849 | } |
1597 | 1850 | $this->cdn_enabled = $cdn_enabled; |
| 1851 | + $this->cdn_streaming_uri = $cdn_streaming_uri; |
1598 | 1852 | $this->cdn_ssl_uri = $cdn_ssl_uri; |
1599 | 1853 | $this->cdn_uri = $cdn_uri; |
1600 | 1854 | $this->cdn_ttl = $cdn_ttl; |
— | — | @@ -1634,6 +1888,7 @@ |
1635 | 1889 | public $content_type; |
1636 | 1890 | public $content_length; |
1637 | 1891 | public $metadata; |
| 1892 | + public $headers; |
1638 | 1893 | public $manifest; |
1639 | 1894 | private $etag; |
1640 | 1895 | |
— | — | @@ -1663,6 +1918,7 @@ |
1664 | 1919 | $this->content_type = NULL; |
1665 | 1920 | $this->content_length = 0; |
1666 | 1921 | $this->metadata = array(); |
| 1922 | + $this->headers = array(); |
1667 | 1923 | $this->manifest = NULL; |
1668 | 1924 | if ($dohead) { |
1669 | 1925 | if (!$this->_initialize() && $force_exists) { |
— | — | @@ -1800,6 +2056,31 @@ |
1801 | 2057 | } |
1802 | 2058 | return NULL; |
1803 | 2059 | } |
| 2060 | + /** |
| 2061 | + * String representation of the Object's public Streaming URI |
| 2062 | + * |
| 2063 | + * A string representing the Object's public Streaming URI assuming that it's |
| 2064 | + * parent Container is CDN-enabled. |
| 2065 | + * |
| 2066 | + * Example: |
| 2067 | + * <code> |
| 2068 | + * # ... authentication/connection/container code excluded |
| 2069 | + * # ... see previous examples |
| 2070 | + * |
| 2071 | + * # Print out the Object's CDN Streaming URI (if it has one) in an HTML img-tag |
| 2072 | + * # |
| 2073 | + * print "<img src='$pic->public_streaming_uri()' />\n"; |
| 2074 | + * </code> |
| 2075 | + * |
| 2076 | + * @return string Object's public Streaming URI or NULL |
| 2077 | + */ |
| 2078 | + function public_streaming_uri() |
| 2079 | + { |
| 2080 | + if ($this->container->cdn_enabled) { |
| 2081 | + return $this->container->cdn_streaming_uri . "/" . $this->name; |
| 2082 | + } |
| 2083 | + return NULL; |
| 2084 | + } |
1804 | 2085 | |
1805 | 2086 | /** |
1806 | 2087 | * Read the remote Object's data |
— | — | @@ -1923,6 +2204,12 @@ |
1924 | 2205 | * "Version" => "1.2.2" |
1925 | 2206 | * ); |
1926 | 2207 | * |
| 2208 | + * # Define additional headers for the object |
| 2209 | + * # |
| 2210 | + * $doc->headers = array( |
| 2211 | + * "Content-Disposition" => "attachment", |
| 2212 | + * ); |
| 2213 | + * |
1927 | 2214 | * # Push the new metadata up to the storage system |
1928 | 2215 | * # |
1929 | 2216 | * $doc->sync_metadata(); |
— | — | @@ -1933,7 +2220,7 @@ |
1934 | 2221 | */ |
1935 | 2222 | function sync_metadata() |
1936 | 2223 | { |
1937 | | - if (!empty($this->metadata) || $this->manifest) { |
| 2224 | + if (!empty($this->metadata) || !empty($this->headers) || $this->manifest) { |
1938 | 2225 | $status = $this->container->cfs_http->update_object($this); |
1939 | 2226 | #if ($status == 401 && $this->_re_auth()) { |
1940 | 2227 | # return $this->sync_metadata(); |
— | — | @@ -1976,8 +2263,8 @@ |
1977 | 2264 | function sync_manifest() |
1978 | 2265 | { |
1979 | 2266 | return $this->sync_metadata(); |
1980 | | - } |
1981 | | - /** |
| 2267 | + } |
| 2268 | + /** |
1982 | 2269 | * Upload Object's data to Cloud Files |
1983 | 2270 | * |
1984 | 2271 | * Write data to the remote Object. The $data argument can either be a |
— | — | @@ -2074,54 +2361,6 @@ |
2075 | 2362 | return True; |
2076 | 2363 | } |
2077 | 2364 | |
2078 | | - /** |
2079 | | - * Copy one Object to another Object to Cloud Files |
2080 | | - * |
2081 | | - * Example: |
2082 | | - * <code> |
2083 | | - * # ... authentication/connection/container code excluded |
2084 | | - * # ... see previous examples |
2085 | | - * |
2086 | | - * $my_docs = $conn->get_container("documents"); |
2087 | | - * $doc = $my_docs->get_object("README"); |
2088 | | - * |
2089 | | - * # Copy README.txt on top of this object (which you must have |
2090 | | - * already written something to). |
2091 | | - * # |
2092 | | - * $doc->copy("/documents/README.txt"); |
2093 | | - * </code> |
2094 | | - * |
2095 | | - * @param string $source Name of existing object |
2096 | | - * @return boolean <kbd>True</kbd> when data uploaded successfully |
2097 | | - * @throws SyntaxException missing required parameters |
2098 | | - * @throws BadContentTypeException if no Content-Type was/could be set |
2099 | | - * @throws MisMatchedChecksumException $verify is set and checksums unequal |
2100 | | - * @throws InvalidResponseException unexpected response |
2101 | | - */ |
2102 | | - function copy($source) |
2103 | | - { |
2104 | | - if (!$source && !is_string($source)) { |
2105 | | - throw new SyntaxException("Missing data source."); |
2106 | | - } |
2107 | | - list($status, $reason, $etag) = |
2108 | | - $this->container->cfs_http->put_object($this, $source); |
2109 | | - #if ($status == 401 && $this->_re_auth()) { |
2110 | | - # return $this->copy($data, $source); |
2111 | | - #} |
2112 | | - if ($status == 412) { |
2113 | | - throw new SyntaxException("Missing Content-Type header"); |
2114 | | - } |
2115 | | - if ($status == 422) { |
2116 | | - throw new MisMatchedChecksumException( |
2117 | | - "Supplied and computed checksums do not match."); |
2118 | | - } |
2119 | | - if ($status != 201) { |
2120 | | - throw new InvalidResponseException("Invalid response (".$status."): " |
2121 | | - . $this->container->cfs_http->get_error()); |
2122 | | - } |
2123 | | - return True; |
2124 | | - } |
2125 | | - |
2126 | 2365 | /** |
2127 | 2366 | * Upload Object data from local filename |
2128 | 2367 | * |
— | — | @@ -2305,8 +2544,8 @@ |
2306 | 2545 | private function _initialize() |
2307 | 2546 | { |
2308 | 2547 | list($status, $reason, $etag, $last_modified, $content_type, |
2309 | | - $content_length, $metadata) = |
2310 | | - $this->container->cfs_http->head_object($this); |
| 2548 | + $content_length, $metadata, $manifest, $headers) = |
| 2549 | + $this->container->cfs_http->head_object($this); |
2311 | 2550 | #if ($status == 401 && $this->_re_auth()) { |
2312 | 2551 | # return $this->_initialize(); |
2313 | 2552 | #} |
— | — | @@ -2322,7 +2561,8 @@ |
2323 | 2562 | $this->content_type = $content_type; |
2324 | 2563 | $this->content_length = $content_length; |
2325 | 2564 | $this->metadata = $metadata; |
2326 | | - $this->manifest = NULL; |
| 2565 | + $this->headers = $headers; |
| 2566 | + $this->manifest = $manifest; |
2327 | 2567 | return True; |
2328 | 2568 | } |
2329 | 2569 | |
— | — | @@ -2349,4 +2589,4 @@ |
2350 | 2590 | * c-hanging-comment-ender-p: nil |
2351 | 2591 | * End: |
2352 | 2592 | */ |
2353 | | -?> |
| 2593 | +?> |
\ No newline at end of file |
Index: trunk/extensions/SwiftMedia/php-cloudfiles/cloudfiles_http.php |
— | — | @@ -29,16 +29,22 @@ |
30 | 30 | */ |
31 | 31 | require_once("cloudfiles_exceptions.php"); |
32 | 32 | |
33 | | -define("PHP_CF_VERSION", "1.7.9"); |
| 33 | +define("PHP_CF_VERSION", "1.7.10"); |
34 | 34 | define("USER_AGENT", sprintf("PHP-CloudFiles/%s", PHP_CF_VERSION)); |
| 35 | +define("MAX_HEADER_NAME_LEN", 128); |
| 36 | +define("MAX_HEADER_VALUE_LEN", 256); |
35 | 37 | define("ACCOUNT_CONTAINER_COUNT", "X-Account-Container-Count"); |
36 | 38 | define("ACCOUNT_BYTES_USED", "X-Account-Bytes-Used"); |
37 | 39 | define("CONTAINER_OBJ_COUNT", "X-Container-Object-Count"); |
38 | 40 | define("CONTAINER_BYTES_USED", "X-Container-Bytes-Used"); |
39 | | -define("METADATA_HEADER", "X-Object-Meta-"); |
40 | 41 | define("MANIFEST_HEADER", "X-Object-Manifest"); |
| 42 | +define("METADATA_HEADER_PREFIX", "X-Object-Meta-"); |
| 43 | +define("CONTENT_HEADER_PREFIX", "Content-"); |
| 44 | +define("ACCESS_CONTROL_HEADER_PREFIX", "Access-Control-"); |
| 45 | +define("ORIGIN_HEADER", "Origin"); |
41 | 46 | define("CDN_URI", "X-CDN-URI"); |
42 | 47 | define("CDN_SSL_URI", "X-CDN-SSL-URI"); |
| 48 | +define("CDN_STREAMING_URI", "X-CDN-Streaming-URI"); |
43 | 49 | define("CDN_ENABLED", "X-CDN-Enabled"); |
44 | 50 | define("CDN_LOG_RETENTION", "X-Log-Retention"); |
45 | 51 | define("CDN_ACL_USER_AGENT", "X-User-Agent-ACL"); |
— | — | @@ -53,6 +59,13 @@ |
54 | 60 | define("AUTH_KEY_HEADER_LEGACY", "X-Storage-Pass"); |
55 | 61 | define("AUTH_TOKEN_LEGACY", "X-Storage-Token"); |
56 | 62 | define("CDN_EMAIL", "X-Purge-Email"); |
| 63 | +define("DESTINATION", "Destination"); |
| 64 | +define("ETAG_HEADER", "ETag"); |
| 65 | +define("LAST_MODIFIED_HEADER", "Last-Modified"); |
| 66 | +define("CONTENT_TYPE_HEADER", "Content-Type"); |
| 67 | +define("CONTENT_LENGTH_HEADER", "Content-Length"); |
| 68 | +define("USER_AGENT_HEADER", "User-Agent"); |
| 69 | + |
57 | 70 | /** |
58 | 71 | * HTTP/cURL wrapper for Cloud Files |
59 | 72 | * |
— | — | @@ -95,11 +108,13 @@ |
96 | 109 | private $_obj_content_type; |
97 | 110 | private $_obj_content_length; |
98 | 111 | private $_obj_metadata; |
| 112 | + private $_obj_headers; |
99 | 113 | private $_obj_manifest; |
100 | 114 | private $_obj_write_resource; |
101 | 115 | private $_obj_write_string; |
102 | 116 | private $_cdn_enabled; |
103 | 117 | private $_cdn_ssl_uri; |
| 118 | + private $_cdn_streaming_uri; |
104 | 119 | private $_cdn_uri; |
105 | 120 | private $_cdn_ttl; |
106 | 121 | private $_cdn_log_retention; |
— | — | @@ -131,6 +146,7 @@ |
132 | 147 | "HEAD" => NULL, # HEAD requests |
133 | 148 | "PUT_CONT" => NULL, # PUT container |
134 | 149 | "DEL_POST" => NULL, # DELETE containers/objects, POST objects |
| 150 | + "COPY" => null, # COPY objects |
135 | 151 | ); |
136 | 152 | |
137 | 153 | $this->_user_read_progress_callback_func = NULL; |
— | — | @@ -150,8 +166,10 @@ |
151 | 167 | $this->_obj_content_length = NULL; |
152 | 168 | $this->_obj_metadata = array(); |
153 | 169 | $this->_obj_manifest = NULL; |
| 170 | + $this->_obj_headers = NULL; |
154 | 171 | $this->_cdn_enabled = NULL; |
155 | 172 | $this->_cdn_ssl_uri = NULL; |
| 173 | + $this->_cdn_streaming_uri = NULL; |
156 | 174 | $this->_cdn_uri = NULL; |
157 | 175 | $this->_cdn_ttl = NULL; |
158 | 176 | $this->_cdn_log_retention = NULL; |
— | — | @@ -212,7 +230,6 @@ |
213 | 231 | curl_setopt($curl_ch, CURLOPT_SSL_VERIFYPEER, True); |
214 | 232 | curl_setopt($curl_ch, CURLOPT_CAINFO, $this->cabundle_path); |
215 | 233 | } |
216 | | - curl_setopt($curl_ch, CURLOPT_SSL_VERIFYPEER, False); |
217 | 234 | curl_setopt($curl_ch, CURLOPT_VERBOSE, $this->dbug); |
218 | 235 | curl_setopt($curl_ch, CURLOPT_FOLLOWLOCATION, 1); |
219 | 236 | curl_setopt($curl_ch, CURLOPT_MAXREDIRS, 4); |
— | — | @@ -249,7 +266,7 @@ |
250 | 267 | } |
251 | 268 | if (!$return_code) { |
252 | 269 | $this->error_str .= ": Failed to obtain valid HTTP response."; |
253 | | - array(0,$this->error_str,array()); |
| 270 | + return array(0,$this->error_str,array()); |
254 | 271 | } |
255 | 272 | if ($return_code == 401) { |
256 | 273 | return array($return_code,"Unauthorized",array()); |
— | — | @@ -393,17 +410,18 @@ |
394 | 411 | |
395 | 412 | if (!$return_code) { |
396 | 413 | $this->error_str .= ": Failed to obtain valid HTTP response."; |
397 | | - return array(0,$this->error_str,NULL,NULL,NULL,NULL,NULL,NULL); |
| 414 | + return array(0,$this->error_str,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); |
398 | 415 | } |
399 | 416 | if ($return_code == 401) { |
400 | | - return array($return_code,"Unauthorized",NULL,NULL,NULL,NULL,NULL,NULL); |
| 417 | + return array($return_code,"Unauthorized",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); |
401 | 418 | } |
402 | 419 | if ($return_code == 404) { |
403 | | - return array($return_code,"Account not found.",NULL,NULL,NULL,NULL,NULL,NULL); |
| 420 | + return array($return_code,"Account not found.",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); |
404 | 421 | } |
405 | 422 | if ($return_code == 204) { |
406 | 423 | return array($return_code,$this->response_reason, |
407 | 424 | $this->_cdn_enabled, $this->_cdn_ssl_uri, |
| 425 | + $this->_cdn_streaming_uri, |
408 | 426 | $this->_cdn_uri, $this->_cdn_ttl, |
409 | 427 | $this->_cdn_log_retention, |
410 | 428 | $this->_cdn_acl_user_agent, |
— | — | @@ -411,10 +429,11 @@ |
412 | 430 | ); |
413 | 431 | } |
414 | 432 | return array($return_code,$this->response_reason, |
415 | | - NULL,NULL,NULL, |
| 433 | + NULL,NULL,NULL,NULL, |
416 | 434 | $this->_cdn_log_retention, |
417 | 435 | $this->_cdn_acl_user_agent, |
418 | | - $this->_cdn_acl_referrer |
| 436 | + $this->_cdn_acl_referrer, |
| 437 | + NULL |
419 | 438 | ); |
420 | 439 | } |
421 | 440 | |
— | — | @@ -511,7 +530,7 @@ |
512 | 531 | |
513 | 532 | if (!$return_code) { |
514 | 533 | $this->error_str .= ": Failed to obtain valid HTTP response."; |
515 | | - array(0,$this->error_str,0,0); |
| 534 | + return array(0,$this->error_str,0,0); |
516 | 535 | } |
517 | 536 | if ($return_code == 404) { |
518 | 537 | return array($return_code,"Account not found.",0,0); |
— | — | @@ -556,16 +575,19 @@ |
557 | 576 | $url_path = $this->_make_path("STORAGE", $container_name); |
558 | 577 | $return_code = $this->_send_request("DEL_POST",$url_path,array(),"DELETE"); |
559 | 578 | |
560 | | - if (!$return_code) { |
561 | | - $this->error_str .= ": Failed to obtain valid HTTP response."; |
562 | | - } |
563 | | - if ($return_code == 409) { |
| 579 | + switch ($return_code) { |
| 580 | + case 204: |
| 581 | + break; |
| 582 | + case 0: |
| 583 | + $this->error_str .= ": Failed to obtain valid HTTP response.";; |
| 584 | + break; |
| 585 | + case 409: |
564 | 586 | $this->error_str = "Container must be empty prior to removing it."; |
565 | | - } |
566 | | - if ($return_code == 404) { |
| 587 | + break; |
| 588 | + case 404: |
567 | 589 | $this->error_str = "Specified container did not exist to delete."; |
568 | | - } |
569 | | - if ($return_code != 204) { |
| 590 | + break; |
| 591 | + default: |
570 | 592 | $this->error_str = "Unexpected HTTP return code: $return_code."; |
571 | 593 | } |
572 | 594 | return $return_code; |
— | — | @@ -701,7 +723,7 @@ |
702 | 724 | |
703 | 725 | if (!$return_code) { |
704 | 726 | $this->error_str .= ": Failed to obtain valid HTTP response."; |
705 | | - array(0,$this->error_str,0,0); |
| 727 | + return array(0,$this->error_str,0,0); |
706 | 728 | } |
707 | 729 | if ($return_code == 404) { |
708 | 730 | return array($return_code,"Container not found.",0,0); |
— | — | @@ -788,10 +810,7 @@ |
789 | 811 | throw new SyntaxException( |
790 | 812 | "Method argument is not a valid CF_Object."); |
791 | 813 | } |
792 | | - $source = NULL; |
793 | | - if (is_string($fp)) { |
794 | | - $source = $fp; |
795 | | - } elseif (!is_resource($fp)) { |
| 814 | + if (!is_resource($fp)) { |
796 | 815 | throw new SyntaxException( |
797 | 816 | "File pointer argument is not a valid resource."); |
798 | 817 | } |
— | — | @@ -799,40 +818,32 @@ |
800 | 819 | $conn_type = "PUT_OBJ"; |
801 | 820 | $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name); |
802 | 821 | |
803 | | - $hdrs = $this->_metadata_headers($obj); |
| 822 | + $hdrs = $this->_headers($obj); |
804 | 823 | |
805 | 824 | $etag = $obj->getETag(); |
806 | | - if (!$source && isset($etag)) { |
| 825 | + if (isset($etag)) { |
807 | 826 | $hdrs[] = "ETag: " . $etag; |
808 | 827 | } |
809 | | - if ($source) { |
810 | | - // If we don't include a content-type it will copy over the existing one. |
811 | | - } elseif (!$obj->content_type) { |
| 828 | + if (!$obj->content_type) { |
812 | 829 | $hdrs[] = "Content-Type: application/octet-stream"; |
813 | 830 | } else { |
814 | 831 | $hdrs[] = "Content-Type: " . $obj->content_type; |
815 | 832 | } |
816 | 833 | |
817 | 834 | $this->_init($conn_type); |
818 | | - if ($source) { |
819 | | - $hdrs[] = "X-Copy-From: " . rawurlencode($source); |
| 835 | + curl_setopt($this->connections[$conn_type], |
| 836 | + CURLOPT_INFILE, $fp); |
| 837 | + if (!$obj->content_length) { |
| 838 | + # We don''t know the Content-Length, so assumed "chunked" PUT |
| 839 | + # |
| 840 | + curl_setopt($this->connections[$conn_type], CURLOPT_UPLOAD, True); |
| 841 | + $hdrs[] = 'Transfer-Encoding: chunked'; |
| 842 | + } else { |
| 843 | + # We know the Content-Length, so use regular transfer |
| 844 | + # |
820 | 845 | curl_setopt($this->connections[$conn_type], |
821 | | - CURLOPT_INFILESIZE, 0); |
822 | | - } else { |
823 | | - curl_setopt($this->connections[$conn_type], |
824 | | - CURLOPT_INFILE, $fp); |
825 | | - if (!$obj->content_length) { |
826 | | - # We don''t know the Content-Length, so assumed "chunked" PUT |
827 | | - # |
828 | | - curl_setopt($this->connections[$conn_type], CURLOPT_UPLOAD, True); |
829 | | - $hdrs[] = 'Transfer-Encoding: chunked'; |
830 | | - } else { |
831 | | - # We know the Content-Length, so use regular transfer |
832 | | - # |
833 | | - curl_setopt($this->connections[$conn_type], |
834 | | - CURLOPT_INFILESIZE, $obj->content_length); |
835 | | - } |
836 | | - } |
| 846 | + CURLOPT_INFILESIZE, $obj->content_length); |
| 847 | + } |
837 | 848 | $return_code = $this->_send_request($conn_type,$url_path,$hdrs); |
838 | 849 | |
839 | 850 | if (!$return_code) { |
— | — | @@ -863,25 +874,29 @@ |
864 | 875 | "Method argument is not a valid CF_Object."); |
865 | 876 | } |
866 | 877 | |
867 | | - if (!is_array($obj->metadata) && !$obj->manifest) { |
868 | | - |
869 | | - $this->error_str = "Metadata array is empty."; |
| 878 | + # TODO: The is_array check isn't in sync with the error message |
| 879 | + if (!$obj->manifest && !(is_array($obj->metadata) || is_array($obj->headers))) { |
| 880 | + $this->error_str = "Metadata and headers arrays are empty."; |
870 | 881 | return 0; |
871 | 882 | } |
872 | 883 | |
873 | 884 | $url_path = $this->_make_path("STORAGE", $obj->container->name,$obj->name); |
874 | 885 | |
875 | | - $hdrs = $this->_metadata_headers($obj); |
| 886 | + $hdrs = $this->_headers($obj); |
876 | 887 | $return_code = $this->_send_request("DEL_POST",$url_path,$hdrs,"POST"); |
877 | | - if (!$return_code) { |
| 888 | + switch ($return_code) { |
| 889 | + case 202: |
| 890 | + break; |
| 891 | + case 0: |
878 | 892 | $this->error_str .= ": Failed to obtain valid HTTP response."; |
879 | | - return 0; |
880 | | - } |
881 | | - if ($return_code == 404) { |
| 893 | + $return_code = 0; |
| 894 | + break; |
| 895 | + case 404: |
882 | 896 | $this->error_str = "Account, Container, or Object not found."; |
883 | | - } |
884 | | - if ($return_code != 202) { |
| 897 | + break; |
| 898 | + default: |
885 | 899 | $this->error_str = "Unexpected HTTP return code: $return_code"; |
| 900 | + break; |
886 | 901 | } |
887 | 902 | return $return_code; |
888 | 903 | } |
— | — | @@ -903,12 +918,12 @@ |
904 | 919 | if (!$return_code) { |
905 | 920 | $this->error_str .= ": Failed to obtain valid HTTP response."; |
906 | 921 | return array(0, $this->error_str." ".$this->response_reason, |
907 | | - NULL, NULL, NULL, NULL, array()); |
| 922 | + NULL, NULL, NULL, NULL, array(), NULL, array()); |
908 | 923 | } |
909 | 924 | |
910 | 925 | if ($return_code == 404) { |
911 | 926 | return array($return_code, $this->response_reason, |
912 | | - NULL, NULL, NULL, NULL, array()); |
| 927 | + NULL, NULL, NULL, NULL, array(), NULL, array()); |
913 | 928 | } |
914 | 929 | if ($return_code == 204 || $return_code == 200) { |
915 | 930 | return array($return_code,$this->response_reason, |
— | — | @@ -917,13 +932,68 @@ |
918 | 933 | $this->_obj_content_type, |
919 | 934 | $this->_obj_content_length, |
920 | 935 | $this->_obj_metadata, |
921 | | - $this->_obj_manifest); |
| 936 | + $this->_obj_manifest, |
| 937 | + $this->_obj_headers); |
922 | 938 | } |
923 | 939 | $this->error_str = "Unexpected HTTP return code: $return_code"; |
924 | 940 | return array($return_code, $this->error_str." ".$this->response_reason, |
925 | | - NULL, NULL, NULL, NULL, array()); |
| 941 | + NULL, NULL, NULL, NULL, array(), NULL, array()); |
926 | 942 | } |
927 | 943 | |
| 944 | + # COPY /v1/Account/Container/Object |
| 945 | + # |
| 946 | + function copy_object($src_obj_name, $dest_obj_name, $container_name_source, $container_name_target, $metadata=NULL, $headers=NULL) |
| 947 | + { |
| 948 | + if (!$src_obj_name) { |
| 949 | + $this->error_str = "Object name not set."; |
| 950 | + return 0; |
| 951 | + } |
| 952 | + |
| 953 | + if ($container_name_source == "") { |
| 954 | + $this->error_str = "Container name source not set."; |
| 955 | + return 0; |
| 956 | + } |
| 957 | + |
| 958 | + if ($container_name_source != "0" and !isset($container_name_source)) { |
| 959 | + $this->error_str = "Container name source not set."; |
| 960 | + return 0; |
| 961 | + } |
| 962 | + |
| 963 | + if ($container_name_target == "") { |
| 964 | + $this->error_str = "Container name target not set."; |
| 965 | + return 0; |
| 966 | + } |
| 967 | + |
| 968 | + if ($container_name_target != "0" and !isset($container_name_target)) { |
| 969 | + $this->error_str = "Container name target not set."; |
| 970 | + return 0; |
| 971 | + } |
| 972 | + |
| 973 | + $conn_type = "COPY"; |
| 974 | + |
| 975 | + $url_path = $this->_make_path("STORAGE", $container_name_source, rawurlencode($src_obj_name)); |
| 976 | + $destination = rawurlencode($container_name_target."/".$dest_obj_name); |
| 977 | + |
| 978 | + $hdrs = self::_process_headers($metadata, $headers); |
| 979 | + $hdrs[DESTINATION] = $destination; |
| 980 | + |
| 981 | + $return_code = $this->_send_request($conn_type,$url_path,$hdrs,"COPY"); |
| 982 | + switch ($return_code) { |
| 983 | + case 201: |
| 984 | + break; |
| 985 | + case 0: |
| 986 | + $this->error_str .= ": Failed to obtain valid HTTP response."; |
| 987 | + $return_code = 0; |
| 988 | + break; |
| 989 | + case 404: |
| 990 | + $this->error_str = "Specified container/object did not exist."; |
| 991 | + break; |
| 992 | + default: |
| 993 | + $this->error_str = "Unexpected HTTP return code: $return_code."; |
| 994 | + } |
| 995 | + return $return_code; |
| 996 | + } |
| 997 | + |
928 | 998 | # DELETE /v1/Account/Container/Object |
929 | 999 | # |
930 | 1000 | function delete_object($container_name, $object_name) |
— | — | @@ -945,14 +1015,17 @@ |
946 | 1016 | |
947 | 1017 | $url_path = $this->_make_path("STORAGE", $container_name,$object_name); |
948 | 1018 | $return_code = $this->_send_request("DEL_POST",$url_path,NULL,"DELETE"); |
949 | | - if (!$return_code) { |
| 1019 | + switch ($return_code) { |
| 1020 | + case 204: |
| 1021 | + break; |
| 1022 | + case 0: |
950 | 1023 | $this->error_str .= ": Failed to obtain valid HTTP response."; |
951 | | - return 0; |
952 | | - } |
953 | | - if ($return_code == 404) { |
| 1024 | + $return_code = 0; |
| 1025 | + break; |
| 1026 | + case 404: |
954 | 1027 | $this->error_str = "Specified container did not exist to delete."; |
955 | | - } |
956 | | - if ($return_code != 204) { |
| 1028 | + break; |
| 1029 | + default: |
957 | 1030 | $this->error_str = "Unexpected HTTP return code: $return_code."; |
958 | 1031 | } |
959 | 1032 | return $return_code; |
— | — | @@ -1011,112 +1084,85 @@ |
1012 | 1085 | |
1013 | 1086 | private function _header_cb($ch, $header) |
1014 | 1087 | { |
1015 | | - preg_match("/^HTTP\/1\.[01] (\d{3}) (.*)/", $header, $matches); |
1016 | | - if (isset($matches[1])) { |
1017 | | - $this->response_status = $matches[1]; |
1018 | | - } |
1019 | | - if (isset($matches[2])) { |
1020 | | - $this->response_reason = $matches[2]; |
1021 | | - } |
1022 | | - if (stripos($header, CDN_ENABLED) === 0) { |
1023 | | - $val = trim(substr($header, strlen(CDN_ENABLED)+1)); |
1024 | | - if (strtolower($val) == "true") { |
1025 | | - $this->_cdn_enabled = True; |
1026 | | - } elseif (strtolower($val) == "false") { |
1027 | | - $this->_cdn_enabled = False; |
1028 | | - } else { |
1029 | | - $this->_cdn_enabled = NULL; |
1030 | | - } |
1031 | | - return strlen($header); |
1032 | | - } |
1033 | | - if (stripos($header, CDN_URI) === 0) { |
1034 | | - $this->_cdn_uri = trim(substr($header, strlen(CDN_URI)+1)); |
1035 | | - return strlen($header); |
1036 | | - } |
1037 | | - if (stripos($header, CDN_SSL_URI) === 0) { |
1038 | | - $this->_cdn_ssl_uri = trim(substr($header, strlen(CDN_SSL_URI)+1)); |
1039 | | - return strlen($header); |
1040 | | - } |
1041 | | - if (stripos($header, CDN_TTL) === 0) { |
1042 | | - $this->_cdn_ttl = trim(substr($header, strlen(CDN_TTL)+1))+0; |
1043 | | - return strlen($header); |
1044 | | - } |
1045 | | - if (stripos($header, MANIFEST_HEADER) === 0) { |
1046 | | - $this->_obj_manifest = trim(substr($header, strlen(MANIFEST_HEADER)+1)); |
1047 | | - return strlen($header); |
1048 | | - } |
1049 | | - if (stripos($header, CDN_LOG_RETENTION) === 0) { |
1050 | | - $this->_cdn_log_retention = |
1051 | | - trim(substr($header, strlen(CDN_LOG_RETENTION)+1)) == "True" ? True : False; |
1052 | | - return strlen($header); |
1053 | | - } |
| 1088 | + $header_len = strlen($header); |
1054 | 1089 | |
1055 | | - if (stripos($header, CDN_ACL_USER_AGENT) === 0) { |
1056 | | - $this->_cdn_acl_user_agent = |
1057 | | - trim(substr($header, strlen(CDN_ACL_USER_AGENT)+1)); |
1058 | | - return strlen($header); |
| 1090 | + if (preg_match("/^(HTTP\/1\.[01]) (\d{3}) (.*)/", $header, $matches)) { |
| 1091 | + $this->response_status = $matches[2]; |
| 1092 | + $this->response_reason = $matches[3]; |
| 1093 | + return $header_len; |
1059 | 1094 | } |
1060 | 1095 | |
1061 | | - if (stripos($header, CDN_ACL_REFERRER) === 0) { |
1062 | | - $this->_cdn_acl_referrer = |
1063 | | - trim(substr($header, strlen(CDN_ACL_REFERRER)+1)); |
1064 | | - return strlen($header); |
| 1096 | + if (strpos($header, ":") === False) |
| 1097 | + return $header_len; |
| 1098 | + list($name, $value) = explode(":", $header, 2); |
| 1099 | + $value = trim($value); |
| 1100 | + |
| 1101 | + switch (strtolower($name)) { |
| 1102 | + case strtolower(CDN_ENABLED): |
| 1103 | + $this->_cdn_enabled = strtolower($value) == "true"; |
| 1104 | + break; |
| 1105 | + case strtolower(CDN_URI): |
| 1106 | + $this->_cdn_uri = $value; |
| 1107 | + break; |
| 1108 | + case strtolower(CDN_SSL_URI): |
| 1109 | + $this->_cdn_ssl_uri = $value; |
| 1110 | + break; |
| 1111 | + case strtolower(CDN_STREAMING_URI): |
| 1112 | + $this->_cdn_streaming_uri = $value; |
| 1113 | + break; |
| 1114 | + case strtolower(CDN_TTL): |
| 1115 | + $this->_cdn_ttl = $value; |
| 1116 | + break; |
| 1117 | + case strtolower(MANIFEST_HEADER): |
| 1118 | + $this->_obj_manifest = $value; |
| 1119 | + break; |
| 1120 | + case strtolower(CDN_LOG_RETENTION): |
| 1121 | + $this->_cdn_log_retention = strtolower($value) == "true"; |
| 1122 | + break; |
| 1123 | + case strtolower(CDN_ACL_USER_AGENT): |
| 1124 | + $this->_cdn_acl_user_agent = $value; |
| 1125 | + break; |
| 1126 | + case strtolower(CDN_ACL_REFERRER): |
| 1127 | + $this->_cdn_acl_referrer = $value; |
| 1128 | + break; |
| 1129 | + case strtolower(ACCOUNT_CONTAINER_COUNT): |
| 1130 | + $this->_account_container_count = (float)$value+0; |
| 1131 | + break; |
| 1132 | + case strtolower(ACCOUNT_BYTES_USED): |
| 1133 | + $this->_account_bytes_used = (float)$value+0; |
| 1134 | + break; |
| 1135 | + case strtolower(CONTAINER_OBJ_COUNT): |
| 1136 | + $this->_container_object_count = (float)$value+0; |
| 1137 | + break; |
| 1138 | + case strtolower(CONTAINER_BYTES_USED): |
| 1139 | + $this->_container_bytes_used = (float)$value+0; |
| 1140 | + break; |
| 1141 | + case strtolower(ETAG_HEADER): |
| 1142 | + $this->_obj_etag = $value; |
| 1143 | + break; |
| 1144 | + case strtolower(LAST_MODIFIED_HEADER): |
| 1145 | + $this->_obj_last_modified = $value; |
| 1146 | + break; |
| 1147 | + case strtolower(CONTENT_TYPE_HEADER): |
| 1148 | + $this->_obj_content_type = $value; |
| 1149 | + break; |
| 1150 | + case strtolower(CONTENT_LENGTH_HEADER): |
| 1151 | + $this->_obj_content_length = (float)$value+0; |
| 1152 | + break; |
| 1153 | + case strtolower(ORIGIN_HEADER): |
| 1154 | + $this->_obj_headers[ORIGIN_HEADER] = $value; |
| 1155 | + break; |
| 1156 | + default: |
| 1157 | + if (strncasecmp($name, METADATA_HEADER_PREFIX, strlen(METADATA_HEADER_PREFIX)) == 0) { |
| 1158 | + $name = substr($name, strlen(METADATA_HEADER_PREFIX)); |
| 1159 | + $this->_obj_metadata[$name] = $value; |
| 1160 | + } |
| 1161 | + elseif ((strncasecmp($name, CONTENT_HEADER_PREFIX, strlen(CONTENT_HEADER_PREFIX)) == 0) || |
| 1162 | + (strncasecmp($name, ACCESS_CONTROL_HEADER_PREFIX, strlen(ACCESS_CONTROL_HEADER_PREFIX)) == 0)) { |
| 1163 | + $this->_obj_headers[$name] = $value; |
| 1164 | + } |
1065 | 1165 | } |
1066 | | - |
1067 | | - if (stripos($header, ACCOUNT_CONTAINER_COUNT) === 0) { |
1068 | | - $this->_account_container_count = (float) trim(substr($header, |
1069 | | - strlen(ACCOUNT_CONTAINER_COUNT)+1))+0; |
1070 | | - return strlen($header); |
1071 | | - } |
1072 | | - if (stripos($header, ACCOUNT_BYTES_USED) === 0) { |
1073 | | - $this->_account_bytes_used = (float) trim(substr($header, |
1074 | | - strlen(ACCOUNT_BYTES_USED)+1))+0; |
1075 | | - return strlen($header); |
1076 | | - } |
1077 | | - if (stripos($header, CONTAINER_OBJ_COUNT) === 0) { |
1078 | | - $this->_container_object_count = (float) trim(substr($header, |
1079 | | - strlen(CONTAINER_OBJ_COUNT)+1))+0; |
1080 | | - return strlen($header); |
1081 | | - } |
1082 | | - if (stripos($header, CONTAINER_BYTES_USED) === 0) { |
1083 | | - $this->_container_bytes_used = (float) trim(substr($header, |
1084 | | - strlen(CONTAINER_BYTES_USED)+1))+0; |
1085 | | - return strlen($header); |
1086 | | - } |
1087 | | - if (stripos($header, METADATA_HEADER) === 0) { |
1088 | | - # $header => X-Object-Meta-Foo: bar baz |
1089 | | - $temp = substr($header, strlen(METADATA_HEADER)); |
1090 | | - # $temp => Foo: bar baz |
1091 | | - $parts = explode(":", $temp); |
1092 | | - # $parts[0] => Foo |
1093 | | - $val = substr(strstr($temp, ":"), 1); |
1094 | | - # $val => bar baz |
1095 | | - $this->_obj_metadata[$parts[0]] = trim($val); |
1096 | | - return strlen($header); |
1097 | | - } |
1098 | | - if (stripos($header, "ETag:") === 0) { |
1099 | | - # $header => ETag: abc123def456... |
1100 | | - $val = substr(strstr($header, ":"), 1); |
1101 | | - # $val => abc123def456... |
1102 | | - $this->_obj_etag = trim($val); |
1103 | | - return strlen($header); |
1104 | | - } |
1105 | | - if (stripos($header, "Last-Modified:") === 0) { |
1106 | | - $val = substr(strstr($header, ":"), 1); |
1107 | | - $this->_obj_last_modified = trim($val); |
1108 | | - return strlen($header); |
1109 | | - } |
1110 | | - if (stripos($header, "Content-Type:") === 0) { |
1111 | | - $val = substr(strstr($header, ":"), 1); |
1112 | | - $this->_obj_content_type = trim($val); |
1113 | | - return strlen($header); |
1114 | | - } |
1115 | | - if (stripos($header, "Content-Length:") === 0) { |
1116 | | - $val = substr(strstr($header, ":"), 1); |
1117 | | - $this->_obj_content_length = (float) trim($val)+0; |
1118 | | - return strlen($header); |
1119 | | - } |
1120 | | - return strlen($header); |
| 1166 | + return $header_len; |
1121 | 1167 | } |
1122 | 1168 | |
1123 | 1169 | private function _read_cb($ch, $fd, $length) |
— | — | @@ -1183,28 +1229,23 @@ |
1184 | 1230 | if (is_array($hdrs)) { |
1185 | 1231 | foreach ($hdrs as $h => $v) { |
1186 | 1232 | if (is_int($h)) { |
1187 | | - $parts = explode(":", $v); |
1188 | | - $header = $parts[0]; |
1189 | | - $value = trim(substr(strstr($v, ":"), 1)); |
1190 | | - } else { |
1191 | | - $header = $h; |
1192 | | - $value = trim($v); |
| 1233 | + list($h, $v) = explode(":", $v, 2); |
1193 | 1234 | } |
1194 | 1235 | |
1195 | | - if (stripos($header, AUTH_TOKEN) === 0) { |
| 1236 | + if (strncasecmp($h, AUTH_TOKEN, strlen(AUTH_TOKEN)) === 0) { |
1196 | 1237 | $has_stoken = True; |
1197 | 1238 | } |
1198 | | - if (stripos($header, "user-agent") === 0) { |
| 1239 | + if (strncasecmp($h, USER_AGENT_HEADER, strlen(USER_AGENT_HEADER)) === 0) { |
1199 | 1240 | $has_uagent = True; |
1200 | 1241 | } |
1201 | | - $new_headers[] = $header . ": " . $value; |
| 1242 | + $new_headers[] = $h . ": " . trim($v); |
1202 | 1243 | } |
1203 | 1244 | } |
1204 | 1245 | if (!$has_stoken) { |
1205 | 1246 | $new_headers[] = AUTH_TOKEN . ": " . $this->auth_token; |
1206 | 1247 | } |
1207 | 1248 | if (!$has_uagent) { |
1208 | | - $new_headers[] = "User-Agent: " . USER_AGENT; |
| 1249 | + $new_headers[] = USER_AGENT_HEADER . ": " . USER_AGENT; |
1209 | 1250 | } |
1210 | 1251 | return $new_headers; |
1211 | 1252 | } |
— | — | @@ -1228,7 +1269,7 @@ |
1229 | 1270 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, True); |
1230 | 1271 | curl_setopt($ch, CURLOPT_CAINFO, $this->cabundle_path); |
1231 | 1272 | } |
1232 | | - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, False); |
| 1273 | + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, True); |
1233 | 1274 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); |
1234 | 1275 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); |
1235 | 1276 | curl_setopt($ch, CURLOPT_MAXREDIRS, 4); |
— | — | @@ -1256,6 +1297,9 @@ |
1257 | 1298 | if ($conn_type == "DEL_POST") { |
1258 | 1299 | curl_setopt($ch, CURLOPT_NOBODY, 1); |
1259 | 1300 | } |
| 1301 | + if ($conn_type == "COPY") { |
| 1302 | + curl_setopt($ch, CURLOPT_NOBODY, 1); |
| 1303 | + } |
1260 | 1304 | $this->connections[$conn_type] = $ch; |
1261 | 1305 | return; |
1262 | 1306 | } |
— | — | @@ -1274,7 +1318,9 @@ |
1275 | 1319 | $this->_obj_content_length = NULL; |
1276 | 1320 | $this->_obj_metadata = array(); |
1277 | 1321 | $this->_obj_manifest = NULL; |
| 1322 | + $this->_obj_headers = NULL; |
1278 | 1323 | $this->_obj_write_string = ""; |
| 1324 | + $this->_cdn_streaming_uri = NULL; |
1279 | 1325 | $this->_cdn_enabled = NULL; |
1280 | 1326 | $this->_cdn_ssl_uri = NULL; |
1281 | 1327 | $this->_cdn_uri = NULL; |
— | — | @@ -1306,30 +1352,71 @@ |
1307 | 1353 | return implode("/",$path); |
1308 | 1354 | } |
1309 | 1355 | |
1310 | | - private function _metadata_headers(&$obj) |
| 1356 | + private function _headers(&$obj) |
1311 | 1357 | { |
1312 | | - $hdrs = array(); |
| 1358 | + $hdrs = self::_process_headers($obj->metadata, $obj->headers); |
1313 | 1359 | if ($obj->manifest) |
1314 | 1360 | $hdrs[MANIFEST_HEADER] = $obj->manifest; |
1315 | | - foreach ($obj->metadata as $k => $v) { |
1316 | | - if (strpos($k,":") !== False) { |
1317 | | - throw new SyntaxException( |
1318 | | - "Metadata keys cannot contain a ':' character."); |
1319 | | - } |
1320 | | - $k = trim($k); |
1321 | | - $key = sprintf("%s%s", METADATA_HEADER, $k); |
1322 | | - if (!array_key_exists($key, $hdrs)) { |
1323 | | - if (strlen($k) > 128 || strlen($v) > 256) { |
1324 | | - $this->error_str = "Metadata key or value exceeds "; |
1325 | | - $this->error_str .= "maximum length: ($k: $v)"; |
1326 | | - return 0; |
| 1361 | + |
| 1362 | + return $hdrs; |
| 1363 | + } |
| 1364 | + |
| 1365 | + private function _process_headers($metadata=null, $headers=null) |
| 1366 | + { |
| 1367 | + $rules = array( |
| 1368 | + array( |
| 1369 | + 'prefix' => METADATA_HEADER_PREFIX, |
| 1370 | + ), |
| 1371 | + array( |
| 1372 | + 'prefix' => '', |
| 1373 | + 'filter' => array( # key order is important, first match decides |
| 1374 | + CONTENT_TYPE_HEADER => false, |
| 1375 | + CONTENT_LENGTH_HEADER => false, |
| 1376 | + CONTENT_HEADER_PREFIX => true, |
| 1377 | + ACCESS_CONTROL_HEADER_PREFIX => true, |
| 1378 | + ORIGIN_HEADER => true, |
| 1379 | + ), |
| 1380 | + ), |
| 1381 | + ); |
| 1382 | + |
| 1383 | + $hdrs = array(); |
| 1384 | + $argc = func_num_args(); |
| 1385 | + $argv = func_get_args(); |
| 1386 | + for ($argi = 0; $argi < $argc; $argi++) { |
| 1387 | + if(!is_array($argv[$argi])) continue; |
| 1388 | + |
| 1389 | + $rule = $rules[$argi]; |
| 1390 | + foreach ($argv[$argi] as $k => $v) { |
| 1391 | + $k = trim($k); |
| 1392 | + $v = trim($v); |
| 1393 | + if (strpos($k, ":") !== False) throw new SyntaxException( |
| 1394 | + "Header names cannot contain a ':' character."); |
| 1395 | + |
| 1396 | + if (array_key_exists('filter', $rule)) { |
| 1397 | + $result = null; |
| 1398 | + foreach ($rule['filter'] as $p => $f) { |
| 1399 | + if (strncasecmp($k, $p, strlen($p)) == 0) { |
| 1400 | + $result = $f; |
| 1401 | + break; |
| 1402 | + } |
| 1403 | + } |
| 1404 | + if (!$result) throw new SyntaxException(sprintf( |
| 1405 | + "Header name %s is not allowed", $k)); |
1327 | 1406 | } |
1328 | | - $hdrs[] = sprintf("%s%s: %s", METADATA_HEADER, $k, trim($v)); |
| 1407 | + |
| 1408 | + $k = $rule['prefix'] . $k; |
| 1409 | + if (strlen($k) > MAX_HEADER_NAME_LEN || strlen($v) > MAX_HEADER_VALUE_LEN) |
| 1410 | + throw new SyntaxException(sprintf( |
| 1411 | + "Header %s exceeds maximum length: %d/%d", |
| 1412 | + $k, strlen($k), strlen($v))); |
| 1413 | + |
| 1414 | + $hdrs[$k] = $v; |
1329 | 1415 | } |
1330 | 1416 | } |
| 1417 | + |
1331 | 1418 | return $hdrs; |
1332 | 1419 | } |
1333 | | - |
| 1420 | + |
1334 | 1421 | private function _send_request($conn_type, $url_path, $hdrs=NULL, $method="GET", $force_new=False) |
1335 | 1422 | { |
1336 | 1423 | $this->_init($conn_type, $force_new); |
— | — | @@ -1342,6 +1429,10 @@ |
1343 | 1430 | ); |
1344 | 1431 | |
1345 | 1432 | switch ($method) { |
| 1433 | + case "COPY": |
| 1434 | + curl_setopt($this->connections[$conn_type], |
| 1435 | + CURLOPT_CUSTOMREQUEST, "COPY"); |
| 1436 | + break; |
1346 | 1437 | case "DELETE": |
1347 | 1438 | curl_setopt($this->connections[$conn_type], |
1348 | 1439 | CURLOPT_CUSTOMREQUEST, "DELETE"); |
— | — | @@ -1394,4 +1485,4 @@ |
1395 | 1486 | * c-hanging-comment-ender-p: nil |
1396 | 1487 | * End: |
1397 | 1488 | */ |
1398 | | -?> |
| 1489 | +?> |
\ No newline at end of file |