W3TCCdnEngine_RackSpaceCloudFiles

Rackspace Cloud Files CDN engine.

Defined (1)

The class is defined in the following location(s).

/CdnEngine_RackSpaceCloudFiles.php  
  1. class CdnEngine_RackSpaceCloudFiles extends CdnEngine_Base { 
  2. private $_access_state; 
  3. private $_container; 
  4. private $_api_files; 
  5. private $_api_cdn; 
  6.  
  7.  
  8.  
  9. function __construct( $config = array() ) { 
  10. $config = array_merge( array( 
  11. 'user_name' => '',  
  12. 'api_key' => '',  
  13. 'region' => '',  
  14. 'container' => '',  
  15. 'cname' => array(),  
  16. 'access_state' => '' 
  17. ), $config ); 
  18.  
  19. $this->_container = $config['container']; 
  20. $this->_new_access_state_callback = $config['new_access_state_callback']; 
  21.  
  22. // init access state 
  23. $this->_access_state = @json_decode( $config['access_state'], true ); 
  24. if ( !is_array( $this->_access_state ) ) 
  25. $this->_access_state = array(); 
  26. $this->_access_state = array_merge( array( 
  27. 'access_token' => '',  
  28. 'access_region_descriptor' => array(),  
  29. 'host_http' => '',  
  30. 'host_https' => '' 
  31. ), $this->_access_state ); 
  32.  
  33. parent::__construct( $config ); 
  34. $this->_create_api( 
  35. array( $this, '_on_new_access_requested_api_files' ),  
  36. array( $this, '_on_new_access_requested_api_cdn' ) ); 
  37.  
  38.  
  39.  
  40. private function _create_api( $new_access_required_callback_api_files,  
  41. $new_access_required_callback_api_cdn ) { 
  42. $this->_api_files = new Cdn_RackSpace_Api_CloudFiles( array( 
  43. 'access_token' => $this->_access_state['access_token'],  
  44. 'access_region_descriptor' => $this->_access_state['access_region_descriptor'],  
  45. 'new_access_required' => $new_access_required_callback_api_files ) ); 
  46.  
  47. $this->_api_cdn = new Cdn_RackSpace_Api_CloudFilesCdn( array( 
  48. 'access_token' => $this->_access_state['access_token'],  
  49. 'access_region_descriptor' => $this->_access_state['access_region_descriptor'],  
  50. 'new_access_required' => $new_access_required_callback_api_cdn ) ); 
  51.  
  52.  
  53.  
  54. /** 
  55. * Called when new access token issued by api objects 
  56. */ 
  57. public function _on_new_access_requested_api_files() { 
  58. $this->_on_new_access_requested(); 
  59. return $this->_api_files; 
  60.  
  61.  
  62.  
  63. /** 
  64. * Called when new access token issued by api objects 
  65. */ 
  66. public function _on_new_access_requested_api_cdn() { 
  67. $this->_on_new_access_requested(); 
  68. return $this->_api_cdn; 
  69.  
  70.  
  71.  
  72. private function _on_new_access_requested() { 
  73. $r = Cdn_RackSpace_Api_Tokens::authenticate( $this->_config['user_name'],  
  74. $this->_config['api_key'] ); 
  75. if ( !isset( $r['access_token'] ) || !isset( $r['services'] ) ) 
  76. throw new \Exception( 'Authentication failed' ); 
  77. $r['regions'] = Cdn_RackSpace_Api_Tokens::cloudfiles_services_by_region( 
  78. $r['services'] ); 
  79.  
  80. if ( !isset( $r['regions'][$this->_config['region']] ) ) 
  81. throw new \Exception( 'Region ' . $this->_config['region'] . ' not found' ); 
  82.  
  83. $this->_access_state['access_token'] = $r['access_token']; 
  84. $this->_access_state['access_region_descriptor'] = 
  85. $r['regions'][$this->_config['region']]; 
  86.  
  87. $this->_create_api( 
  88. array( $this, '_on_new_access_requested_second_time' ),  
  89. array( $this, '_on_new_access_requested_second_time' ) ); 
  90.  
  91. $c = $this->_api_cdn->container_get( $this->_config['container'] ); 
  92.  
  93. $this->_access_state['host_http'] = substr( $c['x-cdn-uri'], 7 ); 
  94. $this->_access_state['host_https'] = substr( $c['x-cdn-ssl-uri'], 8 ); 
  95.  
  96. call_user_func( $this->_new_access_state_callback,  
  97. json_encode( $this->_access_state ) ); 
  98.  
  99.  
  100.  
  101. private function _on_new_access_requested_second_time() { 
  102. throw new \Exception( 'Authentication failed' ); 
  103.  
  104.  
  105.  
  106. /** 
  107. * Formats URL 
  108. */ 
  109. function _format_url( $path ) { 
  110. $domain = $this->get_domain( $path ); 
  111.  
  112. if ( $domain ) { 
  113. $scheme = $this->_get_scheme(); 
  114.  
  115. // it does not support '+', requires '%2B' 
  116. $path = str_replace( '+', '%2B', $path ); 
  117. $url = sprintf( '%s://%s/%s', $scheme, $domain, $path ); 
  118.  
  119. return $url; 
  120.  
  121. return false; 
  122.  
  123. /** 
  124. * Uploads files to CDN 
  125. * @param array $files 
  126. * @param array $results 
  127. * @param boolean $force_rewrite 
  128. * @return boolean 
  129. */ 
  130. function upload( $files, &$results, $force_rewrite = false,  
  131. $timeout_time = NULL ) { 
  132. foreach ( $files as $file ) { 
  133. if ( !is_null( $timeout_time ) && time() > $timeout_time ) 
  134. break; 
  135.  
  136. $local_path = $file['local_path']; 
  137. $remote_path = $file['remote_path']; 
  138.  
  139. if ( !file_exists( $local_path ) ) { 
  140. $results[] = $this->_get_result( $local_path, $remote_path,  
  141. W3TC_CDN_RESULT_ERROR, 'Source file not found.', $file ); 
  142.  
  143. continue; 
  144.  
  145. $file_content = file_get_contents( $local_path ); 
  146.  
  147. $do_write = true; 
  148.  
  149. // rewrite is optional, check md5 
  150. if ( !$force_rewrite ) { 
  151. $object_meta = null; 
  152.  
  153. try { 
  154. $object_meta = $this->_api_files->object_get_meta_or_null( 
  155. $this->_container, $remote_path ); 
  156. } catch ( \Exception $exception ) { 
  157. $results[] = $this->_get_result( $local_path, $remote_path,  
  158. W3TC_CDN_RESULT_ERROR,  
  159. sprintf( 'Unable to check object (%s).', $exception->getMessage() ),  
  160. $file ); 
  161. $do_write = false; 
  162.  
  163. if ( is_array( $object_meta ) && isset( $object_meta['etag'] ) ) { 
  164. $md5_actual = md5( $file_content ); 
  165.  
  166. if ( $md5_actual == $object_meta['etag'] ) { 
  167. $results[] = $this->_get_result( $local_path,  
  168. $remote_path, W3TC_CDN_RESULT_OK,  
  169. 'Object up-to-date.', $file ); 
  170. $do_write = false; 
  171.  
  172. if ( $do_write ) { 
  173. try { 
  174. $this->_api_files->object_create( array( 
  175. 'container' => $this->_container,  
  176. 'name' => $remote_path,  
  177. 'content_type' => Util_Mime::get_mime_type( $local_path ),  
  178. 'content' => $file_content ) ); 
  179. $results[] = $this->_get_result( $local_path, $remote_path,  
  180. W3TC_CDN_RESULT_OK, 'OK', $file ); 
  181. } catch ( \Exception $exception ) { 
  182. $results[] = $this->_get_result( $local_path, $remote_path,  
  183. W3TC_CDN_RESULT_ERROR,  
  184. sprintf( 'Unable to create object (%s).', $exception->getMessage() ),  
  185. $file ); 
  186.  
  187. return !$this->_is_error( $results ); 
  188.  
  189. /** 
  190. * Deletes files from CDN 
  191. * @param array $files 
  192. * @param array $results 
  193. * @return boolean 
  194. */ 
  195. function delete( $files, &$results ) { 
  196. foreach ( $files as $file ) { 
  197. $local_path = $file['local_path']; 
  198. $remote_path = $file['remote_path']; 
  199.  
  200. try { 
  201. $this->_api_files->object_delete( $this->_container, $remote_path ); 
  202. $results[] = $this->_get_result( $local_path, $remote_path,  
  203. W3TC_CDN_RESULT_OK, 'OK', $file ); 
  204. } catch ( \Exception $exception ) { 
  205. $results[] = $this->_get_result( $local_path, $remote_path,  
  206. W3TC_CDN_RESULT_ERROR,  
  207. sprintf( 'Unable to delete object (%s).',  
  208. $exception->getMessage() ),  
  209. $file ); 
  210.  
  211. return !$this->_is_error( $results ); 
  212.  
  213. /** 
  214. * Test CDN connection 
  215. * @param string $error 
  216. * @return boolean 
  217. */ 
  218. function test( &$error ) { 
  219. $filename = 'test_rscf_' . md5( time() ); 
  220.  
  221. try { 
  222. $object = $this->_api_files->object_create( array( 
  223. 'container' => $this->_container,  
  224. 'name' => $filename,  
  225. 'content_type' => 'text/plain',  
  226. 'content' => $filename ) ); 
  227. } catch ( \Exception $exception ) { 
  228. $error = sprintf( 'Unable to write object (%s).', $exception->getMessage() ); 
  229. return false; 
  230.  
  231. $result = true; 
  232. try { 
  233. $r = wp_remote_get( 'http://' . $this->get_host_http() . '/' . $filename ); 
  234.  
  235. if ( $r['body'] != $filename ) { 
  236. $error = 'Failed to retrieve object after storing.'; 
  237. $result = false; 
  238. } catch ( \Exception $exception ) { 
  239. $error = sprintf( 'Unable to read object (%s).', $exception->getMessage() ); 
  240. $result = false; 
  241.  
  242. try { 
  243. $this->_api_files->object_delete( $this->_container, $filename ); 
  244. } catch ( \Exception $exception ) { 
  245. $error = sprintf( 'Unable to delete object (%s).', $exception->getMessage() ); 
  246. $result = false; 
  247.  
  248. return $result; 
  249.  
  250. /** 
  251. * Returns CDN domain 
  252. * @return array 
  253. */ 
  254. function get_domains() { 
  255. if ( Util_Environment::is_https() ) { 
  256. if ( !empty( $this->_config['cname'] ) ) { 
  257. return (array) $this->_config['cname']; 
  258.  
  259. return array( $this->get_host_https() ); 
  260. } else { 
  261. if ( !empty( $this->_config['cname'] ) ) { 
  262. return (array) $this->_config['cname']; 
  263.  
  264. return array( $this->get_host_http() ); 
  265.  
  266. /** 
  267. * Returns VIA string 
  268. * @return string 
  269. */ 
  270. function get_via() { 
  271. return sprintf( 'Rackspace Cloud Files: %s', parent::get_via() ); 
  272.  
  273.  
  274.  
  275. public function get_host_http() { 
  276. if ( empty( $this->_access_state['host_http'] ) ) 
  277. $this->_on_new_access_requested(); 
  278.  
  279. return $this->_access_state['host_http']; 
  280.  
  281.  
  282.  
  283. public function get_host_https() { 
  284. if ( empty( $this->_access_state['host_https'] ) ) 
  285. $this->_on_new_access_requested(); 
  286.  
  287. return $this->_access_state['host_https'];